This commit is contained in:
2025-04-01 00:38:54 +02:00
parent d4d4c0c09d
commit 87da06293a
22351 changed files with 5168854 additions and 7538 deletions

View File

@@ -0,0 +1,169 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task;
use Exception;
use PrestaShop\Module\AutoUpgrade\AjaxResponse;
use PrestaShop\Module\AutoUpgrade\Analytics;
use PrestaShop\Module\AutoUpgrade\Log\Logger;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Translator;
abstract class AbstractTask
{
/**
* usage : key = the step you want to skip
* value = the next step you want instead
* example : public static $skipAction = array();
*
* @var array<string, string>
*/
public static $skipAction = [];
/**
* @var Logger
*/
protected $logger;
/**
* @var Translator
*/
protected $translator;
/**
* @var UpgradeContainer
*/
protected $container;
/**
* @var 'upgrade'|'rollback'|null
*/
const TASK_TYPE = null;
// Task progress details
/**
* @var bool
*/
protected $stepDone;
/**
* @var string
*/
protected $status;
/**
* @var bool
*/
protected $error;
/**
* @var array<string, string|array<string>>
*/
protected $nextParams = [];
/**
* @var string
*/
protected $next;
/**
* @throws Exception
*/
public function __construct(UpgradeContainer $container)
{
$this->container = $container;
$this->logger = $this->container->getLogger();
$this->translator = $this->container->getTranslator();
$this->checkTaskMayRun();
}
/**
* @return string base64 encoded data from AjaxResponse
*/
public function getEncodedResponse(): string
{
return base64_encode($this->getJsonResponse());
}
/**
* @return string Json encoded data from AjaxResponse
*/
public function getJsonResponse(): string
{
return $this->getResponse()->getJson();
}
/**
* Get result of the task and data to send to the next request.
*
* @return AjaxResponse
*/
public function getResponse(): AjaxResponse
{
$response = new AjaxResponse($this->container->getState(), $this->logger);
return $response->setError($this->error)
->setStepDone($this->stepDone)
->setNext($this->next)
->setNextParams($this->nextParams)
->setUpgradeConfiguration($this->container->getUpgradeConfiguration());
}
private function checkTaskMayRun(): void
{
// PrestaShop demo mode
if (defined('_PS_MODE_DEMO_') && _PS_MODE_DEMO_ == true) {
return;
}
$currentAction = get_class($this);
if (isset(self::$skipAction[$currentAction])) {
$this->next = self::$skipAction[$currentAction];
$this->logger->info($this->translator->trans('Action %s skipped', [$currentAction]));
}
}
public function setErrorFlag(): void
{
$this->error = true;
// TODO: Add this? $this->next = 'error';
if (static::TASK_TYPE) {
$this->container->getAnalytics()->track(
ucfirst(static::TASK_TYPE) . ' Failed',
static::TASK_TYPE === 'upgrade' ? Analytics::WITH_UPGRADE_PROPERTIES : Analytics::WITH_ROLLBACK_PROPERTIES
);
}
}
/**
* @throws Exception
*/
public function init(): void
{
$this->container->initPrestaShopCore();
}
abstract public function run(): int;
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task;
class ExitCode
{
const SUCCESS = 0;
const FAIL = 1;
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Miscellaneous;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
/**
* List the files modified in the current installation regards to the original version.
*/
class CheckFilesVersion extends AbstractTask
{
/**
* @throws Exception
*/
public function run(): int
{
// do nothing after this request (see javascript function doAjaxRequest )
$this->next = '';
$checksumCompare = $this->container->getChecksumCompare();
$currentPrestaShopVersion = $this->container->getProperty(UpgradeContainer::PS_VERSION);
$changedFileList = $checksumCompare->getTamperedFilesOnShop($currentPrestaShopVersion);
if ($changedFileList === false) {
$this->nextParams['status'] = 'error';
$this->nextParams['msg'] = $this->translator->trans('Unable to check files for the installed version of PrestaShop.');
return ExitCode::FAIL;
}
if ($checksumCompare->isAuthenticPrestashopVersion($currentPrestaShopVersion)) {
$this->nextParams['status'] = 'ok';
$this->nextParams['msg'] = $this->translator->trans('Core files are ok');
} else {
$this->nextParams['status'] = 'warn';
$this->nextParams['msg'] = $this->translator->trans(
'%modificationscount% file modifications have been detected, including %coremodifications% from core and native modules:',
[
'%modificationscount%' => count(array_merge($changedFileList['core'], $changedFileList['mail'], $changedFileList['translation'])),
'%coremodifications%' => count($changedFileList['core']),
]
);
}
$this->nextParams['result'] = $changedFileList;
$this->container->getFileConfigurationStorage()->save($changedFileList['translation'], UpgradeFileNames::TRANSLATION_FILES_CUSTOM_LIST);
$this->container->getFileConfigurationStorage()->save($changedFileList['mail'], UpgradeFileNames::MAILS_CUSTOM_LIST);
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Miscellaneous;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\VersionUtils;
/**
* 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
{
/**
* @throws Exception
*/
public function run(): int
{
// do nothing after this request (see javascript function doAjaxRequest )
$this->next = '';
$channel = $this->container->getUpgradeConfiguration()->get('channel');
$upgrader = $this->container->getUpgrader();
$checksumCompare = $this->container->getChecksumCompare();
switch ($channel) {
case 'archive':
$version = $this->container->getUpgradeConfiguration()->get('archive.version_num');
break;
case 'directory':
$version = $this->container->getUpgradeConfiguration()->get('directory.version_num');
break;
default:
$upgrader->branch = VersionUtils::splitPrestaShopVersion(_PS_VERSION_)['major'];
$upgrader->channel = $channel;
if ($this->container->getUpgradeConfiguration()->get('channel') == 'private' && !$this->container->getUpgradeConfiguration()->get('private_allow_major')) {
$upgrader->checkPSVersion(false, ['private', 'minor']);
} else {
$upgrader->checkPSVersion(false, ['minor']);
}
$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 = $checksumCompare->getFilesDiffBetweenVersions(_PS_VERSION_, $version);
if (!is_array($diffFileList)) {
$this->nextParams['status'] = 'error';
$this->nextParams['msg'] = sprintf('Unable to generate diff file list between %1$s and %2$s.', _PS_VERSION_, $version);
} else {
$this->container->getFileConfigurationStorage()->save($diffFileList, UpgradeFileNames::FILES_DIFF_LIST);
$this->nextParams['msg'] = $this->translator->trans(
'%modifiedfiles% files will be modified, %deletedfiles% files will be deleted (if they are found).',
[
'%modifiedfiles%' => count($diffFileList['modified']),
'%deletedfiles%' => count($diffFileList['deleted']),
]);
$this->nextParams['result'] = $diffFileList;
}
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Miscellaneous;
use Exception;
use PrestaShop\Module\AutoUpgrade\ChannelInfo;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\Twig\Block\ChannelInfoBlock;
use Twig\Error\LoaderError;
/**
* display informations related to the selected channel : link/changelog for remote channel,
* or configuration values for special channels.
*/
class GetChannelInfo extends AbstractTask
{
/**
* @throws LoaderError
* @throws Exception
*/
public function run(): int
{
// do nothing after this request (see javascript function doAjaxRequest )
$this->next = '';
$channel = $this->container->getUpgradeConfiguration()->getChannel();
$channelInfo = (new ChannelInfo($this->container->getUpgrader(), $this->container->getUpgradeConfiguration(), $channel));
$channelInfoArray = $channelInfo->getInfo();
$this->nextParams['result']['available'] = $channelInfoArray['available'];
$this->nextParams['result']['div'] = (new ChannelInfoBlock(
$this->container->getUpgradeConfiguration(),
$channelInfo,
$this->container->getTwig())
)->render();
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,282 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Miscellaneous;
use Exception;
use PrestaShop\Module\AutoUpgrade\Exceptions\ZipActionException;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeConfiguration;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeConfigurationStorage;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\Upgrader;
use RuntimeException;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\Filesystem\Exception\IOException;
/**
* update configuration after validating the new values.
*/
class UpdateConfig extends AbstractTask
{
/**
* Data being passed by CLI entry point
*
* @var array<string, mixed>
*/
protected $cliParameters;
/**
* @throws Exception
*/
public function run(): int
{
// nothing next
$this->next = '';
// Was coming from AdminSelfUpgrade::currentParams before
$configurationData = $this->getConfigurationData();
$config = [];
// update channel
if (isset($configurationData['channel'])) {
$config['channel'] = $configurationData['channel'];
$config['archive.filename'] = Upgrader::DEFAULT_FILENAME;
// Switch on default theme if major upgrade (i.e: 1.6 -> 1.7)
$config['PS_AUTOUP_CHANGE_DEFAULT_THEME'] = ($configurationData['channel'] === 'major');
}
if (isset($configurationData['private_release_link'], $configurationData['private_release_md5'])) {
$config['channel'] = 'private';
$config['private_release_link'] = $configurationData['private_release_link'];
$config['private_release_md5'] = $configurationData['private_release_md5'];
$config['private_allow_major'] = $configurationData['private_allow_major'];
}
if (!empty($configurationData['archive_prestashop'])) {
$file = $configurationData['archive_prestashop'];
$fullFilePath = $this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH) . DIRECTORY_SEPARATOR . $file;
if (!file_exists($fullFilePath)) {
$this->setErrorFlag();
$this->logger->info($this->translator->trans('File %s does not exist. Unable to select that channel.', [$file]));
return ExitCode::FAIL;
}
try {
$targetVersion = $this->extractPrestashopVersionFromZip($fullFilePath);
} catch (Exception $exception) {
$this->setErrorFlag();
$this->logger->info($this->translator->trans('Unable to retrieve version from zip: %s.', [$exception->getMessage()]));
return ExitCode::FAIL;
}
$xmlFile = $configurationData['archive_xml'];
$fullXmlPath = $this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH) . DIRECTORY_SEPARATOR . $xmlFile;
if (!empty($xmlFile) && !file_exists($fullXmlPath)) {
$this->setErrorFlag();
$this->logger->info($this->translator->trans('File %s does not exist. Unable to select that channel.', [$xmlFile]));
return ExitCode::FAIL;
}
$xmlVersion = $this->getXmlVersion($fullXmlPath);
if ($xmlVersion !== $targetVersion) {
$this->error = true;
$this->logger->info($this->translator->trans('Prestashop version detected in the xml (%s) does not match the zip version (%s).', [$xmlVersion, $targetVersion]));
return ExitCode::FAIL;
}
$config['channel'] = 'archive';
$config['archive.filename'] = $configurationData['archive_prestashop'];
$config['archive.version_num'] = $targetVersion;
$config['archive.xml'] = $configurationData['archive_xml'];
$this->logger->info($this->translator->trans('Upgrade process will use archive.'));
}
if (isset($configurationData['directory_num'])) {
$config['channel'] = 'directory';
if (empty($configurationData['directory_num']) || strpos($configurationData['directory_num'], '.') === false) {
$this->setErrorFlag();
$this->logger->info($this->translator->trans('Version number is missing. Unable to select that channel.'));
return ExitCode::FAIL;
}
$config['directory.version_num'] = $configurationData['directory_num'];
}
foreach (UpgradeConfiguration::UPGRADE_CONST_KEYS as $key) {
if (!isset($configurationData[$key])) {
continue;
}
// The PS_DISABLE_OVERRIDES variable must only be updated on the database side
if ($key === 'PS_DISABLE_OVERRIDES') {
UpgradeConfiguration::updatePSDisableOverrides((bool) $configurationData[$key]);
} else {
$config[$key] = $configurationData[$key];
}
}
if (!$this->writeConfig($config)) {
$this->setErrorFlag();
$this->logger->info($this->translator->trans('Error on saving configuration'));
return ExitCode::FAIL;
}
return ExitCode::SUCCESS;
}
/**
* @param array<string, mixed> $parameters
*/
public function inputCliParameters($parameters): void
{
$this->cliParameters = $parameters;
}
/**
* @return array<string, mixed>
*/
protected function getConfigurationData(): array
{
if (null !== $this->cliParameters) {
return $this->getCLIParams();
}
return $this->getRequestParams();
}
/**
* @return array<string, mixed>
*/
protected function getCLIParams(): array
{
if (empty($this->cliParameters)) {
throw new \RuntimeException('Empty CLI parameters - did CLI entry point failed to provide data?');
}
return $this->cliParameters;
}
/**
* @return array<string, mixed>
*/
protected function getRequestParams(): array
{
return empty($_REQUEST['params']) ? [] : $_REQUEST['params'];
}
/**
* update module configuration (saved in file UpgradeFiles::configFilename) with $new_config.
*
* @param array<string, mixed> $config
*
* @return bool true if success
*
* @throws Exception
*/
private function writeConfig(array $config): bool
{
if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::CONFIG_FILENAME) && !empty($config['channel'])) {
$this->container->getUpgrader()->channel = $config['channel'];
$this->container->getUpgrader()->checkPSVersion();
$this->container->getState()->setInstallVersion($this->container->getUpgrader()->version_num);
$this->container->getState()->setOriginVersion($this->container->getProperty(UpgradeContainer::PS_VERSION));
}
$this->container->getUpgradeConfiguration()->merge($config);
$this->logger->info($this->translator->trans('Configuration successfully updated.') . ' <strong>' . $this->translator->trans('This page will now be reloaded and the module will check if a new version is available.') . '</strong>');
return (new UpgradeConfigurationStorage($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR))->save($this->container->getUpgradeConfiguration(), UpgradeFileNames::CONFIG_FILENAME);
}
/**
* @throws ZipActionException
* @throws Exception
*/
private function extractPrestashopVersionFromZip(string $zipFile): string
{
$internalZipFileName = 'prestashop.zip';
$versionFile = 'install/install_version.php';
if (!file_exists($zipFile)) {
throw new FileNotFoundException("Unable to find $zipFile file");
}
$zip = $this->container->getZipAction()->open($zipFile);
$internalZipContent = $this->container->getZipAction()->extractFileFromArchive($zip, $internalZipFileName);
$zip->close();
$tempInternalZipPath = $this->createTemporaryFile($internalZipContent);
$internalZip = $this->container->getZipAction()->open($tempInternalZipPath);
$fileContent = $this->container->getZipAction()->extractFileFromArchive($internalZip, $versionFile);
$internalZip->close();
@unlink($tempInternalZipPath);
return $this->extractVersionFromContent($fileContent);
}
/**
* @throws IOException
*/
private function createTemporaryFile(string $content): string
{
$tempFilePath = tempnam(sys_get_temp_dir(), 'internal_zip_');
if (file_put_contents($tempFilePath, $content) === false) {
throw new IOException('Unable to create temporary file');
}
return $tempFilePath;
}
/**
* @throws RuntimeException
*/
private function extractVersionFromContent(string $content): string
{
$pattern = "/define\\('_PS_INSTALL_VERSION_', '([\\d.]+)'\\);/";
if (preg_match($pattern, $content, $matches)) {
return $matches[1];
} else {
throw new RuntimeException('Unable to extract version from content');
}
}
private function getXmlVersion(string $xmlPath): string
{
$xml = @simplexml_load_file($xmlPath);
return $xml->ps_root_dir['version'];
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,36 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task;
class NullTask extends AbstractTask
{
public function run(): int
{
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Rollback;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
class NoRollbackFound extends AbstractTask
{
const TASK_TYPE = 'rollback';
public function run(): int
{
$this->logger->info($this->translator->trans('Nothing to restore'));
$this->next = 'rollbackComplete';
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,255 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Rollback;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Progress\Backlog;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Database;
/**
* Restores database from backup file.
*/
class RestoreDb extends AbstractTask
{
const TASK_TYPE = 'rollback';
/**
* @throws Exception
*/
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
$databaseTools = new Database($this->container->getDb());
$ignore_stats_table = [
_DB_PREFIX_ . 'connections',
_DB_PREFIX_ . 'connections_page',
_DB_PREFIX_ . 'connections_source',
_DB_PREFIX_ . 'guest',
_DB_PREFIX_ . 'statssearch',
];
$startTime = time();
// deal with running backup rest if exist
if (file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST)) {
$backlog = Backlog::fromContents($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::QUERIES_TO_RESTORE_LIST));
}
// deal with the next files stored in restoreDbFilenames
$restoreDbFilenames = $this->container->getState()->getRestoreDbFilenames();
if ((!isset($backlog) || !$backlog->getRemainingTotal()) && count($restoreDbFilenames) > 0) {
$currentDbFilename = array_shift($restoreDbFilenames);
$this->container->getState()->setRestoreDbFilenames($restoreDbFilenames);
if (!preg_match('#auto-backupdb_([0-9]{6})_#', $currentDbFilename, $match)) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($this->translator->trans('%s: File format does not match.', [$currentDbFilename]));
return ExitCode::FAIL;
}
$this->container->getState()->setDbStep((int) $match[1]);
$backupdb_path = $this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getRestoreName();
$dot_pos = strrpos($currentDbFilename, '.');
$fileext = substr($currentDbFilename, $dot_pos + 1);
$content = '';
$this->logger->debug($this->translator->trans(
'Opening backup database file %filename% in %extension% mode',
[
'%filename%' => $currentDbFilename,
'%extension%' => $fileext,
]
));
switch ($fileext) {
case 'bz':
case 'bz2':
$fp = bzopen($backupdb_path . DIRECTORY_SEPARATOR . $currentDbFilename, 'r');
if (is_resource($fp)) {
while (!feof($fp)) {
$content .= bzread($fp, 4096);
}
bzclose($fp);
}
break;
case 'gz':
$fp = gzopen($backupdb_path . DIRECTORY_SEPARATOR . $currentDbFilename, 'r');
if (is_resource($fp)) {
while (!feof($fp)) {
$content .= gzread($fp, 4096);
}
gzclose($fp);
}
break;
default:
$fp = fopen($backupdb_path . DIRECTORY_SEPARATOR . $currentDbFilename, 'r');
if (is_resource($fp)) {
while (!feof($fp)) {
$content .= fread($fp, 4096);
}
fclose($fp);
}
}
if (empty($content)) {
$this->logger->error($this->translator->trans('Database backup is empty.'));
$this->next = 'rollback';
return ExitCode::FAIL;
}
// preg_match_all is better than preg_split (what is used in do Upgrade.php)
// This way we avoid extra blank lines
// option s (PCRE_DOTALL) added
$listQuery = preg_split('/;[\n\r]+/Usm', $content);
unset($content);
// Get tables before backup
if ($this->container->getState()->getDbStep() == '1') {
$tables_after_restore = [];
foreach ($listQuery as $q) {
if (preg_match('/`(?<table>' . _DB_PREFIX_ . '[a-zA-Z0-9_-]+)`/', $q, $matches)) {
if (isset($matches['table'])) {
$tables_after_restore[$matches['table']] = $matches['table'];
}
}
}
$tables_after_restore = array_unique($tables_after_restore);
$tables_before_restore = $databaseTools->getAllTables();
$tablesToRemove = array_diff($tables_before_restore, $tables_after_restore, $ignore_stats_table);
if (!empty($tablesToRemove)) {
$this->container->getFileConfigurationStorage()->save($tablesToRemove, UpgradeFileNames::DB_TABLES_TO_CLEAN_LIST);
}
}
$backlog = new Backlog(array_reverse($listQuery), count($listQuery));
}
/* @todo : error if listQuery is not an array (that can happen if toRestoreQueryList is empty for example) */
if (isset($backlog) && $backlog->getRemainingTotal()) {
$this->container->getDb()->execute('SET SESSION sql_mode = \'\'');
$this->container->getDb()->execute('SET FOREIGN_KEY_CHECKS=0');
do {
// @phpstan-ignore booleanNot.alwaysFalse (Need a refacto of this whole task)
if (!$backlog->getRemainingTotal()) {
if (file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST)) {
unlink($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST);
}
$restoreDbFilenamesCount = count($this->container->getState()->getRestoreDbFilenames());
if ($restoreDbFilenamesCount) {
$this->logger->info($this->translator->trans(
'Database restoration file %filename% done. %filescount% file(s) left...',
[
'%filename%' => $this->container->getState()->getDbStep(),
'%filescount%' => $restoreDbFilenamesCount,
]
));
} else {
$this->logger->info($this->translator->trans('Database restoration file %1$s done.', [$this->container->getState()->getDbStep()]));
}
$this->stepDone = true;
$this->status = 'ok';
$this->next = 'restoreDb';
if ($restoreDbFilenamesCount === 0) {
$this->next = 'rollbackComplete';
$this->logger->info($this->translator->trans('Database has been restored.'));
$databaseTools->cleanTablesAfterBackup($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::DB_TABLES_TO_CLEAN_LIST));
$this->container->getFileConfigurationStorage()->clean(UpgradeFileNames::DB_TABLES_TO_CLEAN_LIST);
}
return ExitCode::SUCCESS;
}
$query = trim($backlog->getNext());
if (!empty($query)) {
if (!$this->container->getDb()->execute($query, false)) {
$this->logger->error($this->translator->trans('[SQL ERROR]') . ' ' . $query . ' - ' . $this->container->getDb()->getMsgError());
$this->logger->info($this->translator->trans('Error during database restoration'));
$this->setErrorFlag();
unlink($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST);
return ExitCode::FAIL;
}
}
$time_elapsed = time() - $startTime;
} while ($time_elapsed < $this->container->getUpgradeConfiguration()->getTimePerCall());
$queries_left = $backlog->getRemainingTotal();
if ($queries_left > 0) {
$this->container->getFileConfigurationStorage()->save($backlog->dump(), UpgradeFileNames::QUERIES_TO_RESTORE_LIST);
} elseif (file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST)) {
unlink($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::QUERIES_TO_RESTORE_LIST);
}
$this->stepDone = false;
$this->next = 'restoreDb';
$this->logger->info($this->translator->trans(
'%numberqueries% queries left for file %filename%...',
[
'%numberqueries%' => $queries_left,
'%filename%' => $this->container->getState()->getDbStep(),
]
));
} else {
$this->stepDone = true;
$this->status = 'ok';
$this->next = 'rollbackComplete';
$this->logger->info($this->translator->trans('Database restoration done.'));
$databaseTools->cleanTablesAfterBackup($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::DB_TABLES_TO_CLEAN_LIST));
}
return ExitCode::SUCCESS;
}
public function init(): void
{
// We don't need the whole core being instanciated, only the autoloader
$this->container->initPrestaShopAutoloader();
// Loads the parameters.php file on PrestaShop 1.7, needed for accessing the database
if (file_exists($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH) . '/config/bootstrap.php')) {
require_once $this->container->getProperty(UpgradeContainer::PS_ROOT_PATH) . '/config/bootstrap.php';
}
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Rollback;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
/**
* ajaxProcessRestoreFiles restore the previously saved files,
* and delete files that weren't archived.
*/
class RestoreFiles extends AbstractTask
{
const TASK_TYPE = 'rollback';
/**
* @throws Exception
*/
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
// loop
$this->next = 'restoreFiles';
if (!file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_FROM_ARCHIVE_LIST)
|| !file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_TO_REMOVE_LIST)) {
// cleanup current PS tree
$fromArchive = $this->container->getZipAction()->listContent($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getRestoreFilesFilename());
foreach ($fromArchive as $k => $v) {
$fromArchive[DIRECTORY_SEPARATOR . $v] = DIRECTORY_SEPARATOR . $v;
}
$this->container->getFileConfigurationStorage()->save($fromArchive, UpgradeFileNames::FILES_FROM_ARCHIVE_LIST);
// get list of files to remove
$toRemove = $this->container->getFilesystemAdapter()->listFilesToRemove();
$toRemoveOnly = [];
// let's reverse the array in order to make possible to rmdir
// remove fullpath. This will be added later in the loop.
// we do that for avoiding fullpath to be revealed in a text file
foreach ($toRemove as $k => $v) {
$vfile = str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), '', $v);
$toRemove[] = str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), '', $vfile);
if (!isset($fromArchive[$vfile]) && is_file($v)) {
$toRemoveOnly[$vfile] = str_replace($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), '', $vfile);
}
}
$this->logger->debug($this->translator->trans('%s file(s) will be removed before restoring the backup files.', [count($toRemoveOnly)]));
$this->container->getFileConfigurationStorage()->save($toRemoveOnly, UpgradeFileNames::FILES_TO_REMOVE_LIST);
if (empty($fromArchive) || empty($toRemove)) {
if (empty($fromArchive)) {
$this->logger->error($this->translator->trans('[ERROR] Backup file %s does not exist.', [UpgradeFileNames::FILES_FROM_ARCHIVE_LIST]));
}
if (empty($toRemove)) {
$this->logger->error($this->translator->trans('[ERROR] File "%s" does not exist.', [UpgradeFileNames::FILES_TO_REMOVE_LIST]));
}
$this->logger->info($this->translator->trans('Unable to remove upgraded files.'));
$this->next = 'error';
$this->setErrorFlag();
return ExitCode::FAIL;
}
}
if (!empty($fromArchive)) {
$filepath = $this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getRestoreFilesFilename();
$destExtract = $this->container->getProperty(UpgradeContainer::PS_ROOT_PATH);
$res = $this->container->getZipAction()->extract($filepath, $destExtract);
if (!$res) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($this->translator->trans(
'Unable to extract file %filename% into directory %directoryname%.',
[
'%filename%' => $filepath,
'%directoryname%' => $destExtract,
]
));
return ExitCode::FAIL;
}
if (!empty($toRemoveOnly)) {
foreach ($toRemoveOnly as $fileToRemove) {
@unlink($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH) . $fileToRemove);
}
}
$this->next = 'restoreDb';
$this->logger->debug($this->translator->trans('Files restored.'));
$this->logger->info($this->translator->trans('Files restored. Now restoring database...'));
}
return ExitCode::SUCCESS;
}
public function init(): void
{
// Do nothing
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Rollback;
use Exception;
use PrestaShop\Module\AutoUpgrade\Analytics;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
/**
* First step executed during a rollback.
*/
class Rollback extends AbstractTask
{
const TASK_TYPE = 'rollback';
/**
* @throws Exception
*/
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
// 1st, need to analyse what was wrong.
$restoreName = $this->container->getState()->getRestoreName();
$this->container->getState()->setRestoreFilesFilename($restoreName);
$restoreDbFilenames = $this->container->getState()->getRestoreDbFilenames();
if (empty($restoreName)) {
$this->next = 'noRollbackFound';
return ExitCode::SUCCESS;
}
$files = scandir($this->container->getProperty(UpgradeContainer::BACKUP_PATH));
// find backup filenames, and be sure they exists
foreach ($files as $file) {
if (preg_match('#' . preg_quote('auto-backupfiles_' . $restoreName) . '#', $file)) {
$this->container->getState()->setRestoreFilesFilename($file);
break;
}
}
if (!is_file($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getRestoreFilesFilename())) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($this->translator->trans('[ERROR] File %s is missing: unable to restore files. Operation aborted.', [$this->container->getState()->getRestoreFilesFilename()]));
return ExitCode::FAIL;
}
$files = scandir($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $restoreName);
foreach ($files as $file) {
if (preg_match('#auto-backupdb_[0-9]{6}_' . preg_quote($restoreName) . '#', $file)) {
$restoreDbFilenames[] = $file;
}
}
// order files is important !
sort($restoreDbFilenames);
$this->container->getState()->setRestoreDbFilenames($restoreDbFilenames);
if (count($restoreDbFilenames) == 0) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($this->translator->trans('[ERROR] No backup database files found: it would be impossible to restore the database. Operation aborted.'));
return ExitCode::FAIL;
}
$this->next = 'restoreFiles';
$this->logger->info($this->translator->trans('Restoring files ...'));
// remove tmp files related to restoreFiles
if (file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_FROM_ARCHIVE_LIST)) {
unlink($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_FROM_ARCHIVE_LIST);
}
if (file_exists($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_TO_REMOVE_LIST)) {
unlink($this->container->getProperty(UpgradeContainer::WORKSPACE_PATH) . DIRECTORY_SEPARATOR . UpgradeFileNames::FILES_TO_REMOVE_LIST);
}
$this->container->getAnalytics()->track('Rollback Launched', Analytics::WITH_ROLLBACK_PROPERTIES);
return ExitCode::SUCCESS;
}
public function init(): void
{
// Do nothing
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Rollback;
use PrestaShop\Module\AutoUpgrade\Analytics;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
/**
* Only displays the success message.
*/
class RollbackComplete extends AbstractTask
{
const TASK_TYPE = 'rollback';
public function run(): int
{
$this->logger->info($this->translator->trans('Restoration process done. Congratulations! You can now reactivate your shop.'));
$this->next = '';
$this->container->getAnalytics()->track('Rollback Succeeded', Analytics::WITH_ROLLBACK_PROPERTIES);
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,64 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Runner;
/**
* Execute the whole upgrade process in a single request.
*/
class AllRollbackTasks extends ChainedTasks
{
const initialTask = 'rollback';
/**
* @var string
*/
protected $step = self::initialTask;
/**
* Customize the execution context with several options
* > action: Replace the initial step to run
* > channel: Makes a specific upgrade (minor, major etc.)
* > data: Loads an encoded array of data coming from another request.
*
* @param array<string, string> $options
*/
public function setOptions(array $options): void
{
if (!empty($options['backup'])) {
$this->container->getState()->setRestoreName($options['backup']);
}
}
/**
* Set default config on first run.
*/
public function init(): void
{
// Do nothing
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Runner;
use Exception;
use PrestaShop\Module\AutoUpgrade\AjaxResponse;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
/**
* Execute the whole upgrade process in a single request.
*/
class AllUpgradeTasks extends ChainedTasks
{
const initialTask = 'upgradeNow';
const TASKS_WITH_RESTART = ['upgradeFiles', 'upgradeDb', 'upgradeModules'];
/**
* @var string
*/
protected $step = self::initialTask;
/**
* Customize the execution context with several options
* > action: Replace the initial step to run
* > channel: Makes a specific upgrade (minor, major etc.)
* > data: Loads an encoded array of data coming from another request.
*
* @param array<string, string> $options
*
* @throws Exception
*/
public function setOptions(array $options): void
{
if (!empty($options['action'])) {
$this->step = $options['action'];
}
if (!empty($options['channel'])) {
$this->container->getUpgradeConfiguration()->merge([
'channel' => $options['channel'],
// Switch on default theme if major upgrade (i.e: 1.6 -> 1.7)
'PS_AUTOUP_CHANGE_DEFAULT_THEME' => ($options['channel'] === 'major'),
]);
$this->container->getUpgrader()->channel = $options['channel'];
$this->container->getUpgrader()->checkPSVersion(true);
}
if (!empty($options['data'])) {
$this->container->getState()->importFromEncodedData($options['data']);
}
}
/**
* For some steps, we may require a new request to be made.
* For instance, in case of obsolete autoloader or loaded classes after a file copy.
*/
protected function checkIfRestartRequested(AjaxResponse $response): bool
{
if (parent::checkIfRestartRequested($response)) {
return true;
}
if (!$response->getStepDone()) {
return false;
}
if (!in_array($response->getNext(), self::TASKS_WITH_RESTART)) {
return false;
}
$this->logger->info('Restart requested. Please run the following command to continue your upgrade:');
$args = $_SERVER['argv'];
foreach ($args as $key => $arg) {
if (strpos($arg, '--data') === 0 || strpos($arg, '--action') === 0) {
unset($args[$key]);
}
}
$this->logger->info('$ ' . implode(' ', $args) . ' --action=' . $response->getNext() . ' --data=' . $this->getEncodedResponse());
return true;
}
/**
* Set default config on first run.
*
* @throws Exception
*/
public function init(): void
{
if ($this->step === self::initialTask) {
parent::init();
$this->container->getState()->initDefault(
$this->container->getUpgrader(),
$this->container->getProperty(UpgradeContainer::PS_ROOT_PATH),
$this->container->getProperty(UpgradeContainer::PS_VERSION));
}
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Runner;
use Exception;
use PrestaShop\Module\AutoUpgrade\AjaxResponse;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\TaskRepository;
use Throwable;
/**
* Execute the whole process in a single request, useful in CLI.
*/
abstract class ChainedTasks extends AbstractTask
{
/**
* @var string
*/
protected $step;
/**
* Execute all the tasks from a specific initial step, until the end (complete or error).
*
* @return int Return code (0 for success, any value otherwise)
*
* @throws Exception
*/
public function run(): int
{
$requireRestart = false;
while ($this->canContinue() && !$requireRestart) {
$this->logger->info('=== Step ' . $this->step);
$controller = TaskRepository::get($this->step, $this->container);
$controller->init();
try {
$controller->run();
} catch (Throwable $t) {
$controller->setErrorFlag();
throw $t;
}
$result = $controller->getResponse();
$requireRestart = $this->checkIfRestartRequested($result);
$this->error = $result->getError();
$this->stepDone = $result->getStepDone();
$this->step = $this->next = $result->getNext();
$this->nextParams = $result->getNextParams();
}
return (int) ($this->error || $this->step === 'error');
}
/**
* Customize the execution context with several options.
*
* @param array<string, string> $options
*/
abstract public function setOptions(array $options): void;
/**
* Tell the while loop if it can continue.
*/
protected function canContinue(): bool
{
if (empty($this->step)) {
return false;
}
if ($this->error) {
return false;
}
return $this->step !== 'error';
}
/**
* For some steps, we may require a new request to be made.
* Return true for stopping the process.
*/
protected function checkIfRestartRequested(AjaxResponse $response): bool
{
return false;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Runner;
class SingleTask extends ChainedTasks
{
protected $step;
/** @var bool */
private $stepHasRun = false;
public function setOptions(array $options): void
{
if (!empty($options['action'])) {
$this->step = $options['action'];
}
}
protected function canContinue(): bool
{
if (!$this->stepHasRun) {
$this->stepHasRun = true;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,309 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Progress\Backlog;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\Tools14;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
class BackupDb extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
if (!$this->container->getUpgradeConfiguration()->shouldBackupFilesAndDatabase()) {
$this->stepDone = true;
$this->container->getState()->setDbStep(0);
$this->logger->info($this->translator->trans('Database backup skipped. Now upgrading files...'));
$this->next = 'upgradeFiles';
return ExitCode::SUCCESS;
}
$timeAllowed = $this->container->getUpgradeConfiguration()->getNumberOfFilesPerCall();
$relative_backup_path = str_replace(_PS_ROOT_DIR_, '', $this->container->getProperty(UpgradeContainer::BACKUP_PATH));
$report = '';
if (!\ConfigurationTest::test_dir($relative_backup_path, false, $report)) {
$this->logger->error($this->translator->trans('Backup directory is not writable (%path%).', ['%path%' => $this->container->getProperty(UpgradeContainer::BACKUP_PATH)]));
$this->next = 'error';
$this->setErrorFlag();
return ExitCode::FAIL;
}
$this->stepDone = false;
$this->next = 'backupDb';
$start_time = time();
$time_elapsed = 0;
$ignore_stats_table = [_DB_PREFIX_ . 'connections',
_DB_PREFIX_ . 'connections_page',
_DB_PREFIX_ . 'connections_source',
_DB_PREFIX_ . 'guest',
_DB_PREFIX_ . 'statssearch', ];
// INIT LOOP
if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::DB_TABLES_TO_BACKUP_LIST)) {
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
if (!is_dir($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getBackupName())) {
mkdir($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getBackupName());
}
$this->container->getState()->setDbStep(0);
$listOfTables = $this->container->getDb()->executeS('SHOW TABLES LIKE "' . _DB_PREFIX_ . '%"', true, false);
$tablesToBackup = new Backlog($listOfTables, count($listOfTables));
} else {
$tablesToBackup = Backlog::fromContents($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::DB_TABLES_TO_BACKUP_LIST));
}
$found = 0;
$views = '';
$fp = false;
$backupfile = null;
// MAIN BACKUP LOOP //
$written = 0;
do {
if (null !== $this->container->getState()->getBackupTable()) {
// only insert (schema already done)
$table = $this->container->getState()->getBackupTable();
} else {
if (!$tablesToBackup->getRemainingTotal()) {
break;
}
$table = current($tablesToBackup->getNext());
$this->container->getState()->setBackupLoopLimit(0);
}
// Skip tables which do not start with _DB_PREFIX_
if (strlen($table) <= strlen(_DB_PREFIX_) || strncmp($table, _DB_PREFIX_, strlen(_DB_PREFIX_)) != 0) {
continue;
}
// Ignore stat tables
if (in_array($table, $ignore_stats_table)) {
continue;
}
if ($written == 0 || $written > $this->container->getUpgradeConfiguration()->getMaxSizeToWritePerCall()) {
// increment dbStep will increment filename each time here
$this->container->getState()->setDbStep($this->container->getState()->getDbStep() + 1);
// new file, new step
$written = 0;
if (is_resource($fp)) {
fclose($fp);
}
$backupfile = $this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $this->container->getState()->getBackupName() . DIRECTORY_SEPARATOR . $this->container->getState()->getBackupDbFilename();
$backupfile = preg_replace('#_XXXXXX_#', '_' . str_pad(strval($this->container->getState()->getDbStep()), 6, '0', STR_PAD_LEFT) . '_', $backupfile);
// start init file
// Figure out what compression is available and open the file
if (file_exists($backupfile)) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($this->translator->trans('Backup file %s already exists. Operation aborted.', [$backupfile]));
}
if (function_exists('bzopen')) {
$backupfile .= '.bz2';
$fp = bzopen($backupfile, 'w');
} elseif (function_exists('gzopen')) {
$backupfile .= '.gz';
$fp = gzopen($backupfile, 'w');
} else {
$fp = fopen($backupfile, 'w');
}
if ($fp === false) {
$this->logger->error($this->translator->trans('Unable to create backup database file %s.', [addslashes($backupfile)]));
$this->next = 'error';
$this->setErrorFlag();
$this->logger->info($this->translator->trans('Error during database backup.'));
return ExitCode::FAIL;
}
$written += fwrite($fp, '/* Backup ' . $this->container->getState()->getDbStep() . ' for ' . Tools14::getHttpHost() . __PS_BASE_URI__ . "\n * at " . date('r') . "\n */\n");
$written += fwrite($fp, "\n" . 'SET SESSION sql_mode = \'\';' . "\n\n");
$written += fwrite($fp, "\n" . 'SET NAMES \'utf8\';' . "\n\n");
$written += fwrite($fp, "\n" . 'SET FOREIGN_KEY_CHECKS=0;' . "\n\n");
// end init file
}
// start schema : drop & create table only
if (null === $this->container->getState()->getBackupTable()) {
// Export the table schema
$schema = $this->container->getDb()->executeS('SHOW CREATE TABLE `' . $table . '`', true, false);
if (count($schema) != 1 ||
!(isset($schema[0]['Table'], $schema[0]['Create Table'])
|| isset($schema[0]['View'], $schema[0]['Create View']))) {
fclose($fp);
if (file_exists($backupfile)) {
unlink($backupfile);
}
$this->logger->error($this->translator->trans('An error occurred while backing up. Unable to obtain the schema of %s', [$table]));
$this->logger->info($this->translator->trans('Error during database backup.'));
$this->next = 'error';
$this->setErrorFlag();
return ExitCode::FAIL;
}
// case view
if (isset($schema[0]['View'])) {
$views .= '/* Scheme for view' . $schema[0]['View'] . " */\n";
// If some *upgrade* transform a table in a view, drop both just in case
$views .= 'DROP TABLE IF EXISTS `' . $schema[0]['View'] . '`;' . "\n";
$views .= 'DROP VIEW IF EXISTS `' . $schema[0]['View'] . '`;' . "\n";
$views .= preg_replace('#DEFINER=[^\s]+\s#', 'DEFINER=CURRENT_USER ', $schema[0]['Create View']) . ";\n\n";
$written += fwrite($fp, "\n" . $views);
$ignore_stats_table[] = $schema[0]['View'];
}
// case table
elseif (isset($schema[0]['Table'])) {
// Case common table
$written += fwrite($fp, '/* Scheme for table ' . $schema[0]['Table'] . " */\n");
if (!in_array($schema[0]['Table'], $ignore_stats_table)) {
// If some *upgrade* transform a table in a view, drop both just in case
$written += fwrite($fp, 'DROP TABLE IF EXISTS `' . $schema[0]['Table'] . '`;' . "\n");
$written += fwrite($fp, 'DROP VIEW IF EXISTS `' . $schema[0]['Table'] . '`;' . "\n");
// CREATE TABLE
$written += fwrite($fp, $schema[0]['Create Table'] . ";\n\n");
}
// schema created, now we need to create the missing vars
$this->container->getState()->setBackupTable($table);
$lines = explode("\n", $schema[0]['Create Table']);
$this->container->getState()->setBackupLines($lines);
}
}
// end of schema
// POPULATE TABLE
if (!in_array($table, $ignore_stats_table)) {
do {
$backup_loop_limit = $this->container->getState()->getBackupLoopLimit();
$data = $this->container->getDb()->executeS('SELECT * FROM `' . $table . '` LIMIT ' . (int) $backup_loop_limit . ',200', false, false);
$this->container->getState()->setBackupLoopLimit($this->container->getState()->getBackupLoopLimit() + 200);
$sizeof = $this->container->getDb()->numRows();
if ($data && ($sizeof > 0)) {
// Export the table data
$written += fwrite($fp, 'INSERT INTO `' . $table . "` VALUES\n");
$i = 1;
while ($row = $this->container->getDb()->nextRow($data)) {
// this starts a row
$s = '(';
foreach ($row as $field => $value) {
if ($value === null) {
$s .= 'NULL,';
} else {
$s .= "'" . $this->container->getDb()->escape($value, true) . "',";
}
}
$s = rtrim($s, ',');
if ($i < $sizeof) {
$s .= "),\n";
} else {
$s .= ");\n";
}
$written += fwrite($fp, $s);
++$i;
}
$time_elapsed = time() - $start_time;
} else {
$this->container->getState()->setBackupTable(null);
break;
}
} while (($time_elapsed < $timeAllowed) && ($written < $this->container->getUpgradeConfiguration()->getMaxSizeToWritePerCall()));
}
++$found;
$time_elapsed = time() - $start_time;
$this->logger->debug($this->translator->trans('%s table has been saved.', [$table]));
} while (($time_elapsed < $timeAllowed) && ($written < $this->container->getUpgradeConfiguration()->getMaxSizeToWritePerCall()));
// end of loop
if (is_resource($fp)) {
$written += fwrite($fp, "\n" . 'SET FOREIGN_KEY_CHECKS=1;' . "\n\n");
fclose($fp);
$fp = null;
}
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->computePercentage($tablesToBackup, self::class, UpgradeFiles::class)
);
$this->container->getFileConfigurationStorage()->save($tablesToBackup->dump(), UpgradeFileNames::DB_TABLES_TO_BACKUP_LIST);
if ($tablesToBackup->getRemainingTotal()) {
$this->logger->debug($this->translator->trans('%s tables have been saved.', [$found]));
$this->next = 'backupDb';
$this->stepDone = false;
$this->logger->info($this->translator->trans('Database backup: %s table(s) left...', [$tablesToBackup->getRemainingTotal()]));
return ExitCode::SUCCESS;
}
if ($found == 0 && !empty($backupfile)) {
if (file_exists($backupfile)) {
unlink($backupfile);
}
$this->logger->error($this->translator->trans('No valid tables were found to back up. Backup of file %s canceled.', [$backupfile]));
$this->logger->info($this->translator->trans('Error during database backup for file %s.', [$backupfile]));
$this->setErrorFlag();
return ExitCode::FAIL;
} else {
$this->container->getState()
->setBackupLoopLimit(null)
->setBackupLines(null)
->setBackupTable(null);
if ($found) {
$this->logger->info($this->translator->trans('%s tables have been saved.', [$found]));
}
$this->stepDone = true;
// reset dbStep at the end of this step
$this->container->getState()->setDbStep(0);
$this->logger->info($this->translator->trans('Database backup done in filename %s. Now upgrading files...', [$this->container->getState()->getBackupName()]));
$this->next = 'upgradeFiles';
return ExitCode::SUCCESS;
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Progress\Backlog;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
class BackupFiles extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
if (!$this->container->getUpgradeConfiguration()->shouldBackupFilesAndDatabase()) {
$this->stepDone = true;
$this->next = 'backupDb';
$this->logger->info('File backup skipped.');
return ExitCode::SUCCESS;
}
$this->stepDone = false;
$backupFilesFilename = $this->container->getState()->getBackupFilesFilename();
if (empty($backupFilesFilename)) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->info($this->translator->trans('Error during backupFiles'));
$this->logger->error($this->translator->trans('[ERROR] backupFiles filename has not been set'));
return ExitCode::FAIL;
}
if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::FILES_TO_BACKUP_LIST)) {
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
/** @todo : only add files and dir listed in "originalPrestashopVersion" list */
$filesToBackup = $this->container->getFilesystemAdapter()->listFilesInDir($this->container->getProperty(UpgradeContainer::PS_ROOT_PATH), 'backup', false);
$nbFilesToBackup = count($filesToBackup);
$backlog = new Backlog($filesToBackup, $nbFilesToBackup);
if ($nbFilesToBackup) {
$this->logger->debug($this->translator->trans('%s Files to backup.', [$nbFilesToBackup]));
}
// delete old backup, create new
if (file_exists($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $backupFilesFilename)) {
unlink($this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $backupFilesFilename);
}
$this->logger->debug($this->translator->trans('Backup files initialized in %s', [$backupFilesFilename]));
} else {
$backlog = Backlog::fromContents($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::FILES_TO_BACKUP_LIST));
}
$this->next = 'backupFiles';
$remainingFiles = $backlog->getRemainingTotal();
if ($remainingFiles) {
$this->logger->info($this->translator->trans('Backup files in progress. %d files left', [$remainingFiles]));
$this->stepDone = false;
$res = $this->container->getZipAction()->compress($backlog, $this->container->getProperty(UpgradeContainer::BACKUP_PATH) . DIRECTORY_SEPARATOR . $backupFilesFilename);
if (!$res) {
$this->next = 'error';
$this->logger->info($this->translator->trans('Unable to open archive'));
return ExitCode::FAIL;
}
$this->container->getFileConfigurationStorage()->save($backlog->dump(), UpgradeFileNames::FILES_TO_BACKUP_LIST);
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->computePercentage($backlog, self::class, BackupDb::class)
);
} else {
$this->stepDone = true;
$this->status = 'ok';
$this->next = 'backupDb';
$this->logger->debug($this->translator->trans('All files have been added to archive.'));
$this->logger->info($this->translator->trans('All files saved. Now backing up database'));
}
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
/**
* Clean the database from unwanted entries.
*/
class CleanDatabase extends AbstractTask
{
const TASK_TYPE = 'upgrade';
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
// Clean tabs order
foreach ($this->container->getDb()->ExecuteS('SELECT DISTINCT id_parent FROM ' . _DB_PREFIX_ . 'tab') as $parent) {
$i = 1;
foreach ($this->container->getDb()->ExecuteS('SELECT id_tab FROM ' . _DB_PREFIX_ . 'tab WHERE id_parent = ' . (int) $parent['id_parent'] . ' ORDER BY IF(class_name IN ("AdminHome", "AdminDashboard"), 1, 2), position ASC') as $child) {
$this->container->getDb()->Execute('UPDATE ' . _DB_PREFIX_ . 'tab SET position = ' . (int) ($i++) . ' WHERE id_tab = ' . (int) $child['id_tab'] . ' AND id_parent = ' . (int) $parent['id_parent']);
}
}
$this->status = 'ok';
$this->next = 'upgradeComplete';
$this->logger->info($this->translator->trans('The database has been cleaned.'));
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\FilesystemAdapter;
use PrestaShop\Module\AutoUpgrade\VersionUtils;
/**
* Download PrestaShop archive according to the chosen channel.
*/
class Download extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
if (!\ConfigurationTest::test_fopen() && !\ConfigurationTest::test_curl()) {
$this->logger->error($this->translator->trans('You need allow_url_fopen or cURL enabled for automatic download to work. You can also manually upload it in filepath %s.', [$this->container->getFilePath()]));
$this->next = 'error';
return ExitCode::FAIL;
}
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
$upgrader = $this->container->getUpgrader();
$upgrader->channel = $this->container->getUpgradeConfiguration()->get('channel');
$upgrader->branch = VersionUtils::splitPrestaShopVersion(_PS_VERSION_)['major'];
if ($this->container->getUpgradeConfiguration()->get('channel') == 'private' && !$this->container->getUpgradeConfiguration()->get('private_allow_major')) {
$upgrader->checkPSVersion(false, ['private', 'minor']);
} else {
$upgrader->checkPSVersion();
}
if ($upgrader->channel == 'private') {
$upgrader->link = $this->container->getUpgradeConfiguration()->get('private_release_link');
$upgrader->md5 = $this->container->getUpgradeConfiguration()->get('private_release_md5');
}
$this->logger->debug($this->translator->trans('Downloading from %s', [$upgrader->link]));
$this->logger->debug($this->translator->trans('File will be saved in %s', [$this->container->getFilePath()]));
if (file_exists($this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH))) {
FilesystemAdapter::deleteDirectory($this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH), false);
$this->logger->debug($this->translator->trans('Download directory has been emptied'));
}
$report = '';
$relative_download_path = str_replace(_PS_ROOT_DIR_, '', $this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH));
if (\ConfigurationTest::test_dir($relative_download_path, false, $report)) {
$res = $upgrader->downloadLast($this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH), $this->container->getProperty(UpgradeContainer::ARCHIVE_FILENAME));
if ($res) {
$md5file = md5_file(realpath($this->container->getProperty(UpgradeContainer::ARCHIVE_FILEPATH)));
if ($md5file == $upgrader->md5) {
$this->next = 'unzip';
$this->logger->debug($this->translator->trans('Download complete.'));
$this->logger->info($this->translator->trans('Download complete. Now extracting...'));
} else {
$this->logger->error($this->translator->trans('Download complete but MD5 sum does not match (%s).', [$md5file]));
$this->logger->info($this->translator->trans('Download complete but MD5 sum does not match (%s). Operation aborted.', [$md5file]));
$this->next = 'error';
}
} else {
if ($upgrader->channel == 'private') {
$this->logger->error($this->translator->trans('Error during download. The private key may be incorrect.'));
} else {
$this->logger->error($this->translator->trans('Error during download'));
}
$this->next = 'error';
}
} else {
$this->logger->error($this->translator->trans('Download directory %s is not writable.', [$this->container->getProperty(UpgradeContainer::DOWNLOAD_PATH)]));
$this->next = 'error';
}
return $this->next == 'error' ? ExitCode::FAIL : ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,132 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\FilesystemAdapter;
use Symfony\Component\Filesystem\Filesystem;
/**
* extract chosen version into $this->upgradeClass->latestPath directory.
*/
class Unzip extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
$filepath = $this->container->getFilePath();
$destExtract = $this->container->getProperty(UpgradeContainer::LATEST_PATH);
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
if (file_exists($destExtract)) {
FilesystemAdapter::deleteDirectory($destExtract, false);
$this->logger->debug($this->translator->trans('"/latest" directory has been emptied'));
}
$relative_extract_path = str_replace(_PS_ROOT_DIR_, '', $destExtract);
$report = '';
if (!\ConfigurationTest::test_dir($relative_extract_path, false, $report)) {
$this->logger->error($this->translator->trans('Extraction directory %s is not writable.', [$destExtract]));
$this->next = 'error';
$this->setErrorFlag();
return ExitCode::FAIL;
}
$res = $this->container->getZipAction()->extract($filepath, $destExtract);
if (!$res) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->info($this->translator->trans(
'Unable to extract %filepath% file into %destination% folder...',
[
'%filepath%' => $filepath,
'%destination%' => $destExtract,
]
));
return ExitCode::FAIL;
}
// From PrestaShop 1.7, we zip all the files in another package
// which must be unzipped too
$newZip = $destExtract . DIRECTORY_SEPARATOR . 'prestashop.zip';
if (file_exists($newZip)) {
@unlink($destExtract . DIRECTORY_SEPARATOR . '/index.php');
@unlink($destExtract . DIRECTORY_SEPARATOR . '/Install_PrestaShop.html');
$subRes = $this->container->getZipAction()->extract($newZip, $destExtract);
if (!$subRes) {
$this->next = 'error';
$this->logger->info($this->translator->trans(
'Unable to extract %filepath% file into %destination% folder...',
[
'%filepath%' => $filepath,
'%destination%' => $destExtract,
]
));
return ExitCode::FAIL;
}
} else {
$filesystem = new Filesystem();
$zipSubfolder = $destExtract . '/prestashop/';
if (!is_dir($zipSubfolder)) {
$this->next = 'error';
$this->logger->error(
$this->translator->trans('No prestashop/ folder found in the ZIP file. Aborting.'));
return ExitCode::FAIL;
}
// /!\ On PS 1.6, files are unzipped in a subfolder PrestaShop
foreach (scandir($zipSubfolder) as $file) {
if ($file[0] === '.') {
continue;
}
$filesystem->rename($zipSubfolder . $file, $destExtract . '/' . $file);
}
}
$this->next = 'backupFiles';
$this->logger->info($this->translator->trans('File extraction complete. Now backing up files...'));
@unlink($newZip);
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Analytics;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\FilesystemAdapter;
/**
* Ends the upgrade process and displays the success message.
*/
class UpgradeComplete extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
$this->logger->info($this->container->getState()->getWarningExists() ?
$this->translator->trans('Upgrade process done, but some warnings have been found.') :
$this->translator->trans('Upgrade process done. Congratulations! You can now reactivate your shop.')
);
$this->next = '';
if ($this->container->getUpgradeConfiguration()->get('channel') != 'archive' && file_exists($this->container->getFilePath()) && unlink($this->container->getFilePath())) {
$this->logger->debug($this->translator->trans('%s removed', [$this->container->getFilePath()]));
} elseif (is_file($this->container->getFilePath())) {
$this->logger->debug('<strong>' . $this->translator->trans('Please remove %s by FTP', [$this->container->getFilePath()]) . '</strong>');
}
if ($this->container->getUpgradeConfiguration()->get('channel') != 'directory' && file_exists($this->container->getProperty(UpgradeContainer::LATEST_PATH)) && FilesystemAdapter::deleteDirectory($this->container->getProperty(UpgradeContainer::LATEST_PATH))) {
$this->logger->debug($this->translator->trans('%s removed', [$this->container->getProperty(UpgradeContainer::LATEST_PATH)]));
} elseif (is_dir($this->container->getProperty(UpgradeContainer::LATEST_PATH))) {
$this->logger->debug('<strong>' . $this->translator->trans('Please remove %s by FTP', [$this->container->getProperty(UpgradeContainer::LATEST_PATH)]) . '</strong>');
}
// removing temporary files
$this->container->getFileConfigurationStorage()->cleanAll();
$this->container->getAnalytics()->track('Upgrade Succeeded', Analytics::WITH_UPGRADE_PROPERTIES);
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use PrestaShop\Module\AutoUpgrade\Exceptions\UpgradeException;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader17;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader80;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\CoreUpgrader\CoreUpgrader81;
class UpgradeDb extends AbstractTask
{
const TASK_TYPE = 'upgrade';
public function run(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
try {
$this->getCoreUpgrader()->doUpgrade();
} catch (UpgradeException $e) {
$this->next = 'error';
$this->setErrorFlag();
foreach ($e->getQuickInfos() as $log) {
$this->logger->debug($log);
}
$this->logger->error($this->translator->trans('Error during database upgrade. You may need to restore your database.'));
$this->logger->error($e->getMessage());
return ExitCode::FAIL;
}
$this->next = 'upgradeModules';
$this->stepDone = true;
$this->logger->info($this->translator->trans('Database upgraded. Now upgrading your Addons modules...'));
return ExitCode::SUCCESS;
}
public function getCoreUpgrader(): CoreUpgrader
{
if (version_compare($this->container->getState()->getInstallVersion(), '8', '<')) {
return new CoreUpgrader17($this->container, $this->logger);
}
if (version_compare($this->container->getState()->getInstallVersion(), '8.1', '<')) {
return new CoreUpgrader80($this->container, $this->logger);
}
return new CoreUpgrader81($this->container, $this->logger);
}
public function init(): void
{
$this->logger->info($this->translator->trans('Cleaning file cache'));
$this->container->getCacheCleaner()->cleanFolders();
$this->logger->info($this->translator->trans('Running opcache_reset'));
$this->container->resetOpcache();
// Migrating settings file
$this->container->initPrestaShopAutoloader();
parent::init();
}
}

View File

@@ -0,0 +1,283 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Progress\Backlog;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\FilesystemAdapter;
class UpgradeFiles extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @var string
*/
private $destUpgradePath;
/**
* @throws Exception
*/
public function run(): int
{
// The first call must init the list of files be upgraded.
if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::FILES_TO_UPGRADE_LIST)) {
return $this->warmUp();
}
// later we could choose between _PS_ROOT_DIR_ or _PS_TEST_DIR_
$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 = Backlog::fromContents(
$this->container->getFileConfigurationStorage()->load(UpgradeFileNames::FILES_TO_UPGRADE_LIST)
);
// @TODO : does not upgrade files in modules, translations if they have not a correct md5 (or crc32, or whatever) from previous version
for ($i = 0; $i < $this->container->getUpgradeConfiguration()->getNumberOfFilesPerCall(); ++$i) {
if (!$filesToUpgrade->getRemainingTotal()) {
$this->next = 'upgradeDb';
$this->logger->info($this->translator->trans('All files upgraded. Now upgrading database...'));
$this->stepDone = true;
break;
}
$file = $filesToUpgrade->getNext();
// 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';
$this->logger->error($this->translator->trans('Error when trying to upgrade file %s.', [$file]));
break;
}
}
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->computePercentage($filesToUpgrade, self::class, UpgradeDb::class)
);
$this->container->getFileConfigurationStorage()->save($filesToUpgrade->dump(), UpgradeFileNames::FILES_TO_UPGRADE_LIST);
$countOfRemainingBacklog = $filesToUpgrade->getRemainingTotal();
if ($countOfRemainingBacklog > 0) {
$this->logger->info($this->translator->trans('%s files left to upgrade.', [$countOfRemainingBacklog]));
$this->stepDone = false;
}
return $this->next == 'error' ? ExitCode::FAIL : ExitCode::SUCCESS;
}
/**
* upgradeThisFile.
*
* @param mixed $orig The absolute path to the file from the upgrade archive
*
* @throws Exception
*/
public function upgradeThisFile($orig): bool
{
// 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_)
$file = str_replace($this->container->getProperty(UpgradeContainer::LATEST_PATH), '', $orig);
// 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]));
return true;
}
if (is_dir($orig)) {
// if $dest is not a directory (that can happen), just remove that file
if (!is_dir($dest) && file_exists($dest)) {
unlink($dest);
$this->logger->debug($this->translator->trans('[WARNING] File %1$s has been deleted.', [$file]));
}
if (!file_exists($dest)) {
if (mkdir($dest)) {
$this->logger->debug($this->translator->trans('Directory %1$s created.', [$file]));
return true;
} else {
$this->next = 'error';
$this->logger->error($this->translator->trans('Error while creating directory %s.', [$dest]));
return false;
}
} else { // directory already exists
$this->logger->debug($this->translator->trans('Directory %s already exists.', [$file]));
return true;
}
} elseif (is_file($orig)) {
$translationAdapter = $this->container->getTranslationAdapter();
if ($translationAdapter->isTranslationFile($file) && file_exists($dest)) {
$type_trad = $translationAdapter->getTranslationFileType($file);
if ($translationAdapter->mergeTranslationFile($orig, $dest, $type_trad)) {
$this->logger->info($this->translator->trans('[TRANSLATION] The translation files have been merged into file %s.', [$dest]));
return true;
}
$this->logger->warning($this->translator->trans(
'[TRANSLATION] The translation files have not been merged into file %filename%. Switch to copy %filename%.',
['%filename%' => $dest]
));
}
// upgrade exception were above. This part now process all files that have to be upgraded (means to modify or to remove)
// delete before updating (and this will also remove deprecated files)
if (copy($orig, $dest)) {
$this->logger->debug($this->translator->trans('Copied %1$s.', [$file]));
return true;
} else {
$this->next = 'error';
$this->logger->error($this->translator->trans('Error while copying file %s', [$file]));
return false;
}
} elseif (is_file($dest)) {
if (file_exists($dest)) {
unlink($dest);
}
$this->logger->debug(sprintf('removed file %1$s.', $file));
return true;
} elseif (is_dir($dest)) {
FilesystemAdapter::deleteDirectory($dest);
$this->logger->debug(sprintf('removed dir %1$s.', $file));
return true;
} else {
return true;
}
}
/**
* First call of this task needs a warmup, where we load the files list to be upgraded.
*
* @throws Exception
*/
protected function warmUp(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
// 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]));
$this->logger->error($this->translator->trans('A file may be missing, or the release is stored in a subfolder by mistake.'));
$this->next = 'error';
return ExitCode::FAIL;
}
// 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');
}
// 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);
// $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 in list_files_to_upgrade 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]);
} 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);
}
}
}
// Now, we get the list of files that are either new or must be modified
$list_files_to_upgrade = $this->container->getFilesystemAdapter()->listFilesInDir(
$newReleasePath, 'upgrade', true
);
// Add our previously created list of deleted files
$list_files_to_upgrade = array_reverse(array_merge($list_files_diff, $list_files_to_upgrade));
$total_files_to_upgrade = count($list_files_to_upgrade);
$this->container->getFileConfigurationStorage()->save(
(new Backlog($list_files_to_upgrade, $total_files_to_upgrade))->dump(),
UpgradeFileNames::FILES_TO_UPGRADE_LIST
);
if ($total_files_to_upgrade === 0) {
$this->logger->error($this->translator->trans('[ERROR] Unable to find files to upgrade.'));
$this->next = 'error';
return ExitCode::FAIL;
}
$this->logger->info($this->translator->trans('%s files will be upgraded.', [$total_files_to_upgrade]));
$this->next = 'upgradeFiles';
$this->stepDone = false;
return ExitCode::SUCCESS;
}
public function init(): void
{
// Do nothing. Overrides parent init for avoiding core to be loaded here.
}
}

View File

@@ -0,0 +1,227 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Exceptions\UpgradeException;
use PrestaShop\Module\AutoUpgrade\Parameters\UpgradeFileNames;
use PrestaShop\Module\AutoUpgrade\Progress\Backlog;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\UpgradeContainer;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleDownloader;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleDownloaderContext;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleMigration;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleMigrationContext;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleUnzipper;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleUnzipperContext;
use PrestaShop\Module\AutoUpgrade\UpgradeTools\Module\ModuleVersionAdapter;
use Symfony\Component\Filesystem\Filesystem;
/**
* Upgrade all partners modules according to the installed prestashop version.
*/
class UpgradeModules extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
if (!$this->container->getFileConfigurationStorage()->exists(UpgradeFileNames::MODULES_TO_UPGRADE_LIST)) {
return $this->warmUp();
}
$listModules = Backlog::fromContents($this->container->getFileConfigurationStorage()->load(UpgradeFileNames::MODULES_TO_UPGRADE_LIST));
// add local modules that we want to upgrade to the list
$localModules = $this->getLocalModules();
if (!empty($localModules)) {
foreach ($localModules as $currentLocalModule) {
$listModules[$currentLocalModule['name']] = [
'id' => $currentLocalModule['id_module'],
'name' => $currentLocalModule['name'],
'is_local' => true,
];
}
}
$modulesPath = $this->container->getProperty(UpgradeContainer::PS_ROOT_PATH) . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR;
$moduleDownloader = new ModuleDownloader($this->translator, $this->logger, $this->container->getState()->getInstallVersion());
$moduleUnzipper = new ModuleUnzipper($this->translator, $this->container->getZipAction(), $modulesPath);
$moduleMigration = new ModuleMigration($this->translator, $this->logger);
if ($listModules->getRemainingTotal()) {
$moduleInfos = $listModules->getNext();
$zipFullPath = $this->container->getProperty(UpgradeContainer::TMP_PATH) . DIRECTORY_SEPARATOR . $moduleInfos['name'] . '.zip';
try {
$this->logger->debug($this->translator->trans('Updating module %module%...', ['%module%' => $moduleInfos['name']]));
$moduleDownloaderContext = new ModuleDownloaderContext($zipFullPath, $moduleInfos);
$moduleDownloader->downloadModule($moduleDownloaderContext);
$moduleUnzipperContext = new ModuleUnzipperContext($zipFullPath, $moduleInfos['name']);
$moduleUnzipper->unzipModule($moduleUnzipperContext);
$dbVersion = (new ModuleVersionAdapter())->get($moduleInfos['name']);
$module = \Module::getInstanceByName($moduleInfos['name']);
if (!($module instanceof \Module)) {
throw (new UpgradeException($this->translator->trans('[WARNING] Error when trying to retrieve module %s instance.', [$moduleInfos['name']])))->setSeverity(UpgradeException::SEVERITY_WARNING);
}
$moduleMigrationContext = new ModuleMigrationContext($module, $dbVersion);
if (!$moduleMigration->needMigration($moduleMigrationContext)) {
$this->logger->info($this->translator->trans('Module %s does not need to be migrated. Module is up to date.', [$moduleInfos['name']]));
} else {
$moduleMigration->runMigration($moduleMigrationContext);
}
$moduleMigration->saveVersionInDb($moduleMigrationContext);
} catch (UpgradeException $e) {
$this->handleException($e);
if ($e->getSeverity() === UpgradeException::SEVERITY_ERROR) {
return ExitCode::FAIL;
}
} finally {
// Cleanup of module assets
(new Filesystem())->remove([$zipFullPath]);
}
}
$modules_left = $listModules->getRemainingTotal();
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->computePercentage($listModules, self::class, CleanDatabase::class)
);
$this->container->getFileConfigurationStorage()->save($listModules->dump(), UpgradeFileNames::MODULES_TO_UPGRADE_LIST);
if ($modules_left) {
$this->stepDone = false;
$this->next = 'upgradeModules';
$this->logger->info($this->translator->trans('%s modules left to upgrade.', [$modules_left]));
} else {
$this->stepDone = true;
$this->status = 'ok';
$this->next = 'cleanDatabase';
$this->logger->info($this->translator->trans('Addons modules files have been upgraded.'));
}
return ExitCode::SUCCESS;
}
/**
* Get the list of module zips in admin/autoupgrade/modules
* These zips will be used to upgrade related modules instead of using distant zips on addons
*
* @return array<string, mixed>
*/
private function getLocalModules(): array
{
$localModuleDir = sprintf(
'%s%sautoupgrade%smodules',
_PS_ADMIN_DIR_,
DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR
);
$zipFileNames = [];
$zipFiles = glob($localModuleDir . DIRECTORY_SEPARATOR . '*.zip');
if (empty($zipFiles)) {
return [];
}
foreach ($zipFiles as $zipFile) {
$zipFileNames[] = pSQL(pathinfo($zipFile, PATHINFO_FILENAME));
}
$sql = sprintf(
"SELECT id_module, name FROM %smodule WHERE name IN ('%s')",
_DB_PREFIX_,
implode("','", $zipFileNames)
);
return \Db::getInstance()->executeS($sql);
}
public function warmUp(): int
{
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
try {
$modulesToUpgrade = $this->container->getModuleAdapter()->listModulesToUpgrade(
$this->container->getState()->getModules_addons(),
$this->container->getState()->getModulesVersions()
);
$modulesToUpgrade = array_reverse($modulesToUpgrade);
$total_modules_to_upgrade = count($modulesToUpgrade);
$this->container->getFileConfigurationStorage()->save(
(new Backlog($modulesToUpgrade, $total_modules_to_upgrade))->dump(),
UpgradeFileNames::MODULES_TO_UPGRADE_LIST
);
} catch (UpgradeException $e) {
$this->handleException($e);
return ExitCode::FAIL;
}
if ($total_modules_to_upgrade) {
$this->logger->info($this->translator->trans('%s modules will be upgraded.', [$total_modules_to_upgrade]));
}
$this->stepDone = false;
$this->next = 'upgradeModules';
return ExitCode::SUCCESS;
}
private function handleException(UpgradeException $e): void
{
if ($e->getSeverity() === UpgradeException::SEVERITY_ERROR) {
$this->next = 'error';
$this->setErrorFlag();
$this->logger->error($e->getMessage());
}
if ($e->getSeverity() === UpgradeException::SEVERITY_WARNING) {
$this->logger->warning($e->getMessage());
}
foreach ($e->getQuickInfos() as $log) {
$this->logger->warning($log);
}
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
namespace PrestaShop\Module\AutoUpgrade\Task\Upgrade;
use Exception;
use PrestaShop\Module\AutoUpgrade\Analytics;
use PrestaShop\Module\AutoUpgrade\Task\AbstractTask;
use PrestaShop\Module\AutoUpgrade\Task\ExitCode;
use PrestaShop\Module\AutoUpgrade\VersionUtils;
/**
* very first step of the upgrade process. The only thing done is the selection
* of the next step.
*/
class UpgradeNow extends AbstractTask
{
const TASK_TYPE = 'upgrade';
/**
* @throws Exception
*/
public function run(): int
{
$this->logger->info($this->translator->trans('Starting upgrade...'));
$this->container->getState()->setProgressPercentage(
$this->container->getCompletionCalculator()->getBasePercentageOfTask(self::class)
);
$this->container->getWorkspace()->createFolders();
$channel = $this->container->getUpgradeConfiguration()->get('channel');
$upgrader = $this->container->getUpgrader();
$upgrader->branch = VersionUtils::splitPrestaShopVersion(_PS_VERSION_)['major'];
$upgrader->channel = $channel;
if ($this->container->getUpgradeConfiguration()->get('channel') == 'private' && !$this->container->getUpgradeConfiguration()->get('private_allow_major')) {
$upgrader->checkPSVersion(false, ['private', 'minor']);
} else {
$upgrader->checkPSVersion();
}
if ($upgrader->isLastVersion()) {
$this->next = '';
$this->logger->info($this->translator->trans('You already have the %s version.', [$upgrader->version_name]));
return ExitCode::SUCCESS;
}
switch ($channel) {
case 'directory':
// if channel directory is chosen, we assume it's "ready for use"
$this->next = 'backupFiles';
$this->logger->debug($this->translator->trans('Downloading and unzipping steps have been skipped, upgrade process will now remove sample data.'));
$this->logger->info($this->translator->trans('Shop deactivated. Now backing up files...'));
break;
case 'archive':
$this->next = 'unzip';
$this->logger->debug($this->translator->trans('Downloading step has been skipped, upgrade process will now unzip the local archive.'));
$this->logger->info($this->translator->trans('Shop deactivated. Extracting files...'));
break;
default:
$this->next = 'download';
$this->logger->info($this->translator->trans('Shop deactivated. Now downloading... (this can take a while)'));
if ($upgrader->channel == 'private') {
$upgrader->link = $this->container->getUpgradeConfiguration()->get('private_release_link');
$upgrader->md5 = $this->container->getUpgradeConfiguration()->get('private_release_md5');
}
$this->logger->debug($this->translator->trans('Downloaded archive will come from %s', [$upgrader->link]));
$this->logger->debug($this->translator->trans('MD5 hash will be checked against %s', [$upgrader->md5]));
}
$this->container->getAnalytics()->track('Upgrade Launched', Analytics::WITH_UPGRADE_PROPERTIES);
return ExitCode::SUCCESS;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;