diff --git a/.github/workflows/e2e_nightly_upgrade.yml b/.github/workflows/e2e_nightly_upgrade.yml index 9b96f76b6..71b3abcfe 100755 --- a/.github/workflows/e2e_nightly_upgrade.yml +++ b/.github/workflows/e2e_nightly_upgrade.yml @@ -16,12 +16,12 @@ jobs: runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: 12 + node-version: 16 - name: Install dependencies shell: bash @@ -61,7 +61,7 @@ jobs: steps: # Setup PrestaShop and Install Autoupgrade module - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - run: | cp -r .github .github_dev @@ -94,9 +94,9 @@ jobs: # Install Module with user interface - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: 12 + node-version: 16 - name: Install dependencies run: npm install @@ -162,7 +162,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - uses: actions/download-artifact@v2 name: Download reports @@ -173,7 +173,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v2 with: - node-version: 12 + node-version: 16 - name: Install dependencies shell: bash @@ -206,7 +206,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - uses: actions/download-artifact@v2 name: Download report diff --git a/.github/workflows/nightly_upgrade.yml b/.github/workflows/nightly_upgrade.yml index 637b60dee..9d058ac60 100644 --- a/.github/workflows/nightly_upgrade.yml +++ b/.github/workflows/nightly_upgrade.yml @@ -8,7 +8,7 @@ jobs: name: Set up matrix runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - uses: shivammathur/setup-php@v2 with: php-version: 7.4 @@ -22,12 +22,10 @@ jobs: strategy: fail-fast: false matrix: - from: ['8.0.4', '1.7.6.9', '1.7.7.0', '1.6.1.24'] + from: ['8.0.4', '1.7.6.9', '1.7.7.0'] ps-versions: ${{ fromJson(needs.get_matrix.outputs.matrix) }} branch: ['dev', 'master'] exclude: - - from: '1.6.1.24' - ps-versions: {branch: 'develop'} - from: '1.7.6.9' ps-versions: {branch: 'develop'} - from: '1.7.7.0' @@ -39,7 +37,7 @@ jobs: outputs: result: ${{ steps.export-result.outputs.result }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - if: ${{ matrix.branch != 'dev' }} run: | cp -r .github .github_dev @@ -76,7 +74,7 @@ jobs: matrix: ps-versions: ${{ fromJson(needs.get_matrix.outputs.matrix) }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - uses: actions/download-artifact@v2 with: path: ./artifacts/ diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 983d1620a..0f1125fad 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v3.1.0 - name: PHP syntax checker 5.6 uses: prestashop/github-action-php-lint/5.6@master @@ -50,10 +50,10 @@ jobs: php-version: '5.6' - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v3.1.0 - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: vendor key: php-${{ hashFiles('composer.lock') }} @@ -76,7 +76,7 @@ jobs: with: php-version: ${{ matrix.php-versions }} extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv, ext-zip - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 with: fetch-depth: 0 @@ -89,21 +89,21 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - presta-versions: ['1.6.1.18', '1.7.2.5', '1.7.3.4', '1.7.4.4', '1.7.5.1', '1.7.6', '1.7.7', '1.7.8', '8.0.0', 'latest'] + presta-versions: ['1.7.2.5', '1.7.3.4', '1.7.4.4', '1.7.5.1', '1.7.6', '1.7.7', '1.7.8', '8.0.0', 'latest'] steps: - name: Checkout - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v3.1.0 # Add vendor folder in cache to make next builds faster - name: Cache vendor folder - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: vendor key: php-${{ hashFiles('composer.lock') }} # Add composer local folder in cache to make next builds faster - name: Cache composer folder - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ~/.composer/cache key: php-composer-cache diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml index bc5bf1adb..97a00f1ab 100644 --- a/.github/workflows/upgrade.yml +++ b/.github/workflows/upgrade.yml @@ -4,14 +4,14 @@ jobs: upgrade: strategy: matrix: - from: ['1.6.1.11', '1.7.6.9', '1.7.6.1', '1.7.7.0'] + from: ['1.7.6.9', '1.7.6.1', '1.7.7.0'] ps-versions: - channel: minor - channel: major runs-on: ubuntu-latest name: Upgrade steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3.1.0 - name: Composer Install run: composer install - name: Upgrade & Rollback diff --git a/AdminSelfUpgrade.php b/AdminSelfUpgrade.php index 045980143..a65355dee 100755 --- a/AdminSelfUpgrade.php +++ b/AdminSelfUpgrade.php @@ -522,21 +522,6 @@ public function display() parent::display(); } - /** - * @deprecated - * Method allowing errors on very old tabs to be displayed. - * On the next major of this module, use an admin controller and get rid of this. - * - * This method is called by functions.php available in the admin root folder. - */ - public function displayErrors() - { - if (empty($this->_errors)) { - return; - } - echo implode(' - ', $this->_errors); - } - /** * Adapter for trans calls, existing only on PS 1.7. * Making them available for PS 1.6 as well. diff --git a/ajax-upgradetabconfig.php b/ajax-upgradetabconfig.php index 35c4bbfab..139033ffd 100644 --- a/ajax-upgradetabconfig.php +++ b/ajax-upgradetabconfig.php @@ -63,7 +63,6 @@ function autoupgrade_init_container($callerFilePath) } define('AUTOUPGRADE_MODULE_DIR', _PS_MODULE_DIR_ . 'autoupgrade' . DIRECTORY_SEPARATOR); - require_once AUTOUPGRADE_MODULE_DIR . 'functions.php'; require_once AUTOUPGRADE_MODULE_DIR . 'vendor/autoload.php'; $dir = Tools14::safeOutput(Tools14::getValue('dir')); diff --git a/autoupgrade.php b/autoupgrade.php index d86da025b..7c13cad1b 100644 --- a/autoupgrade.php +++ b/autoupgrade.php @@ -36,7 +36,7 @@ public function __construct() $this->name = 'autoupgrade'; $this->tab = 'administration'; $this->author = 'PrestaShop'; - $this->version = '4.16.4'; + $this->version = '5.0.0'; $this->need_instance = 1; $this->bootstrap = true; @@ -159,7 +159,7 @@ public function hookDashboardZoneOne($params) public function getContent() { global $cookie; - header('Location: index.php?tab=AdminSelfUpgrade&token=' . md5(pSQL(_COOKIE_KEY_ . 'AdminSelfUpgrade' . (int) Tab::getIdFromClassName('AdminSelfUpgrade') . (int) $cookie->id_employee))); + header('Location: index.php?controller=AdminSelfUpgrade&token=' . md5(pSQL(_COOKIE_KEY_ . 'AdminSelfUpgrade' . (int) Tab::getIdFromClassName('AdminSelfUpgrade') . (int) $cookie->id_employee))); exit; } diff --git a/classes/PrestashopConfiguration.php b/classes/PrestashopConfiguration.php index d5fc75d1a..863664df9 100644 --- a/classes/PrestashopConfiguration.php +++ b/classes/PrestashopConfiguration.php @@ -76,6 +76,7 @@ public function getPrestaShopVersion() $this->psRootDir . '/config/settings.inc.php', $this->psRootDir . '/config/autoload.php', $this->psRootDir . '/app/AppKernel.php', + $this->psRootDir . '/src/Core/Version.php', ]; foreach ($files as $file) { if (!file_exists($file)) { diff --git a/classes/TaskRunner/Miscellaneous/CompareReleases.php b/classes/TaskRunner/Miscellaneous/CompareReleases.php index d452b2b77..5b7719517 100644 --- a/classes/TaskRunner/Miscellaneous/CompareReleases.php +++ b/classes/TaskRunner/Miscellaneous/CompareReleases.php @@ -31,7 +31,7 @@ use PrestaShop\Module\AutoUpgrade\TaskRunner\AbstractTask; /** - * get the list of all modified and deleted files between current version + * This class gets the list of all modified and deleted files between current version * and target version (according to channel configuration). */ class CompareReleases extends AbstractTask @@ -61,6 +61,8 @@ public function run() $version = $upgrader->version_num; } + // Get list of differences between these two versions. The differences will be fetched from a local + // XML file if it exists, or from PrestaShop API. $diffFileList = $upgrader->getDiffFilesList(_PS_VERSION_, $version); if (!is_array($diffFileList)) { $this->nextParams['status'] = 'error'; diff --git a/classes/TaskRunner/Upgrade/UpgradeDb.php b/classes/TaskRunner/Upgrade/UpgradeDb.php index 2a5392d33..990bc640b 100644 --- a/classes/TaskRunner/Upgrade/UpgradeDb.php +++ b/classes/TaskRunner/Upgrade/UpgradeDb.php @@ -29,11 +29,9 @@ use PrestaShop\Module\AutoUpgrade\TaskRunner\AbstractTask; use PrestaShop\Module\AutoUpgrade\UpgradeException; -use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader16; use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader17; use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader80; use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader81; -use PrestaShop\Module\AutoUpgrade\UpgradeTools\SettingsFileWriter; class UpgradeDb extends AbstractTask { @@ -61,10 +59,6 @@ public function run() public function getCoreUpgrader() { - if (version_compare($this->container->getState()->getInstallVersion(), '1.7', '<')) { - return new CoreUpgrader16($this->container, $this->logger); - } - if (version_compare($this->container->getState()->getInstallVersion(), '8', '<')) { return new CoreUpgrader17($this->container, $this->logger); } @@ -85,7 +79,6 @@ public function init() // Migrating settings file $this->container->initPrestaShopAutoloader(); - (new SettingsFileWriter($this->translator))->migrateSettingsFile($this->logger); parent::init(); } } diff --git a/classes/TaskRunner/Upgrade/UpgradeFiles.php b/classes/TaskRunner/Upgrade/UpgradeFiles.php index f22251861..eae4e77ea 100644 --- a/classes/TaskRunner/Upgrade/UpgradeFiles.php +++ b/classes/TaskRunner/Upgrade/UpgradeFiles.php @@ -38,7 +38,7 @@ class UpgradeFiles extends AbstractTask public function run() { - // The first call must init the list of files be upgraded + // The first call must init the list of files be upgraded. if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::FILES_TO_UPGRADE_LIST)) { return $this->warmUp(); } @@ -47,6 +47,8 @@ public function run() $this->destUpgradePath = $this->container->getProperty(UpgradeContainer::PS_ROOT_PATH); $this->next = 'upgradeFiles'; + + // Now we load the list of files to be upgraded, prepared previously by warmUp method. $filesToUpgrade = $this->container->getFileConfigurationStorage()->load(UpgradeFileNames::FILES_TO_UPGRADE_LIST); if (!is_array($filesToUpgrade)) { $this->next = 'error'; @@ -68,6 +70,8 @@ public function run() } $file = array_pop($filesToUpgrade); + + // Note - upgrade this file means do whatever is needed for that file to be in the final state, delete included. if (!$this->upgradeThisFile($file)) { // put the file back to the begin of the list $this->next = 'error'; @@ -119,7 +123,7 @@ protected function listFilesToUpgrade($dir) continue; } $list[] = str_replace($this->container->getProperty(UpgradeContainer::LATEST_PATH), '', $fullPath); - if (is_dir($fullPath) && strpos($dir . DIRECTORY_SEPARATOR . $file, 'install') === false) { + if (is_dir($fullPath)) { $list = array_merge($list, $this->listFilesToUpgrade($fullPath)); } } @@ -137,9 +141,15 @@ public function upgradeThisFile($file) // translations_custom and mails_custom list are currently not used // later, we could handle customization with some kind of diff functions // for now, just copy $file in str_replace($this->latestRootDir,_PS_ROOT_DIR_) + + // The path to the file from the upgrade archive $orig = $this->container->getProperty(UpgradeContainer::LATEST_PATH) . $file; + + // The path to the file in our prestashop directory $dest = $this->destUpgradePath . $file; + // Skip files that we want to avoid touching. They may be already excluded from the list from before, + // but again, as a safety precaution. if ($this->container->getFilesystemAdapter()->isFileSkipped($file, $dest, 'upgrade')) { $this->logger->debug($this->translator->trans('%s ignored', [$file], 'Modules.Autoupgrade.Admin')); @@ -221,6 +231,7 @@ public function upgradeThisFile($file) */ protected function warmUp() { + // Get path to the folder with release we will use to upgrade and check if it's valid $newReleasePath = $this->container->getProperty(UpgradeContainer::LATEST_PATH); if (!$this->container->getFilesystemAdapter()->isReleaseValid($newReleasePath)) { $this->logger->error($this->translator->trans('Could not assert the folder %s contains a valid PrestaShop release, exiting.', [$newReleasePath], 'Modules.Autoupgrade.Admin')); @@ -230,42 +241,57 @@ protected function warmUp() return false; } + // Replace the name of the admin folder inside the release to match our admin folder name $admin_dir = str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH) . DIRECTORY_SEPARATOR, '', $this->container->getProperty(UpgradeContainer::PS_ADMIN_PATH)); if (file_exists($newReleasePath . DIRECTORY_SEPARATOR . 'admin')) { rename($newReleasePath . DIRECTORY_SEPARATOR . 'admin', $newReleasePath . DIRECTORY_SEPARATOR . $admin_dir); } elseif (file_exists($newReleasePath . DIRECTORY_SEPARATOR . 'admin-dev')) { rename($newReleasePath . DIRECTORY_SEPARATOR . 'admin-dev', $newReleasePath . DIRECTORY_SEPARATOR . $admin_dir); } + + // Rename develop installer directory, it would be ignored anyway because it's present in getFilesToIgnoreOnUpgrade() if (file_exists($newReleasePath . DIRECTORY_SEPARATOR . 'install-dev')) { rename($newReleasePath . DIRECTORY_SEPARATOR . 'install-dev', $newReleasePath . DIRECTORY_SEPARATOR . 'install'); } - // list saved in UpgradeFileNames::toUpgradeFileList - // get files differences (previously generated) - $admin_dir = trim(str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), '', $this->container->getProperty(UpgradeContainer::PS_ADMIN_PATH)), DIRECTORY_SEPARATOR); + // Now, we will get the list of changed and removed files between the versions. This was generated previously by + // CompareReleases task. $filepath_list_diff = $this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_DIFF_LIST; $list_files_diff = []; + + // We check if that file exists first and load it if (file_exists($filepath_list_diff)) { $list_files_diff = $this->container->getFileConfigurationStorage()->load(UpgradeFileNames::FILES_DIFF_LIST); - // only keep list of files to delete. The modified files will be listed with _listFilesToUpgrade + // $list_files_diff now contains an array with a list of changed and deleted files. + // We only keep list of files to delete. The modified files will be listed with listFilesToUpgrade below. $list_files_diff = $list_files_diff['deleted']; + + // Admin folder name in this deleted files list is standard /admin/. + // We will need to change it to our own admin folder name. + $admin_dir = trim(str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), '', $this->container->getProperty(UpgradeContainer::PS_ADMIN_PATH)), DIRECTORY_SEPARATOR); foreach ($list_files_diff as $k => $path) { if (preg_match('#autoupgrade#', $path)) { unset($list_files_diff[$k]); - } else { - $list_files_diff[$k] = str_replace('/' . 'admin', '/' . $admin_dir, $path); + } elseif (substr($path, 0, 6) === '/admin') { + // Please make sure that the condition to check if the string starts with /admin stays here, because it was replacing + // admin even in the middle of a path, not deleting some files as a result. + // Also, do not use DIRECTORY_SEPARATOR, keep forward slash, because the path come from the XML standardized. + $list_files_diff[$k] = '/' . $admin_dir . substr($path, 6); } - } // do not replace by DIRECTORY_SEPARATOR + } } + // Now, we get the list of files that are either new or must be modified $list_files_to_upgrade = $this->listFilesToUpgrade($newReleasePath); if (false === $list_files_to_upgrade) { return false; } - // also add files to remove + // Add our previously created list of deleted files $list_files_to_upgrade = array_reverse(array_merge($list_files_diff, $list_files_to_upgrade)); + // Now, some files should be updated as an absolute last step, if they are present in the list, + // we will put them to the end of it. $filesToMoveToTheEnd = [ DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php', DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR . 'ClassLoader.php', @@ -287,7 +313,8 @@ protected function warmUp() } } - // save in a serialized array in UpgradeFileNames::toUpgradeFileList + // Save in a serialized array in UpgradeFileNames::toUpgradeFileList, to be later used by the upgrade step itself above, + // after run() is called. $this->container->getFileConfigurationStorage()->save($list_files_to_upgrade, UpgradeFileNames::FILES_TO_UPGRADE_LIST); $total_files_to_upgrade = count($list_files_to_upgrade); diff --git a/classes/Tools14.php b/classes/Tools14.php index 585808c65..de9b0fb15 100755 --- a/classes/Tools14.php +++ b/classes/Tools14.php @@ -29,84 +29,14 @@ use Tab; +/** + * Useful collection of utilities that are guaranteed to work on every PHP and PrestaShop version supported. + */ class Tools14 { - protected static $file_exists_cache = []; protected static $_forceCompile; protected static $_caching; - /** - * Random password generator. - * - * @param int $length Desired length (optional) - * - * @return string Password - */ - public static function passwdGen($length = 8) - { - $str = 'abcdefghijkmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - for ($i = 0, $passwd = ''; $i < $length; ++$i) { - $passwd .= self::substr($str, mt_rand(0, self::strlen($str) - 1), 1); - } - - return $passwd; - } - - /** - * Redirect user to another page. - * - * @param string $url Desired URL - * @param string $baseUri Base URI (optional) - */ - public static function redirect($url, $baseUri = __PS_BASE_URI__) - { - if (strpos($url, 'http://') === false && strpos($url, 'https://') === false) { - global $link; - if (strpos($url, $baseUri) !== false && strpos($url, $baseUri) == 0) { - $url = substr($url, strlen($baseUri)); - } - $explode = explode('?', $url, 2); - // don't use ssl if url is home page - // used when logout for example - $useSSL = !empty($url); - $url = $link->getPageLink($explode[0], $useSSL); - if (isset($explode[1])) { - $url .= '?' . $explode[1]; - } - $baseUri = ''; - } - - if (isset($_SERVER['HTTP_REFERER']) && ($url == $_SERVER['HTTP_REFERER'])) { - header('Location: ' . $_SERVER['HTTP_REFERER']); - } else { - header('Location: ' . $baseUri . $url); - } - exit; - } - - /** - * Redirect url wich allready PS_BASE_URI. - * - * @param string $url Desired URL - */ - public static function redirectLink($url) - { - if (!preg_match('@^https?://@i', $url)) { - global $link; - if (strpos($url, __PS_BASE_URI__) !== false && strpos($url, __PS_BASE_URI__) == 0) { - $url = substr($url, strlen(__PS_BASE_URI__)); - } - $explode = explode('?', $url, 2); - $url = $link->getPageLink($explode[0]); - if (isset($explode[1])) { - $url .= '?' . $explode[1]; - } - } - - header('Location: ' . $url); - exit; - } - /** * Redirect user to another admin page. * @@ -118,22 +48,9 @@ public static function redirectAdmin($url) exit; } - /** - * getProtocol return the set protocol according to configuration (http[s]). - * - * @param bool true if require ssl - * - * @return string (http|https) - */ - public static function getProtocol($use_ssl = null) - { - return null !== $use_ssl && $use_ssl ? 'https://' : 'http://'; - } - /** * getHttpHost return the current host used, with the protocol (http or https) if $http is true * This function should not be used to choose http or https domain name. - * Use Tools14::getShopDomain() or Tools14::getShopDomainSsl instead. * * @param bool $http * @param bool $entities @@ -153,135 +70,6 @@ public static function getHttpHost($http = false, $entities = false) return $host; } - /** - * getShopDomain returns domain name according to configuration and ignoring ssl. - * - * @param bool $http if true, return domain name with protocol - * @param bool $entities if true, - * - * @return string domain - */ - public static function getShopDomain($http = false, $entities = false) - { - if (!($domain = Configuration::get('PS_SHOP_DOMAIN'))) { - $domain = self::getHttpHost(); - } - if ($entities) { - $domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8'); - } - if ($http) { - $domain = 'http://' . $domain; - } - - return $domain; - } - - /** - * getShopDomainSsl returns domain name according to configuration and depending on ssl activation. - * - * @param bool $http if true, return domain name with protocol - * @param bool $entities if true, - * - * @return string domain - */ - public static function getShopDomainSsl($http = false, $entities = false) - { - if (!($domain = Configuration::get('PS_SHOP_DOMAIN_SSL'))) { - $domain = self::getHttpHost(); - } - if ($entities) { - $domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8'); - } - if ($http) { - $domain = (Configuration::get('PS_SSL_ENABLED') ? 'https://' : 'http://') . $domain; - } - - return $domain; - } - - /** - * Get the server variable SERVER_NAME. - * - * @return string server name - */ - public static function getServerName() - { - if (isset($_SERVER['HTTP_X_FORWARDED_SERVER']) && $_SERVER['HTTP_X_FORWARDED_SERVER']) { - return $_SERVER['HTTP_X_FORWARDED_SERVER']; - } - - return $_SERVER['SERVER_NAME']; - } - - /** - * Get the server variable REMOTE_ADDR, or the first ip of HTTP_X_FORWARDED_FOR (when using proxy). - * - * @return string $remote_addr ip of client - */ - public static function getRemoteAddr() - { - // This condition is necessary when using CDN, don't remove it. - if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] && (!isset($_SERVER['REMOTE_ADDR']) || preg_match('/^127\..*/i', trim($_SERVER['REMOTE_ADDR'])) || preg_match('/^172\.16.*/i', trim($_SERVER['REMOTE_ADDR'])) || preg_match('/^192\.168\.*/i', trim($_SERVER['REMOTE_ADDR'])) || preg_match('/^10\..*/i', trim($_SERVER['REMOTE_ADDR'])))) { - if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')) { - $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); - - return $ips[0]; - } else { - return $_SERVER['HTTP_X_FORWARDED_FOR']; - } - } - - return $_SERVER['REMOTE_ADDR']; - } - - /** - * Check if the current page use SSL connection on not. - * - * @return bool uses SSL - */ - public static function usingSecureMode() - { - if (isset($_SERVER['HTTPS'])) { - return $_SERVER['HTTPS'] == 1 || strtolower($_SERVER['HTTPS']) == 'on'; - } - // $_SERVER['SSL'] exists only in some specific configuration - if (isset($_SERVER['SSL'])) { - return $_SERVER['SSL'] == 1 || strtolower($_SERVER['SSL']) == 'on'; - } - - return false; - } - - /** - * Get the current url prefix protocol (https/http). - * - * @return string protocol - */ - public static function getCurrentUrlProtocolPrefix() - { - if (self::usingSecureMode()) { - return 'https://'; - } else { - return 'http://'; - } - } - - /** - * Secure an URL referrer. - * - * @param string $referrer URL referrer - * - * @return secured referrer - */ - public static function secureReferrer($referrer) - { - if (preg_match('/^http[s]?:\/\/' . self::getServerName() . '(:' . _PS_SSL_PORT_ . ')?\/.*$/Ui', $referrer)) { - return $referrer; - } - - return __PS_BASE_URI__; - } - /** * Get a value from $_POST / $_GET * if unavailable, take a default value. @@ -305,236 +93,6 @@ public static function getValue($key, $defaultValue = false) return !is_string($ret) ? $ret : stripslashes($ret); } - public static function getIsset($key) - { - if (!isset($key) || empty($key) || !is_string($key)) { - return false; - } - - return isset($_POST[$key]) ? true : (isset($_GET[$key]) ? true : false); - } - - /** - * Change language in cookie while clicking on a flag. - * - * @return string iso code - */ - public static function setCookieLanguage() - { - global $cookie; - - /* If language does not exist or is disabled, erase it */ - if ($cookie->id_lang) { - $lang = new Language((int) $cookie->id_lang); - if (!Validate::isLoadedObject($lang) || !$lang->active) { - $cookie->id_lang = null; - } - } - - /* Automatically detect language if not already defined */ - if (!$cookie->id_lang && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $array = explode(',', self::strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); - if (self::strlen($array[0]) > 2) { - $tab = explode('-', $array[0]); - $string = $tab[0]; - } else { - $string = $array[0]; - } - if (Validate::isLanguageIsoCode($string)) { - $lang = new Language((int) (Language::getIdByIso($string))); - if (Validate::isLoadedObject($lang) && $lang->active) { - $cookie->id_lang = (int) ($lang->id); - } - } - } - - /* If language file not present, you must use default language file */ - if (!$cookie->id_lang || !Validate::isUnsignedId($cookie->id_lang)) { - $cookie->id_lang = (int) (Configuration::get('PS_LANG_DEFAULT')); - } - - $iso = Language::getIsoById((int) $cookie->id_lang); - @include_once _PS_THEME_DIR_ . 'lang/' . $iso . '.php'; - - return $iso; - } - - /** - * Set cookie id_lang. - */ - public static function switchLanguage() - { - global $cookie; - - if ($id_lang = (int) (self::getValue('id_lang')) && Validate::isUnsignedId($id_lang)) { - $cookie->id_lang = $id_lang; - } - } - - /** - * Set cookie currency from POST or default currency. - * - * @return Currency object - */ - public static function setCurrency() - { - global $cookie; - - if (self::isSubmit('SubmitCurrency')) { - if (isset($_POST['id_currency']) && is_numeric($_POST['id_currency'])) { - $currency = Currency::getCurrencyInstance((int) ($_POST['id_currency'])); - if (is_object($currency) && $currency->id && !$currency->deleted) { - $cookie->id_currency = (int) ($currency->id); - } - } - } - - if ((int) $cookie->id_currency) { - $currency = Currency::getCurrencyInstance((int) $cookie->id_currency); - if (is_object($currency) && (int) $currency->id && (int) $currency->deleted != 1 && $currency->active) { - return $currency; - } - } - $currency = Currency::getCurrencyInstance((int) (Configuration::get('PS_CURRENCY_DEFAULT'))); - if (is_object($currency) && $currency->id) { - $cookie->id_currency = (int) ($currency->id); - } - - return $currency; - } - - /** - * Return price with currency sign for a given product. - * - * @param float $price Product price - * @param object $currency Current currency (object, id_currency, NULL => getCurrent()) - * - * @return string Price correctly formated (sign, decimal separator...) - */ - public static function displayPrice($price, $currency = null, $no_utf8 = false) - { - if ($currency === null) { - $currency = Currency::getCurrent(); - } - /* if you modified this function, don't forget to modify the Javascript function formatCurrency (in tools.js) */ - if (is_int($currency)) { - $currency = Currency::getCurrencyInstance((int) ($currency)); - } - $c_char = (is_array($currency) ? $currency['sign'] : $currency->sign); - $c_format = (is_array($currency) ? $currency['format'] : $currency->format); - $c_decimals = (is_array($currency) ? (int) ($currency['decimals']) : (int) ($currency->decimals)) * _PS_PRICE_DISPLAY_PRECISION_; - $c_blank = (is_array($currency) ? $currency['blank'] : $currency->blank); - $blank = ($c_blank ? ' ' : ''); - $ret = 0; - if (($isNegative = ($price < 0))) { - $price *= -1; - } - $price = self::ps_round($price, $c_decimals); - switch ($c_format) { - /* X 0,000.00 */ - case 1: - $ret = $c_char . $blank . number_format($price, $c_decimals, '.', ','); - break; - /* 0 000,00 X*/ - case 2: - $ret = number_format($price, $c_decimals, ',', ' ') . $blank . $c_char; - break; - /* X 0.000,00 */ - case 3: - $ret = $c_char . $blank . number_format($price, $c_decimals, ',', '.'); - break; - /* 0,000.00 X */ - case 4: - $ret = number_format($price, $c_decimals, '.', ',') . $blank . $c_char; - break; - } - if ($isNegative) { - $ret = '-' . $ret; - } - if ($no_utf8) { - return str_replace('€', chr(128), $ret); - } - - return $ret; - } - - public static function displayPriceSmarty($params, &$smarty) - { - if (array_key_exists('currency', $params)) { - $currency = Currency::getCurrencyInstance((int) ($params['currency'])); - if (Validate::isLoadedObject($currency)) { - return self::displayPrice($params['price'], $currency, false); - } - } - - return self::displayPrice($params['price']); - } - - /** - * Return price converted. - * - * @param float $price Product price - * @param object $currency Current currency object - * @param bool $to_currency convert to currency or from currency to default currency - */ - public static function convertPrice($price, $currency = null, $to_currency = true) - { - if ($currency === null) { - $currency = Currency::getCurrent(); - } elseif (is_numeric($currency)) { - $currency = Currency::getCurrencyInstance($currency); - } - - $c_id = (is_array($currency) ? $currency['id_currency'] : $currency->id); - $c_rate = (is_array($currency) ? $currency['conversion_rate'] : $currency->conversion_rate); - - if ($c_id != (int) (Configuration::get('PS_CURRENCY_DEFAULT'))) { - if ($to_currency) { - $price *= $c_rate; - } else { - $price /= $c_rate; - } - } - - return $price; - } - - /** - * Display date regarding to language preferences. - * - * @param array $params Date, format... - * @param object $smarty Smarty object for language preferences - * - * @return string Date - */ - public static function dateFormat($params, &$smarty) - { - return self::displayDate($params['date'], $smarty->ps_language->id, (isset($params['full']) ? $params['full'] : false)); - } - - /** - * Display date regarding to language preferences. - * - * @param string $date Date to display format UNIX - * @param int $id_lang Language id - * @param bool $full With time or not (optional) - * - * @return string Date - */ - public static function displayDate($date, $id_lang, $full = false, $separator = '-') - { - if (!$date || !($time = strtotime($date))) { - return $date; - } - if (!Validate::isDate($date) || !Validate::isBool($full)) { - exit(self::displayError('Invalid date')); - } - - $language = Language::getLanguage((int) $id_lang); - - return date($full ? $language['date_format_full'] : $language['date_format_lite'], $time); - } - /** * Sanitize a string. * @@ -561,20 +119,6 @@ public static function htmlentitiesUTF8($string, $type = ENT_QUOTES) return htmlentities($string, $type, 'utf-8'); } - public static function htmlentitiesDecodeUTF8($string) - { - if (is_array($string)) { - return array_map(['Tools', 'htmlentitiesDecodeUTF8'], $string); - } - - return html_entity_decode($string, ENT_QUOTES, 'utf-8'); - } - - public static function safePostVars() - { - $_POST = array_map(['Tools', 'htmlentitiesUTF8'], $_POST); - } - /** * Delete directory and subdirectories. * @@ -634,1755 +178,103 @@ public static function displayError($string = 'Fatal error', $htmlentities = tru } /** - * Display an error with detailed object. - * - * @param mixed $object - * @param bool $kill + * Check if submit has been posted. * - * @return $object if $kill = false; + * @param string $submit submit name */ - public static function dieObject($object, $kill = true) + public static function isSubmit($submit) { - echo '
';
-        print_r($object);
-        echo '

'; - if ($kill) { - exit('END'); - } - - return $object; + return + isset($_POST[$submit]) || isset($_POST[$submit . '_x']) || isset($_POST[$submit . '_y']) + || isset($_GET[$submit]) || isset($_GET[$submit . '_x']) || isset($_GET[$submit . '_y']) + ; } /** - * ALIAS OF dieObject() - Display an error with detailed object. + * Encrypt password. * * @param object $object Object to display */ - public static function d($object, $kill = true) + public static function encrypt($passwd) { - return self::dieObject($object, $kill = true); + return md5(pSQL(_COOKIE_KEY_ . $passwd)); } /** - * ALIAS OF dieObject() - Display an error with detailed object but don't stop the execution. + * Encrypt password. * * @param object $object Object to display */ - public static function p($object) + public static function getAdminToken($string) { - return self::dieObject($object, false); + return !empty($string) ? self::encrypt($string) : false; } - /** - * Check if submit has been posted. - * - * @param string $submit submit name - */ - public static function isSubmit($submit) + public static function getAdminTokenLite($tab) { - return - isset($_POST[$submit]) || isset($_POST[$submit . '_x']) || isset($_POST[$submit . '_y']) - || isset($_GET[$submit]) || isset($_GET[$submit . '_x']) || isset($_GET[$submit . '_y']) - ; + global $cookie; + + return self::getAdminToken($tab . (int) Tab::getIdFromClassName($tab) . (int) $cookie->id_employee); } - /** - * Get meta tages for a given page. - * - * @param int $id_lang Language id - * - * @return array Meta tags - */ - public static function getMetaTags($id_lang, $page_name) - { - global $maintenance; - - if (!(isset($maintenance) && (!in_array(self::getRemoteAddr(), explode(',', Configuration::get('PS_MAINTENANCE_IP')))))) { - /* Products specifics meta tags */ - if ($id_product = self::getValue('id_product')) { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `name`, `meta_title`, `meta_description`, `meta_keywords`, `description_short` - FROM `' . _DB_PREFIX_ . 'product` p - LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (pl.`id_product` = p.`id_product`) - WHERE pl.id_lang = ' . (int) ($id_lang) . ' AND pl.id_product = ' . (int) ($id_product) . ' AND p.active = 1'); - if ($row) { - if (empty($row['meta_description'])) { - $row['meta_description'] = strip_tags($row['description_short']); - } - - return self::completeMetaTags($row, $row['name']); - } - } - - /* Categories specifics meta tags */ - elseif ($id_category = self::getValue('id_category')) { - $page_number = (int) self::getValue('p'); - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `name`, `meta_title`, `meta_description`, `meta_keywords`, `description` - FROM `' . _DB_PREFIX_ . 'category_lang` - WHERE id_lang = ' . (int) ($id_lang) . ' AND id_category = ' . (int) ($id_category)); - if ($row) { - if (empty($row['meta_description'])) { - $row['meta_description'] = strip_tags($row['description']); - } - - // Paginate title - if (!empty($row['meta_title'])) { - $row['meta_title'] = $row['meta_title'] . (!empty($page_number) ? ' (' . $page_number . ')' : '') . ' - ' . Configuration::get('PS_SHOP_NAME'); - } else { - $row['meta_title'] = $row['name'] . (!empty($page_number) ? ' (' . $page_number . ')' : '') . ' - ' . Configuration::get('PS_SHOP_NAME'); - } - - return self::completeMetaTags($row, $row['name']); - } - } - - /* Manufacturers specifics meta tags */ - elseif ($id_manufacturer = self::getValue('id_manufacturer')) { - $page_number = (int) self::getValue('p'); - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `name`, `meta_title`, `meta_description`, `meta_keywords` - FROM `' . _DB_PREFIX_ . 'manufacturer_lang` ml - LEFT JOIN `' . _DB_PREFIX_ . 'manufacturer` m ON (ml.`id_manufacturer` = m.`id_manufacturer`) - WHERE ml.id_lang = ' . (int) ($id_lang) . ' AND ml.id_manufacturer = ' . (int) ($id_manufacturer)); - if ($row) { - if (empty($row['meta_description'])) { - $row['meta_description'] = strip_tags($row['meta_description']); - } - $row['meta_title'] .= $row['name'] . (!empty($page_number) ? ' (' . $page_number . ')' : ''); - $row['meta_title'] .= ' - ' . Configuration::get('PS_SHOP_NAME'); - - return self::completeMetaTags($row, $row['meta_title']); - } - } - - /* Suppliers specifics meta tags */ - elseif ($id_supplier = self::getValue('id_supplier')) { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `name`, `meta_title`, `meta_description`, `meta_keywords` - FROM `' . _DB_PREFIX_ . 'supplier_lang` sl - LEFT JOIN `' . _DB_PREFIX_ . 'supplier` s ON (sl.`id_supplier` = s.`id_supplier`) - WHERE sl.id_lang = ' . (int) ($id_lang) . ' AND sl.id_supplier = ' . (int) ($id_supplier)); - - if ($row) { - if (empty($row['meta_description'])) { - $row['meta_description'] = strip_tags($row['meta_description']); - } - if (!empty($row['meta_title'])) { - $row['meta_title'] = $row['meta_title'] . ' - ' . Configuration::get('PS_SHOP_NAME'); - } - - return self::completeMetaTags($row, $row['name']); - } - } - - /* CMS specifics meta tags */ - elseif ($id_cms = self::getValue('id_cms')) { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `meta_title`, `meta_description`, `meta_keywords` - FROM `' . _DB_PREFIX_ . 'cms_lang` - WHERE id_lang = ' . (int) ($id_lang) . ' AND id_cms = ' . (int) ($id_cms)); - if ($row) { - $row['meta_title'] = $row['meta_title'] . ' - ' . Configuration::get('PS_SHOP_NAME'); - - return self::completeMetaTags($row, $row['meta_title']); - } - } - - /* CMS category specifics meta tags */ - elseif ($id_cms = self::getValue('id_cms_category')) { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' - SELECT `meta_title`, `meta_description`, `meta_keywords` - FROM `' . _DB_PREFIX_ . 'cms_category_lang` - WHERE id_lang = ' . (int) ($id_lang) . ' AND id_cms_category = ' . (int) ($id_cms)); - if ($row) { - $row['meta_title'] = $row['meta_title'] . ' - ' . Configuration::get('PS_SHOP_NAME'); - - return self::completeMetaTags($row, $row['meta_title']); - } - } - } - - /* Default meta tags */ - return self::getHomeMetaTags($id_lang, $page_name); - } - - /** - * Get meta tags for a given page. - * - * @param int $id_lang Language id - * - * @return array Meta tags - */ - public static function getHomeMetaTags($id_lang, $page_name) - { - /* Metas-tags */ - $metas = Meta::getMetaByPage($page_name, $id_lang); - $ret['meta_title'] = (isset($metas['title']) && $metas['title']) ? $metas['title'] . ' - ' . Configuration::get('PS_SHOP_NAME') : Configuration::get('PS_SHOP_NAME'); - $ret['meta_description'] = (isset($metas['description']) && $metas['description']) ? $metas['description'] : ''; - $ret['meta_keywords'] = (isset($metas['keywords']) && $metas['keywords']) ? $metas['keywords'] : ''; - - return $ret; - } - - public static function completeMetaTags($metaTags, $defaultValue) - { - global $cookie; - - if (empty($metaTags['meta_title'])) { - $metaTags['meta_title'] = $defaultValue . ' - ' . Configuration::get('PS_SHOP_NAME'); - } - if (empty($metaTags['meta_description'])) { - $metaTags['meta_description'] = Configuration::get('PS_META_DESCRIPTION', (int) ($cookie->id_lang)) ? Configuration::get('PS_META_DESCRIPTION', (int) ($cookie->id_lang)) : ''; - } - if (empty($metaTags['meta_keywords'])) { - $metaTags['meta_keywords'] = Configuration::get('PS_META_KEYWORDS', (int) ($cookie->id_lang)) ? Configuration::get('PS_META_KEYWORDS', (int) ($cookie->id_lang)) : ''; - } - - return $metaTags; - } - - /** - * Encrypt password. - * - * @param object $object Object to display - */ - public static function encrypt($passwd) - { - return md5(pSQL(_COOKIE_KEY_ . $passwd)); - } - - /** - * Get token to prevent CSRF. - * - * @param string $token token to encrypt - */ - public static function getToken($page = true) - { - global $cookie; - if ($page === true) { - return self::encrypt($cookie->id_customer . $cookie->passwd . $_SERVER['SCRIPT_NAME']); - } else { - return self::encrypt($cookie->id_customer . $cookie->passwd . $page); - } - } - - /** - * Encrypt password. - * - * @param object $object Object to display - */ - public static function getAdminToken($string) - { - return !empty($string) ? self::encrypt($string) : false; - } - - public static function getAdminTokenLite($tab) - { - global $cookie; - - return self::getAdminToken($tab . (int) Tab::getIdFromClassName($tab) . (int) $cookie->id_employee); - } - - /** - * Get the user's journey. - * - * @param int $id_category Category ID - * @param string $path Path end - * @param bool $linkOntheLastItem Put or not a link on the current category - * @param string [optionnal] $categoryType defined what type of categories is used (products or cms) - */ - public static function getPath($id_category, $path = '', $linkOntheLastItem = false, $categoryType = 'products') - { - global $link, $cookie; - - if ($id_category == 1) { - return '' . $path . ''; - } - - $pipe = Configuration::get('PS_NAVIGATION_PIPE'); - if (empty($pipe)) { - $pipe = '>'; - } - - $fullPath = ''; - - if ($categoryType === 'products') { - $category = Db::getInstance()->getRow(' - SELECT id_category, level_depth, nleft, nright - FROM ' . _DB_PREFIX_ . 'category - WHERE id_category = ' . (int) $id_category); - - if (isset($category['id_category'])) { - $categories = Db::getInstance()->ExecuteS(' - SELECT c.id_category, cl.name, cl.link_rewrite - FROM ' . _DB_PREFIX_ . 'category c - LEFT JOIN ' . _DB_PREFIX_ . 'category_lang cl ON (cl.id_category = c.id_category) - WHERE c.nleft <= ' . (int) $category['nleft'] . ' AND c.nright >= ' . (int) $category['nright'] . ' AND cl.id_lang = ' . (int) ($cookie->id_lang) . ' AND c.id_category != 1 - ORDER BY c.level_depth ASC - LIMIT ' . (int) $category['level_depth']); - - $n = 1; - $nCategories = (int) sizeof($categories); - foreach ($categories as $category) { - $fullPath .= - (($n < $nCategories || $linkOntheLastItem) ? '' : '') . - htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8') . - (($n < $nCategories || $linkOntheLastItem) ? '' : '') . - (($n++ != $nCategories || !empty($path)) ? '' . $pipe . '' : ''); - } - - return $fullPath . $path; - } - } elseif ($categoryType === 'CMS') { - $category = new CMSCategory((int) ($id_category), (int) ($cookie->id_lang)); - if (!Validate::isLoadedObject($category)) { - exit(self::displayError()); - } - $categoryLink = $link->getCMSCategoryLink($category); - - if ($path != $category->name) { - $fullPath .= '' . htmlentities($category->name, ENT_NOQUOTES, 'UTF-8') . '' . $pipe . '' . $path; - } else { - $fullPath = ($linkOntheLastItem ? '' : '') . htmlentities($path, ENT_NOQUOTES, 'UTF-8') . ($linkOntheLastItem ? '' : ''); - } - - return self::getPath((int) ($category->id_parent), $fullPath, $linkOntheLastItem, $categoryType); - } - } - - /** - * @param string [optionnal] $type_cat defined what type of categories is used (products or cms) - */ - public static function getFullPath($id_category, $end, $type_cat = 'products') - { - global $cookie; - - $pipe = (Configuration::get('PS_NAVIGATION_PIPE') ? Configuration::get('PS_NAVIGATION_PIPE') : '>'); - - if ($type_cat === 'products') { - $category = new Category((int) ($id_category), (int) ($cookie->id_lang)); - } elseif ($type_cat === 'CMS') { - $category = new CMSCategory((int) ($id_category), (int) ($cookie->id_lang)); - } - - if (!Validate::isLoadedObject($category)) { - $id_category = 1; - } - if ($id_category == 1) { - return htmlentities($end, ENT_NOQUOTES, 'UTF-8'); - } - - return self::getPath($id_category, $category->name, true, $type_cat) . '' . $pipe . ' ' . htmlentities($end, ENT_NOQUOTES, 'UTF-8') . ''; - } - - /** - * @deprecated - */ - public static function getCategoriesTotal() - { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT COUNT(`id_category`) AS total FROM `' . _DB_PREFIX_ . 'category`'); - - return (int) ($row['total']); - } - - /** - * @deprecated - */ - public static function getProductsTotal() - { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT COUNT(`id_product`) AS total FROM `' . _DB_PREFIX_ . 'product`'); - - return (int) ($row['total']); - } - - /** - * @deprecated - */ - public static function getCustomersTotal() - { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT COUNT(`id_customer`) AS total FROM `' . _DB_PREFIX_ . 'customer`'); - - return (int) ($row['total']); - } - - /** - * @deprecated - */ - public static function getOrdersTotal() - { - $row = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT COUNT(`id_order`) AS total FROM `' . _DB_PREFIX_ . 'orders`'); - - return (int) ($row['total']); - } - - /* - ** Historyc translation function kept for compatibility - ** Removing soon - */ - public static function historyc_l($key, $translations) - { - global $cookie; - if (!$translations || !is_array($translations)) { - exit(self::displayError()); - } - $iso = strtoupper(Language::getIsoById($cookie->id_lang)); - $lang = key_exists($iso, $translations) ? $translations[$iso] : false; - - return ($lang && is_array($lang) && key_exists($key, $lang)) ? stripslashes($lang[$key]) : $key; - } - - /** - * Return the friendly url from the provided string. - * - * @param string $str - * @param bool $utf8_decode => needs to be marked as deprecated - * - * @return string - */ - public static function link_rewrite($str, $utf8_decode = false) - { - return self::str2url($str); - } - - /** - * Return a friendly url made from the provided string - * If the mbstring library is available, the output is the same as the js function of the same name. - * - * @param string $str - * - * @return string - */ - public static function str2url($str) - { - if (function_exists('mb_strtolower')) { - $str = mb_strtolower($str, 'utf-8'); - } - - $str = trim($str); - $str = self::replaceAccentedChars($str); - - // Remove all non-whitelist chars. - $str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]-]/', '', $str); - $str = preg_replace('/[\s\'\:\/\[\]-]+/', ' ', $str); - $str = preg_replace('/[ ]/', '-', $str); - $str = preg_replace('/[\/]/', '-', $str); - - // If it was not possible to lowercase the string with mb_strtolower, we do it after the transformations. - // This way we lose fewer special chars. - if (!function_exists('mb_strtolower')) { - $str = strtolower($str); - } - - return $str; - } - - /** - * Replace all accented chars by their equivalent non accented chars. - * - * @param string $str - * - * @return string - */ - public static function replaceAccentedChars($str) - { - $str = preg_replace('/[\x{0105}\x{0104}\x{00E0}\x{00E1}\x{00E2}\x{00E3}\x{00E4}\x{00E5}]/u', 'a', $str); - $str = preg_replace('/[\x{00E7}\x{010D}\x{0107}\x{0106}]/u', 'c', $str); - $str = preg_replace('/[\x{010F}]/u', 'd', $str); - $str = preg_replace('/[\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{011B}\x{0119}\x{0118}]/u', 'e', $str); - $str = preg_replace('/[\x{00EC}\x{00ED}\x{00EE}\x{00EF}]/u', 'i', $str); - $str = preg_replace('/[\x{0142}\x{0141}\x{013E}\x{013A}]/u', 'l', $str); - $str = preg_replace('/[\x{00F1}\x{0148}]/u', 'n', $str); - $str = preg_replace('/[\x{00F2}\x{00F3}\x{00F4}\x{00F5}\x{00F6}\x{00F8}\x{00D3}]/u', 'o', $str); - $str = preg_replace('/[\x{0159}\x{0155}]/u', 'r', $str); - $str = preg_replace('/[\x{015B}\x{015A}\x{0161}]/u', 's', $str); - $str = preg_replace('/[\x{00DF}]/u', 'ss', $str); - $str = preg_replace('/[\x{0165}]/u', 't', $str); - $str = preg_replace('/[\x{00F9}\x{00FA}\x{00FB}\x{00FC}\x{016F}]/u', 'u', $str); - $str = preg_replace('/[\x{00FD}\x{00FF}]/u', 'y', $str); - $str = preg_replace('/[\x{017C}\x{017A}\x{017B}\x{0179}\x{017E}]/u', 'z', $str); - $str = preg_replace('/[\x{00E6}]/u', 'ae', $str); - $str = preg_replace('/[\x{0153}]/u', 'oe', $str); - - return $str; - } - - /** - * Truncate strings. - * - * @param string $str - * @param int $maxLen Max length - * @param string $suffix Suffix optional - * - * @return string $str truncated - */ - /* CAUTION : Use it only on module hookEvents. - ** For other purposes use the smarty function instead */ - public static function truncate($str, $maxLen, $suffix = '...') - { - if (self::strlen($str) <= $maxLen) { - return $str; - } - $str = utf8_decode($str); - - return utf8_encode(substr($str, 0, $maxLen - self::strlen($suffix)) . $suffix); - } - - /** - * Generate date form. - * - * @param int $year Year to select - * @param int $month Month to select - * @param int $day Day to select - * - * @return array $tab html data with 3 cells :['days'], ['months'], ['years'] - */ - public static function dateYears() - { - $tab = []; - for ($i = date('Y'); $i >= 1900; --$i) { - $tab[] = $i; - } - - return $tab; - } - - public static function dateDays() - { - for ($i = 1; $i != 32; ++$i) { - $tab[] = $i; - } - - return $tab; - } - - public static function dateMonths() - { - for ($i = 1; $i != 13; ++$i) { - $tab[$i] = date('F', mktime(0, 0, 0, $i, date('m'), date('Y'))); - } - - return $tab; - } - - public static function hourGenerate($hours, $minutes, $seconds) - { - return implode(':', [$hours, $minutes, $seconds]); - } - - public static function dateFrom($date) - { - $tab = explode(' ', $date); - if (!isset($tab[1])) { - $date .= ' ' . self::hourGenerate(0, 0, 0); - } - - return $date; - } - - public static function dateTo($date) - { - $tab = explode(' ', $date); - if (!isset($tab[1])) { - $date .= ' ' . self::hourGenerate(23, 59, 59); - } - - return $date; - } - - /** - * @deprecated - */ - public static function getExactTime() - { - return time() + microtime(); - } - - public static function strtolower($str) - { - if (is_array($str)) { - return false; - } - if (function_exists('mb_strtolower')) { - return mb_strtolower($str, 'utf-8'); - } - - return strtolower($str); - } - - public static function strlen($str, $encoding = 'UTF-8') - { - if (is_array($str)) { - return false; - } - $str = html_entity_decode($str, ENT_COMPAT, 'UTF-8'); - if (function_exists('mb_strlen')) { - return mb_strlen($str, $encoding); - } - - return strlen($str); - } - - public static function stripslashes($string) - { - if (_PS_MAGIC_QUOTES_GPC_) { - $string = stripslashes($string); - } - - return $string; - } - - public static function strtoupper($str) - { - if (is_array($str)) { - return false; - } - if (function_exists('mb_strtoupper')) { - return mb_strtoupper($str, 'utf-8'); - } - - return strtoupper($str); - } - - public static function substr($str, $start, $length = false, $encoding = 'utf-8') - { - if (is_array($str)) { - return false; - } - if (function_exists('mb_substr')) { - return mb_substr($str, (int) ($start), ($length === false ? self::strlen($str) : (int) ($length)), $encoding); - } - - return substr($str, $start, ($length === false ? self::strlen($str) : (int) ($length))); - } - - public static function ucfirst($str) - { - return self::strtoupper(self::substr($str, 0, 1)) . self::substr($str, 1); - } - - public static function orderbyPrice(&$array, $orderWay) - { - foreach ($array as &$row) { - $row['price_tmp'] = Product::getPriceStatic($row['id_product'], true, ((isset($row['id_product_attribute']) && !empty($row['id_product_attribute'])) ? (int) ($row['id_product_attribute']) : null), 2); - } - if (strtolower($orderWay) == 'desc') { - uasort($array, 'cmpPriceDesc'); - } else { - uasort($array, 'cmpPriceAsc'); - } - foreach ($array as &$row) { - unset($row['price_tmp']); - } - } - - public static function iconv($from, $to, $string) - { - if (function_exists('iconv')) { - return iconv($from, $to . '//TRANSLIT', str_replace('¥', '¥', str_replace('£', '£', str_replace('€', '€', $string)))); - } - - return html_entity_decode(htmlentities($string, ENT_NOQUOTES, $from), ENT_NOQUOTES, $to); - } - - public static function isEmpty($field) - { - return $field === '' || $field === null; - } - - /** - * @deprecated - **/ - public static function getTimezones($select = false) - { - static $_cache = 0; - - // One select - if ($select) { - // No cache - if (!$_cache) { - $tmz = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT `name` FROM ' . _DB_PREFIX_ . 'timezone WHERE id_timezone = ' . (int) ($select)); - $_cache = $tmz['name']; - } - - return $_cache; - } - - // Multiple select - $tmz = Db::getInstance(_PS_USE_SQL_SLAVE_)->s('SELECT * FROM ' . _DB_PREFIX_ . 'timezone'); - $tab = []; - foreach ($tmz as $timezone) { - $tab[$timezone['id_timezone']] = str_replace('_', ' ', $timezone['name']); - } - - return $tab; - } - - /** - * @deprecated - **/ - public static function ps_set_magic_quotes_runtime($var) - { - if (function_exists('set_magic_quotes_runtime')) { - set_magic_quotes_runtime($var); - } - } - - public static function ps_round($value, $precision = 0) - { - $method = (int) (Configuration::get('PS_PRICE_ROUND_MODE')); - if ($method == PS_ROUND_UP) { - return self::ceilf($value, $precision); - } elseif ($method == PS_ROUND_DOWN) { - return self::floorf($value, $precision); - } - - return round($value, $precision); - } - - public static function ceilf($value, $precision = 0) - { - $precisionFactor = $precision == 0 ? 1 : pow(10, $precision); - $tmp = $value * $precisionFactor; - $tmp2 = (string) $tmp; - // If the current value has already the desired precision - if (strpos($tmp2, '.') === false) { - return $value; - } - if ($tmp2[strlen($tmp2) - 1] == 0) { - return $value; - } - - return ceil($tmp) / $precisionFactor; - } - - public static function floorf($value, $precision = 0) - { - $precisionFactor = $precision == 0 ? 1 : pow(10, $precision); - $tmp = $value * $precisionFactor; - $tmp2 = (string) $tmp; - // If the current value has already the desired precision - if (strpos($tmp2, '.') === false) { - return $value; - } - if ($tmp2[strlen($tmp2) - 1] == 0) { - return $value; - } - - return floor($tmp) / $precisionFactor; - } - - /** - * file_exists() wrapper with cache to speedup performance. - * - * @param string $filename File name - * - * @return bool Cached result of file_exists($filename) - */ - public static function file_exists_cache($filename) - { - if (!isset(self::$file_exists_cache[$filename])) { - self::$file_exists_cache[$filename] = file_exists($filename); - } - - return self::$file_exists_cache[$filename]; - } - - /** - * Check config & source file to settle which dl method to use - */ - public static function shouldUseFopen($url) - { - return in_array(ini_get('allow_url_fopen'), ['On', 'on', '1']) || !preg_match('/^https?:\/\//', $url); - } - - public static function file_get_contents($url, $use_include_path = false, $stream_context = null, $curl_timeout = 5) - { - if (!extension_loaded('openssl') && strpos('https://', $url) === true) { - $url = str_replace('https', 'http', $url); - } - if ($stream_context == null && preg_match('/^https?:\/\//', $url)) { - $stream_context = @stream_context_create(['http' => ['timeout' => $curl_timeout, 'header' => "User-Agent:MyAgent/1.0\r\n"]]); - } - if (self::shouldUseFopen($url)) { - $var = @file_get_contents($url, $use_include_path, $stream_context); - - /* PSCSX-3205 buffer output ? */ - if (self::getValue('ajaxMode') && ob_get_level() && ob_get_length() > 0) { - ob_clean(); - } - - if ($var) { - return $var; - } - } elseif (function_exists('curl_init')) { - $curl = curl_init(); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($curl, CURLOPT_TIMEOUT, $curl_timeout); - curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); - $opts = stream_context_get_options($stream_context); - if (isset($opts['http']['method']) && self::strtolower($opts['http']['method']) == 'post') { - curl_setopt($curl, CURLOPT_POST, true); - if (isset($opts['http']['content'])) { - parse_str($opts['http']['content'], $datas); - curl_setopt($curl, CURLOPT_POSTFIELDS, $datas); - } - } - $content = curl_exec($curl); - curl_close($curl); - - return $content; - } - - return false; - } - - public static function simplexml_load_file($url, $class_name = null) - { - return @simplexml_load_string(self::file_get_contents($url), $class_name); - } - - public static function minifyHTML($html_content) - { - if (strlen($html_content) > 0) { - //set an alphabetical order for args - $html_content = preg_replace_callback( - '/(<[a-zA-Z0-9]+)((\s?[a-zA-Z0-9]+=[\"\\\'][^\"\\\']*[\"\\\']\s?)*)>/', ['Tools', 'minifyHTMLpregCallback'], $html_content); - - require_once _PS_TOOL_DIR_ . 'minify_html/minify_html.class.php'; - $html_content = str_replace(chr(194) . chr(160), ' ', $html_content); - $html_content = Minify_HTML::minify($html_content, ['xhtml', 'cssMinifier', 'jsMinifier']); - - if (Configuration::get('PS_HIGH_HTML_THEME_COMPRESSION')) { - //$html_content = preg_replace('/"([^\>\s"]*)"/i', '$1', $html_content);//FIXME create a js bug - $html_content = preg_replace('/]*dtd\">/is', '', $html_content); - $html_content = preg_replace('/\s\>/is', '>', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('', '', $html_content); - //$html_content = str_replace('

', '', $html_content);//FIXME doesnt work... - $html_content = str_replace("\n", '', $html_content); //TODO with bellow - $html_content = str_replace('', '', $html_content); - $html_content = str_replace('