1<?php
2/**
3 * Copyright since 2007 PrestaShop SA and Contributors
4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
5 *
6 * NOTICE OF LICENSE
7 *
8 * This source file is subject to the Open Software License (OSL 3.0)
9 * that is bundled with this package in the file LICENSE.md.
10 * It is also available through the world-wide-web at this URL:
11 * https://opensource.org/licenses/OSL-3.0
12 * If you did not receive a copy of the license and are unable to
13 * obtain it through the world-wide-web, please send an email
14 * to license@prestashop.com so we can send you a copy immediately.
15 *
16 * DISCLAIMER
17 *
18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
19 * versions in the future. If you wish to customize PrestaShop for your
20 * needs please refer to https://devdocs.prestashop.com/ for more information.
21 *
22 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
23 * @copyright Since 2007 PrestaShop SA and Contributors
24 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
25 */
26
27namespace {
28    $root_dir = realpath(__DIR__ . '/../../..');
29
30    require_once $root_dir . '/vendor/paragonie/random_compat/lib/random.php';
31
32    if (!class_exists('PhpEncryptionEngine')) {
33        require_once $root_dir . '/classes/PhpEncryptionEngine.php';
34        class PhpEncryptionEngine extends \PhpEncryptionEngineCore
35        {
36        }
37    }
38
39    if (!class_exists('PhpEncryptionLegacyEngine')) {
40        require_once $root_dir . '/classes/PhpEncryptionLegacyEngine.php';
41        class PhpEncryptionLegacyEngine extends \PhpEncryptionLegacyEngineCore
42        {
43        }
44    }
45
46    if (!class_exists('PhpEncryption')) {
47        require_once $root_dir . '/classes/PhpEncryption.php';
48        class PhpEncryption extends \PhpEncryptionCore
49        {
50        }
51    }
52}
53
54namespace PrestaShopBundle\Install {
55    use AppKernel;
56    use Cache;
57    use Cart;
58    use Composer\Script\Event;
59    use Configuration;
60    use Context;
61    use Country;
62    use Db;
63    use Employee;
64    use FileLogger;
65    use Language;
66    use Module;
67    use PhpEncryption;
68    use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
69    use PrestaShop\PrestaShop\Core\Addon\AddonListFilter;
70    use PrestaShop\PrestaShop\Core\Addon\AddonListFilterOrigin;
71    use PrestaShop\PrestaShop\Core\Addon\AddonListFilterStatus;
72    use PrestaShop\PrestaShop\Core\Addon\AddonListFilterType;
73    use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder;
74    use PrestaShop\PrestaShop\Core\Addon\Theme\ThemeManagerBuilder;
75    use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
76    use PrestaShop\PrestaShop\Core\Domain\MailTemplate\Command\GenerateThemeMailTemplatesCommand;
77    use PrestaShop\PrestaShop\Core\Exception\CoreException;
78    use PrestaShopBundle\Service\Database\Upgrade as UpgradeDatabase;
79    use RandomLib;
80    use Shop;
81    use Symfony\Component\Filesystem\Exception\IOException;
82    use Symfony\Component\Filesystem\Filesystem;
83    use Symfony\Component\Yaml\Yaml;
84    use Tools;
85    use Validate;
86
87    class Upgrade
88    {
89        /** @var \FileLogger */
90        private $logger;
91        private $infoList = [];
92        private $warningList = [];
93        private $failureList = [];
94        private $nextQuickInfo = [];
95        private $nextErrors = [];
96        private $next;
97        private $nextDesc;
98        private $inAutoUpgrade = false;
99        private $translator;
100        private $installDir;
101        private $adminDir = null;
102        private $oldVersion;
103        private $db;
104        private $idEmployee = 0;
105        private $disableCustomModules = false;
106        private $changeToDefaultTheme = false;
107        private $updateDefaultTheme = false;
108        // used for translations
109        public static $l_cache;
110
111        public const FILE_PREFIX = 'PREFIX_';
112        public const ENGINE_TYPE = 'ENGINE_TYPE';
113        public const DB_NAME = 'DB_NAME';
114
115        private static $classes14 = ['Cache', 'CacheFS', 'CarrierModule', 'Db', 'FrontController', 'Helper', 'ImportModule',
116            'MCached', 'Module', 'ModuleGraph', 'ModuleGraphEngine', 'ModuleGrid', 'ModuleGridEngine',
117            'MySQL', 'Order', 'OrderDetail', 'OrderDiscount', 'OrderHistory', 'OrderMessage', 'OrderReturn',
118            'OrderReturnState', 'OrderSlip', 'OrderState', 'PDF', 'RangePrice', 'RangeWeight', 'StockMvt',
119            'StockMvtReason', 'SubDomain', 'Shop', 'Tax', 'TaxRule', 'TaxRulesGroup', 'WebserviceKey', 'WebserviceRequest', '', ];
120
121        private static $incompatibleModules = [
122            'bankwire',
123            'blockbanner',
124            'blockcart',
125            'blockcategories',
126            'blockcms',
127            'blockcmsinfo',
128            'blockcontact',
129            'blockcurrencies',
130            'blocklanguages',
131            'blocklayered',
132            'blockmyaccount',
133            'blocknewsletter',
134            'blocksearch',
135            'blocksocial',
136            'blocktopmenu',
137            'blockuserinfo',
138            'cheque',
139            'homefeatured',
140            'homeslider',
141            'onboarding',
142            'socialsharing',
143            'vatnumber',
144            'blockadvertising',
145            'blockbestsellers',
146            'blockcustomerprivacy',
147            'blocklink',
148            'blockmanufacturer',
149            'blocknewproducts',
150            'blockpermanentlinks',
151            'blockrss',
152            'blocksharefb',
153            'blockspecials',
154            'blocksupplier',
155            'blockviewed',
156            'crossselling',
157            'followup',
158            'productscategory',
159            'producttooltip',
160            'mailalert',
161            'blockcontactinfos',
162            'blockfacebook',
163            'blockmyaccountfooter',
164            'blockpaymentlogo',
165            'blockstore',
166            'blocktags',
167            'productpaymentlogos',
168            'sendtoafriend',
169            'themeconfigurator',
170        ];
171
172        public function __construct($cacheDir, $installDir)
173        {
174            $this->logger = new FileLogger();
175            $this->logger->setFilename($cacheDir . @date('Ymd') . '_upgrade.log');
176            $this->installDir = $installDir;
177            $this->db = Db::getInstance();
178        }
179
180        public function setDisableCustomModules($value)
181        {
182            $this->disableCustomModules = (bool) $value;
183        }
184
185        public function setUpdateDefaultTheme($value)
186        {
187            $this->updateDefaultTheme = (bool) $value;
188        }
189
190        public function setAdminDir($value)
191        {
192            $this->adminDir = $value;
193        }
194
195        public function setIdEmployee($id)
196        {
197            $this->idEmployee = (int) $id;
198        }
199
200        public function setChangeToDefaultTheme($value)
201        {
202            $this->changeToDefaultTheme = (bool) $value;
203        }
204
205        private function defineConst()
206        {
207            // retrocompatibility (is present in some upgrade scripts)
208            if (!defined('INSTALL_PATH')) {
209                define('INSTALL_PATH', $this->installDir);
210            }
211            require_once INSTALL_PATH . 'install_version.php';
212            // needed for upgrade before 1.5
213            if (!defined('__PS_BASE_URI__')) {
214                define('__PS_BASE_URI__', str_replace('//', '/', '/' . trim(preg_replace('#/(install(-dev)?/upgrade)$#', '/', str_replace('\\', '/', dirname($_SERVER['REQUEST_URI']))), '/') . '/'));
215            }
216            if (!defined('_THEME_NAME_')) {
217                define('_THEME_NAME_', 'default');
218            }
219            if (!defined('_PS_SMARTY_FAST_LOAD_')) {
220                define('_PS_SMARTY_FAST_LOAD_', true);
221            }
222
223            // if _PS_ROOT_DIR_ is defined, use it instead of "guessing" the module dir.
224            if (defined('_PS_ROOT_DIR_') && !defined('_PS_MODULE_DIR_')) {
225                define('_PS_MODULE_DIR_', _PS_ROOT_DIR_ . '/modules/');
226            } elseif (!defined('_PS_MODULE_DIR_')) {
227                define('_PS_MODULE_DIR_', _PS_INSTALL_PATH_ . '/../modules/');
228            }
229
230            if (!defined('_PS_INSTALLER_PHP_UPGRADE_DIR_')) {
231                define('_PS_INSTALLER_PHP_UPGRADE_DIR_', _PS_INSTALL_PATH_ . 'upgrade/php/');
232            }
233
234            if (!defined('_PS_INSTALLER_SQL_UPGRADE_DIR_')) {
235                define('_PS_INSTALLER_SQL_UPGRADE_DIR_', _PS_INSTALL_PATH_ . 'upgrade/sql/');
236            }
237
238            if (!defined('_THEMES_DIR_')) {
239                define('_THEMES_DIR_', __PS_BASE_URI__ . 'themes/');
240            }
241            if (!defined('_PS_IMG_')) {
242                define('_PS_IMG_', __PS_BASE_URI__ . 'img/');
243            }
244            if (!defined('_PS_JS_DIR_')) {
245                define('_PS_JS_DIR_', __PS_BASE_URI__ . 'js/');
246            }
247            if (!defined('_PS_CSS_DIR_')) {
248                define('_PS_CSS_DIR_', __PS_BASE_URI__ . 'css/');
249            }
250
251            $this->oldVersion = Configuration::get('PS_VERSION_DB');
252            if (empty($this->oldVersion)) {
253                $this->oldVersion = Configuration::get('PS_INSTALL_VERSION');
254            }
255            // Since 1.4.4.0
256            // Fix complete version number if there is not all 4 numbers
257            // Eg. replace 1.4.3 by 1.4.3.0
258            // Will result in file 1.4.3.0.sql will be skipped if oldversion is 1.4.3
259            $arrayVersion = preg_split('#\.#', $this->oldVersion);
260            $versionNumbers = count($arrayVersion);
261
262            if ($versionNumbers != 4) {
263                $arrayVersion = array_pad($arrayVersion, 4, '0');
264            }
265
266            $this->oldVersion = implode('.', $arrayVersion);
267            // End of fix
268
269            if (!defined('_PS_CACHE_ENABLED_')) {
270                define('_PS_CACHE_ENABLED_', '0');
271            }
272            if (!defined('_MYSQL_ENGINE_')) {
273                define('_MYSQL_ENGINE_', 'MyISAM');
274            }
275
276            if (!defined('_PS_TOOL_DIR_')) {
277                define('_PS_TOOL_DIR_', _PS_ROOT_DIR_ . '/tools/');
278            }
279            if (!defined('_PS_TRANSLATIONS_DIR_')) {
280                define('_PS_TRANSLATIONS_DIR_', _PS_ROOT_DIR_ . '/translations/');
281            }
282            if (!defined('_PS_MODULE_DIR_')) {
283                define('_PS_MODULE_DIR_', _PS_ROOT_DIR_ . '/modules/');
284            }
285            if (!defined('_PS_MAILS_DIR_')) {
286                define('_PS_MAILS_DIR_', _PS_ROOT_DIR_ . '/mails/');
287            }
288            if (!defined('_MEDIA_SERVER_1_')) {
289                define('_MEDIA_SERVER_1_', '');
290            }
291
292            if (!defined('_PS_USE_SQL_SLAVE_')) {
293                define('_PS_USE_SQL_SLAVE_', false);
294            }
295        }
296
297        private function initContext()
298        {
299            $smarty = null;
300            Cache::clean('*');
301
302            Context::getContext()->shop = new Shop(1);
303            Shop::setContext(Shop::CONTEXT_SHOP, 1);
304
305            if (!isset(Context::getContext()->language) || !Validate::isLoadedObject(Context::getContext()->language)) {
306                $idLang = (int) $this->getConfValue('PS_LANG_DEFAULT');
307                Context::getContext()->language = new Language($idLang ? $idLang : null);
308            }
309            if (!isset(Context::getContext()->country) || !Validate::isLoadedObject(Context::getContext()->country)) {
310                if ($id_country = (int) $this->getConfValue('PS_COUNTRY_DEFAULT')) {
311                    Context::getContext()->country = new Country((int) $id_country);
312                }
313            }
314
315            Context::getContext()->cart = new Cart();
316            Context::getContext()->employee = new Employee(1);
317
318            require_once _PS_ROOT_DIR_ . '/config/smarty.config.inc.php';
319
320            Context::getContext()->smarty = $smarty;
321            Language::loadLanguages();
322
323            $this->translator = Context::getContext()->getTranslator();
324        }
325
326        private function getConfValue($name)
327        {
328            $sql = 'SELECT IF(cl.`id_lang` IS NULL, c.`value`, cl.`value`) AS value
329			FROM `' . _DB_PREFIX_ . 'configuration` c
330			LEFT JOIN `' . _DB_PREFIX_ . 'configuration_lang` cl ON (c.`id_configuration` = cl.`id_configuration`)
331			WHERE c.`name`=\'' . pSQL($name) . '\'';
332
333            $id_shop = Shop::getContextShopID(true);
334            $id_shop_group = Shop::getContextShopGroupID(true);
335            if ($id_shop) {
336                $sql .= ' AND c.`id_shop` = ' . (int) $id_shop;
337            }
338            if ($id_shop_group) {
339                $sql .= ' AND c.`id_shop_group` = ' . (int) $id_shop_group;
340            }
341
342            return $this->db->getValue($sql);
343        }
344
345        private function getThemeManager($idEmployee)
346        {
347            $context = Context::getContext();
348            $context->employee = new Employee((int) $idEmployee);
349
350            return (new ThemeManagerBuilder($context, Db::getInstance()))->build();
351        }
352
353        private function checkVersion()
354        {
355            $versionCompare = version_compare(_PS_INSTALL_VERSION_, $this->oldVersion);
356            if ($versionCompare == '-1') {
357                $this->logError('Current version: %current%. Version to install: %future%.', 27, ['%current%' => $this->oldVersion, '%future%' => _PS_INSTALL_VERSION_]);
358            } elseif ($versionCompare == 0) {
359                $this->logError('You already have the %future% version.', 28, ['%future%' => _PS_INSTALL_VERSION_]);
360            }
361
362            if (strpos(_PS_INSTALL_VERSION_, '.') === false) {
363                $this->logError(
364                    '%install_version% is not a valid version number.',
365                    40,
366                    ['%install_version%' => _PS_INSTALL_VERSION_]
367                );
368            }
369        }
370
371        private function getSQLFiles()
372        {
373            //custom sql file creation
374            $neededUpgradeFiles = [];
375            if (!$this->hasFailure()) {
376                $upgradeFiles = [];
377                if (!file_exists(_PS_INSTALLER_SQL_UPGRADE_DIR_)) {
378                    $this->logError('Unable to find upgrade directory in the installation path.', 31);
379                }
380
381                if ($handle = opendir(_PS_INSTALLER_SQL_UPGRADE_DIR_)) {
382                    while (false !== ($file = readdir($handle))) {
383                        if (!in_array($file, ['.', '..', 'index.php'])) {
384                            $upgradeFiles[] = str_replace('.sql', '', $file);
385                        }
386                    }
387                    closedir($handle);
388                }
389                if (empty($upgradeFiles)) {
390                    $this->logError('Cannot find the SQL upgrade files. Please verify that the %folder% folder is not empty)', 31, ['%folder%' => _PS_INSTALLER_SQL_UPGRADE_DIR_]);
391                }
392                natcasesort($upgradeFiles);
393
394                $neededUpgradeFiles = [];
395                foreach ($upgradeFiles as $version) {
396                    if (version_compare($version, $this->oldVersion) == 1 && version_compare(_PS_INSTALL_VERSION_, $version) != -1) {
397                        $neededUpgradeFiles[] = $version;
398                    }
399                }
400            }
401            if (!$this->hasFailure() && empty($neededUpgradeFiles)) {
402                $this->logError('No upgrade is possible.', 32);
403            }
404
405            $sqlContentVersion = [];
406            $mysqlEngine = (defined('_MYSQL_ENGINE_') ? _MYSQL_ENGINE_ : 'MyISAM');
407            if (!$this->hasFailure()) {
408                foreach ($neededUpgradeFiles as $version) {
409                    $file = _PS_INSTALLER_SQL_UPGRADE_DIR_ . $version . '.sql';
410                    if (!file_exists($file)) {
411                        $this->logError('Error while loading SQL upgrade file "%file%.sql".', 33, ['%file%' => $version]);
412                    }
413                    if (!$sqlContent = file_get_contents($file)) {
414                        $this->logError('Error while loading SQL upgrade file "%file%.sql".', 33, ['%file%' => $version]);
415                    }
416                    $sqlContent .= "\n";
417                    $sqlContent = str_replace([self::FILE_PREFIX, self::ENGINE_TYPE, self::DB_NAME], [_DB_PREFIX_, $mysqlEngine, _DB_NAME_], $sqlContent);
418                    $sqlContent = preg_split("/;\s*[\r\n]+/", $sqlContent);
419
420                    $sqlContentVersion[$version] = $sqlContent;
421                }
422            }
423
424            return $sqlContentVersion;
425        }
426
427        private function upgradeDoctrineSchema()
428        {
429            $schemaUpgrade = new UpgradeDatabase();
430            $schemaUpgrade->addDoctrineSchemaUpdate();
431            $output = $schemaUpgrade->execute();
432            if (0 !== $output['prestashop:schema:update-without-foreign']['exitCode']) {
433                $msgErrors = explode("\n", $output['prestashop:schema:update-without-foreign']['output']);
434                $this->logError('Error upgrading doctrine schema', 43);
435                foreach ($msgErrors as $msgError) {
436                    $this->logError('Doctrine SQL Error : ' . $msgError, 43);
437                }
438            }
439        }
440
441        public function upgradeDb($sqlContentVersion)
442        {
443            $db = $this->db;
444            foreach ($sqlContentVersion as $version => $sqlContent) {
445                foreach ($sqlContent as $query) {
446                    $query = trim($query);
447                    if (!empty($query)) {
448                        /* If php code have to be executed */
449                        if (strpos($query, '/* PHP:') !== false) {
450                            /* Parsing php code */
451                            $pos = strpos($query, '/* PHP:') + strlen('/* PHP:');
452                            $phpString = substr($query, $pos, strlen($query) - $pos - strlen(' */;'));
453                            $php = explode('::', $phpString);
454                            preg_match('/\((.*)\)/', $phpString, $pattern);
455                            $paramsString = trim($pattern[0], '()');
456                            preg_match_all('/([^,]+),? ?/', $paramsString, $parameters);
457                            if (isset($parameters[1])) {
458                                $parameters = $parameters[1];
459                            } else {
460                                $parameters = [];
461                            }
462                            if (is_array($parameters)) {
463                                foreach ($parameters as &$parameter) {
464                                    $parameter = str_replace('\'', '', $parameter);
465                                }
466                                unset($parameter);
467                            }
468
469                            $phpRes = null;
470                            /* Call a simple function */
471                            if (strpos($phpString, '::') === false) {
472                                $func_name = str_replace($pattern[0], '', $php[0]);
473                                if (!file_exists(_PS_INSTALLER_PHP_UPGRADE_DIR_ . strtolower($func_name) . '.php')) {
474                                    $this->logWarning('[ERROR] ' . $version . ' PHP - missing file ' . $query, 41, [], true);
475                                } else {
476                                    require_once _PS_INSTALLER_PHP_UPGRADE_DIR_ . Tools::strtolower($func_name) . '.php';
477                                    $phpRes = call_user_func_array($func_name, $parameters);
478                                }
479                            } else {
480                                /* Or an object method, not supported */
481                                $this->logWarning('[ERROR] ' . $version . ' PHP - Object Method call is forbidden (' . $php[0] . '::' . str_replace($pattern[0], '', $php[1]) . ')', 42, [], true);
482                            }
483                            if ((is_array($phpRes) && !empty($phpRes['error'])) || $phpRes === false) {
484                                $this->logWarning('[ERROR] PHP ' . $version . ' ' . $query . "\n" . '
485								' . (empty($phpRes['error']) ? '' : $phpRes['error'] . "\n") . '
486								' . (empty($phpRes['msg']) ? '' : ' - ' . $phpRes['msg']), $version, [], true);
487                            } else {
488                                $this->logInfo('[OK] PHP ' . $version . ' : ' . $query, $version, [], true);
489                            }
490                        } else {
491                            if (!$db->execute($query)) {
492                                $error = $db->getMsgError();
493                                $error_number = $db->getNumberError();
494
495                                $duplicates = ['1050', '1054', '1060', '1061', '1062', '1091'];
496                                if (!in_array($error_number, $duplicates)) {
497                                    $this->logWarning('SQL ' . $version . '
498								' . $error_number . ' in ' . $query . ': ' . $error, $version, [], true);
499                                } else {
500                                    $this->logInfo('SQL ' . $version . '
501								' . $error_number . ' in ' . $query . ': ' . $error, $version, [], true);
502                                }
503                            } else {
504                                $this->logInfo('[OK] SQL ' . $version . ' : ' . $query, $version, [], true);
505                            }
506                        }
507                    }
508                }
509            }
510            // reload config after DB upgrade
511            Configuration::loadConfiguration();
512        }
513
514        private function disableCustomModules()
515        {
516            $moduleManagerBuilder = ModuleManagerBuilder::getInstance();
517            $moduleRepository = $moduleManagerBuilder->buildRepository();
518            $moduleRepository->clearCache();
519
520            $filters = new AddonListFilter();
521            $filters->setType(AddonListFilterType::MODULE)
522                ->removeStatus(AddonListFilterStatus::UNINSTALLED);
523
524            $installedProducts = $moduleRepository->getFilteredList($filters);
525            /** @var \PrestaShop\PrestaShop\Adapter\Module\Module $installedProduct */
526            foreach ($installedProducts as $installedProduct) {
527                if (!(
528                        $installedProduct->attributes->has('origin_filter_value')
529                        && in_array(
530                            $installedProduct->attributes->get('origin_filter_value'),
531                            [
532                                AddonListFilterOrigin::ADDONS_NATIVE,
533                                AddonListFilterOrigin::ADDONS_NATIVE_ALL,
534                            ]
535                        )
536                        && 'PrestaShop' === $installedProduct->attributes->get('author')
537                    )
538                    && 'autoupgrade' !== $installedProduct->attributes->get('name')) {
539                    $moduleName = $installedProduct->attributes->get('name');
540                    $this->logInfo('Disabling custom module ' . $moduleName);
541                    Module::disableAllByName($moduleName);
542                }
543            }
544
545            return true;
546        }
547
548        private function disableIncompatibleModules()
549        {
550            $fs = new Filesystem();
551
552            $moduleManagerBuilder = ModuleManagerBuilder::getInstance();
553            $moduleManagerRepository = $moduleManagerBuilder->buildRepository();
554            $moduleManagerRepository->clearCache();
555
556            $filters = new AddonListFilter();
557            $filters->setStatus(AddonListFilterStatus::ON_DISK | AddonListFilterStatus::INSTALLED);
558
559            $list = $moduleManagerRepository->getFilteredList($filters, true);
560            /** @var string $moduleName */
561            /** @var \PrestaShop\PrestaShop\Adapter\Module\Module $module */
562            foreach ($list as $moduleName => $module) {
563                if (in_array($moduleName, self::$incompatibleModules)) {
564                    $this->logInfo("Uninstalling module $moduleName, not supported in this PrestaShop version.");
565                    $module->onUninstall();
566                    $fs->remove(_PS_MODULE_DIR_ . $moduleName);
567                } else {
568                    $attributes = $module->attributes;
569                    if ($attributes->get('compatibility')) {
570                        $maxVersion = $attributes->get('compatibility')->to;
571                        if (version_compare($maxVersion, _PS_INSTALL_VERSION_) == -1 && Module::isEnabled($moduleName)) {
572                            $this->logInfo("Disabling module $moduleName. Max supported version : " . $maxVersion);
573                            Module::disableAllByName($moduleName);
574                        }
575                    }
576                }
577            }
578
579            return true;
580        }
581
582        private function enableNativeModules()
583        {
584            $moduleManagerBuilder = ModuleManagerBuilder::getInstance();
585            $moduleManagerRepository = $moduleManagerBuilder->buildRepository();
586            $moduleManagerRepository->clearCache();
587
588            $filters = new AddonListFilter();
589            $filters->setOrigin(AddonListFilterOrigin::ADDONS_NATIVE | AddonListFilterOrigin::ADDONS_NATIVE_ALL);
590
591            $list = $moduleManagerRepository->getFilteredList($filters, true);
592            /** @var string $moduleName */
593            /** @var \PrestaShop\PrestaShop\Adapter\Module\Module $module */
594            foreach ($list as $moduleName => $module) {
595                if ('PrestaShop' === $module->attributes->get('author')) {
596                    if (!$moduleManagerBuilder->build()->isInstalled($moduleName)) {
597                        $this->logInfo('Installing native module ' . $moduleName);
598                        $module = $moduleManagerRepository->getModule($moduleName);
599                        $module->onInstall();
600                        $module->onEnable();
601                    } else {
602                        $this->logInfo('Native module ' . $moduleName . ' already installed');
603                    }
604                }
605            }
606
607            return true;
608        }
609
610        private function cleanCache()
611        {
612            // Settings updated, compile and cache directories must be emptied
613            $install_dir = realpath(rtrim(_PS_INSTALL_PATH_, '\\/') . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
614            $tools_dir = $install_dir . 'tools' . DIRECTORY_SEPARATOR;
615            $arrayToClean = [
616                $tools_dir . 'smarty' . DIRECTORY_SEPARATOR . 'cache',
617                $tools_dir . 'smarty' . DIRECTORY_SEPARATOR . 'compile',
618                $tools_dir . 'smarty_v2' . DIRECTORY_SEPARATOR . 'cache',
619                $tools_dir . 'smarty_v2' . DIRECTORY_SEPARATOR . 'compile',
620                $install_dir . 'app' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR,
621                $install_dir . 'cache' . DIRECTORY_SEPARATOR . 'smarty' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR,
622                $install_dir . 'cache' . DIRECTORY_SEPARATOR . 'smarty' . DIRECTORY_SEPARATOR . 'compile' . DIRECTORY_SEPARATOR,
623            ];
624
625            foreach ($arrayToClean as $dir) {
626                if (file_exists($dir)) {
627                    foreach (scandir($dir, SCANDIR_SORT_NONE) as $file) {
628                        if ($file[0] != '.' && $file != 'index.php' && $file != '.htaccess') {
629                            if (is_file($dir . $file)) {
630                                unlink($dir . $file);
631                            } elseif (is_dir($dir . $file . DIRECTORY_SEPARATOR)) {
632                                //\Tools14::deleteDirectory($dir . $file . DIRECTORY_SEPARATOR, true);
633                            }
634                            // To more log
635                            //$this->logInfo('[CLEANING CACHE] File %file% removed', null, array('%file%' => $file));
636                        }
637                    }
638                } else {
639                    $this->logInfo('[SKIP] directory "%directory%" does not exist and cannot be emptied.', null, ['%directory%' => str_replace($tools_dir, '', $dir)]);
640                }
641            }
642
643            if (file_exists(_PS_ROOT_DIR_ . '/var/cache/dev/class_index.php')) {
644                unlink(_PS_ROOT_DIR_ . '/var/cache/dev/class_index.php');
645            }
646            if (file_exists(_PS_ROOT_DIR_ . '/var/cache/prod/class_index.php')) {
647                unlink(_PS_ROOT_DIR_ . '/var/cache/prod/class_index.php');
648            }
649
650            // Clear XML files
651            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/blog-fr.xml')) {
652                unlink(_PS_ROOT_DIR_ . '/config/xml/blog-fr.xml');
653            }
654            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/default_country_modules_list.xml')) {
655                unlink(_PS_ROOT_DIR_ . '/config/xml/default_country_modules_list.xml');
656            }
657            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/modules_list.xml')) {
658                unlink(_PS_ROOT_DIR_ . '/config/xml/modules_list.xml');
659            }
660            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/modules_native_addons.xml')) {
661                unlink(_PS_ROOT_DIR_ . '/config/xml/modules_native_addons.xml');
662            }
663            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/must_have_modules_list.xml')) {
664                unlink(_PS_ROOT_DIR_ . '/config/xml/must_have_modules_list.xml');
665            }
666            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/tab_modules_list.xml')) {
667                unlink(_PS_ROOT_DIR_ . '/config/xml/tab_modules_list.xml');
668            }
669            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/trusted_modules_list.xml')) {
670                unlink(_PS_ROOT_DIR_ . '/config/xml/trusted_modules_list.xml');
671            }
672            if (file_exists(_PS_ROOT_DIR_ . '/config/xml/untrusted_modules_list.xml')) {
673                unlink(_PS_ROOT_DIR_ . '/config/xml/untrusted_modules_list.xml');
674            }
675        }
676
677        private function cleanDefaultThemeCache()
678        {
679            $separator = addslashes(DIRECTORY_SEPARATOR);
680            $file = _PS_ROOT_DIR_ . $separator . 'themes' . $separator . _THEME_NAME_ . $separator . 'cache' . $separator;
681            if (file_exists($file)) {
682                foreach (scandir($file, SCANDIR_SORT_NONE) as $cache) {
683                    if ($cache[0] != '.' && $cache != 'index.php' && $cache != '.htaccess' && file_exists($file . $cache) && !is_dir($file . $cache)) {
684                        if (file_exists($file . $cache)) {
685                            unlink($file . $cache);
686                        }
687                    }
688                }
689            }
690        }
691
692        private function updateDbImagesLegacy()
693        {
694            $db = $this->db;
695            $db->execute('UPDATE `' . _DB_PREFIX_ . 'configuration` SET `name` = \'PS_LEGACY_IMAGES\' WHERE name LIKE \'0\' AND `value` = 1');
696            $db->execute('UPDATE `' . _DB_PREFIX_ . 'configuration` SET `value` = 0 WHERE `name` LIKE \'PS_LEGACY_IMAGES\'');
697            if ($db->getValue('SELECT COUNT(id_product_download) FROM `' . _DB_PREFIX_ . 'product_download` WHERE `active` = 1') > 0) {
698                $db->execute('UPDATE `' . _DB_PREFIX_ . 'configuration` SET `value` = 1 WHERE `name` LIKE \'PS_VIRTUAL_PROD_FEATURE_ACTIVE\'');
699            }
700        }
701
702        private function cleanupOldDirectories()
703        {
704            if ($this->adminDir) {
705                $path = $this->adminDir . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR
706                    . 'template' . DIRECTORY_SEPARATOR . 'controllers' . DIRECTORY_SEPARATOR . 'modules'
707                    . DIRECTORY_SEPARATOR . 'header.tpl';
708                if (file_exists($path)) {
709                    unlink($path);
710                }
711            }
712        }
713
714        private function updateLangs()
715        {
716            $langs = $this->db->executeS('SELECT * FROM `' . _DB_PREFIX_ . 'lang` WHERE `active` = 1');
717
718            if (is_array($langs)) {
719                foreach ($langs as $lang) {
720                    $isoCode = $lang['iso_code'];
721
722                    if (Validate::isLangIsoCode($isoCode)) {
723                        $errorsLanguage = [];
724
725                        Language::downloadLanguagePack($isoCode, AppKernel::VERSION, $errorsLanguage);
726
727                        $lang_pack = Language::getLangDetails($isoCode);
728                        Language::installSfLanguagePack($lang_pack['locale'], $errorsLanguage);
729                        self::generateEmailsLanguagePack($lang_pack, $errorsLanguage);
730
731                        if (empty($errorsLanguage)) {
732                            Language::loadLanguages();
733                        } else {
734                            $this->logError('Error updating translations', 44);
735                        }
736
737                        Language::updateMultilangTable($isoCode);
738                    }
739                }
740            }
741        }
742
743        /**
744         * @param array $langPack
745         * @param array $errors
746         */
747        private static function generateEmailsLanguagePack($langPack, &$errors = [])
748        {
749            $locale = $langPack['locale'];
750            $sfContainer = SymfonyContainer::getInstance();
751            if (null === $sfContainer) {
752                $errors[] = Context::getContext()->getTranslator()->trans(
753                    'Cannot generate emails because the Symfony container is unavailable.',
754                    [],
755                    'Admin.Notifications.Error'
756                );
757
758                return;
759            }
760
761            $mailTheme = Configuration::get('PS_MAIL_THEME');
762            /** @var GenerateThemeMailTemplatesCommand $generateCommand */
763            $generateCommand = new GenerateThemeMailTemplatesCommand(
764                $mailTheme,
765                $locale,
766                false,
767                '',
768                ''
769            );
770            /** @var CommandBusInterface $commandBus */
771            $commandBus = $sfContainer->get('prestashop.core.command_bus');
772            try {
773                $commandBus->handle($generateCommand);
774            } catch (CoreException $e) {
775                $errors[] = Context::getContext()->getTranslator()->trans(
776                    'Cannot generate email templates: %s.',
777                    [$e->getMessage()],
778                    'Admin.Notifications.Error'
779                );
780            }
781        }
782
783        private function updateHtaccess()
784        {
785            if (!class_exists('\Tools2', false) && class_exists('\ToolsCore')) {
786                eval('class Tools2 extends \ToolsCore{}');
787            }
788
789            /* @phpstan-ignore-next-line */
790            if (class_exists('\Tools2') && method_exists('\Tools2', 'generateHtaccess')) {
791                $url_rewrite = (bool) $this->db->getValue('SELECT `value` FROM `' . _DB_PREFIX_ . 'configuration` WHERE name=\'PS_REWRITING_SETTINGS\'');
792
793                \Tools2::generateHtaccess(null, $url_rewrite);
794            }
795        }
796
797        private function updateTheme()
798        {
799            $themeManager = $this->getThemeManager($this->idEmployee);
800            $themeName = ($this->changeToDefaultTheme ? 'classic' : _THEME_NAME_);
801
802            $isThemeEnabled = $themeManager->enable($themeName, true);
803            if (!$isThemeEnabled) {
804                $themeErrors = $themeManager->getErrors($themeName);
805                $this->logError($themeErrors, 45);
806            }
807        }
808
809        public function run()
810        {
811            Tools::clearAllCache();
812
813            $this->defineConst();
814            $this->initContext();
815            $this->checkVersion();
816
817            $sqlContentVersion = $this->getSQLFiles();
818
819            if (!$this->hasFailure()) {
820                $this->disableIncompatibleModules();
821
822                if ($this->disableCustomModules) {
823                    $this->disableCustomModules();
824                }
825
826                $this->upgradeDb($sqlContentVersion);
827                $this->upgradeDoctrineSchema();
828
829                $this->enableNativeModules();
830
831                $this->cleanCache();
832
833                $this->updateDbImagesLegacy();
834                if ($this->updateDefaultTheme) {
835                    $this->cleanDefaultThemeCache();
836                }
837                $this->cleanupOldDirectories();
838                $this->updateLangs();
839                $this->updateHtaccess();
840
841                if ($this->idEmployee) {
842                    $this->updateTheme();
843                }
844            }
845        }
846
847        public function doUpgradeDb()
848        {
849            Tools::clearAllCache();
850
851            $this->defineConst();
852            $this->initContext();
853            $this->checkVersion();
854
855            $sqlContentVersion = $this->getSQLFiles();
856
857            if (!$this->hasFailure()) {
858                $this->upgradeDb($sqlContentVersion);
859                $this->upgradeDoctrineSchema();
860            }
861
862            $this->next = 'DisableModules';
863            $this->nextDesc = $this->getTranslator()->trans('Database upgrade completed.', [], 'Install');
864            $this->nextQuickInfo[] = $this->getTranslator()->trans('Database upgrade completed.', [], 'Install');
865            $this->nextQuickInfo[] = $this->getTranslator()->trans('Disabling modules now...', [], 'Install');
866        }
867
868        public function doDisableModules()
869        {
870            $this->defineConst();
871            $this->initContext();
872
873            $this->disableIncompatibleModules();
874
875            if ($this->disableCustomModules) {
876                $this->disableCustomModules();
877            }
878
879            $this->next = 'EnableModules';
880            $this->nextDesc = $this->getTranslator()->trans('Modules successfully disabled.', [], 'Install');
881            $this->nextQuickInfo[] = $this->getTranslator()->trans('Modules successfully disabled.', [], 'Install');
882            $this->nextQuickInfo[] = $this->getTranslator()->trans('Enabling modules now...', [], 'Install');
883        }
884
885        public function doEnableModules()
886        {
887            $this->defineConst();
888            $this->initContext();
889
890            $this->enableNativeModules();
891
892            $this->next = 'UpdateImage';
893            $this->nextDesc = $this->getTranslator()->trans('Modules successfully enabled.', [], 'Install');
894            $this->nextQuickInfo[] = $this->getTranslator()->trans('Modules successfully enabled.', [], 'Install');
895            $this->nextQuickInfo[] = $this->getTranslator()->trans('Upgrading images now...', [], 'Install');
896        }
897
898        public function doUpdateImage()
899        {
900            $this->defineConst();
901            $this->initContext();
902
903            $this->cleanCache();
904
905            $this->updateDbImagesLegacy();
906            if ($this->updateDefaultTheme) {
907                $this->cleanDefaultThemeCache();
908            }
909            $this->cleanupOldDirectories();
910
911            $this->next = 'UpdateLangHtaccess';
912            $this->nextDesc = $this->getTranslator()->trans('Images successfully upgraded.', [], 'Install');
913            $this->nextQuickInfo[] = $this->getTranslator()->trans('Images successfully upgraded.', [], 'Install');
914            $this->nextQuickInfo[] = $this->getTranslator()->trans('Upgrading languages now...', [], 'Install');
915        }
916
917        public function doUpdateLangHtaccess()
918        {
919            $this->defineConst();
920            $this->initContext();
921
922            $this->updateLangs();
923            $this->updateHtaccess();
924
925            $this->next = 'UpdateTheme';
926            $this->nextDesc = $this->getTranslator()->trans('Languages successfully upgraded.', [], 'Install');
927            $this->nextQuickInfo[] = $this->getTranslator()->trans('Languages successfully upgraded.', [], 'Install');
928            $this->nextQuickInfo[] = $this->getTranslator()->trans('Upgrading theme now...', [], 'Install');
929        }
930
931        public function doUpdateTheme()
932        {
933            $this->defineConst();
934            $this->initContext();
935
936            if ($this->idEmployee) {
937                $this->updateTheme();
938            }
939
940            $this->next = 'UpgradeComplete';
941            $this->nextDesc = $this->getTranslator()->trans('Theme successfully upgraded.', [], 'Install');
942            $this->nextQuickInfo[] = $this->getTranslator()->trans('Theme successfully upgraded.', [], 'Install');
943        }
944
945        public function getTranslator()
946        {
947            return $this->translator;
948        }
949
950        public function logInfo($quickInfo, $id = null, $transVariables = [], $dbInfo = false)
951        {
952            $info = $this->getTranslator()->trans($quickInfo, $transVariables, 'Install');
953            if ($this->inAutoUpgrade) {
954                if ($dbInfo) {
955                    $this->nextQuickInfo[] = '<div class="upgradeDbOk">' . $info . '</div>';
956                } else {
957                    $this->nextQuickInfo[] = $info;
958                }
959                $this->infoList[] = $info;
960            } else {
961                if (!empty($quickInfo)) {
962                    $this->logger->logInfo($info);
963                }
964                if ($id !== null) {
965                    if (!is_numeric($id)) {
966                        $customInfo = '<action result="info" id="' . $id . '"><![CDATA[' . htmlentities($info) . "]]></action>\n";
967                    } else {
968                        $customInfo = '<action result="info" id="' . $id . '" />' . "\n";
969                    }
970                    $this->infoList[] = $customInfo;
971                }
972            }
973        }
974
975        public function logWarning($quickInfo, $id, $transVariables = [], $dbInfo = false)
976        {
977            $info = $this->getTranslator()->trans($quickInfo, $transVariables, 'Install');
978            if ($this->inAutoUpgrade) {
979                if ($dbInfo) {
980                    $this->nextQuickInfo[] = '<div class="upgradeDbError">' . $info . '</div>';
981                } else {
982                    $this->nextQuickInfo[] = $info;
983                }
984                $this->nextErrors[] = $info;
985                $this->warningList[] = $info;
986                if (empty($this->failureList)) {
987                    $this->nextDesc = $this->getTranslator()->trans('Warning detected during upgrade.', [], 'Install');
988                }
989            } else {
990                if (!empty($quickInfo)) {
991                    $this->logger->logWarning($info);
992                }
993                if ($id !== null) {
994                    if (!is_numeric($id)) {
995                        $customWarning = '<action result="warning" id="' . $id . '"><![CDATA[' . htmlentities($info) . "]]></action>\n";
996                    } else {
997                        $customWarning = '<action result="warning" id="' . $id . '" />' . "\n";
998                    }
999                    $this->warningList[] = $customWarning;
1000                }
1001            }
1002        }
1003
1004        public function logError($quickInfo, $id, $transVariables = [], $dbInfo = false)
1005        {
1006            $info = $this->getTranslator()->trans($quickInfo, $transVariables, 'Install');
1007            if ($this->inAutoUpgrade) {
1008                if ($dbInfo) {
1009                    $this->nextQuickInfo[] = '<div class="upgradeDbError">' . $info . '</div>';
1010                } else {
1011                    $this->nextQuickInfo[] = $info;
1012                }
1013                $this->nextErrors[] = $info;
1014                $this->failureList[] = $info;
1015                $this->nextDesc = $this->getTranslator()->trans('Error detected during upgrade.', [], 'Install');
1016                $this->next = 'error';
1017            } else {
1018                if (!empty($quickInfo)) {
1019                    $this->logger->logError($info);
1020                }
1021                if ($id !== null) {
1022                    if (!is_numeric($id)) {
1023                        $customError = '<action result="error" id="' . $id . '"><![CDATA[' . htmlentities($info) . "]]></action>\n";
1024                    } else {
1025                        $customError = '<action result="error" id="' . $id . '" />' . "\n";
1026                    }
1027                    $this->failureList[] = $customError;
1028                }
1029            }
1030        }
1031
1032        public function getInAutoUpgrade()
1033        {
1034            return $this->inAutoUpgrade;
1035        }
1036
1037        public function setInAutoUpgrade($value)
1038        {
1039            $this->inAutoUpgrade = $value;
1040        }
1041
1042        public function getNext()
1043        {
1044            return $this->next;
1045        }
1046
1047        public function getNextDesc()
1048        {
1049            return $this->nextDesc;
1050        }
1051
1052        public function getInfoList()
1053        {
1054            return $this->infoList;
1055        }
1056
1057        public function getWarningList()
1058        {
1059            return $this->warningList;
1060        }
1061
1062        public function getFailureList()
1063        {
1064            return $this->failureList;
1065        }
1066
1067        public function getNextQuickInfo()
1068        {
1069            return $this->nextQuickInfo;
1070        }
1071
1072        public function getNextErrors()
1073        {
1074            return $this->nextErrors;
1075        }
1076
1077        public function hasInfo()
1078        {
1079            return !empty($this->infoList);
1080        }
1081
1082        public function hasWarning()
1083        {
1084            return !empty($this->warningList);
1085        }
1086
1087        public function hasFailure()
1088        {
1089            return !empty($this->failureList);
1090        }
1091
1092        public const SETTINGS_FILE = 'config/settings.inc.php';
1093
1094        /* @phpstan-ignore-next-line */
1095        public static function migrateSettingsFile(Event $event = null)
1096        {
1097            if ($event !== null) {
1098                /* @phpstan-ignore-next-line */
1099                $event->getIO()->write('Migrating old setting file...');
1100            }
1101
1102            $root_dir = realpath(__DIR__ . '/../../../');
1103
1104            $phpParametersFilepath = $root_dir . '/app/config/parameters.php';
1105            $addNewCookieKey = false;
1106            if (file_exists($phpParametersFilepath)) {
1107                $default_parameters = require $phpParametersFilepath;
1108                if (!array_key_exists('new_cookie_key', $default_parameters['parameters'])) {
1109                    $addNewCookieKey = true;
1110                } else {
1111                    if ($event !== null) {
1112                        /* @phpstan-ignore-next-line */
1113                        $event->getIO()->write('parameters file already exists!');
1114                        /* @phpstan-ignore-next-line */
1115                        $event->getIO()->write('Finished...');
1116                    }
1117
1118                    return false;
1119                }
1120            }
1121
1122            if (!file_exists($phpParametersFilepath) && !file_exists($root_dir . '/app/config/parameters.yml')
1123                && !file_exists($root_dir . '/' . self::SETTINGS_FILE)) {
1124                if ($event !== null) {
1125                    /* @phpstan-ignore-next-line */
1126                    $event->getIO()->write('No file to migrate!');
1127                    /* @phpstan-ignore-next-line */
1128                    $event->getIO()->write('Finished...');
1129                }
1130
1131                return false;
1132            }
1133
1134            $filesystem = new Filesystem();
1135            $exportPhpConfigFile = function ($config, $destination) use ($filesystem) {
1136                try {
1137                    $filesystem->dumpFile($destination, '<?php return ' . var_export($config, true) . ';' . "\n");
1138                } catch (IOException $e) {
1139                    return false;
1140                }
1141
1142                return true;
1143            };
1144
1145            $fileMigrated = false;
1146            if (!$addNewCookieKey) {
1147                $default_parameters = Yaml::parse(file_get_contents($root_dir . '/app/config/parameters.yml.dist'));
1148            }
1149            $default_parameters['parameters']['new_cookie_key'] = PhpEncryption::createNewRandomKey();
1150
1151            if ($addNewCookieKey) {
1152                $exportPhpConfigFile($default_parameters, $phpParametersFilepath);
1153                if ($event !== null) {
1154                    /* @phpstan-ignore-next-line */
1155                    $event->getIO()->write('parameters file already exists!');
1156                    /* @phpstan-ignore-next-line */
1157                    $event->getIO()->write("add new parameter 'new_cookie_key'");
1158                    /* @phpstan-ignore-next-line */
1159                    $event->getIO()->write('Finished...');
1160                }
1161
1162                return false;
1163            }
1164
1165            if (file_exists($root_dir . '/' . self::SETTINGS_FILE)) {
1166                $tmp_settings = file_get_contents($root_dir . '/' . self::SETTINGS_FILE);
1167            } else {
1168                $tmp_settings = null;
1169            }
1170
1171            if (!file_exists($root_dir . '/app/config/parameters.yml') && $tmp_settings && strpos($tmp_settings, '_DB_SERVER_') !== false) {
1172                $tmp_settings = preg_replace('/(\'|")\_/', '$1_LEGACY_', $tmp_settings);
1173                $tmp_settings_file = str_replace('/settings', '/tmp_settings', $root_dir . '/' . self::SETTINGS_FILE);
1174                file_put_contents($tmp_settings_file, $tmp_settings);
1175                include $tmp_settings_file;
1176                @unlink($tmp_settings_file);
1177                $factory = new RandomLib\Factory();
1178                $generator = $factory->getLowStrengthGenerator();
1179                $secret = $generator->generateString(64);
1180
1181                if (!defined('_LEGACY_NEW_COOKIE_KEY_')) {
1182                    define('_LEGACY_NEW_COOKIE_KEY_', $default_parameters['parameters']['new_cookie_key']);
1183                }
1184
1185                $db_server_port = explode(':', _LEGACY_DB_SERVER_);
1186                if (count($db_server_port) == 1) {
1187                    $db_server = $db_server_port[0];
1188                    $db_port = 3306;
1189                } else {
1190                    $db_server = $db_server_port[0];
1191                    $db_port = $db_server_port[1];
1192                }
1193
1194                $parameters = [
1195                    'parameters' => [
1196                        'database_host' => $db_server,
1197                        'database_port' => $db_port,
1198                        'database_user' => _LEGACY_DB_USER_,
1199                        'database_password' => _LEGACY_DB_PASSWD_,
1200                        'database_name' => _LEGACY_DB_NAME_,
1201                        'database_prefix' => _LEGACY_DB_PREFIX_,
1202                        'database_engine' => defined(_LEGACY_MYSQL_ENGINE_) ? _LEGACY_MYSQL_ENGINE_ : 'InnoDB',
1203                        'cookie_key' => _LEGACY_COOKIE_KEY_,
1204                        'cookie_iv' => _LEGACY_COOKIE_IV_,
1205                        'new_cookie_key' => _LEGACY_NEW_COOKIE_KEY_,
1206                        'ps_caching' => defined(_LEGACY_PS_CACHING_SYSTEM_) ? _LEGACY_PS_CACHING_SYSTEM_ : 'CacheMemcache',
1207                        'ps_cache_enable' => defined(_LEGACY_PS_CACHE_ENABLED_) ? _LEGACY_PS_CACHE_ENABLED_ : false,
1208                        'ps_creation_date' => defined(_LEGACY_PS_CREATION_DATE_) ? _LEGACY_PS_CREATION_DATE_ : date('Y-m-d H:i:s'),
1209                        'secret' => $secret,
1210                        'mailer_transport' => 'smtp',
1211                        'mailer_host' => '127.0.0.1',
1212                        'mailer_user' => '',
1213                        'mailer_password' => '',
1214                    ] + $default_parameters['parameters'],
1215                ];
1216            } elseif (file_exists($root_dir . '/app/config/parameters.yml')) {
1217                $parameters = Yaml::parse(file_get_contents($root_dir . '/app/config/parameters.yml'));
1218                if (empty($parameters['parameters'])) {
1219                    $parameters['parameters'] = [];
1220                }
1221                // add potentially missing default entries
1222                $parameters['parameters'] = $parameters['parameters'] + $default_parameters['parameters'];
1223            } else {
1224                $parameters = $default_parameters;
1225            }
1226
1227            if (!empty($parameters) && $exportPhpConfigFile($parameters, $phpParametersFilepath)) {
1228                $fileMigrated = true;
1229                $settings_content = "<?php\n";
1230                $settings_content .= '//@deprecated 1.7';
1231
1232                file_put_contents($root_dir . '/' . self::SETTINGS_FILE, $settings_content);
1233                file_put_contents($root_dir . '/app/config/parameters.yml', 'parameters:');
1234            }
1235
1236            if ($event !== null) {
1237                if (!$fileMigrated) {
1238                    /* @phpstan-ignore-next-line */
1239                    $event->getIO()->write('No old config file present!');
1240                }
1241                /* @phpstan-ignore-next-line */
1242                $event->getIO()->write('Finished...');
1243            }
1244
1245            return true;
1246        }
1247    }
1248}
1249