5795 lines
215 KiB
PHP
5795 lines
215 KiB
PHP
<?php
|
|
/*
|
|
* 2007-2014 PrestaShop
|
|
*
|
|
* NOTICE OF LICENSE
|
|
*
|
|
* This source file is subject to the Open Software License (OSL 3.0)
|
|
* that is bundled with this package in the file LICENSE.txt.
|
|
* It is also available through the world-wide-web at this URL:
|
|
* http://opensource.org/licenses/osl-3.0.php
|
|
* 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 http://www.prestashop.com for more information.
|
|
*
|
|
* @author PrestaShop SA <contact@prestashop.com>
|
|
* @copyright 2007-2014 PrestaShop SA
|
|
* @version Release: $Revision: 11834 $
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
|
* International Registered Trademark & Property of PrestaShop SA
|
|
*/
|
|
|
|
// _PS_ADMIN_DIR_ is defined in ajax-upgradetab, but may be not defined in direct call
|
|
if (!defined('_PS_ADMIN_DIR_') && defined('PS_ADMIN_DIR'))
|
|
define('_PS_ADMIN_DIR_', PS_ADMIN_DIR);
|
|
|
|
// Note : we cannot use the native AdminTab because
|
|
// we don't know the current PrestaShop version number
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/AdminSelfTab.php');
|
|
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/classes/Upgrader.php');
|
|
|
|
if (!class_exists('Upgrader', false))
|
|
{
|
|
if (file_exists(_PS_ROOT_DIR_.'/override/classes/Upgrader.php'))
|
|
require_once(_PS_ROOT_DIR_.'/override/classes/Upgrader.php');
|
|
else
|
|
eval('class Upgrader extends UpgraderCore{}');
|
|
}
|
|
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/classes/Tools14.php');
|
|
if (!class_exists('Tools', false))
|
|
eval('class Tools extends Tools14{}');
|
|
|
|
class AdminSelfUpgrade extends AdminSelfTab
|
|
{
|
|
public $multishop_context;
|
|
public $multishop_context_group = false;
|
|
public $_html = '';
|
|
// used for translations
|
|
public static $l_cache;
|
|
// retrocompatibility
|
|
public $noTabLink = array();
|
|
public $id = -1;
|
|
|
|
public $ajax = false;
|
|
public $nextResponseType = 'json'; // json, xml
|
|
public $next = 'N/A';
|
|
|
|
public $upgrader = null;
|
|
public $standalone = true;
|
|
|
|
/**
|
|
* set to false if the current step is a loop
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $stepDone = true;
|
|
public $status = true;
|
|
public $warning_exists = false;
|
|
public $error = '0';
|
|
public $next_desc = '';
|
|
public $nextParams = array();
|
|
public $nextQuickInfo = array();
|
|
public $nextErrors = array();
|
|
public $currentParams = array();
|
|
/**
|
|
* @var array theses values will be automatically added in "nextParams"
|
|
* if their properties exists
|
|
*/
|
|
public $ajaxParams = array(
|
|
// autoupgrade options
|
|
'install_version',
|
|
'backupName',
|
|
'backupFilesFilename',
|
|
'backupDbFilename',
|
|
'restoreName',
|
|
'restoreFilesFilename',
|
|
'restoreDbFilenames',
|
|
'installedLanguagesIso',
|
|
'modules_addons',
|
|
'warning_exists',
|
|
);
|
|
|
|
/**
|
|
* installedLanguagesIso is an array of iso_code of each installed languages
|
|
*
|
|
* @var array
|
|
* @access public
|
|
*/
|
|
public $installedLanguagesIso = array();
|
|
|
|
/**
|
|
* modules_addons is an array of array(id_addons => name_module).
|
|
*
|
|
* @var array
|
|
* @access public
|
|
*/
|
|
public $modules_addons = array();
|
|
|
|
public $autoupgradePath = null;
|
|
public $downloadPath = null;
|
|
public $backupPath = null;
|
|
public $latestPath = null;
|
|
public $tmpPath = null;
|
|
|
|
/**
|
|
* autoupgradeDir
|
|
*
|
|
* @var string directory relative to admin dir
|
|
*/
|
|
public $autoupgradeDir = 'autoupgrade';
|
|
public $latestRootDir = '';
|
|
public $prodRootDir = '';
|
|
public $adminDir = '';
|
|
public $root_writable = null;
|
|
public $module_version = null;
|
|
|
|
public $lastAutoupgradeVersion = '';
|
|
public $destDownloadFilename = 'prestashop.zip';
|
|
|
|
/**
|
|
* configFilename contains all configuration specific to the autoupgrade module
|
|
*
|
|
* @var string
|
|
* @access public
|
|
*/
|
|
public $configFilename = 'config.var';
|
|
/**
|
|
* during upgradeFiles process,
|
|
* this files contains the list of queries left to upgrade in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toUpgradeQueriesList = 'queriesToUpgrade.list';
|
|
/**
|
|
* during upgradeFiles process,
|
|
* this files contains the list of files left to upgrade in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toUpgradeFileList = 'filesToUpgrade.list';
|
|
/**
|
|
* during upgradeModules process,
|
|
* this files contains the list of modules left to upgrade in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toUpgradeModuleList = 'modulesToUpgrade.list';
|
|
/**
|
|
* during upgradeFiles process,
|
|
* this files contains the list of files left to upgrade in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $diffFileList = 'filesDiff.list';
|
|
/**
|
|
* during backupFiles process,
|
|
* this files contains the list of files left to save in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toBackupFileList = 'filesToBackup.list';
|
|
/**
|
|
* during backupDb process,
|
|
* this files contains the list of tables left to save in a serialized array.
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toBackupDbList = 'tablesToBackup.list';
|
|
/**
|
|
* during restoreDb process,
|
|
* this file contains a serialized array of queries which left to execute for restoring database
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toRestoreQueryList = 'queryToRestore.list';
|
|
/**
|
|
* during restoreFiles process,
|
|
* this file contains difference between queryToRestore and queries present in a backupFiles archive
|
|
* (this file is deleted in init() method if you reload the page)
|
|
* @var string
|
|
*/
|
|
public $toRemoveFileList = 'filesToRemove.list';
|
|
/**
|
|
* during restoreFiles process,
|
|
* contains list of files present in backupFiles archive
|
|
*
|
|
* @var string
|
|
*/
|
|
public $fromArchiveFileList = 'filesFromArchive.list';
|
|
|
|
/**
|
|
* mailCustomList contains list of mails files which are customized,
|
|
* relative to original files for the current PrestaShop version
|
|
*
|
|
* @var string
|
|
*/
|
|
public $mailCustomList = 'mails-custom.list';
|
|
|
|
/**
|
|
* tradCustomList contains list of mails files which are customized,
|
|
* relative to original files for the current PrestaShop version
|
|
*
|
|
* @var string
|
|
*/
|
|
public $tradCustomList = 'translations-custom.list';
|
|
/**
|
|
* tmp_files contains an array of filename which will be removed
|
|
* at the beginning of the upgrade process
|
|
*
|
|
* @var array
|
|
*/
|
|
public $tmp_files = array(
|
|
'toUpgradeFileList',
|
|
'toUpgradeQueriesList',
|
|
'diffFileList',
|
|
'toBackupFileList',
|
|
'toBackupDbList',
|
|
'toRestoreQueryList',
|
|
'toRemoveFileList',
|
|
'fromArchiveFileList',
|
|
'tradCustomList',
|
|
'mailCustomList',
|
|
);
|
|
|
|
public $install_version;
|
|
public $keepImages = null;
|
|
public $updateDefaultTheme = null;
|
|
public $keepMails = null;
|
|
public $manualMode = null;
|
|
public $deactivateCustomModule = null;
|
|
|
|
public $sampleFileList = array();
|
|
private $restoreIgnoreFiles = array();
|
|
private $restoreIgnoreAbsoluteFiles = array();
|
|
private $backupIgnoreFiles = array();
|
|
private $backupIgnoreAbsoluteFiles = array();
|
|
private $excludeFilesFromUpgrade = array();
|
|
private $excludeAbsoluteFilesFromUpgrade = array();
|
|
|
|
public static $classes14 = array('Cache', 'CacheFS', 'CarrierModule', 'Db', 'FrontController', 'Helper','ImportModule',
|
|
'MCached', 'Module', 'ModuleGraph', 'ModuleGraphEngine', 'ModuleGrid', 'ModuleGridEngine',
|
|
'MySQL', 'Order', 'OrderDetail', 'OrderDiscount', 'OrderHistory', 'OrderMessage', 'OrderReturn',
|
|
'OrderReturnState', 'OrderSlip', 'OrderState', 'PDF', 'RangePrice', 'RangeWeight', 'StockMvt',
|
|
'StockMvtReason', 'SubDomain', 'Shop', 'Tax', 'TaxRule', 'TaxRulesGroup', 'WebserviceKey', 'WebserviceRequest', '');
|
|
|
|
private $restoreName = null;
|
|
private $backupName = null;
|
|
private $backupFilesFilename = null;
|
|
private $backupDbFilename = null;
|
|
private $restoreFilesFilename = null;
|
|
private $restoreDbFilenames = array();
|
|
|
|
public static $loopBackupFiles = 400;
|
|
public static $maxBackupFileSize = 15728640; // 15 Mo
|
|
public static $loopBackupDbTime = 6;
|
|
public static $max_written_allowed = 4194304; // 4096 ko
|
|
public static $loopUpgradeFiles = 600;
|
|
public static $loopRestoreFiles = 400;
|
|
public static $loopRestoreQueryTime = 6;
|
|
public static $loopUpgradeModulesTime = 6;
|
|
public static $loopRemoveSamples = 400;
|
|
|
|
/* usage : key = the step you want to ski
|
|
* value = the next step you want instead
|
|
* example : public static $skipAction = array();
|
|
* initial order upgrade:
|
|
* download, unzip, removeSamples, backupFiles, backupDb, upgradeFiles, upgradeDb, upgradeModules, cleanDatabase, upgradeComplete
|
|
* initial order rollback: rollback, restoreFiles, restoreDb, rollbackComplete
|
|
*/
|
|
public static $skipAction = array();
|
|
|
|
/**
|
|
* if set to true, will use pclZip library
|
|
* even if ZipArchive is available
|
|
*/
|
|
public static $force_pclZip = false;
|
|
|
|
protected $_includeContainer = true;
|
|
|
|
public $_fieldsUpgradeOptions = array();
|
|
public $_fieldsBackupOptions = array();
|
|
/**
|
|
* replace tools encrypt
|
|
*
|
|
* @param mixed $string
|
|
* @return void
|
|
*/
|
|
public function encrypt($string)
|
|
{
|
|
return md5(_COOKIE_KEY_.$string);
|
|
}
|
|
|
|
public function checkToken()
|
|
{
|
|
// simple checkToken in ajax-mode, to be free of Cookie class (and no Tools::encrypt() too )
|
|
if ($this->ajax && isset($_COOKIE['id_employee']))
|
|
return ($_COOKIE['autoupgrade'] == $this->encrypt($_COOKIE['id_employee']));
|
|
else
|
|
return parent::checkToken();
|
|
}
|
|
|
|
/**
|
|
* create cookies id_employee, id_tab and autoupgrade (token)
|
|
*/
|
|
public function createCustomToken()
|
|
{
|
|
// ajax-mode for autoupgrade, we can't use the classic authentication
|
|
// so, we'll create a cookie in admin dir, based on cookie key
|
|
global $cookie;
|
|
$id_employee = $cookie->id_employee;
|
|
if ($cookie->id_lang)
|
|
$iso_code = $_COOKIE['iso_code'] = Language::getIsoById((int)$cookie->id_lang);
|
|
else
|
|
$iso_code = 'en';
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
$cookiePath = __PS_BASE_URI__.$admin_dir;
|
|
setcookie('id_employee', $id_employee, time() + 7200, $cookiePath);
|
|
setcookie('id_tab', $this->id, time() + 7200, $cookiePath);
|
|
setcookie('iso_code', $iso_code, time() + 7200, $cookiePath);
|
|
setcookie('autoupgrade', $this->encrypt($id_employee), time() + 7200, $cookiePath);
|
|
return false;
|
|
}
|
|
|
|
public function viewAccess($disable = false)
|
|
{
|
|
if ($this->ajax)
|
|
return true;
|
|
else
|
|
{
|
|
// simple access : we'll allow only admin
|
|
global $cookie;
|
|
if ($cookie->profile == 1)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function __construct()
|
|
{
|
|
@set_time_limit(0);
|
|
@ini_set('max_execution_time', '0');
|
|
@ini_set('magic_quotes_runtime', '0');
|
|
|
|
global $ajax, $currentIndex;
|
|
|
|
if (!empty($ajax))
|
|
$this->ajax = true;
|
|
|
|
$this->init();
|
|
// retrocompatibility when used in module : Tab can't work,
|
|
// but we saved the tab id in a cookie.
|
|
if (class_exists('Tab', false))
|
|
parent::__construct();
|
|
elseif (isset($_COOKIE['id_tab']))
|
|
$this->id = $_COOKIE['id_tab'];
|
|
|
|
// Database instanciation (need to be cached because there will be at least 100k calls in the upgrade process
|
|
if (!class_exists('Db', false))
|
|
{
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/db/Db.php');
|
|
eval('abstract class Db extends DbCore{}');
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/db/MySQL.php');
|
|
eval('class MySQL extends MySQLCore{}');
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/db/DbMySQLi.php');
|
|
eval('class DbMySQLi extends DbMySQLiCore{}');
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/db/DbPDO.php');
|
|
eval('class DbPDO extends DbPDOCore{}');
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/db/DbQuery.php');
|
|
eval('class DbQuery extends DbQueryCore{}');
|
|
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/alias.php');
|
|
}
|
|
$this->db = Db::getInstance();
|
|
|
|
// Performance settings, if your server has a low memory size, lower these values
|
|
$perf_array = array(
|
|
'loopBackupFiles' => array(400, 800, 1600),
|
|
'maxBackupFileSize' => array(15728640, 31457280, 62914560),
|
|
'loopBackupDbTime' => array(6, 12, 25),
|
|
'max_written_allowed' => array(4194304, 8388608, 16777216),
|
|
'loopUpgradeFiles' => array(600, 1200, 2400),
|
|
'loopRestoreFiles' => array(400, 800, 1600),
|
|
'loopRestoreQueryTime' => array(6, 12, 25),
|
|
'loopUpgradeModulesTime' => array(6, 12, 25),
|
|
'loopRemoveSamples' => array(400, 800, 1600)
|
|
);
|
|
switch ($this->getConfig('PS_AUTOUP_PERFORMANCE'))
|
|
{
|
|
case 3:
|
|
foreach ($perf_array as $property => $values)
|
|
self::$$property = $values[2];
|
|
break;
|
|
case 2:
|
|
foreach ($perf_array as $property => $values)
|
|
self::$$property = $values[1];
|
|
break;
|
|
case 1:
|
|
default:
|
|
foreach ($perf_array as $property => $values)
|
|
self::$$property = $values[0];
|
|
}
|
|
/* Bug with backwardcompatibility overrinding currentIndex */
|
|
if (version_compare(_PS_VERSION_,'1.5.0.0','>'))
|
|
$this->currentIndex = $_SERVER['SCRIPT_NAME'].(($controller = Tools14::getValue('controller')) ? '?controller='.$controller: '');
|
|
else
|
|
$this->currentIndex = $currentIndex;
|
|
|
|
if (defined('_PS_ADMIN_DIR_'))
|
|
{
|
|
$file_tab = @filemtime($this->autoupgradePath.DIRECTORY_SEPARATOR.'ajax-upgradetab.php');
|
|
$file = @filemtime(_PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$this->autoupgradeDir.DIRECTORY_SEPARATOR.'ajax-upgradetab.php');
|
|
|
|
if ($file_tab < $file)
|
|
@copy(_PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$this->autoupgradeDir.DIRECTORY_SEPARATOR.'ajax-upgradetab.php',
|
|
$this->autoupgradePath.DIRECTORY_SEPARATOR.'ajax-upgradetab.php');
|
|
}
|
|
}
|
|
|
|
protected function l($string, $class = 'AdminTab', $addslashes = FALSE, $htmlentities = TRUE)
|
|
{
|
|
// need to be called in order to populate $classInModule
|
|
$str = self::findTranslation('autoupgrade', $string, 'AdminSelfUpgrade');
|
|
$str = $htmlentities ? str_replace('"', '"', htmlentities($str, ENT_QUOTES, 'utf-8')) : $str;
|
|
$str = $addslashes ? addslashes($str) : stripslashes($str);
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* findTranslation (initially in Module class), to make translations works
|
|
*
|
|
* @param string $name module name
|
|
* @param string $string string to translate
|
|
* @param string $source current class
|
|
* @return string translated string
|
|
*/
|
|
public static function findTranslation($name, $string, $source)
|
|
{
|
|
static $_MODULES;
|
|
if (!is_array($_MODULES))
|
|
{
|
|
// note: $_COOKIE[iso_code] is set in createCustomToken();
|
|
$files_to_try = array(
|
|
_PS_MODULE_DIR_.'autoupgrade'.DIRECTORY_SEPARATOR.'translations'.DIRECTORY_SEPARATOR.$_COOKIE['iso_code'].'.php', // 1.5
|
|
_PS_MODULE_DIR_.'autoupgrade'.DIRECTORY_SEPARATOR.$_COOKIE['iso_code'].'.php' // 1.4
|
|
);
|
|
// translations may be in "autoupgrade/translations/iso_code.php" or "autoupgrade/iso_code.php",
|
|
// try both locations.
|
|
foreach ($files_to_try as $file)
|
|
if (file_exists($file) && include($file))
|
|
{
|
|
$_MODULES = !empty($_MODULES) ? array_merge($_MODULES, $_MODULE) : $_MODULE;
|
|
break;
|
|
}
|
|
}
|
|
$cache_key = $name.'|'.$string.'|'.$source;
|
|
|
|
if (!isset(self::$l_cache[$cache_key]))
|
|
{
|
|
if (!is_array($_MODULES))
|
|
return $string;
|
|
// set array key to lowercase for 1.3 compatibility
|
|
$_MODULES = array_change_key_case($_MODULES);
|
|
if (defined('_THEME_NAME_'))
|
|
$currentKey = '<{'.strtolower($name).'}'.strtolower(_THEME_NAME_).'>'.strtolower($source).'_'.md5($string);
|
|
else
|
|
$currentKey = '<{'.strtolower($name).'}default>'.strtolower($source).'_'.md5($string);
|
|
// note : we should use a variable to define the default theme (instead of "prestashop")
|
|
$defaultKey = '<{'.strtolower($name).'}prestashop>'.strtolower($source).'_'.md5($string);
|
|
$currentKey = $defaultKey;
|
|
|
|
if (isset($_MODULES[$currentKey]))
|
|
$ret = stripslashes($_MODULES[$currentKey]);
|
|
elseif (isset($_MODULES[strtolower($currentKey)]))
|
|
$ret = stripslashes($_MODULES[strtolower($currentKey)]);
|
|
elseif (isset($_MODULES[$defaultKey]))
|
|
$ret = stripslashes($_MODULES[$defaultKey]);
|
|
elseif (isset($_MODULES[strtolower($defaultKey)]))
|
|
$ret = stripslashes($_MODULES[strtolower($defaultKey)]);
|
|
else
|
|
$ret = stripslashes($string);
|
|
|
|
self::$l_cache[$cache_key] = $ret;
|
|
}
|
|
return self::$l_cache[$cache_key];
|
|
}
|
|
|
|
/**
|
|
* function to set configuration fields display
|
|
*
|
|
* @return void
|
|
*/
|
|
private function _setFields()
|
|
{
|
|
$this->_fieldsBackupOptions['PS_AUTOUP_BACKUP'] = array(
|
|
'title' => $this->l('Back up my files and database'), 'cast' => 'intval', 'validation' => 'isBool', 'defaultValue' => '1',
|
|
'type' => 'bool', 'desc' => $this->l('Automatically back up your database and files in order to restore your shop if needed. This is experimental: you should still perform your own manual backup for safety.'),
|
|
);
|
|
$this->_fieldsBackupOptions['PS_AUTOUP_KEEP_IMAGES'] = array(
|
|
'title' => $this->l('Back up my images'), 'cast' => 'intval', 'validation' => 'isBool', 'defaultValue' => '1',
|
|
'type' => 'bool', 'desc' => $this->l('To save time, you can decide not to back your images up. In any case, always make sure you did back them up manually.'),
|
|
);
|
|
|
|
$this->_fieldsUpgradeOptions['PS_AUTOUP_PERFORMANCE'] = array(
|
|
'title' => $this->l('Server performance'), 'cast' => 'intval', 'validation' => 'isInt', 'defaultValue' => '1',
|
|
'type' => 'select', 'desc' => $this->l('Unless you are using a dedicated server, select "Low".').'<br />'.
|
|
$this->l('A high value can cause the upgrade to fail if your server is not powerful enough to process the upgrade tasks in a short amount of time.'),
|
|
'choices' => array(1 => $this->l('Low (recommended)'), 2 => $this->l('Medium'), 3 => $this->l('High'))
|
|
);
|
|
|
|
$this->_fieldsUpgradeOptions['PS_AUTOUP_CUSTOM_MOD_DESACT'] = array(
|
|
'title' => $this->l('Disable non-native modules'), 'cast' => 'intval', 'validation' => 'isBool',
|
|
'type' => 'bool', 'desc' => $this->l('As non-native modules can experience some compatibility issues, we recommend to disable them by default.').'<br />'.
|
|
$this->l('Keeping them enabled might prevent you from loading the "Modules" page properly after the upgrade.'),
|
|
);
|
|
|
|
$this->_fieldsUpgradeOptions['PS_AUTOUP_UPDATE_DEFAULT_THEME'] = array(
|
|
'title' => $this->l('Upgrade and switch to the default theme of the new version'), 'cast' => 'intval', 'validation' => 'isBool', 'defaultValue' => '1',
|
|
'type' => 'bool', 'desc' => $this->l('This will change your theme: your shop will then use the default theme of the version of PrestaShop you are upgrading to.').'<br />'
|
|
.$this->l('If you customized the default PrestaShop theme in its folder (folder name "prestashop" in 1.4, "default" in 1.5, "bootstrap-default" in 1.6), enabling this option will lose your modifications.').'<br />'
|
|
.$this->l('If you are using your own theme, enabling this option will switch your shop to the updated default theme, and your own theme will be safe.'),
|
|
);
|
|
|
|
$this->_fieldsUpgradeOptions['PS_AUTOUP_KEEP_MAILS'] = array(
|
|
'title' => $this->l('Upgrade the default e-mails'), 'cast' => 'intval', 'validation' => 'isBool',
|
|
'type' => 'bool', 'desc' => $this->l('This will upgrade the default PrestaShop e-mails.').'<br />'
|
|
.$this->l('If you customized the default PrestaShop e-mail templates, enabling this option will lose your modifications.'),
|
|
);
|
|
|
|
/* Developers only options */
|
|
if (defined('_PS_MODE_DEV_') && _PS_MODE_DEV_)
|
|
{
|
|
$this->_fieldsUpgradeOptions['PS_AUTOUP_MANUAL_MODE'] = array(
|
|
'title' => $this->l('Step by step mode'), 'cast' => 'intval', 'validation' => 'isBool',
|
|
'type' => 'bool', 'desc' => $this->l('Allows to perform the upgrade step by step (debug mode).'),
|
|
);
|
|
|
|
$this->_fieldsUpgradeOptions['PS_DISPLAY_ERRORS'] = array(
|
|
'title' => $this->l('Display PHP errors'), 'cast' => 'intval', 'validation' => 'isBool', 'defaultValue' => '0',
|
|
'type' => 'bool', 'desc' => $this->l('This option will keep PHP\'s "display_errors" setting to On (or force it).').'<br />'
|
|
.$this->l('This is not recommended as the upgrade will immediately fail if a PHP error occurs during an Ajax call.'),
|
|
);
|
|
}
|
|
elseif ($this->getConfig('PS_DISPLAY_ERRORS'))
|
|
$this->writeConfig(array('PS_DISPLAY_ERRORS' => '0'));
|
|
}
|
|
|
|
public function configOk()
|
|
{
|
|
$allowed_array = $this->getCheckCurrentPsConfig();
|
|
$allowed = array_product($allowed_array);
|
|
return $allowed;
|
|
}
|
|
|
|
public function getCheckCurrentPsConfig()
|
|
{
|
|
static $allowed_array;
|
|
|
|
if(empty($allowed_array))
|
|
{
|
|
$allowed_array = array();
|
|
$allowed_array['fopen'] = ConfigurationTest::test_fopen() || ConfigurationTest::test_curl();
|
|
$allowed_array['root_writable'] = $this->getRootWritable();
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
$allowed_array['admin_au_writable'] = ConfigurationTest::test_dir($admin_dir.DIRECTORY_SEPARATOR.$this->autoupgradeDir, false, $report);
|
|
$allowed_array['shop_deactivated'] = (!Configuration::get('PS_SHOP_ENABLE') || (isset($_SERVER['HTTP_HOST']) && in_array($_SERVER['HTTP_HOST'], array('127.0.0.1', 'localhost'))));
|
|
$allowed_array['cache_deactivated'] = !(defined('_PS_CACHE_ENABLED_') && _PS_CACHE_ENABLED_);
|
|
$allowed_array['module_version_ok'] = $this->checkAutoupgradeLastVersion();
|
|
if (version_compare(_PS_VERSION_,'1.5.0.0','<'))
|
|
$allowed_array['test_mobile'] = ConfigurationTest::test_mobile();
|
|
}
|
|
return $allowed_array;
|
|
}
|
|
|
|
public function getRootWritable()
|
|
{
|
|
// Root directory permissions cannot be checked recursively anymore, it takes too much time
|
|
$this->root_writable = ConfigurationTest::test_dir('/', false, $report);
|
|
$this->root_writable_report = $report;
|
|
|
|
return $this->root_writable;
|
|
}
|
|
|
|
public function getModuleVersion()
|
|
{
|
|
if (is_null($this->module_version))
|
|
{
|
|
if (file_exists(_PS_ROOT_DIR_.'/modules/autoupgrade/config.xml')
|
|
&& $xml_module_version = simplexml_load_file(_PS_ROOT_DIR_.'/modules/autoupgrade/config.xml')
|
|
)
|
|
$this->module_version = (string)$xml_module_version->version;
|
|
else
|
|
$this->module_version = false;
|
|
}
|
|
return $this->module_version;
|
|
}
|
|
|
|
public function checkAutoupgradeLastVersion()
|
|
{
|
|
if ($this->getModuleVersion())
|
|
$this->lastAutoupgradeVersion = version_compare($this->module_version, $this->upgrader->autoupgrade_last_version, '>=');
|
|
else
|
|
$this->lastAutoupgradeVersion = true;
|
|
|
|
return $this->lastAutoupgradeVersion;
|
|
}
|
|
|
|
public function cleanTmpFiles()
|
|
{
|
|
foreach($this->tmp_files as $tmp_file)
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->$tmp_file))
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->$tmp_file);
|
|
}
|
|
|
|
/**
|
|
* init to build informations we need
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init()
|
|
{
|
|
// For later use, let's set up prodRootDir and adminDir
|
|
// This way it will be easier to upgrade a different path if needed
|
|
$this->prodRootDir = _PS_ROOT_DIR_;
|
|
$this->adminDir = _PS_ADMIN_DIR_;
|
|
if (!defined('__PS_BASE_URI__'))
|
|
{
|
|
// _PS_DIRECTORY_ replaces __PS_BASE_URI__ in 1.5
|
|
if (defined('_PS_DIRECTORY_'))
|
|
define('__PS_BASE_URI__', _PS_DIRECTORY_);
|
|
else
|
|
define('__PS_BASE_URI__', realpath(dirname($_SERVER['SCRIPT_NAME'])).'/../../');
|
|
}
|
|
// from $_POST or $_GET
|
|
$this->action = empty($_REQUEST['action'])?null:$_REQUEST['action'];
|
|
$this->currentParams = empty($_REQUEST['params'])?null:$_REQUEST['params'];
|
|
// test writable recursively
|
|
if(version_compare(_PS_VERSION_,'1.4.6.0','<') || !class_exists('ConfigurationTest', false))
|
|
{
|
|
require_once(dirname(__FILE__).'/classes/ConfigurationTest.php');
|
|
if(!class_exists('ConfigurationTest', false) AND class_exists('ConfigurationTestCore'))
|
|
eval('class ConfigurationTest extends ConfigurationTestCore{}');
|
|
}
|
|
$this->initPath();
|
|
$upgrader = new Upgrader();
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
if (isset($matches[1]))
|
|
$upgrader->branch = $matches[1];
|
|
$channel = $this->getConfig('channel');
|
|
switch ($channel)
|
|
{
|
|
case 'archive':
|
|
$this->install_version = $this->getConfig('archive.version_num');
|
|
$this->destDownloadFilename = $this->getConfig('archive.filename');
|
|
$upgrader->checkPSVersion(true, array('archive'));
|
|
break;
|
|
case 'directory';
|
|
$this->install_version = $this->getConfig('directory.version_num');
|
|
$upgrader->checkPSVersion(true, array('directory'));
|
|
break;
|
|
default:
|
|
$upgrader->channel = $channel;
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$upgrader->checkPSVersion(true, array('private', 'minor'));
|
|
else
|
|
$upgrader->checkPSVersion(true, array('minor'));
|
|
$this->install_version = $upgrader->version_num;
|
|
}
|
|
|
|
if (is_null($this->install_version) || empty($this->install_version))
|
|
$this->install_version = _PS_VERSION_;
|
|
|
|
// If you have defined this somewhere, you know what you do
|
|
/* load options from configuration if we're not in ajax mode */
|
|
if (!$this->ajax)
|
|
{
|
|
$this->createCustomToken();
|
|
|
|
$postData = 'version='._PS_VERSION_.'&method=listing&action=native&iso_code=all';
|
|
$xml_local = $this->prodRootDir.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'modules_native_addons.xml';
|
|
$xml = $upgrader->getApiAddons($xml_local, $postData, true);
|
|
|
|
if (is_object($xml))
|
|
foreach ($xml as $mod)
|
|
$this->modules_addons[(string)$mod->id] = (string)$mod->name;
|
|
|
|
// installedLanguagesIso is used to merge translations files
|
|
$iso_ids = Language::getIsoIds(false);
|
|
foreach($iso_ids as $v)
|
|
$this->installedLanguagesIso[] = $v['iso_code'];
|
|
|
|
$rand = dechex ( mt_rand(0, min(0xffffffff, mt_getrandmax() ) ) );
|
|
$date = date('Ymd-His');
|
|
$this->backupName = 'V'._PS_VERSION_.'_'.$date.'-'.$rand;
|
|
$this->backupFilesFilename = 'auto-backupfiles_'.$this->backupName.'.zip';
|
|
$this->backupDbFilename = 'auto-backupdb_XXXXXX_'.$this->backupName.'.sql';
|
|
// removing temporary files
|
|
$this->cleanTmpFiles();
|
|
}
|
|
else
|
|
{
|
|
foreach($this->ajaxParams as $prop)
|
|
if(property_exists($this, $prop))
|
|
$this->{$prop} = isset($this->currentParams[$prop])?$this->currentParams[$prop]:'';
|
|
}
|
|
|
|
$this->keepImages = $this->getConfig('PS_AUTOUP_KEEP_IMAGES');
|
|
$this->updateDefaultTheme = $this->getConfig('PS_AUTOUP_UPDATE_DEFAULT_THEME');
|
|
$this->keepMails = $this->getConfig('PS_AUTOUP_KEEP_MAILS');
|
|
$this->manualMode = (defined('_PS_MODE_DEV_') && _PS_MODE_DEV_)? (bool)$this->getConfig('PS_AUTOUP_MANUAL_MODE') : false;
|
|
$this->deactivateCustomModule = $this->getConfig('PS_AUTOUP_CUSTOM_MOD_DESACT');
|
|
|
|
// during restoration, do not remove :
|
|
$this->restoreIgnoreAbsoluteFiles[] = '/config/settings.inc.php';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '/modules/autoupgrade';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '/admin/autoupgrade';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '.';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '..';
|
|
|
|
// during backup, do not save
|
|
$this->backupIgnoreAbsoluteFiles[] = '/tools/smarty_v2/compile';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/tools/smarty_v2/cache';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/tools/smarty/compile';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/tools/smarty/cache';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/cache/smarty/compile';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/cache/smarty/cache';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/cache/tcpdf';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/cache/cachefs';
|
|
|
|
// do not care about the two autoupgrade dir we use;
|
|
$this->backupIgnoreAbsoluteFiles[] = '/modules/autoupgrade';
|
|
$this->backupIgnoreAbsoluteFiles[] = '/admin/autoupgrade';
|
|
|
|
$this->backupIgnoreFiles[] = '.';
|
|
$this->backupIgnoreFiles[] = '..';
|
|
$this->backupIgnoreFiles[] = '.svn';
|
|
$this->backupIgnoreFiles[] = '.git';
|
|
$this->backupIgnoreFiles[] = $this->autoupgradeDir;
|
|
|
|
$this->excludeFilesFromUpgrade[] = '.';
|
|
$this->excludeFilesFromUpgrade[] = '..';
|
|
$this->excludeFilesFromUpgrade[] = '.svn';
|
|
$this->excludeFilesFromUpgrade[] = '.git';
|
|
// do not copy install, neither settings.inc.php in case it would be present
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/config/settings.inc.php';
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/install';
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/install-dev';
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/config/modules_list.xml';
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/config/xml/modules_list.xml';
|
|
// this will exclude autoupgrade dir from admin, and autoupgrade from modules
|
|
$this->excludeFilesFromUpgrade[] = $this->autoupgradeDir;
|
|
|
|
if ($this->keepImages === '0')
|
|
{
|
|
$this->backupIgnoreAbsoluteFiles[] = '/img';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '/img';
|
|
}
|
|
else
|
|
{
|
|
$this->backupIgnoreAbsoluteFiles[] = '/img/tmp';
|
|
$this->restoreIgnoreAbsoluteFiles[] = '/img/tmp';
|
|
}
|
|
|
|
if (!$this->updateDefaultTheme) /* If set to false, we need to preserve the default themes */
|
|
{
|
|
if (version_compare(_PS_VERSION_, '1.6.0.0', '>'))
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/themes/default-bootstrap';
|
|
elseif (version_compare(_PS_VERSION_, '1.5.0.0', '>'))
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/themes/default';
|
|
else
|
|
$this->excludeAbsoluteFilesFromUpgrade[] = '/themes/prestashop';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* create some required directories if they does not exists
|
|
*
|
|
* Also set nextParams (removeList and filesToUpgrade) if they
|
|
* exists in currentParams
|
|
*
|
|
*/
|
|
public function initPath()
|
|
{
|
|
// If not exists in this sessions, "create"
|
|
// session handling : from current to next params
|
|
if (isset($this->currentParams['removeList']))
|
|
$this->nextParams['removeList'] = $this->currentParams['removeList'];
|
|
|
|
if (isset($this->currentParams['filesToUpgrade']))
|
|
$this->nextParams['filesToUpgrade'] = $this->currentParams['filesToUpgrade'];
|
|
|
|
if (isset($this->currentParams['modulesToUpgrade']))
|
|
$this->nextParams['modulesToUpgrade'] = $this->currentParams['modulesToUpgrade'];
|
|
|
|
// set autoupgradePath, to be used in backupFiles and backupDb config values
|
|
$this->autoupgradePath = $this->adminDir.DIRECTORY_SEPARATOR.$this->autoupgradeDir;
|
|
// directory missing
|
|
if (!file_exists($this->autoupgradePath))
|
|
if (!mkdir($this->autoupgradePath))
|
|
$this->_errors[] = sprintf($this->l('unable to create directory %s'), $this->autoupgradePath);
|
|
|
|
if (!is_writable($this->autoupgradePath))
|
|
$this->_errors[] = sprintf($this->l('Unable to write in the directory "%s"'), $this->autoupgradePath);
|
|
|
|
$this->downloadPath = $this->autoupgradePath.DIRECTORY_SEPARATOR.'download';
|
|
if (!file_exists($this->downloadPath))
|
|
if (!mkdir($this->downloadPath))
|
|
$this->_errors[] = sprintf($this->l('unable to create directory %s'),$this->downloadPath);
|
|
|
|
$this->backupPath = $this->autoupgradePath.DIRECTORY_SEPARATOR.'backup';
|
|
$tmp = "order deny,allow\ndeny from all";
|
|
if (!file_exists($this->backupPath))
|
|
if (!mkdir($this->backupPath))
|
|
$this->_errors[] = sprintf($this->l('unable to create directory %s'),$this->backupPath);
|
|
if (!file_exists($this->backupPath.DIRECTORY_SEPARATOR.'index.php'))
|
|
if (!copy(_PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'index.php', $this->backupPath.DIRECTORY_SEPARATOR.'index.php'))
|
|
$this->_errors[] = sprintf($this->l('unable to create file %s'), $this->backupPath.DIRECTORY_SEPARATOR.'index.php');
|
|
if (!file_exists($this->backupPath.DIRECTORY_SEPARATOR.'.htaccess'))
|
|
if (!file_put_contents($this->backupPath.DIRECTORY_SEPARATOR.'.htaccess', $tmp))
|
|
$this->_errors[] = sprintf($this->l('unable to create file %s'), $this->backupPath.DIRECTORY_SEPARATOR.'.htaccess');
|
|
|
|
// directory missing
|
|
$this->latestPath = $this->autoupgradePath.DIRECTORY_SEPARATOR.'latest';
|
|
if (!file_exists($this->latestPath))
|
|
if (!mkdir($this->latestPath))
|
|
$this->_errors[] = sprintf($this->l('unable to create directory %s'),$this->latestPath);
|
|
|
|
$this->tmpPath = $this->autoupgradePath.DIRECTORY_SEPARATOR.'tmp';
|
|
if (!file_exists($this->tmpPath))
|
|
if (!mkdir($this->tmpPath))
|
|
$this->_errors[] = sprintf($this->l('unable to create directory %s'),$this->tmpPath);
|
|
|
|
$this->latestRootDir = $this->latestPath.DIRECTORY_SEPARATOR.'prestashop';
|
|
}
|
|
|
|
/**
|
|
* getFilePath return the path to the zipfile containing prestashop.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function getFilePath()
|
|
{
|
|
return $this->downloadPath.DIRECTORY_SEPARATOR.$this->destDownloadFilename;
|
|
}
|
|
|
|
public function postProcess()
|
|
{
|
|
$this->_setFields();
|
|
|
|
// set default configuration to default channel & dafault configuration for backup and upgrade
|
|
// (can be modified in expert mode)
|
|
$config = $this->getConfig('channel');
|
|
if ($config === false)
|
|
{
|
|
$config = array();
|
|
$config['channel'] = Upgrader::DEFAULT_CHANNEL;
|
|
$this->writeConfig($config);
|
|
if (class_exists('Configuration', false))
|
|
Configuration::updateValue('PS_UPGRADE_CHANNEL', $config['channel']);
|
|
|
|
$this->writeConfig(array (
|
|
'PS_AUTOUP_PERFORMANCE' => '1',
|
|
'PS_AUTOUP_CUSTOM_MOD_DESACT' => '1',
|
|
'PS_AUTOUP_UPDATE_DEFAULT_THEME' => '1',
|
|
'PS_AUTOUP_KEEP_MAILS' => '1',
|
|
'PS_AUTOUP_BACKUP' => '1',
|
|
'PS_AUTOUP_KEEP_IMAGES' => '0'
|
|
));
|
|
}
|
|
|
|
if (Tools14::isSubmit('putUnderMaintenance'))
|
|
Configuration::updateValue('PS_SHOP_ENABLE', 0);
|
|
|
|
if (Tools14::isSubmit('customSubmitAutoUpgrade'))
|
|
{
|
|
$config_keys = array_keys(array_merge($this->_fieldsUpgradeOptions, $this->_fieldsBackupOptions));
|
|
$config = array();
|
|
foreach ($config_keys as $key)
|
|
if (isset($_POST[$key]))
|
|
$config[$key] = $_POST[$key];
|
|
$res = $this->writeConfig($config);
|
|
if ($res)
|
|
Tools14::redirectAdmin($this->currentIndex.'&conf=6&token='.Tools14::getValue('token'));
|
|
}
|
|
|
|
if (Tools14::isSubmit('deletebackup'))
|
|
{
|
|
$res = false;
|
|
$name = Tools14::getValue('name');
|
|
$filelist = scandir($this->backupPath);
|
|
foreach($filelist as $filename)
|
|
// the following will match file or dir related to the selected backup
|
|
if (!empty($filename) && $filename[0] != '.' && $filename != 'index.php' && $filename != '.htaccess'
|
|
&& preg_match('#^(auto-backupfiles_|)'.preg_quote($name).'(\.zip|)$#', $filename, $matches))
|
|
{
|
|
if (is_file($this->backupPath.DIRECTORY_SEPARATOR.$filename))
|
|
$res &= unlink($this->backupPath.DIRECTORY_SEPARATOR.$filename);
|
|
elseif (!empty($name) && is_dir($this->backupPath.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR))
|
|
$res = self::deleteDirectory($this->backupPath.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR);
|
|
}
|
|
if ($res)
|
|
Tools14::redirectAdmin($this->currentIndex.'&conf=1&token='.Tools14::getValue('token'));
|
|
else
|
|
$this->_errors[] = sprintf($this->l('Error when trying to delete backups %s'), $name);
|
|
}
|
|
parent::postProcess();
|
|
}
|
|
|
|
/**
|
|
* ends the rollback process
|
|
*
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessRollbackComplete()
|
|
{
|
|
$this->next_desc = $this->l('Restoration process done. Congratulations! You can now reactivate your shop.');
|
|
$this->next = '';
|
|
}
|
|
|
|
/**
|
|
* ends the upgrade process
|
|
*
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessUpgradeComplete()
|
|
{
|
|
if (!$this->warning_exists)
|
|
$this->next_desc = $this->l('Upgrade process done. Congratulations! You can now reactivate your shop.');
|
|
else
|
|
$this->next_desc = $this->l('Upgrade process done, but some warnings have been found.');
|
|
$this->next = '';
|
|
|
|
if ($this->getConfig('channel') != 'archive' && file_exists($this->getFilePath()) && unlink($this->getFilePath()))
|
|
$this->nextQuickInfo[] = sprintf('%s removed', $this->getFilePath());
|
|
elseif (is_file($this->getFilePath()))
|
|
$this->nextQuickInfo[] = '<strong>'.sprintf('Please remove %s by ftp', $this->getFilePath()).'</strong>';
|
|
|
|
if ($this->getConfig('channel') != 'directory' && file_exists($this->latestRootDir) && self::deleteDirectory($this->latestRootDir))
|
|
$this->nextQuickInfo[] = sprintf('%s removed', $this->latestRootDir);
|
|
elseif(is_dir($this->latestRootDir))
|
|
$this->nextQuickInfo[] = '<strong>'.sprintf('Please remove %s by ftp', $this->latestRootDir).'</strong>';
|
|
}
|
|
|
|
// Simplification of _displayForm original function
|
|
protected function _displayForm($name, $fields, $tabname, $size, $icon)
|
|
{
|
|
$confValues = $this->getConfig();
|
|
$required = false;
|
|
|
|
$this->_html .= '
|
|
<fieldset id="'.$name.'Block"><legend><img src="../img/admin/'.strval($icon).'.gif" />'.$tabname.'</legend>';
|
|
foreach ($fields as $key => $field)
|
|
{
|
|
if (isset($field['required']) && $field['required'])
|
|
$required = true;
|
|
|
|
if (isset($field['disabled']) && $field['disabled'])
|
|
$disabled = true;
|
|
else
|
|
$disabled = false;
|
|
|
|
|
|
if (isset($confValues[$key]))
|
|
$val = $confValues[$key];
|
|
else
|
|
$val = isset($field['defaultValue'])?$field['defaultValue']:false;
|
|
|
|
if (!in_array($field['type'], array('image', 'radio', 'container', 'container_end')) || isset($field['show']))
|
|
$this->_html .= '<div style="clear: both; padding-top:15px;">'.($field['title'] ? '<label >'.$field['title'].'</label>' : '').'<div class="margin-form" style="padding-top:5px;">';
|
|
|
|
/* Display the appropriate input type for each field */
|
|
switch ($field['type'])
|
|
{
|
|
case 'disabled':
|
|
$this->_html .= $field['disabled'];
|
|
break;
|
|
|
|
|
|
case 'bool':
|
|
$this->_html .= '<label class="t" for="'.$key.'_on">
|
|
<img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /></label>
|
|
<input type="radio" '.($disabled?'disabled="disabled"':'').' name="'.$key.'" id="'.$key.'_on" value="1"'.($val ? ' checked="checked"' : '').(isset($field['js']['on']) ? $field['js']['on'] : '').' />
|
|
<label class="t" for="'.$key.'_on"> '.$this->l('Yes').'</label>
|
|
<label class="t" for="'.$key.'_off"><img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /></label>
|
|
<input type="radio" '.($disabled?'disabled="disabled"':'').' name="'.$key.'" id="'.$key.'_off" value="0" '.(!$val ? 'checked="checked"' : '').(isset($field['js']['off']) ? $field['js']['off'] : '').'/>
|
|
<label class="t" for="'.$key.'_off"> '.$this->l('No').'</label>';
|
|
break;
|
|
|
|
case 'radio':
|
|
foreach ($field['choices'] as $cValue => $cKey)
|
|
$this->_html .= '<input '.($disabled?'disabled="disabled"':'').' type="radio" name="'.$key.'" id="'.$key.$cValue.'_on" value="'.(int)($cValue).'"'.(($cValue == $val) ? ' checked="checked"' : '').(isset($field['js'][$cValue]) ? ' '.$field['js'][$cValue] : '').' /><label class="t" for="'.$key.$cValue.'_on"> '.$cKey.'</label><br />';
|
|
$this->_html .= '<br />';
|
|
break;
|
|
|
|
case 'select':
|
|
$this->_html .= '<select name='.$key.'>';
|
|
foreach ($field['choices'] as $cValue => $cKey)
|
|
$this->_html .= '<option value="'.(int)$cValue.'"'.(($cValue == $val) ? ' selected="selected"' : '').'>'.$cKey.'</option>';
|
|
$this->_html .= '</select>';
|
|
break;
|
|
|
|
case 'textarea':
|
|
$this->_html .= '<textarea '.($disabled?'disabled="disabled"':'').' name='.$key.' cols="'.$field['cols'].'" rows="'.$field['rows'].'">'.htmlentities($val, ENT_COMPAT, 'UTF-8').'</textarea>';
|
|
break;
|
|
|
|
case 'container':
|
|
$this->_html .= '<div id="'.$key.'">';
|
|
break;
|
|
|
|
case 'container_end':
|
|
$this->_html .= (isset($field['content']) === true ? $field['content'] : '').'</div>';
|
|
break;
|
|
|
|
case 'text':
|
|
default:
|
|
$this->_html .= '<input '.($disabled?'disabled="disabled"':'').' type="'.$field['type'].'"'.(isset($field['id']) === true ? ' id="'.$field['id'].'"' : '').' size="'.(isset($field['size']) ? (int)($field['size']) : 5).'" name="'.$key.'" value="'.($field['type'] == 'password' ? '' : htmlentities($val, ENT_COMPAT, 'UTF-8')).'" />'.(isset($field['next']) ? ' '.strval($field['next']) : '');
|
|
}
|
|
$this->_html .= ((isset($field['required']) && $field['required'] && !in_array($field['type'], array('image', 'radio'))) ? ' <sup>*</sup>' : '');
|
|
$this->_html .= (isset($field['desc']) ? '<p style="clear:both">'.((isset($field['thumb']) && $field['thumb'] && $field['thumb']['pos'] == 'after') ? '<img src="'.$field['thumb']['file'].'" alt="'.$field['title'].'" title="'.$field['title'].'" style="float:left;" />' : '' ).$field['desc'].'</p>' : '');
|
|
if (!in_array($field['type'], array('image', 'radio', 'container', 'container_end')) || isset($field['show']))
|
|
$this->_html .= '</div></div>';
|
|
}
|
|
|
|
$this->_html .= ' <div align="center" style="margin-top: 20px;">
|
|
<input type="submit" value="'.$this->l(' Save ', 'AdminPreferences').'" name="customSubmitAutoUpgrade" class="button" />
|
|
</div>
|
|
'.($required ? '<div class="small"><sup>*</sup> '.$this->l('Required field', 'AdminPreferences').'</div>' : '').'
|
|
</fieldset>
|
|
<br/>';
|
|
}
|
|
|
|
/**
|
|
* return the value of $key, configuration saved in $this->configFilename.
|
|
* if $key is empty, will return an array with all configuration;
|
|
*
|
|
* @param string $key
|
|
* @access public
|
|
* @return array or string
|
|
*/
|
|
public function getConfig($key = '')
|
|
{
|
|
static $config = array();
|
|
if (count($config) == 0)
|
|
{
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename))
|
|
{
|
|
$config_content = Tools14::file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename);
|
|
$config = @unserialize(base64_decode($config_content));
|
|
}
|
|
else
|
|
$config = array();
|
|
}
|
|
if (empty($key))
|
|
return $config;
|
|
elseif (isset($config[$key]))
|
|
return trim($config[$key]);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* reset module configuration with $new_config values (previous config will be totally lost)
|
|
*
|
|
* @param array $new_config
|
|
* @return boolean true if success
|
|
*/
|
|
public function resetConfig($new_config)
|
|
{
|
|
return (bool)file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename, base64_encode(serialize($new_config)));
|
|
}
|
|
|
|
/**
|
|
* update module configuration (saved in file $this->configFilename) with $new_config
|
|
*
|
|
* @param array $new_config
|
|
* @return boolean true if success
|
|
*/
|
|
public function writeConfig($new_config)
|
|
{
|
|
if (!file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename))
|
|
return $this->resetConfig($new_config);
|
|
|
|
$config = file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename);
|
|
$config_unserialized = @unserialize(base64_decode($config));
|
|
if (!is_array($config_unserialized))
|
|
$config_unserialized = @unserialize($config); // retrocompat, before base64_decode implemented
|
|
$config = $config_unserialized;
|
|
|
|
foreach($new_config as $key => $val)
|
|
$config[$key] = $val;
|
|
$this->next_desc = $this->l('Configuration successfully updated.').' <strong>'.$this->l('This page will now be reloaded and the module will check if a new version is available.').'</strong>';
|
|
return (bool)file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->configFilename, base64_encode(serialize($config)));
|
|
}
|
|
|
|
/**
|
|
* update configuration after validating the new values
|
|
*
|
|
* @access public
|
|
*/
|
|
public function ajaxProcessUpdateConfig()
|
|
{
|
|
$config = array();
|
|
// nothing next
|
|
$this->next = '';
|
|
// update channel
|
|
if (isset($this->currentParams['channel']))
|
|
$config['channel'] = $this->currentParams['channel'];
|
|
if (isset($this->currentParams['private_release_link']) && isset($this->currentParams['private_release_md5']))
|
|
{
|
|
$config['channel'] = 'private';
|
|
$config['private_release_link'] = $this->currentParams['private_release_link'];
|
|
$config['private_release_md5'] = $this->currentParams['private_release_md5'];
|
|
$config['private_allow_major'] = $this->currentParams['private_allow_major'];
|
|
}
|
|
// if (!empty($this->currentParams['archive_name']) && !empty($this->currentParams['archive_num']))
|
|
if (!empty($this->currentParams['archive_prestashop']))
|
|
{
|
|
$file = $this->currentParams['archive_prestashop'];
|
|
if (!file_exists($this->downloadPath.DIRECTORY_SEPARATOR.$file))
|
|
{
|
|
$this->error = 1;
|
|
$this->next_desc = sprintf($this->l('File %s does not exist. Unable to select that channel.'), $file);
|
|
return false;
|
|
}
|
|
if (empty($this->currentParams['archive_num']))
|
|
{
|
|
$this->error = 1;
|
|
$this->next_desc = sprintf($this->l('Version number is missing. Unable to select that channel.'), $file);
|
|
return false;
|
|
}
|
|
$config['channel'] = 'archive';
|
|
$config['archive.filename'] = $this->currentParams['archive_prestashop'];
|
|
$config['archive.version_num'] = $this->currentParams['archive_num'];
|
|
// $config['archive_name'] = $this->currentParams['archive_name'];
|
|
$this->next_desc = $this->l('Upgrade process will use archive.');
|
|
}
|
|
if (isset($this->currentParams['directory_num']))
|
|
{
|
|
$config['channel'] = 'directory';
|
|
if (empty($this->currentParams['directory_num']) || strpos($this->currentParams['directory_num'], '.') === false)
|
|
{
|
|
$this->error = 1;
|
|
$this->next_desc = sprintf($this->l('Version number is missing. Unable to select that channel.'));
|
|
return false;
|
|
}
|
|
|
|
$config['directory.version_num'] = $this->currentParams['directory_num'];
|
|
}
|
|
if (isset($this->currentParams['skip_backup']))
|
|
$config['skip_backup'] = $this->currentParams['skip_backup'];
|
|
|
|
if (!$this->writeConfig($config))
|
|
{
|
|
$this->error = 1;
|
|
$this->next_desc = $this->l('Error on saving configuration');
|
|
}
|
|
|
|
}
|
|
/** returns an array containing information related to the channel $channel
|
|
*
|
|
* @param string $channel name of the channel
|
|
* @return <array> available, version_num, version_name, link, md5, changelog
|
|
*/
|
|
public function getInfoForChannel($channel)
|
|
{
|
|
$upgrade_info = array();
|
|
$public_channel = array('minor', 'major', 'rc', 'beta', 'alpha');
|
|
$upgrader = new Upgrader();
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
$upgrader->branch = $matches[1];
|
|
$upgrader->channel = $channel;
|
|
if (in_array($channel, $public_channel))
|
|
{
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$upgrader->checkPSVersion(false, array('minor'));
|
|
|
|
$upgrade_info = array();
|
|
$upgrade_info['branch'] = $upgrader->branch;
|
|
$upgrade_info['available'] = $upgrader->available;
|
|
$upgrade_info['version_num'] = $upgrader->version_num;
|
|
$upgrade_info['version_name'] = $upgrader->version_name;
|
|
$upgrade_info['link'] = $upgrader->link;
|
|
$upgrade_info['md5'] = $upgrader->md5;
|
|
$upgrade_info['changelog'] = $upgrader->changelog;
|
|
}
|
|
else
|
|
{
|
|
switch ($channel)
|
|
{
|
|
case 'private':
|
|
if (!$this->getConfig('private_allow_major'))
|
|
$upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$upgrader->checkPSVersion(false, array('minor'));
|
|
|
|
$upgrade_info['available'] = $upgrader->available;
|
|
$upgrade_info['branch'] = $upgrader->branch;
|
|
$upgrade_info['version_num'] = $upgrader->version_num;
|
|
$upgrade_info['version_name'] = $upgrader->version_name;
|
|
$upgrade_info['link'] = $this->getConfig('private_release_link');
|
|
$upgrade_info['md5'] = $this->getConfig('private_release_md5');
|
|
$upgrade_info['changelog'] = $upgrader->changelog;
|
|
break;
|
|
case 'archive':
|
|
$upgrade_info['available'] = true;
|
|
break;
|
|
case 'directory':
|
|
$upgrade_info['available'] = true;
|
|
break;
|
|
}
|
|
}
|
|
return $upgrade_info;
|
|
}
|
|
|
|
/**
|
|
* display informations related to the selected channel : link/changelog for remote channel,
|
|
* or configuration values for special channels
|
|
*
|
|
* @access public
|
|
*/
|
|
public function ajaxProcessGetChannelInfo()
|
|
{
|
|
// do nothing after this request (see javascript function doAjaxRequest )
|
|
$this->next = '';
|
|
|
|
$channel = $this->currentParams['channel'];
|
|
$upgrade_info = $this->getInfoForChannel($channel);
|
|
$this->nextParams['result']['available'] = $upgrade_info['available'];
|
|
|
|
$this->nextParams['result']['div'] = $this->divChannelInfos($upgrade_info);
|
|
|
|
}
|
|
|
|
/**
|
|
* get the list of all modified and deleted files between current version
|
|
* and target version (according to channel configuration)
|
|
*
|
|
* @access public
|
|
*/
|
|
public function ajaxProcessCompareReleases()
|
|
{
|
|
// do nothing after this request (see javascript function doAjaxRequest )
|
|
$this->next = '';
|
|
$channel = $this->getConfig('channel');
|
|
$this->upgrader = new Upgrader();
|
|
switch ($channel)
|
|
{
|
|
case 'archive':
|
|
$version = $this->getConfig('archive.version_num');
|
|
break;
|
|
case 'directory':
|
|
$version = $this->getConfig('directory.version_num');
|
|
break;
|
|
default:
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
$this->upgrader->branch = $matches[1];
|
|
$this->upgrader->channel = $channel;
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$this->upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$this->upgrader->checkPSVersion(false, array('minor'));
|
|
$version = $this->upgrader->version_num;
|
|
}
|
|
|
|
$diffFileList = $this->upgrader->getDiffFilesList(_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
|
|
{
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->diffFileList, base64_encode(serialize($diffFileList)));
|
|
if (count($diffFileList) > 0)
|
|
$this->nextParams['msg'] = sprintf($this->l('%1$s files will be modified, %2$s files will be deleted (if they are found).'),
|
|
count($diffFileList['modified']), count($diffFileList['deleted']));
|
|
else
|
|
$this->nextParams['msg'] = $this->l('No diff files found.');
|
|
$this->nextParams['result'] = $diffFileList;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* list the files modified in the current installation regards to the original version
|
|
*
|
|
* @access public
|
|
*/
|
|
public function ajaxProcessCheckFilesVersion()
|
|
{
|
|
// do nothing after this request (see javascript function doAjaxRequest )
|
|
$this->next = '';
|
|
$this->upgrader = new Upgrader();
|
|
|
|
$changedFileList = $this->upgrader->getChangedFilesList();
|
|
if ($this->upgrader->isAuthenticPrestashopVersion() === true
|
|
&& !is_array($changedFileList) )
|
|
{
|
|
$this->nextParams['status'] = 'error';
|
|
$this->nextParams['msg'] = $this->l('Unable to check files for the installed version of PrestaShop.');
|
|
$testOrigCore = false;
|
|
}
|
|
else
|
|
{
|
|
if ($this->upgrader->isAuthenticPrestashopVersion() === true)
|
|
{
|
|
$this->nextParams['status'] = 'ok';
|
|
$testOrigCore = true;
|
|
}
|
|
else
|
|
{
|
|
$testOrigCore = false;
|
|
$this->nextParams['status'] = 'warn';
|
|
}
|
|
|
|
if (!isset($changedFileList['core']))
|
|
$changedFileList['core'] = array();
|
|
|
|
if (!isset($changedFileList['translation']))
|
|
$changedFileList['translation'] = array();
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->tradCustomList, base64_encode(serialize($changedFileList['translation'])));
|
|
|
|
if (!isset($changedFileList['mail']))
|
|
$changedFileList['mail'] = array();
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->mailCustomList, base64_encode(serialize($changedFileList['mail'])));
|
|
|
|
|
|
if ($changedFileList === false)
|
|
{
|
|
$changedFileList = array();
|
|
$this->nextParams['msg'] = $this->l('Unable to check files');
|
|
$this->nextParams['status'] = 'error';
|
|
}
|
|
else
|
|
{
|
|
$this->nextParams['msg'] = ($testOrigCore ? $this->l('Core files are ok') : sprintf($this->l('%1$s file modifications have been detected, including %2$s from core and native modules:'), count(array_merge($changedFileList['core'], $changedFileList['mail'], $changedFileList['translation'])), count($changedFileList['core'])));
|
|
}
|
|
$this->nextParams['result'] = $changedFileList;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* very first step of the upgrade process. The only thing done is the selection
|
|
* of the next step
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessUpgradeNow()
|
|
{
|
|
$this->next_desc = $this->l('Starting upgrade...');
|
|
|
|
$channel = $this->getConfig('channel');
|
|
$this->next = 'download';
|
|
if (!is_object($this->upgrader))
|
|
$this->upgrader = new Upgrader();
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
$this->upgrader->branch = $matches[1];
|
|
$this->upgrader->channel = $channel;
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$this->upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$this->upgrader->checkPSVersion(false, array('minor'));
|
|
|
|
switch ($channel)
|
|
{
|
|
case 'directory' :
|
|
// if channel directory is chosen, we assume it's "ready for use" (samples already removed for example)
|
|
$this->next = 'removeSamples';
|
|
$this->nextQuickInfo[] = $this->l('Skip downloading and unziping steps, upgrade process will now remove sample data.');
|
|
$this->next_desc = $this->l('Shop deactivated. Removing sample files...');
|
|
break;
|
|
case 'archive' :
|
|
$this->next = 'unzip';
|
|
$this->nextQuickInfo[] = $this->l('Skip downloading step, upgrade process will now unzip the local archive.');
|
|
$this->next_desc = $this->l('Shop deactivated. Extracting files...');
|
|
break;
|
|
default :
|
|
$this->next = 'download';
|
|
$this->next_desc = $this->l('Shop deactivated. Now downloading... (this can take a while)');
|
|
if ($this->upgrader->channel == 'private')
|
|
{
|
|
$this->upgrader->link = $this->getConfig('private_release_link');
|
|
$this->upgrader->md5 = $this->getConfig('private_release_md5');
|
|
}
|
|
$this->nextQuickInfo[] = sprintf($this->l('Downloaded archive will come from %s'), $this->upgrader->link);
|
|
$this->nextQuickInfo[] = sprintf($this->l('MD5 hash will be checked against %s'), $this->upgrader->md5);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* extract chosen version into $this->latestPath directory
|
|
*
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessUnzip()
|
|
{
|
|
$filepath = $this->getFilePath();
|
|
$destExtract = $this->latestPath;
|
|
|
|
if (file_exists($destExtract))
|
|
{
|
|
self::deleteDirectory($destExtract, false);
|
|
$this->nextQuickInfo[] = $this->l('"/latest" directory has been emptied');
|
|
}
|
|
$relative_extract_path = str_replace(_PS_ROOT_DIR_, '', $destExtract);
|
|
$report = '';
|
|
if (ConfigurationTest::test_dir($relative_extract_path, false, $report))
|
|
{
|
|
|
|
if ($this->ZipExtract($filepath, $destExtract))
|
|
{
|
|
// Unsetting to force listing
|
|
unset($this->nextParams['removeList']);
|
|
$this->next = 'removeSamples';
|
|
$this->next_desc = $this->l('File extraction complete. Removing sample files...');
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = sprintf($this->l('Unable to extract %1$s file into %2$s folder...'), $filepath, $destExtract);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->next_desc = $this->l('Extraction directory is not writable.');
|
|
$this->nextQuickInfo[] = $this->l('Extraction directory is not writable.');
|
|
$this->nextErrors[] = sprintf($this->l('Extraction directory %s is not writable.'), $destExtract);
|
|
$this->next = 'error';
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* _listSampleFiles will make a recursive call to scandir() function
|
|
* and list all file which match to the $fileext suffixe (this can be an extension or whole filename)
|
|
*
|
|
* @param string $dir directory to look in
|
|
* @param string $fileext suffixe filename
|
|
* @return void
|
|
*/
|
|
private function _listSampleFiles($dir, $fileext = '.jpg'){
|
|
$res = false;
|
|
$dir = rtrim($dir,'/').DIRECTORY_SEPARATOR;
|
|
$toDel = false;
|
|
if (is_dir($dir) && is_readable($dir))
|
|
$toDel = scandir($dir);
|
|
// copied (and kind of) adapted from AdminImages.php
|
|
if (is_array($toDel))
|
|
foreach ($toDel AS $file)
|
|
{
|
|
if ($file[0] != '.')
|
|
{
|
|
if (preg_match('#'.preg_quote($fileext,'#').'$#i',$file))
|
|
{
|
|
$this->sampleFileList[] = $dir.$file;
|
|
}
|
|
else if (is_dir($dir.$file))
|
|
{
|
|
$res &= $this->_listSampleFiles($dir.$file, $fileext);
|
|
}
|
|
}
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
public function _listFilesInDir($dir, $way = 'backup', $list_directories = false)
|
|
{
|
|
$list = array();
|
|
$dir = rtrim($dir,'/').DIRECTORY_SEPARATOR;
|
|
$allFiles = false;
|
|
if (is_dir($dir) && is_readable($dir))
|
|
$allFiles = scandir($dir);
|
|
if (is_array($allFiles))
|
|
foreach ($allFiles as $file)
|
|
if ($file[0] != '.')
|
|
{
|
|
$fullPath = $dir.$file;
|
|
if (!$this->_skipFile($file, $fullPath, $way))
|
|
{
|
|
if (is_dir($fullPath))
|
|
{
|
|
$list = array_merge($list, $this->_listFilesInDir($fullPath, $way, $list_directories));
|
|
if ($list_directories)
|
|
$list[] = $fullPath;
|
|
}
|
|
else
|
|
$list[] = $fullPath;
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
|
|
/**
|
|
* this function list all files that will be remove to retrieve the filesystem states before the upgrade
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function _listFilesToRemove()
|
|
{
|
|
$prev_version = preg_match('#auto-backupfiles_V([0-9.]*)_#', $this->restoreFilesFilename, $matches);
|
|
if ($prev_version)
|
|
$prev_version = $matches[1];
|
|
|
|
if (!$this->upgrader)
|
|
$this->upgrader = new Upgrader();
|
|
|
|
$toRemove = false;
|
|
// note : getDiffFilesList does not include files moved by upgrade scripts,
|
|
// so this method can't be trusted to fully restore directory
|
|
// $toRemove = $this->upgrader->getDiffFilesList(_PS_VERSION_, $prev_version, false);
|
|
// if we can't find the diff file list corresponding to _PS_VERSION_ and prev_version,
|
|
// let's assume to remove every files
|
|
if (!$toRemove)
|
|
$toRemove = $this->_listFilesInDir($this->prodRootDir, 'restore', true);
|
|
|
|
$admin_dir = str_replace($this->prodRootDir, '', $this->adminDir);
|
|
// if a file in "ToRemove" has been skipped during backup,
|
|
// just keep it
|
|
foreach ($toRemove as $key => $file)
|
|
{
|
|
$filename = substr($file, strrpos($file, '/')+1);
|
|
$toRemove[$key] = preg_replace('#^/admin#', $admin_dir, $file);
|
|
// this is a really sensitive part, so we add an extra checks: preserve everything that contains "autoupgrade"
|
|
if ($this->_skipFile($filename, $file, 'backup') || strpos($file, $this->autoupgradeDir))
|
|
unset($toRemove[$key]);
|
|
}
|
|
return $toRemove;
|
|
}
|
|
|
|
/**
|
|
* list files to upgrade and return it as array
|
|
*
|
|
* @param string $dir
|
|
* @return number of files found
|
|
*/
|
|
public function _listFilesToUpgrade($dir)
|
|
{
|
|
static $list = array();
|
|
if (!is_dir($dir))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] %s does not exist or is not a directory.'), $dir);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] %s does not exist or is not a directory.'), $dir);
|
|
$this->next_desc = $this->l('Nothing has been extracted. It seems the unzipping step has been skipped.');
|
|
$this->next = 'error';
|
|
return false;
|
|
}
|
|
|
|
$allFiles = scandir($dir);
|
|
foreach ($allFiles as $file)
|
|
{
|
|
$fullPath = $dir.DIRECTORY_SEPARATOR.$file;
|
|
|
|
if (!$this->_skipFile($file, $fullPath, "upgrade"))
|
|
{
|
|
$list[] = str_replace($this->latestRootDir, '', $fullPath);
|
|
// if is_dir, we will create it :)
|
|
if (is_dir($fullPath))
|
|
if (strpos($dir.DIRECTORY_SEPARATOR.$file, 'install') === false)
|
|
$this->_listFilesToUpgrade($fullPath);
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
|
|
public function ajaxProcessUpgradeFiles()
|
|
{
|
|
$this->nextParams = $this->currentParams;
|
|
|
|
$admin_dir = str_replace($this->prodRootDir.DIRECTORY_SEPARATOR, '', $this->adminDir);
|
|
if (file_exists($this->latestRootDir.DIRECTORY_SEPARATOR.'admin'))
|
|
rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin', $this->latestRootDir.DIRECTORY_SEPARATOR.$admin_dir);
|
|
elseif (file_exists($this->latestRootDir.DIRECTORY_SEPARATOR.'admin-dev'))
|
|
rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.$admin_dir);
|
|
if (file_exists($this->latestRootDir.DIRECTORY_SEPARATOR.'install-dev'))
|
|
rename($this->latestRootDir.DIRECTORY_SEPARATOR.'install-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.'install');
|
|
|
|
if (!isset($this->nextParams['filesToUpgrade']))
|
|
{
|
|
// list saved in $this->toUpgradeFileList
|
|
// get files differences (previously generated)
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
$filepath_list_diff = $this->autoupgradePath.DIRECTORY_SEPARATOR.$this->diffFileList;
|
|
if (file_exists($filepath_list_diff))
|
|
{
|
|
$list_files_diff = unserialize(base64_decode(file_get_contents($filepath_list_diff)));
|
|
// only keep list of files to delete. The modified files will be listed with _listFilesToUpgrade
|
|
$list_files_diff = $list_files_diff['deleted'];
|
|
foreach ($list_files_diff as $k => $path)
|
|
if (preg_match("#autoupgrade#", $path))
|
|
unset($list_files_diff[$k]);
|
|
else
|
|
$list_files_diff[$k] = str_replace('/'.'admin', '/'.$admin_dir, $path); // do not replace by DIRECTORY_SEPARATOR
|
|
}
|
|
else
|
|
$list_files_diff = array();
|
|
|
|
if (!($list_files_to_upgrade = $this->_listFilesToUpgrade($this->latestRootDir)))
|
|
return false;
|
|
|
|
// also add files to remove
|
|
$list_files_to_upgrade = array_merge($list_files_diff, $list_files_to_upgrade);
|
|
// save in a serialized array in $this->toUpgradeFileList
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toUpgradeFileList, base64_encode(serialize($list_files_to_upgrade)));
|
|
$this->nextParams['filesToUpgrade'] = $this->toUpgradeFileList;
|
|
$total_files_to_upgrade = count($list_files_to_upgrade);
|
|
|
|
if ($total_files_to_upgrade == 0)
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('[ERROR] Unable to find files to upgrade.');
|
|
$this->nextErrors[] = $this->l('[ERROR] Unable to find files to upgrade.');
|
|
$this->next_desc = $this->l('Unable to list files to upgrade');
|
|
$this->next = 'error';
|
|
return false;
|
|
}
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s files will be upgraded.'), $total_files_to_upgrade);
|
|
|
|
$this->next_desc = sprintf($this->l('%s files will be upgraded.'), $total_files_to_upgrade);
|
|
$this->next = 'upgradeFiles';
|
|
$this->stepDone = false;
|
|
return true;
|
|
}
|
|
|
|
// later we could choose between _PS_ROOT_DIR_ or _PS_TEST_DIR_
|
|
$this->destUpgradePath = $this->prodRootDir;
|
|
|
|
$this->next = 'upgradeFiles';
|
|
$filesToUpgrade = @unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->nextParams['filesToUpgrade'])));
|
|
if (!is_array($filesToUpgrade))
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('filesToUpgrade is not an array');
|
|
$this->nextQuickInfo[] = $this->l('filesToUpgrade is not an array');
|
|
$this->nextErrors[] = $this->l('filesToUpgrade is not an array');
|
|
return false;
|
|
}
|
|
|
|
// @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 < self::$loopUpgradeFiles; $i++)
|
|
{
|
|
if (count($filesToUpgrade) <= 0)
|
|
{
|
|
$this->next = 'upgradeDb';
|
|
if (file_exists(($this->nextParams['filesToUpgrade'])))
|
|
unlink($this->nextParams['filesToUpgrade']);
|
|
$this->next_desc = $this->l('All files upgraded. Now upgrading database...');
|
|
$this->nextResponseType = 'json';
|
|
$this->stepDone = true;
|
|
break;
|
|
}
|
|
|
|
$file = array_shift($filesToUpgrade);
|
|
if (!$this->upgradeThisFile($file))
|
|
{
|
|
// put the file back to the begin of the list
|
|
$totalFiles = array_unshift($filesToUpgrade, $file);
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Error when trying to upgrade file %s.'), $file);
|
|
$this->nextErrors[] = sprintf($this->l('Error when trying to upgrade file %s.'), $file);
|
|
break;
|
|
}
|
|
}
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->nextParams['filesToUpgrade'], base64_encode(serialize($filesToUpgrade)));
|
|
if (count($filesToUpgrade) > 0)
|
|
{
|
|
if (count($filesToUpgrade))
|
|
{
|
|
$this->next_desc = sprintf($this->l('%1$s files left to upgrade.'), count($filesToUpgrade));
|
|
$this->nextQuickInfo[] = sprintf($this->l('%2$s files left to upgrade.'), (isset($file)?$file:''), count($filesToUpgrade));
|
|
$this->stepDone = false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private function createCacheFsDirectories($level_depth, $directory = false)
|
|
{
|
|
if (!$directory)
|
|
{
|
|
if (!defined('_PS_CACHEFS_DIRECTORY_'))
|
|
define('_PS_CACHEFS_DIRECTORY_', $this->prodRootDir.'/cache/cachefs/');
|
|
$directory = _PS_CACHEFS_DIRECTORY_;
|
|
}
|
|
$chars = '0123456789abcdef';
|
|
for ($i = 0; $i < strlen($chars); $i++)
|
|
{
|
|
$new_dir = $directory.$chars[$i].'/';
|
|
if (mkdir($new_dir, 0775) && chmod($new_dir, 0775) && $level_depth - 1 > 0)
|
|
self::createCacheFsDirectories($level_depth - 1, $new_dir);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* list modules to upgrade and save them in a serialized array in $this->toUpgradeModuleList
|
|
*
|
|
* @param string $dir
|
|
* @return number of files found
|
|
*/
|
|
public function _listModulesToUpgrade()
|
|
{
|
|
static $list = array();
|
|
|
|
$dir = $this->prodRootDir.DIRECTORY_SEPARATOR.'modules';
|
|
|
|
if (!is_dir($dir))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] %s does not exist or is not a directory.'), $dir);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] %s does not exist or is not a directory.'), $dir);
|
|
$this->next_desc = $this->l('Nothing has been extracted. It seems the unzip step has been skipped.');
|
|
$this->next = 'error';
|
|
return false;
|
|
}
|
|
|
|
$allModules = scandir($dir);
|
|
foreach ($allModules as $module_name)
|
|
{
|
|
if (is_file($dir.DIRECTORY_SEPARATOR.$module_name))
|
|
continue;
|
|
elseif (is_dir($dir.DIRECTORY_SEPARATOR.$module_name.DIRECTORY_SEPARATOR))
|
|
{
|
|
if(is_array($this->modules_addons))
|
|
$id_addons = array_search($module_name, $this->modules_addons);
|
|
if (isset($id_addons) && $id_addons)
|
|
if ($module_name != $this->autoupgradeDir)
|
|
$list[] = array('id' => $id_addons, 'name' => $module_name);
|
|
}
|
|
}
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toUpgradeModuleList, base64_encode(serialize($list)));
|
|
$this->nextParams['modulesToUpgrade'] = $this->toUpgradeModuleList;
|
|
return count($list);
|
|
}
|
|
|
|
/**
|
|
* upgrade all partners modules according to the installed prestashop version
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessUpgradeModules()
|
|
{
|
|
$start_time = time();
|
|
if (!isset($this->nextParams['modulesToUpgrade']))
|
|
{
|
|
// list saved in $this->toUpgradeFileList
|
|
$total_modules_to_upgrade = $this->_listModulesToUpgrade();
|
|
if ($total_modules_to_upgrade)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s modules will be upgraded.'), $total_modules_to_upgrade);
|
|
$this->next_desc = sprintf($this->l('%s modules will be upgraded.'), $total_modules_to_upgrade);
|
|
}
|
|
$this->stepDone = false;
|
|
$this->next = 'upgradeModules';
|
|
return true;
|
|
}
|
|
|
|
$this->next = 'upgradeModules';
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->nextParams['modulesToUpgrade']))
|
|
$listModules = @unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->nextParams['modulesToUpgrade'])));
|
|
else
|
|
$listModules = array();
|
|
|
|
if (!is_array($listModules))
|
|
{
|
|
$this->next = 'upgradeComplete';
|
|
$this->warning_exists = true;
|
|
$this->next_desc = $this->l('upgradeModule step has not ended correctly.');
|
|
$this->nextQuickInfo[] = $this->l('listModules is not an array. No module has been updated.');
|
|
$this->nextErrors[] = $this->l('listModules is not an array. No module has been updated.');
|
|
return true;
|
|
}
|
|
|
|
$time_elapsed = time() - $start_time;
|
|
// module list
|
|
if (count($listModules) > 0)
|
|
{
|
|
do
|
|
{
|
|
$module_info = array_shift($listModules);
|
|
|
|
$this->upgradeThisModule($module_info['id'], $module_info['name']);
|
|
$time_elapsed = time() - $start_time;
|
|
}
|
|
while (($time_elapsed < self::$loopUpgradeModulesTime) && count($listModules) > 0);
|
|
|
|
$modules_left = count($listModules);
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toUpgradeModuleList, base64_encode(serialize($listModules)));
|
|
unset($listModules);
|
|
|
|
$this->next = 'upgradeModules';
|
|
if ($modules_left)
|
|
$this->next_desc = sprintf($this->l('%s modules left to upgrade.'), $modules_left);
|
|
$this->stepDone = false;
|
|
}
|
|
else
|
|
{
|
|
if (version_compare($this->install_version, '1.5.0.0', '>='))
|
|
{
|
|
$modules_to_delete['backwardcompatibility'] = 'Backward Compatibility';
|
|
$modules_to_delete['dibs'] = 'Dibs';
|
|
$modules_to_delete['cloudcache'] = 'Cloudcache';
|
|
$modules_to_delete['mobile_theme'] = 'The 1.4 mobile_theme';
|
|
$modules_to_delete['trustedshops'] = 'Trustedshops';
|
|
$modules_to_delete['dejala'] = 'Dejala';
|
|
$modules_to_delete['stripejs'] = 'Stripejs';
|
|
$modules_to_delete['blockvariouslinks'] = 'Block Various Links';
|
|
|
|
foreach($modules_to_delete as $key => $module)
|
|
{
|
|
Db::getInstance()->execute('DELETE ms.*, hm.*
|
|
FROM `'._DB_PREFIX_.'module_shop` ms
|
|
INNER JOIN `'._DB_PREFIX_.'hook_module` hm USING (`id_module`)
|
|
INNER JOIN `'._DB_PREFIX_.'module` m USING (`id_module`)
|
|
WHERE m.`name` LIKE \''.pSQL($key).'\'');
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'module` SET `active` = 0 WHERE `name` LIKE \''.pSQL($key).'\'');
|
|
|
|
$path = $this->prodRootDir.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$key.DIRECTORY_SEPARATOR;
|
|
if (file_exists($path.$key.'.php'))
|
|
{
|
|
if (self::deleteDirectory($path))
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s module is not compatible with 1.5.X, it will be removed from your ftp.'), $module);
|
|
else
|
|
$this->nextErrors[] = sprintf($this->l('%1$s module is not compatible with 1.5.X, please remove it on your ftp.'), $module);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->stepDone = true;
|
|
$this->status = 'ok';
|
|
$this->next = 'cleanDatabase';
|
|
$this->next_desc = $this->l('Addons modules files have been upgraded.');
|
|
$this->nextQuickInfo[] = $this->l('Addons modules files have been upgraded.');
|
|
if ($this->manualMode)
|
|
$this->writeConfig(array('PS_AUTOUP_MANUAL_MODE' => '0'));
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* upgrade module $name (identified by $id_module on addons server)
|
|
*
|
|
* @param mixed $id_module
|
|
* @param mixed $name
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function upgradeThisModule($id_module, $name)
|
|
{
|
|
$zip_fullpath = $this->tmpPath.DIRECTORY_SEPARATOR.$name.'.zip';
|
|
|
|
$dest_extract = $this->prodRootDir.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR;
|
|
|
|
$addons_url = 'api.addons.prestashop.com';
|
|
$protocolsList = array('https://' => 443, 'http://' => 80);
|
|
if (!extension_loaded('openssl'))
|
|
unset($protocolsList['https://']);
|
|
else
|
|
unset($protocolsList['http://']);
|
|
|
|
$postData = 'version='.$this->install_version.'&method=module&id_module='.(int)$id_module;
|
|
|
|
// Make the request
|
|
$opts = array(
|
|
'http'=>array(
|
|
'method'=> 'POST',
|
|
'content' => $postData,
|
|
'header' => 'Content-type: application/x-www-form-urlencoded',
|
|
'timeout' => 10,
|
|
)
|
|
);
|
|
$context = stream_context_create($opts);
|
|
foreach ($protocolsList as $protocol => $port)
|
|
{
|
|
// file_get_contents can return false if https is not supported (or warning)
|
|
$content = Tools14::file_get_contents($protocol.$addons_url, false, $context);
|
|
if ($content == false || substr($content, 5) == '<?xml')
|
|
continue;
|
|
if ($content !== null)
|
|
{
|
|
if ((bool)file_put_contents($zip_fullpath, $content))
|
|
{
|
|
if (filesize($zip_fullpath) <= 300)
|
|
unlink($zip_fullpath);
|
|
// unzip in modules/[mod name] old files will be conserved
|
|
elseif ($this->ZipExtract($zip_fullpath, $dest_extract))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('The files of module %s have been upgraded.'), $name);
|
|
if (file_exists($zip_fullpath))
|
|
unlink($zip_fullpath);
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[WARNING] Error when trying to upgrade module %s.'), $name);
|
|
$this->warning_exists = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] Unable to write module %s\'s zip file in temporary directory.'), $name);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] Unable to write module %s\'s zip file in temporary directory.'), $name);
|
|
$this->warning_exists = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] No response from Addons server.'));
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] No response from Addons server.'));
|
|
$this->warning_exists = 1;
|
|
}
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function ajaxProcessUpgradeDb()
|
|
{
|
|
$this->nextParams = $this->currentParams;
|
|
if (!$this->doUpgrade())
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('Error during database upgrade. You may need to restore your database.');
|
|
return false;
|
|
}
|
|
$this->next = 'upgradeModules';
|
|
$this->next_desc = $this->l('Database upgraded. Now upgrading your Addons modules...');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Clean the database from unwanted entires
|
|
*
|
|
* @return void
|
|
*/
|
|
public function ajaxProcessCleanDatabase()
|
|
{
|
|
global $warningExists;
|
|
|
|
/* Clean tabs order */
|
|
foreach ($this->db->ExecuteS('SELECT DISTINCT id_parent FROM '._DB_PREFIX_.'tab') as $parent)
|
|
{
|
|
$i = 1;
|
|
foreach ($this->db->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->db->Execute('UPDATE '._DB_PREFIX_.'tab SET position = '.(int)($i++).' WHERE id_tab = '.(int)$child['id_tab'].' AND id_parent = '.(int)$parent['id_parent']);
|
|
}
|
|
|
|
/* Clean configuration integrity */
|
|
$this->db->Execute('DELETE FROM `'._DB_PREFIX_.'configuration_lang` WHERE (`value` IS NULL AND `date_upd` IS NULL) OR `value` LIKE ""', false);
|
|
|
|
$this->status = 'ok';
|
|
$this->next = 'upgradeComplete';
|
|
$this->next_desc = $this->l('The database has been cleaned.');
|
|
$this->nextQuickInfo[] = $this->l('The database has been cleaned.');
|
|
}
|
|
|
|
/**
|
|
* This function now replaces doUpgrade.php or upgrade.php
|
|
*
|
|
* @return void
|
|
*/
|
|
public function doUpgrade()
|
|
{
|
|
// Initialize
|
|
// setting the memory limit to 128M only if current is lower
|
|
$memory_limit = ini_get('memory_limit');
|
|
if ((substr($memory_limit,-1) != 'G')
|
|
&& ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128)
|
|
|| is_numeric($memory_limit) AND (intval($memory_limit) < 131072))
|
|
)
|
|
@ini_set('memory_limit','128M');
|
|
|
|
/* Redefine REQUEST_URI if empty (on some webservers...) */
|
|
if (!isset($_SERVER['REQUEST_URI']) || empty($_SERVER['REQUEST_URI']))
|
|
{
|
|
if (!isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['SCRIPT_FILENAME']))
|
|
$_SERVER['SCRIPT_NAME'] = $_SERVER['SCRIPT_FILENAME'];
|
|
if (isset($_SERVER['SCRIPT_NAME']))
|
|
{
|
|
if (basename($_SERVER['SCRIPT_NAME']) == 'index.php' && empty($_SERVER['QUERY_STRING']))
|
|
$_SERVER['REQUEST_URI'] = dirname($_SERVER['SCRIPT_NAME']).'/';
|
|
else
|
|
{
|
|
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
|
|
if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING']))
|
|
$_SERVER['REQUEST_URI'] .= '?'.$_SERVER['QUERY_STRING'];
|
|
}
|
|
}
|
|
}
|
|
$_SERVER['REQUEST_URI'] = str_replace('//', '/', $_SERVER['REQUEST_URI']);
|
|
|
|
define('INSTALL_VERSION', $this->install_version);
|
|
// 1.4
|
|
define('INSTALL_PATH', realpath($this->latestRootDir.DIRECTORY_SEPARATOR.'install'));
|
|
// 1.5 ...
|
|
define('_PS_INSTALL_PATH_', INSTALL_PATH.DIRECTORY_SEPARATOR);
|
|
|
|
|
|
define('PS_INSTALLATION_IN_PROGRESS', true);
|
|
define('SETTINGS_FILE', $this->prodRootDir . '/config/settings.inc.php');
|
|
define('DEFINES_FILE', $this->prodRootDir .'/config/defines.inc.php');
|
|
define('INSTALLER__PS_BASE_URI', substr($_SERVER['REQUEST_URI'], 0, -1 * (strlen($_SERVER['REQUEST_URI']) - strrpos($_SERVER['REQUEST_URI'], '/')) - strlen(substr(dirname($_SERVER['REQUEST_URI']), strrpos(dirname($_SERVER['REQUEST_URI']), '/')+1))));
|
|
// define('INSTALLER__PS_BASE_URI_ABSOLUTE', 'http://'.ToolsInstall::getHttpHost(false, true).INSTALLER__PS_BASE_URI);
|
|
|
|
// XML Header
|
|
// header('Content-Type: text/xml');
|
|
|
|
$filePrefix = 'PREFIX_';
|
|
$engineType = 'ENGINE_TYPE';
|
|
|
|
$mysqlEngine = (defined('_MYSQL_ENGINE_') ? _MYSQL_ENGINE_ : 'MyISAM');
|
|
|
|
if (function_exists('date_default_timezone_set'))
|
|
date_default_timezone_set('Europe/Paris');
|
|
|
|
// if _PS_ROOT_DIR_ is defined, use it instead of "guessing" the module dir.
|
|
if (defined('_PS_ROOT_DIR_') AND !defined('_PS_MODULE_DIR_'))
|
|
define('_PS_MODULE_DIR_', _PS_ROOT_DIR_.'/modules/');
|
|
else if (!defined('_PS_MODULE_DIR_'))
|
|
define('_PS_MODULE_DIR_', INSTALL_PATH.'/../modules/');
|
|
|
|
$upgrade_dir_php = 'upgrade/php';
|
|
if (!file_exists(INSTALL_PATH.DIRECTORY_SEPARATOR.$upgrade_dir_php))
|
|
{
|
|
$upgrade_dir_php = 'php';
|
|
if (!file_exists(INSTALL_PATH.DIRECTORY_SEPARATOR.$upgrade_dir_php))
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('/install/upgrade/php directory is missing in archive or directory');
|
|
$this->nextQuickInfo[] = '/install/upgrade/php directory is missing in archive or directory';
|
|
$this->nextErrors[] = '/install/upgrade/php directory is missing in archive or directory.';
|
|
return false;
|
|
}
|
|
}
|
|
define('_PS_INSTALLER_PHP_UPGRADE_DIR_', INSTALL_PATH.DIRECTORY_SEPARATOR.$upgrade_dir_php.DIRECTORY_SEPARATOR);
|
|
|
|
//old version detection
|
|
global $oldversion, $logger;
|
|
$oldversion = false;
|
|
if (file_exists(SETTINGS_FILE))
|
|
{
|
|
include_once(SETTINGS_FILE);
|
|
|
|
// include_once(DEFINES_FILE);
|
|
$oldversion = _PS_VERSION_;
|
|
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l('The config/settings.inc.php file was not found.');
|
|
$this->nextErrors[] = $this->l('The config/settings.inc.php file was not found.');
|
|
return false;
|
|
}
|
|
|
|
if (!defined('__PS_BASE_URI__'))
|
|
define('__PS_BASE_URI__', realpath(dirname($_SERVER['SCRIPT_NAME'])).'/../../');
|
|
|
|
if (!defined('_THEMES_DIR_'))
|
|
define('_THEMES_DIR_', __PS_BASE_URI__.'themes/');
|
|
|
|
$oldversion = _PS_VERSION_;
|
|
$versionCompare = version_compare(INSTALL_VERSION, $oldversion);
|
|
|
|
if ($versionCompare == '-1')
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Current version: %1$s. Version to install: %2$s.'), $oldversion, INSTALL_VERSION);
|
|
$this->nextErrors[] = sprintf($this->l('Current version: %1$s. Version to install: %2$s'), $oldversion, INSTALL_VERSION);
|
|
$this->nextQuickInfo[] = $this->l('[ERROR] Version to install is too old.');
|
|
$this->nextErrors[] = $this->l('[ERROR] Version to install is too old.');
|
|
return false;
|
|
}
|
|
elseif ($versionCompare == 0)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l(sprintf('You already have the %s version.',INSTALL_VERSION));
|
|
$this->nextErrors[] = $this->l(sprintf('You already have the %s version.',INSTALL_VERSION));
|
|
return false;
|
|
}
|
|
elseif ($versionCompare === false)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l('There is no older version. Did you delete or rename the config/settings.inc.php file?');
|
|
$this->nextErrors[] = $this->l('There is no older version. Did you delete or rename the config/settings.inc.php file?');
|
|
return false;
|
|
}
|
|
|
|
//check DB access
|
|
$this->db;
|
|
error_reporting(E_ALL);
|
|
$resultDB = MySql::tryToConnect(_DB_SERVER_, _DB_USER_, _DB_PASSWD_, _DB_NAME_);
|
|
if ($resultDB !== 0)
|
|
{
|
|
// $logger->logError('Invalid database configuration.');
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l('Invalid database configuration');
|
|
$this->nextErrors[] = $this->l('Invalid database configuration');
|
|
return false;
|
|
}
|
|
|
|
//custom sql file creation
|
|
$upgradeFiles = array();
|
|
|
|
$upgrade_dir_sql = INSTALL_PATH.'/upgrade/sql';
|
|
// if 1.4;
|
|
if (!file_exists($upgrade_dir_sql))
|
|
$upgrade_dir_sql = INSTALL_PATH.'/sql/upgrade';
|
|
|
|
if (!file_exists($upgrade_dir_sql))
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('Unable to find upgrade directory in the installation path.');
|
|
return false;
|
|
}
|
|
|
|
if ($handle = opendir($upgrade_dir_sql))
|
|
{
|
|
while (false !== ($file = readdir($handle)))
|
|
if ($file != '.' AND $file != '..')
|
|
$upgradeFiles[] = str_replace(".sql", "", $file);
|
|
closedir($handle);
|
|
}
|
|
if (empty($upgradeFiles))
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Cannot find the SQL upgrade files. Please check that the %s folder is not empty.'), $upgrade_dir_sql);
|
|
$this->nextErrors[] = sprintf($this->l('Cannot find the SQL upgrade files. Please check that the %s folder is not empty.'), $upgrade_dir_sql);
|
|
// fail 31
|
|
return false;
|
|
}
|
|
natcasesort($upgradeFiles);
|
|
$neededUpgradeFiles = array();
|
|
|
|
$arrayVersion = explode('.', $oldversion);
|
|
$versionNumbers = count($arrayVersion);
|
|
if ($versionNumbers != 4)
|
|
$arrayVersion = array_pad($arrayVersion, 4, '0');
|
|
|
|
$oldversion = implode('.', $arrayVersion);
|
|
|
|
foreach ($upgradeFiles as $version)
|
|
if (version_compare($version, $oldversion) == 1 && version_compare(INSTALL_VERSION, $version) != -1)
|
|
$neededUpgradeFiles[] = $version;
|
|
|
|
if (empty($neededUpgradeFiles) || count($neededUpgradeFiles) === 0)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l('No upgrade is possible.');
|
|
$this->nextErrors[] = $this->l('No upgrade is possible.');
|
|
if (strpos(INSTALL_VERSION, '.') === false)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s is not a valid version number.'), INSTALL_VERSION);
|
|
$this->nextErrors[] = sprintf($this->l('%s is not a valid version number.'), INSTALL_VERSION);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
$sqlContentVersion = array();
|
|
if ($this->deactivateCustomModule)
|
|
{
|
|
require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.'deactivate_custom_modules.php');
|
|
deactivate_custom_modules();
|
|
}
|
|
|
|
if (version_compare(INSTALL_VERSION, '1.5.6.1', '='))
|
|
{
|
|
$filename = _PS_INSTALLER_PHP_UPGRADE_DIR_.'migrate_orders.php';
|
|
$content = file_get_contents($filename);
|
|
$str_old[] = '$values_order_detail = array();';
|
|
$str_old[] = '$values_order = array();';
|
|
$str_old[] = '$col_order_detail = array();';
|
|
$content = str_replace($str_old, '', $content);
|
|
file_put_contents($filename, $content);
|
|
}
|
|
|
|
foreach($neededUpgradeFiles as $version)
|
|
{
|
|
$file = $upgrade_dir_sql.DIRECTORY_SEPARATOR.$version.'.sql';
|
|
if (!file_exists($file))
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Error while loading SQL upgrade file "%s.sql".'), $version);
|
|
$this->nextErrors[] = sprintf($this->l('Error while loading SQL upgrade file "%s.sql".'), $version);
|
|
return false;
|
|
$logger->logError('Error while loading SQL upgrade file.');
|
|
}
|
|
if (!$sqlContent = file_get_contents($file)."\n")
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l(sprintf('Error while loading SQL upgrade file %s.', $version));
|
|
$this->nextErrors[] = $this->l(sprintf('Error while loading sql SQL file %s.', $version));
|
|
return false;
|
|
$logger->logError(sprintf('Error while loading sql upgrade file %s.', $version));
|
|
}
|
|
$sqlContent = str_replace(array($filePrefix, $engineType), array(_DB_PREFIX_, $mysqlEngine), $sqlContent);
|
|
$sqlContent = preg_split("/;\s*[\r\n]+/",$sqlContent);
|
|
$sqlContentVersion[$version] = $sqlContent;
|
|
}
|
|
|
|
//sql file execution
|
|
global $requests, $warningExist;
|
|
$requests = '';
|
|
$warningExist = false;
|
|
|
|
// Configuration::loadConfiguration();
|
|
$request = '';
|
|
|
|
foreach ($sqlContentVersion as $upgrade_file => $sqlContent)
|
|
foreach ($sqlContent as $query)
|
|
{
|
|
$query = trim($query);
|
|
if(!empty($query))
|
|
{
|
|
/* If php code have to be executed */
|
|
if (strpos($query, '/* PHP:') !== false)
|
|
{
|
|
/* Parsing php code */
|
|
$pos = strpos($query, '/* PHP:') + strlen('/* PHP:');
|
|
$phpString = substr($query, $pos, strlen($query) - $pos - strlen(' */;'));
|
|
$php = explode('::', $phpString);
|
|
preg_match('/\((.*)\)/', $phpString, $pattern);
|
|
$paramsString = trim($pattern[0], '()');
|
|
preg_match_all('/([^,]+),? ?/', $paramsString, $parameters);
|
|
if (isset($parameters[1]))
|
|
$parameters = $parameters[1];
|
|
else
|
|
$parameters = array();
|
|
if (is_array($parameters))
|
|
foreach ($parameters AS &$parameter)
|
|
$parameter = str_replace('\'', '', $parameter);
|
|
|
|
// reset phpRes to a null value
|
|
$phpRes = null;
|
|
/* Call a simple function */
|
|
if (strpos($phpString, '::') === false)
|
|
{
|
|
$func_name = str_replace($pattern[0], '', $php[0]);
|
|
if (version_compare(INSTALL_VERSION, '1.5.5.0', '=') && $func_name == 'fix_download_product_feature_active')
|
|
continue;
|
|
|
|
if (!file_exists(_PS_INSTALLER_PHP_UPGRADE_DIR_.strtolower($func_name).'.php'))
|
|
{
|
|
$this->nextQuickInfo[] = '<div class="upgradeDbError">[ERROR] '.$upgrade_file.' PHP - missing file '.$query.'</div>';
|
|
$this->nextErrors[] = '[ERROR] '.$upgrade_file.' PHP - missing file '.$query;
|
|
$warningExist = true;
|
|
}
|
|
else
|
|
{
|
|
require_once(_PS_INSTALLER_PHP_UPGRADE_DIR_.strtolower($func_name).'.php');
|
|
$phpRes = call_user_func_array($func_name, $parameters);
|
|
}
|
|
}
|
|
/* Or an object method */
|
|
else
|
|
{
|
|
$func_name = array($php[0], str_replace($pattern[0], '', $php[1]));
|
|
$this->nextQuickInfo[] = '<div class="upgradeDbError">[ERROR] '.$upgrade_file.' PHP - Object Method call is forbidden ( '.$php[0].'::'.str_replace($pattern[0], '', $php[1]).')</div>';
|
|
$this->nextErrors[] = '[ERROR] '.$upgrade_file.' PHP - Object Method call is forbidden ('.$php[0].'::'.str_replace($pattern[0], '', $php[1]).')';
|
|
$warningExist = true;
|
|
}
|
|
|
|
if (isset($phpRes) && (is_array($phpRes) && !empty($phpRes['error'])) || $phpRes === false)
|
|
{
|
|
// $this->next = 'error';
|
|
$this->nextQuickInfo[] = '
|
|
<div class="upgradeDbError">
|
|
[ERROR] PHP '.$upgrade_file.' '.$query."\n".'
|
|
'.(empty($phpRes['error']) ? '' : $phpRes['error']."\n").'
|
|
'.(empty($phpRes['msg']) ? '' : ' - '.$phpRes['msg']."\n").'
|
|
</div>';
|
|
$this->nextErrors[] = '
|
|
[ERROR] PHP '.$upgrade_file.' '.$query."\n".'
|
|
'.(empty($phpRes['error']) ? '' : $phpRes['error']."\n").'
|
|
'.(empty($phpRes['msg']) ? '' : ' - '.$phpRes['msg']."\n");
|
|
$warningExist = true;
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = '<div class="upgradeDbOk">[OK] PHP '.$upgrade_file.' : '.$query.'</div>';
|
|
if (isset($phpRes))
|
|
unset($phpRes);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (strstr($query, 'CREATE TABLE') !== false)
|
|
{
|
|
$pattern = '/CREATE TABLE.*[`]*'._DB_PREFIX_.'([^`]*)[`]*\s\(/';
|
|
preg_match($pattern, $query, $matches);;
|
|
if (isset($matches[1]) && $matches[1])
|
|
{
|
|
$drop = 'DROP TABLE IF EXISTS `'._DB_PREFIX_.$matches[1].'`;';
|
|
$result = $this->db->execute($drop, false);
|
|
if ($result)
|
|
$this->nextQuickInfo[] = '<div class="upgradeDbOk">'.sprintf($this->l('[DROP] SQL %s table has been dropped.'), '`'._DB_PREFIX_.$matches[1].'`').'</div>';
|
|
}
|
|
}
|
|
$result = $this->db->execute($query, false);
|
|
if (!$result)
|
|
{
|
|
$error = $this->db->getMsgError();
|
|
$error_number = $this->db->getNumberError();
|
|
$this->nextQuickInfo[] = '
|
|
<div class="upgradeDbError">
|
|
[WARNING] SQL '.$upgrade_file.'
|
|
'.$error_number.' in '.$query.': '.$error.'</div>';
|
|
|
|
$duplicates = array('1050', '1054', '1060', '1061', '1062', '1091');
|
|
if (!in_array($error_number, $duplicates))
|
|
{
|
|
$this->nextErrors[] = 'SQL '.$upgrade_file.' '.$error_number.' in '.$query.': '.$error;
|
|
$warningExist = true;
|
|
}
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = '<div class="upgradeDbOk">[OK] SQL '.$upgrade_file.' '.$query.'</div>';
|
|
}
|
|
if (isset($query))
|
|
unset($query);
|
|
}
|
|
}
|
|
if ($this->next == 'error')
|
|
{
|
|
$this->next_desc = $this->l('An error happened during the database upgrade.');
|
|
return false;
|
|
}
|
|
|
|
$this->nextQuickInfo[] = $this->l('Database upgrade OK'); // no error !
|
|
|
|
# At this point, database upgrade is over.
|
|
# Now we need to add all previous missing settings items, and reset cache and compile directories
|
|
$this->writeNewSettings();
|
|
|
|
// Settings updated, compile and cache directories must be emptied
|
|
$arrayToClean[] = $this->prodRootDir.'/tools/smarty/cache/';
|
|
$arrayToClean[] = $this->prodRootDir.'/tools/smarty/compile/';
|
|
$arrayToClean[] = $this->prodRootDir.'/tools/smarty_v2/cache/';
|
|
$arrayToClean[] = $this->prodRootDir.'/tools/smarty_v2/compile/';
|
|
if (version_compare(INSTALL_VERSION, '1.5.0.0', '>'))
|
|
{
|
|
$arrayToClean[] = $this->prodRootDir.'/cache/smarty/cache/';
|
|
$arrayToClean[] = $this->prodRootDir.'/cache/smarty/compile/';
|
|
}
|
|
|
|
foreach ($arrayToClean as $dir)
|
|
if (!file_exists($dir))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[SKIP] directory "%s" doesn\'t exist and cannot be emptied.'), str_replace($this->prodRootDir, '', $dir));
|
|
continue;
|
|
}
|
|
else
|
|
foreach (scandir($dir) as $file)
|
|
if ($file[0] != '.' && $file != 'index.php' && $file != '.htaccess')
|
|
{
|
|
if (is_file($dir.$file))
|
|
unlink($dir.$file);
|
|
elseif(is_dir($dir.$file.DIRECTORY_SEPARATOR))
|
|
self::deleteDirectory($dir.$file.DIRECTORY_SEPARATOR);
|
|
$this->nextQuickInfo[] = sprintf($this->l('[CLEANING CACHE] File %s removed'), $file);
|
|
}
|
|
|
|
if (version_compare(INSTALL_VERSION, '1.5.0.0', '>'))
|
|
{
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'configuration` SET `name` = \'PS_LEGACY_IMAGES\' WHERE name LIKE \'0\' AND `value` = 1');
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'configuration` SET `value` = 0 WHERE `name` LIKE \'PS_LEGACY_IMAGES\'');
|
|
if (Db::getInstance()->getValue('SELECT COUNT(id_product_download) FROM `'._DB_PREFIX_.'product_download` WHERE `active` = 1') > 0)
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'configuration` SET `value` = 1 WHERE `name` LIKE \'PS_VIRTUAL_PROD_FEATURE_ACTIVE\'');
|
|
|
|
if (defined('_THEME_NAME_') && $this->updateDefaultTheme && preg_match('#(default|prestashop|default-boostrap)$#', _THEME_NAME_))
|
|
{
|
|
$separator = addslashes(DIRECTORY_SEPARATOR);
|
|
$file = _PS_ROOT_DIR_.$separator.'themes'.$separator._THEME_NAME_.$separator.'cache'.$separator;
|
|
if (file_exists($file))
|
|
foreach (scandir($file) as $cache)
|
|
if ($cache[0] != '.' && $cache != 'index.php' && $cache != '.htaccess' && file_exists($file.$cache) && !is_dir($file.$cache))
|
|
if (file_exists($dir.$cache))
|
|
unlink($file.$cache);
|
|
}
|
|
|
|
if (version_compare(_PS_VERSION_, '1.5.0.0', '<='))
|
|
{
|
|
$dir = _PS_ROOT_DIR_.'/controllers/';
|
|
if (file_exists($dir))
|
|
foreach (scandir($dir) as $file)
|
|
if (!is_dir($file) && $file[0] != '.' && $file != 'index.php' && $file != '.htaccess')
|
|
if (file_exists($dir.basename(str_replace('.php', '', $file).'.php')))
|
|
unlink($dir.basename($file));
|
|
|
|
$dir = _PS_ROOT_DIR_.'/classes/';
|
|
foreach(self::$classes14 as $class)
|
|
if (file_exists($dir.basename($class).'.php'))
|
|
unlink($dir.basename($class).'.php');
|
|
|
|
$dir = _PS_ADMIN_DIR_.'/tabs/';
|
|
if (file_exists($dir))
|
|
foreach (scandir($dir) as $file)
|
|
if (!is_dir($file) && $file[0] != '.' && $file != 'index.php' && $file != '.htaccess')
|
|
if (file_exists($dir.basename(str_replace('.php', '', $file).'.php')))
|
|
unlink($dir.basename($file));
|
|
}
|
|
|
|
if (version_compare($this->install_version, '1.5.4.0', '>='))
|
|
{
|
|
// Upgrade languages
|
|
if (!defined('_PS_TOOL_DIR_'))
|
|
define('_PS_TOOL_DIR_', _PS_ROOT_DIR_.'/tools/');
|
|
if (!defined('_PS_TRANSLATIONS_DIR_'))
|
|
define('_PS_TRANSLATIONS_DIR_', _PS_ROOT_DIR_.'/translations/');
|
|
if (!defined('_PS_MODULES_DIR_'))
|
|
define('_PS_MODULES_DIR_', _PS_ROOT_DIR_.'/modules/');
|
|
if (!defined('_PS_MAILS_DIR_'))
|
|
define('_PS_MAILS_DIR_', _PS_ROOT_DIR_.'/mails/');
|
|
$langs = Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'lang` WHERE `active` = 1');
|
|
require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php');
|
|
if (is_array($langs))
|
|
foreach ($langs as $lang)
|
|
{
|
|
$lang_pack = Tools14::jsonDecode(Tools14::file_get_contents('http'.(extension_loaded('openssl')? 's' : '').'://www.prestashop.com/download/lang_packs/get_language_pack.php?version='.$this->install_version.'&iso_lang='.$lang['iso_code']));
|
|
|
|
if (!$lang_pack)
|
|
continue;
|
|
elseif ($content = Tools14::file_get_contents('http'.(extension_loaded('openssl')? 's' : '').'://translations.prestashop.com/download/lang_packs/gzip/'.$lang_pack->version.'/'.$lang['iso_code'].'.gzip'))
|
|
{
|
|
$file = _PS_TRANSLATIONS_DIR_.$lang['iso_code'].'.gzip';
|
|
if ((bool)file_put_contents($file, $content))
|
|
{
|
|
$gz = new Archive_Tar($file, true);
|
|
$files_list = $gz->listContent();
|
|
if (!$this->keepMails)
|
|
{
|
|
$files_listing = array();
|
|
foreach($files_list as $i => $file)
|
|
if (preg_match('/^mails\/'.$lang['iso_code'].'\/.*/', $file['filename']))
|
|
unset($files_list[$i]);
|
|
foreach($files_list as $file)
|
|
if (isset($file['filename']) && is_string($file['filename']))
|
|
$files_listing[] = $file['filename'];
|
|
if (is_array($files_listing))
|
|
$gz->extractList($files_listing, _PS_TRANSLATIONS_DIR_.'../', '');
|
|
}
|
|
else
|
|
$gz->extract(_PS_TRANSLATIONS_DIR_.'../', false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (version_compare(INSTALL_VERSION, '1.6.0.0', '>'))
|
|
{
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Tools.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Tools.php');
|
|
if (!class_exists('Tools2', false) AND class_exists('ToolsCore'))
|
|
eval('class Tools2 extends ToolsCore{}');
|
|
|
|
if (class_exists('Tools2') && method_exists('Tools2', 'generateHtaccess'))
|
|
{
|
|
$url_rewrite = (bool)Db::getInstance()->getvalue('SELECT `value` FROM `'._DB_PREFIX_.'configuration` WHERE name=\'PS_REWRITING_SETTINGS\'');
|
|
|
|
if (!defined('_MEDIA_SERVER_1_'))
|
|
define('_MEDIA_SERVER_1_', '');
|
|
if (!defined('_MEDIA_SERVER_2_'))
|
|
define('_MEDIA_SERVER_2_', '');
|
|
if (!defined('_MEDIA_SERVER_3_'))
|
|
define('_MEDIA_SERVER_3_', '');
|
|
if (!defined('_PS_USE_SQL_SLAVE_'))
|
|
define('_PS_USE_SQL_SLAVE_', false);
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/ObjectModel.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/ObjectModel.php');
|
|
if (!class_exists('ObjectModel', false) AND class_exists('ObjectModelCore'))
|
|
eval('abstract class ObjectModel extends ObjectModelCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Configuration.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Configuration.php');
|
|
if (!class_exists('Configuration', false) AND class_exists('ConfigurationCore'))
|
|
eval('class Configuration extends ConfigurationCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/cache/Cache.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/cache/Cache.php');
|
|
if (!class_exists('Cache', false) AND class_exists('CacheCore'))
|
|
eval('abstract class Cache extends CacheCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/PrestaShopCollection.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/PrestaShopCollection.php');
|
|
if(!class_exists('PrestaShopCollection', false) AND class_exists('PrestaShopCollectionCore'))
|
|
eval('class PrestaShopCollection extends PrestaShopCollectionCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/shop/ShopUrl.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/shop/ShopUrl.php');
|
|
if (!class_exists('ShopUrl', false) AND class_exists('ShopUrlCore'))
|
|
eval('class ShopUrl extends ShopUrlCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/shop/Shop.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/shop/Shop.php');
|
|
if (!class_exists('Shop', false) AND class_exists('ShopCore'))
|
|
eval('class Shop extends ShopCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Translate.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Translate.php');
|
|
if (!class_exists('Translate', false) AND class_exists('TranslateCore'))
|
|
eval('class Translate extends TranslateCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/module/Module.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/module/Module.php');
|
|
if (!class_exists('Module', false) AND class_exists('ModuleCore'))
|
|
eval('class Module extends ModuleCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Validate.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Validate.php');
|
|
if (!class_exists('Validate', false) AND class_exists('ValidateCore'))
|
|
eval('class Validate extends ValidateCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Language.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Language.php');
|
|
if (!class_exists('Language', false) AND class_exists('LanguageCore'))
|
|
eval('class Language extends LanguageCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Tab.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Tab.php');
|
|
if (!class_exists('Tab', false) AND class_exists('TabCore'))
|
|
eval('class Tab extends TabCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Dispatcher.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Dispatcher.php');
|
|
if (!class_exists('Dispatcher', false) AND class_exists('DispatcherCore'))
|
|
eval('class Dispatcher extends DispatcherCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Hook.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Hook.php');
|
|
if (!class_exists('Hook', false) AND class_exists('HookCore'))
|
|
eval('class Hook extends HookCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Context.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Context.php');
|
|
if (!class_exists('Context', false) AND class_exists('ContextCore'))
|
|
eval('class Context extends ContextCore{}');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/Group.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/Group.php');
|
|
if (!class_exists('Group', false) AND class_exists('GroupCore'))
|
|
eval('class Group extends GroupCore{}');
|
|
|
|
Tools2::generateHtaccess(null, $url_rewrite);
|
|
}
|
|
}
|
|
|
|
if (version_compare($this->install_version, '1.6.0.2', '>'))
|
|
{
|
|
$path = $this->adminDir.DIRECTORY_SEPARATOR.'themes'.DIRECTORY_SEPARATOR.'default'.DIRECTORY_SEPARATOR.'template'.DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.'header.tpl';
|
|
if (file_exists($path))
|
|
unlink($path);
|
|
}
|
|
}
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/cache/class_index.php'))
|
|
unlink(_PS_ROOT_DIR_.'/cache/class_index.php');
|
|
|
|
// Clear XML files
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/blog-fr.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/blog-fr.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/default_country_modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/default_country_modules_list.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/modules_list.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/modules_native_addons.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/modules_native_addons.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/must_have_modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/must_have_modules_list.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/tab_modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/tab_modules_list.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/trusted_modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/trusted_modules_list.xml');
|
|
if (file_exists(_PS_ROOT_DIR_.'/config/xml/untrusted_modules_list.xml'))
|
|
unlink(_PS_ROOT_DIR_.'/config/xml/untrusted_modules_list.xml');
|
|
|
|
if ($this->deactivateCustomModule)
|
|
{
|
|
$exist = Db::getInstance()->getValue('SELECT `id_configuration` FROM `'._DB_PREFIX_.'configuration` WHERE `name` LIKE \'PS_DISABLE_OVERRIDES\'');
|
|
if ($exist)
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'configuration` SET value = 1 WHERE `name` LIKE \'PS_DISABLE_OVERRIDES\'');
|
|
else
|
|
Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'configuration` (name, value, date_add, date_upd) VALUES ("PS_DISABLE_OVERRIDES", 1, NOW(), NOW())');
|
|
|
|
if (file_exists(_PS_ROOT_DIR_.'/classes/PrestaShopAutoload.php'))
|
|
require_once(_PS_ROOT_DIR_.'/classes/PrestaShopAutoload.php');
|
|
|
|
if (version_compare($this->install_version, '1.6.0.0', '>') && class_exists('PrestaShopAutoload') && method_exists('PrestaShopAutoload', 'generateIndex'))
|
|
{
|
|
if (!defined('_PS_CORE_DIR_'))
|
|
define('_PS_CORE_DIR_', _PS_ROOT_DIR_);
|
|
PrestaShopAutoload::getInstance()->_include_override_path = false;
|
|
PrestaShopAutoload::getInstance()->generateIndex();
|
|
}
|
|
}
|
|
|
|
if ($this->updateDefaultTheme)
|
|
{
|
|
if (version_compare(INSTALL_VERSION, '1.6.0.0', '>'))
|
|
{
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'shop`
|
|
SET id_theme = (SELECT id_theme FROM `'._DB_PREFIX_.'theme` WHERE name LIKE \'default-bootstrap\')');
|
|
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'theme` WHERE name LIKE \'default\' OR name LIKE \'prestashop\'');
|
|
}
|
|
elseif (version_compare(INSTALL_VERSION, '1.5.0.0', '>'))
|
|
{
|
|
Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'shop`
|
|
SET id_theme = (SELECT id_theme FROM `'._DB_PREFIX_.'theme` WHERE name LIKE \'default\')');
|
|
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'theme` WHERE name LIKE \'prestashop\'');
|
|
}
|
|
}
|
|
|
|
// delete cache filesystem if activated
|
|
if (defined('_PS_CACHE_ENABLED_') && _PS_CACHE_ENABLED_)
|
|
{
|
|
$depth = (int)$this->db->getValue('SELECT value
|
|
FROM '._DB_PREFIX_.'configuration
|
|
WHERE name = "PS_CACHEFS_DIRECTORY_DEPTH"');
|
|
if($depth)
|
|
{
|
|
if (!defined('_PS_CACHEFS_DIRECTORY_'))
|
|
define('_PS_CACHEFS_DIRECTORY_', $this->prodRootDir.'/cache/cachefs/');
|
|
self::deleteDirectory(_PS_CACHEFS_DIRECTORY_, false);
|
|
if (class_exists('CacheFs', false))
|
|
self::createCacheFsDirectories((int)$depth);
|
|
}
|
|
}
|
|
|
|
$this->db->execute('UPDATE `'._DB_PREFIX_.'configuration` SET value="0" WHERE name = "PS_HIDE_OPTIMIZATION_TIS"', false);
|
|
$this->db->execute('UPDATE `'._DB_PREFIX_.'configuration` SET value="1" WHERE name = "PS_NEED_REBUILD_INDEX"', false);
|
|
$this->db->execute('UPDATE `'._DB_PREFIX_.'configuration` SET value="'.INSTALL_VERSION.'" WHERE name = "PS_VERSION_DB"', false);
|
|
|
|
if ($warningExist)
|
|
{
|
|
$this->warning_exists = true;
|
|
$this->nextQuickInfo[] = $this->l('Warning detected during upgrade.');
|
|
$this->nextErrors[] = $this->l('Warning detected during upgrade.');
|
|
$this->next_desc = $this->l('Warning detected during upgrade.');
|
|
}
|
|
else
|
|
$this->next_desc = $this->l('Database upgrade completed');
|
|
|
|
return true;
|
|
}
|
|
|
|
public function writeNewSettings()
|
|
{
|
|
// note : duplicated line
|
|
$mysqlEngine = (defined('_MYSQL_ENGINE_') ? _MYSQL_ENGINE_ : 'MyISAM');
|
|
|
|
$oldLevel = error_reporting(E_ALL);
|
|
//refresh conf file
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/classes/AddConfToFile.php');
|
|
copy(SETTINGS_FILE, str_replace('.php', '.old.php', SETTINGS_FILE));
|
|
$confFile = new AddConfToFile(SETTINGS_FILE, 'w');
|
|
if ($confFile->error)
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('Error when opening settings.inc.php file in write mode');
|
|
$this->nextQuickInfo[] = $confFile->error;
|
|
$this->nextErrors[] = $this->l('Error when opening settings.inc.php file in write mode').': '.$confFile->error;
|
|
return false;
|
|
}
|
|
$datas = array(
|
|
array('_DB_SERVER_', _DB_SERVER_),
|
|
array('_DB_NAME_', _DB_NAME_),
|
|
array('_DB_USER_', _DB_USER_),
|
|
array('_DB_PASSWD_', _DB_PASSWD_),
|
|
array('_DB_PREFIX_', _DB_PREFIX_),
|
|
array('_MYSQL_ENGINE_', $mysqlEngine),
|
|
array('_PS_CACHING_SYSTEM_', (defined('_PS_CACHING_SYSTEM_') AND _PS_CACHING_SYSTEM_ != 'CacheMemcache') ? _PS_CACHING_SYSTEM_ : 'CacheMemcache'),
|
|
array('_PS_CACHE_ENABLED_', defined('_PS_CACHE_ENABLED_') ? _PS_CACHE_ENABLED_ : '0'),
|
|
array('_MEDIA_SERVER_1_', defined('_MEDIA_SERVER_1_') ? _MEDIA_SERVER_1_ : ''),
|
|
array('_MEDIA_SERVER_2_', defined('_MEDIA_SERVER_2_') ? _MEDIA_SERVER_2_ : ''),
|
|
array('_MEDIA_SERVER_3_', defined('_MEDIA_SERVER_3_') ? _MEDIA_SERVER_3_ : ''),
|
|
array('_COOKIE_KEY_', _COOKIE_KEY_),
|
|
array('_COOKIE_IV_', _COOKIE_IV_),
|
|
array('_PS_CREATION_DATE_', defined("_PS_CREATION_DATE_") ? _PS_CREATION_DATE_ : date('Y-m-d')),
|
|
array('_PS_VERSION_', INSTALL_VERSION)
|
|
);
|
|
if (defined('_RIJNDAEL_KEY_'))
|
|
$datas[] = array('_RIJNDAEL_KEY_', _RIJNDAEL_KEY_);
|
|
if (defined('_RIJNDAEL_IV_'))
|
|
$datas[] = array('_RIJNDAEL_IV_', _RIJNDAEL_IV_);
|
|
if(!defined('_PS_CACHE_ENABLED_'))
|
|
define('_PS_CACHE_ENABLED_', '0');
|
|
if(!defined('_MYSQL_ENGINE_'))
|
|
define('_MYSQL_ENGINE_', 'MyISAM');
|
|
|
|
// if install version is before 1.5
|
|
if (version_compare(INSTALL_VERSION, '1.5.0.0', '<='))
|
|
{
|
|
$datas[] = array('_DB_TYPE_', _DB_TYPE_);
|
|
$datas[] = array('__PS_BASE_URI__', __PS_BASE_URI__);
|
|
$datas[] = array('_THEME_NAME_', _THEME_NAME_);
|
|
}
|
|
else
|
|
$datas[] = array('_PS_DIRECTORY_', __PS_BASE_URI__);
|
|
foreach ($datas AS $data){
|
|
$confFile->writeInFile($data[0], $data[1]);
|
|
}
|
|
|
|
if ($confFile->error != false)
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('Error when generating new settings.inc.php file.');
|
|
$this->nextQuickInfo[] = $confFile->error;
|
|
$this->nextErrors[] = $this->l('Error when generating new settings.inc.php file.').' '.$confFile->error;
|
|
return false;
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = $this->l('Settings file updated');
|
|
error_reporting($oldLevel);
|
|
}
|
|
|
|
/**
|
|
* getTranslationFileType
|
|
*
|
|
* @param string $file filepath to check
|
|
* @access public
|
|
* @return string type of translation item
|
|
*/
|
|
public function getTranslationFileType($file)
|
|
{
|
|
$type = false;
|
|
// line shorter
|
|
$separator = addslashes(DIRECTORY_SEPARATOR);
|
|
$translation_dir = $separator.'translations'.$separator;
|
|
if (version_compare(_PS_VERSION_, '1.5.0.5', '<'))
|
|
$regex_module = '#'.$separator.'modules'.$separator.'.*'.$separator.'('.implode('|', $this->installedLanguagesIso).')\.php#';
|
|
else
|
|
$regex_module = '#'.$separator.'modules'.$separator.'.*'.$translation_dir.'('.implode('|', $this->installedLanguagesIso).')\.php#';
|
|
|
|
if (preg_match($regex_module, $file))
|
|
$type = 'module';
|
|
elseif (preg_match('#'.$translation_dir.'('.implode('|', $this->installedLanguagesIso).')'.$separator.'admin\.php#', $file))
|
|
$type = 'back office';
|
|
elseif (preg_match('#'.$translation_dir.'('.implode('|', $this->installedLanguagesIso).')'.$separator.'errors\.php#', $file))
|
|
$type = 'error message';
|
|
elseif (preg_match('#'.$translation_dir.'('.implode('|', $this->installedLanguagesIso).')'.$separator.'fields\.php#', $file))
|
|
$type = 'field';
|
|
elseif (preg_match('#'.$translation_dir.'('.implode('|', $this->installedLanguagesIso).')'.$separator.'pdf\.php#', $file))
|
|
$type = 'pdf';
|
|
elseif (preg_match('#'.$separator.'themes'.$separator.'(default|prestashop)'.$separator.'lang'.$separator.'('.implode('|', $this->installedLanguagesIso).')\.php#', $file))
|
|
$type = 'front office';
|
|
|
|
return $type;
|
|
}
|
|
|
|
/**
|
|
* return true if $file is a translation file
|
|
*
|
|
* @param string $file filepath (from prestashop root)
|
|
* @access public
|
|
* @return boolean
|
|
*/
|
|
public function isTranslationFile($file)
|
|
{
|
|
if ($this->getTranslationFileType($file) !== false)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* merge the translations of $orig into $dest, according to the $type of translation file
|
|
*
|
|
* @param string $orig file from upgrade package
|
|
* @param string $dest filepath of destination
|
|
* @param string $type type of translation file (module, bo, fo, field, pdf, error)
|
|
* @access public
|
|
* @return boolean
|
|
*/
|
|
public function mergeTranslationFile($orig, $dest, $type)
|
|
{
|
|
switch ($type)
|
|
{
|
|
case 'front office':
|
|
$var_name = '_LANG';
|
|
break;
|
|
case 'back office':
|
|
$var_name = '_LANGADM';
|
|
break;
|
|
case 'error message':
|
|
$var_name = '_ERRORS';
|
|
break;
|
|
case 'field':
|
|
$var_name = '_FIELDS';
|
|
break;
|
|
case 'module':
|
|
$var_name = '_MODULE';
|
|
// if current version is before 1.5.0.5, module has no translations dir
|
|
if (version_compare(_PS_VERSION_, '1.5.0.5', '<') && (version_compare($this->install_version, '1.5.0.5', '>')))
|
|
$dest = str_replace(DIRECTORY_SEPARATOR.'translations', '', $dest);
|
|
|
|
break;
|
|
case 'pdf':
|
|
$var_name = '_LANGPDF';
|
|
break;
|
|
case 'mail':
|
|
$var_name = '_LANGMAIL';
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if (!file_exists($orig))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[NOTICE] File %s does not exist, merge skipped.'), $orig);
|
|
return true;
|
|
}
|
|
include($orig);
|
|
if (!isset($$var_name))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[WARNING] %1$s variable missing in file %2$s. Merge skipped.'), $var_name, $orig);
|
|
return true;
|
|
}
|
|
$var_orig = $$var_name;
|
|
|
|
if (!file_exists($dest))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[NOTICE] File %s does not exist, merge skipped.'), $dest);
|
|
return false;
|
|
}
|
|
include($dest);
|
|
if (!isset($$var_name))
|
|
{
|
|
// in that particular case : file exists, but variable missing, we need to delete that file
|
|
// (if not, this invalid file will be copied in /translations during upgradeDb process)
|
|
if ('module' == $type && file_exists($dest))
|
|
unlink($dest);
|
|
$this->nextQuickInfo[] = sprintf($this->l('[WARNING] %1$s variable missing in file %2$s. File %2$s deleted and merge skipped.'), $var_name, $dest);
|
|
return false;
|
|
}
|
|
$var_dest = $$var_name;
|
|
|
|
$merge = array_merge($var_orig, $var_dest);
|
|
|
|
if ($fd = fopen($dest, 'w'))
|
|
{
|
|
fwrite($fd, "<?php\n\nglobal \$".$var_name.";\n\$".$var_name." = array();\n");
|
|
foreach ($merge as $k => $v)
|
|
{
|
|
if (get_magic_quotes_gpc())
|
|
$v = stripslashes($v);
|
|
if ('mail' == $type)
|
|
fwrite($fd, '$'.$var_name.'[\''.$this->db->escape($k).'\'] = \''.$this->db->escape($v).'\';'."\n");
|
|
else
|
|
fwrite($fd, '$'.$var_name.'[\''.$this->db->escape($k, true).'\'] = \''.$this->db->escape($v, true).'\';'."\n");
|
|
}
|
|
fwrite($fd, "\n?>");
|
|
fclose($fd);
|
|
}
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* upgradeThisFile
|
|
*
|
|
* @param mixed $file
|
|
* @return void
|
|
*/
|
|
public function upgradeThisFile($file)
|
|
{
|
|
|
|
// note : keepMails is handled in skipFiles
|
|
// 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_)
|
|
$orig = $this->latestRootDir.$file;
|
|
$dest = $this->destUpgradePath.$file;
|
|
|
|
if ($this->_skipFile($file, $dest, 'upgrade'))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s ignored'), $file);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (is_dir($orig))
|
|
{
|
|
// if $dest is not a directory (that can happen), just remove that file
|
|
if (!is_dir($dest) AND file_exists($dest))
|
|
{
|
|
unlink($dest);
|
|
$this->nextQuickInfo[] = sprintf($this->l('[WARNING] File %1$s has been deleted.'), $file);
|
|
}
|
|
if (!file_exists($dest))
|
|
{
|
|
if (mkdir($dest))
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('Directory %1$s created.'), $file);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Error while creating directory %s.'), $dest);
|
|
$this->nextErrors[] = $this->next_desc = sprintf($this->l('Error while creating directory %s.'), $dest);
|
|
return false;
|
|
}
|
|
}
|
|
else // directory already exists
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('Directory %1$s already exists.'), $file);
|
|
return true;
|
|
}
|
|
}
|
|
elseif (is_file($orig))
|
|
{
|
|
if ($this->isTranslationFile($file) && file_exists($dest))
|
|
{
|
|
$type_trad = $this->getTranslationFileType($file);
|
|
$res = $this->mergeTranslationFile($orig, $dest, $type_trad);
|
|
if ($res)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[TRANSLATION] The translation files have been merged into file %1$s.'), $dest);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[TRANSLATION] The translation files have not been merged into file %1$s. Switch to copy %2$s.'), $dest, $dest);
|
|
$this->nextErrors[] = sprintf($this->l('[TRANSLATION] The translation files have not been merged into file %1$s. Switch to copy %2$s.'), $dest, $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->nextQuickInfo[] = sprintf($this->l('Copied %1$s.'), $file);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('error for copying %1$s'), $file);
|
|
$this->nextErrors[] = $this->next_desc = sprintf($this->l('Error while copying file %1$s'), $file);
|
|
return false;
|
|
}
|
|
}
|
|
elseif (is_file($dest))
|
|
{
|
|
if (file_exists($dest))
|
|
unlink($dest);
|
|
$this->nextQuickInfo[] = sprintf('removed file %1$s.', $file);
|
|
return true;
|
|
}
|
|
elseif (is_dir($dest))
|
|
{
|
|
if (strpos($dest, DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR) === false)
|
|
self::deleteDirectory($dest, true);
|
|
$this->nextQuickInfo[] = sprintf('removed dir %1$s.', $file);
|
|
return true;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public function ajaxProcessRollback()
|
|
{
|
|
// 1st, need to analyse what was wrong.
|
|
$this->nextParams = $this->currentParams;
|
|
$this->restoreFilesFilename = $this->restoreName;
|
|
if (!empty($this->restoreName))
|
|
{
|
|
$files = scandir($this->backupPath);
|
|
// find backup filenames, and be sure they exists
|
|
foreach($files as $file)
|
|
if (preg_match('#'.preg_quote('auto-backupfiles_'.$this->restoreName).'#', $file))
|
|
{
|
|
$this->restoreFilesFilename = $file;
|
|
break;
|
|
}
|
|
if (!is_file($this->backupPath.DIRECTORY_SEPARATOR.$this->restoreFilesFilename))
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf('[ERROR] file %s is missing : unable to restore files. Operation aborted.', $this->restoreFilesFilename);
|
|
$this->nextErrors[] = $this->next_desc = sprintf($this->l('[ERROR] File %s is missing: unable to restore files. Operation aborted.'), $this->restoreFilesFilename);
|
|
return false;
|
|
}
|
|
$files = scandir($this->backupPath.DIRECTORY_SEPARATOR.$this->restoreName);
|
|
foreach($files as $file)
|
|
if (preg_match('#auto-backupdb_[0-9]{6}_'.preg_quote($this->restoreName).'#', $file))
|
|
$this->restoreDbFilenames[] = $file;
|
|
|
|
// order files is important !
|
|
if (is_array($this->restoreDbFilenames))
|
|
sort($this->restoreDbFilenames);
|
|
if (count($this->restoreDbFilenames) == 0)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = $this->l('[ERROR] No backup database files found: it would be impossible to restore the database. Operation aborted.');
|
|
$this->nextErrors[] = $this->next_desc = $this->l('[ERROR] No backup database files found: it would be impossible to restore the database. Operation aborted.');
|
|
return false;
|
|
}
|
|
|
|
$this->next = 'restoreFiles';
|
|
$this->next_desc = $this->l('Restoring files ...');
|
|
// remove tmp files related to restoreFiles
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->fromArchiveFileList))
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->fromArchiveFileList);
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList))
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList);
|
|
}
|
|
else
|
|
$this->next = 'noRollbackFound';
|
|
}
|
|
|
|
public function ajaxProcessNoRollbackFound()
|
|
{
|
|
$this->next_desc = $this->l('Nothing to restore');
|
|
$this->next = 'rollbackComplete';
|
|
}
|
|
|
|
/**
|
|
* ajaxProcessRestoreFiles restore the previously saved files,
|
|
* and delete files that weren't archived
|
|
*
|
|
* @return boolean true if succeed
|
|
*/
|
|
public function ajaxProcessRestoreFiles()
|
|
{
|
|
// loop
|
|
$this->next = 'restoreFiles';
|
|
if (!file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->fromArchiveFileList)
|
|
|| !file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList))
|
|
{
|
|
// cleanup current PS tree
|
|
$fromArchive = $this->_listArchivedFiles($this->backupPath.DIRECTORY_SEPARATOR.$this->restoreFilesFilename);
|
|
foreach($fromArchive as $k => $v)
|
|
$fromArchive[$k] = '/'.$v;
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->fromArchiveFileList, base64_encode(serialize($fromArchive)));
|
|
// get list of files to remove
|
|
$toRemove = $this->_listFilesToRemove();
|
|
// 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)
|
|
$toRemove[$k] = str_replace($this->prodRootDir, '', $v);
|
|
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s file(s) will be removed before restoring the backup files.'), count($toRemove));
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList, base64_encode(serialize($toRemove)));
|
|
|
|
if ($fromArchive === false || $toRemove === false)
|
|
{
|
|
if (!$fromArchive)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] Backup file %s does not exist.'), $this->fromArchiveFileList);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] Backup file %s does not exist.'), $this->fromArchiveFileList);
|
|
}
|
|
if (!$toRemove)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] File "%s" does not exist.'), $this->toRemoveFileList);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] File "%s" does not exist.'), $this->toRemoveFileList);
|
|
}
|
|
$this->next_desc = $this->l('Unable to remove upgraded files.');
|
|
$this->next = 'error';
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// first restoreFiles step
|
|
if (!isset($toRemove))
|
|
$toRemove = unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList)));
|
|
|
|
if (count($toRemove) > 0)
|
|
{
|
|
for($i=0;$i<self::$loopRestoreFiles ;$i++)
|
|
{
|
|
if (count($toRemove) <= 0)
|
|
{
|
|
$this->stepDone = true;
|
|
$this->status = 'ok';
|
|
$this->next = 'restoreFiles';
|
|
$this->next_desc = $this->l('Files from upgrade has been removed.');
|
|
$this->nextQuickInfo[] = $this->l('Files from upgrade has been removed.');
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList, base64_encode(serialize($toRemove)));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$filename = array_shift($toRemove);
|
|
$file = rtrim($this->prodRootDir, DIRECTORY_SEPARATOR).$filename;
|
|
if (file_exists($file))
|
|
{
|
|
if (is_file($file))
|
|
{
|
|
@chmod($file, 0777); // NT ?
|
|
if (@unlink($file))
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s files removed'), $filename);
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = sprintf($this->l('Error when removing %1$s.'), $filename);
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %s not removed.'), $filename);
|
|
$this->nextErrors[] = sprintf($this->l('File %s not removed.'), $filename);
|
|
return false;
|
|
}
|
|
}
|
|
elseif (is_dir($file))
|
|
{
|
|
if ($this->isDirEmpty($file))
|
|
{
|
|
self::deleteDirectory($file, true);
|
|
$this->nextQuickInfo[] = sprintf($this->l('[NOTICE] %s deleted.'), $filename);
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = sprintf($this->l('[NOTICE] Directory %s skipped (directory not empty).'), $filename);
|
|
}
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = sprintf($this->l('[NOTICE] %s does not exist'), $filename);
|
|
}
|
|
}
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRemoveFileList, base64_encode(serialize($toRemove)));
|
|
if (count($toRemove))
|
|
$this->next_desc = sprintf($this->l('%s file(s) left to remove.'), count($toRemove));
|
|
$this->next = 'restoreFiles';
|
|
return true;
|
|
}
|
|
|
|
|
|
// very second restoreFiles step : extract backup
|
|
// if (!isset($fromArchive))
|
|
// $fromArchive = unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->fromArchiveFileList)));
|
|
$filepath = $this->backupPath.DIRECTORY_SEPARATOR.$this->restoreFilesFilename;
|
|
$destExtract = $this->prodRootDir;
|
|
if ($this->ZipExtract($filepath, $destExtract))
|
|
{
|
|
$this->next = 'restoreDb';
|
|
$this->next_desc = $this->l('Files restored. Now restoring database...');
|
|
// get new file list
|
|
$this->nextQuickInfo[] = $this->l('Files restored.');
|
|
// once it's restored, do not delete the archive file. This has to be done manually
|
|
// and we do not empty the var, to avoid infinite loop.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->next_desc = sprintf($this->l('Unable to extract file %1$s into directory %2$s .'), $filepath, $destExtract);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function isDirEmpty($dir, $ignore = array('.svn', '.git'))
|
|
{
|
|
$array_ignore = array_merge(array('.', '..'), $ignore);
|
|
$content = scandir($dir);
|
|
foreach($content as $filename)
|
|
if (!in_array($filename, $array_ignore))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete directory and subdirectories
|
|
*
|
|
* @param string $dirname Directory name
|
|
*/
|
|
public static function deleteDirectory($dirname, $delete_self = true)
|
|
{
|
|
return Tools14::deleteDirectory($dirname, $delete_self);
|
|
}
|
|
/**
|
|
* try to restore db backup file
|
|
*/
|
|
public function ajaxProcessRestoreDb()
|
|
{
|
|
$skip_ignore_tables = false;
|
|
$ignore_stats_table = array(
|
|
_DB_PREFIX_.'connections',
|
|
_DB_PREFIX_.'connections_page',
|
|
_DB_PREFIX_.'connections_source',
|
|
_DB_PREFIX_.'guest',
|
|
_DB_PREFIX_.'statssearch'
|
|
);
|
|
$this->nextParams['dbStep'] = $this->currentParams['dbStep'];
|
|
$start_time = time();
|
|
$db = $this->db;
|
|
$listQuery = array();
|
|
$errors = array();
|
|
|
|
// deal with running backup rest if exist
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList))
|
|
$listQuery = unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList)));
|
|
|
|
// deal with the next files stored in restoreDbFilenames
|
|
if (empty($listQuery) && is_array($this->restoreDbFilenames) && count($this->restoreDbFilenames) > 0)
|
|
{
|
|
$currentDbFilename = array_shift($this->restoreDbFilenames);
|
|
if (!preg_match('#auto-backupdb_([0-9]{6})_#', $currentDbFilename, $match))
|
|
{
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->nextQuickInfo[] = $this->next_desc = $this->l(sprintf('%s: File format does not match.', $currentDbFilename));
|
|
return false;
|
|
}
|
|
$this->nextParams['dbStep'] = $match[1];
|
|
$backupdb_path = $this->backupPath.DIRECTORY_SEPARATOR.$this->restoreName;
|
|
|
|
$dot_pos = strrpos($currentDbFilename, '.');
|
|
$fileext = substr($currentDbFilename, $dot_pos+1);
|
|
$requests = array();
|
|
$content = '';
|
|
|
|
$this->nextQuickInfo[] = $this->l(sprintf('Opening backup database file %1s in %2s mode', $currentDbFilename, $fileext));
|
|
|
|
switch ($fileext)
|
|
{
|
|
case 'bz':
|
|
case 'bz2':
|
|
if ($fp = bzopen($backupdb_path.DIRECTORY_SEPARATOR.$currentDbFilename, 'r'))
|
|
while(!feof($fp))
|
|
$content .= bzread($fp, 4096);
|
|
else
|
|
die("error when trying to open in bzmode"); // @todo : handle error
|
|
break;
|
|
case 'gz':
|
|
if ($fp = gzopen($backupdb_path.DIRECTORY_SEPARATOR.$currentDbFilename, 'r'))
|
|
while(!feof($fp))
|
|
$content .= gzread($fp, 4096);
|
|
gzclose($fp);
|
|
break;
|
|
default :
|
|
if ($fp = fopen($backupdb_path.DIRECTORY_SEPARATOR.$currentDbFilename, 'r'))
|
|
while(!feof($fp))
|
|
$content .= fread($fp, 4096);
|
|
fclose($fp);
|
|
}
|
|
$currentDbFilename = '';
|
|
|
|
if (empty($content))
|
|
{
|
|
$this->nextErrors[] = $this->l('Database backup is empty.');
|
|
$this->nextQuickInfo[] = $this->l('Database backup is empty.');
|
|
$this->next = 'rollback';
|
|
return false;
|
|
}
|
|
|
|
// 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);
|
|
|
|
// @TODO : drop all old tables (created in upgrade)
|
|
// This part has to be executed only onces (if dbStep=0)
|
|
if ($this->nextParams['dbStep'] == '1')
|
|
{
|
|
$all_tables = $this->db->executeS('SHOW TABLES LIKE "'._DB_PREFIX_.'%"', true, false);
|
|
$drops = array();
|
|
foreach ($all_tables as $k => $v)
|
|
{
|
|
$table = array_shift($v);
|
|
$drops['drop table '.$k] = 'DROP TABLE IF EXISTS `'.bqSql($table).'`';
|
|
$drops['drop view '.$k] = 'DROP VIEW IF EXISTS `'.bqSql($table).'`';
|
|
}
|
|
unset($all_tables);
|
|
$listQuery = array_merge($drops, $listQuery);
|
|
}
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList, base64_encode(serialize($listQuery)));
|
|
}
|
|
// @todo : error if listQuery is not an array (that can happen if toRestoreQueryList is empty for example)
|
|
$time_elapsed = time() - $start_time;
|
|
if (is_array($listQuery) && (count($listQuery) > 0))
|
|
{
|
|
do
|
|
{
|
|
if (count($listQuery) == 0)
|
|
{
|
|
if (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList))
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList);
|
|
|
|
if (count($this->restoreDbFilenames))
|
|
$this->next_desc = sprintf($this->l('Database restoration file %1$s done. %2$s file(s) left...'), $this->nextParams['dbStep'], count($this->restoreDbFilenames));
|
|
else
|
|
$this->next_desc = sprintf($this->l('Database restoration file %1$s done.'), $this->nextParams['dbStep']);
|
|
|
|
$this->nextQuickInfo[] = $this->next_desc;
|
|
$this->stepDone = true;
|
|
$this->status = 'ok';
|
|
$this->next = 'restoreDb';
|
|
if (count($this->restoreDbFilenames) == 0)
|
|
{
|
|
$this->next = 'rollbackComplete';
|
|
$this->nextQuickInfo[] = $this->next_desc = $this->l('Database has been restored.');
|
|
}
|
|
return true;
|
|
}
|
|
// filesForBackup already contains all the correct files
|
|
if (count($listQuery) == 0)
|
|
continue;
|
|
|
|
$query = array_shift($listQuery);
|
|
if (!empty($query))
|
|
if (!$this->db->execute($query, false))
|
|
{
|
|
if (is_array($listQuery))
|
|
$listQuery = array_unshift($listQuery, $query);
|
|
$this->nextErrors[] = $this->l('[SQL ERROR] ').$query.' - '.$this->db->getMsgError();
|
|
$this->nextQuickInfo[] = $this->l('[SQL ERROR] ').$query.' - '.$this->db->getMsgError();
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->next_desc = $this->l('Error during database restoration');
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList);
|
|
return false;
|
|
}
|
|
// note : theses queries can be too big and can cause issues for display
|
|
// else
|
|
// $this->nextQuickInfo[] = '[OK] '.$query;
|
|
|
|
$time_elapsed = time() - $start_time;
|
|
}
|
|
while ($time_elapsed < self::$loopRestoreQueryTime);
|
|
|
|
$queries_left = count($listQuery);
|
|
|
|
if ($queries_left > 0)
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList, base64_encode(serialize($listQuery)));
|
|
elseif (file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList))
|
|
unlink($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toRestoreQueryList);
|
|
|
|
$this->stepDone = false;
|
|
$this->next = 'restoreDb';
|
|
$this->nextQuickInfo[] = $this->next_desc = sprintf($this->l('%1$s queries left for file %2$s...'), $queries_left, $this->nextParams['dbStep']);
|
|
unset($query);
|
|
unset($listQuery);
|
|
}
|
|
else
|
|
{
|
|
$this->stepDone = true;
|
|
$this->status = 'ok';
|
|
$this->next = 'rollbackComplete';
|
|
$this->nextQuickInfo[] = $this->next_desc = $this->l('Database restoration done.');
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function ajaxProcessMergeTranslations()
|
|
{
|
|
}
|
|
|
|
public function ajaxProcessBackupDb()
|
|
{
|
|
if (!$this->getConfig('PS_AUTOUP_BACKUP'))
|
|
{
|
|
$this->stepDone = true;
|
|
$this->nextParams['dbStep'] = 0;
|
|
$this->next_desc = sprintf($this->l('Database backup skipped. Now upgrading files...'), $this->backupName);
|
|
$this->next = 'upgradeFiles';
|
|
return true;
|
|
}
|
|
|
|
$relative_backup_path = str_replace(_PS_ROOT_DIR_, '', $this->backupPath);
|
|
$report = '';
|
|
if (!ConfigurationTest::test_dir($relative_backup_path, false, $report))
|
|
{
|
|
$this->next_desc = $this->l('Backup directory is not writable ');
|
|
$this->nextQuickInfo[] = 'Backup directory is not writable ';
|
|
$this->nextErrors[] = 'Backup directory is not writable "'.$this->backupPath.'"';
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
return false;
|
|
}
|
|
|
|
$this->stepDone = false;
|
|
$this->next = 'backupDb';
|
|
$this->nextParams = $this->currentParams;
|
|
$start_time = time();
|
|
|
|
$psBackupAll = true;
|
|
$psBackupDropTable = true;
|
|
if (!$psBackupAll)
|
|
{
|
|
$ignore_stats_table = array(_DB_PREFIX_.'connections',
|
|
_DB_PREFIX_.'connections_page',
|
|
_DB_PREFIX_.'connections_source',
|
|
_DB_PREFIX_.'guest',
|
|
_DB_PREFIX_.'statssearch');
|
|
}
|
|
else
|
|
$ignore_stats_table = array();
|
|
|
|
// INIT LOOP
|
|
if (!file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupDbList))
|
|
{
|
|
if (!is_dir($this->backupPath.DIRECTORY_SEPARATOR.$this->backupName))
|
|
{
|
|
mkdir($this->backupPath.DIRECTORY_SEPARATOR.$this->backupName);
|
|
}
|
|
$this->nextParams['dbStep'] = 0;
|
|
$tablesToBackup = $this->db->executeS('SHOW TABLES LIKE "'._DB_PREFIX_.'%"', true, false);
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupDbList, base64_encode(serialize($tablesToBackup)));
|
|
}
|
|
|
|
if (!isset($tablesToBackup))
|
|
$tablesToBackup = unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupDbList)));
|
|
$found = 0;
|
|
$views = '';
|
|
|
|
// MAIN BACKUP LOOP //
|
|
$written = 0;
|
|
do
|
|
{
|
|
if (!empty($this->nextParams['backup_table']))
|
|
{
|
|
// only insert (schema already done)
|
|
$table = $this->nextParams['backup_table'];
|
|
$lines = $this->nextParams['backup_lines'];
|
|
}
|
|
else
|
|
{
|
|
if (count($tablesToBackup) == 0)
|
|
break;
|
|
$table = current(array_shift($tablesToBackup));
|
|
$this->nextParams['backup_loop_limit'] = 0;
|
|
}
|
|
|
|
if ($written == 0 || $written > self::$max_written_allowed)
|
|
{
|
|
// increment dbStep will increment filename each time here
|
|
$this->nextParams['dbStep']++;
|
|
// new file, new step
|
|
$written = 0;
|
|
if (isset($fp))
|
|
fclose($fp);
|
|
$backupfile = $this->backupPath.DIRECTORY_SEPARATOR.$this->backupName.DIRECTORY_SEPARATOR.$this->backupDbFilename;
|
|
$backupfile = preg_replace("#_XXXXXX_#", '_'.str_pad($this->nextParams['dbStep'], 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->error = 1;
|
|
$this->nextErrors[] = sprintf($this->l('Backup file %s already exists. Operation aborted.'), $backupfile);
|
|
$this->nextQuickInfo[] = sprintf($this->l('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->nextErrors[] = sprintf($this->l('Unable to create backup database file %s.'), addslashes($backupfile));
|
|
$this->nextQuickInfo[] = sprintf($this->l('Unable to create backup database file %s.'), addslashes($backupfile));
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->next_desc = $this->l('Error during database backup.');
|
|
return false;
|
|
}
|
|
|
|
$written += fwrite($fp, '/* Backup ' . $this->nextParams['dbStep'] . ' for ' . Tools14::getHttpHost(false, false) . __PS_BASE_URI__ . "\n * at " . date('r') . "\n */\n");
|
|
$written += fwrite($fp, "\n".'SET NAMES \'utf8\';'."\n\n");
|
|
// end init file
|
|
}
|
|
|
|
|
|
// Skip tables which do not start with _DB_PREFIX_
|
|
if (strlen($table) <= strlen(_DB_PREFIX_) || strncmp($table, _DB_PREFIX_, strlen(_DB_PREFIX_)) != 0)
|
|
continue;
|
|
|
|
// start schema : drop & create table only
|
|
if (empty($this->currentParams['backup_table']))
|
|
{
|
|
// Export the table schema
|
|
$schema = $this->db->executeS('SHOW CREATE TABLE `' . $table . '`', true, false);
|
|
|
|
if (count($schema) != 1 ||
|
|
!((isset($schema[0]['Table']) && isset($schema[0]['Create Table']))
|
|
|| (isset($schema[0]['View']) && isset($schema[0]['Create View']))))
|
|
{
|
|
fclose($fp);
|
|
if (file_exists($backupfile))
|
|
unlink($backupfile);
|
|
$this->nextErrors[] = sprintf($this->l('An error occurred while backing up. Unable to obtain the schema of %s'), $table);
|
|
$this->nextQuickInfo[] = sprintf($this->l('An error occurred while backing up. Unable to obtain the schema of %s'), $table);
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->next_desc = $this->l('Error during database backup.');
|
|
return false;
|
|
}
|
|
|
|
// case view
|
|
if (isset($schema[0]['View']))
|
|
{
|
|
$views .= '/* Scheme for view' . $schema[0]['View'] . " */\n";
|
|
if ($psBackupDropTable)
|
|
{
|
|
// If some *upgrade* transform a table in a view, drop both just in case
|
|
$views .= 'DROP VIEW IF EXISTS `'.$schema[0]['View'].'`;'."\n";
|
|
$views .= 'DROP TABLE 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);
|
|
}
|
|
// case table
|
|
elseif (isset($schema[0]['Table']))
|
|
{
|
|
// Case common table
|
|
$written += fwrite($fp, '/* Scheme for table ' . $schema[0]['Table'] . " */\n");
|
|
if ($psBackupDropTable && !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 VIEW IF EXISTS `'.$schema[0]['Table'].'`;'."\n");
|
|
$written += fwrite($fp, 'DROP TABLE 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->nextParams['backup_table'] = $table;
|
|
$lines = $this->nextParams['backup_lines'] = explode("\n", $schema[0]['Create Table']);
|
|
}
|
|
}
|
|
// end of schema
|
|
|
|
// POPULATE TABLE
|
|
if (!in_array($table, $ignore_stats_table))
|
|
{
|
|
do
|
|
{
|
|
$backup_loop_limit = $this->nextParams['backup_loop_limit'];
|
|
$data = $this->db->executeS('SELECT * FROM `'.$table.'` LIMIT '.(int)$backup_loop_limit.',200', false, false);
|
|
$this->nextParams['backup_loop_limit'] += 200;
|
|
$sizeof = $this->db->numRows();
|
|
if ($data && ($sizeof > 0))
|
|
{
|
|
// Export the table data
|
|
$written += fwrite($fp, 'INSERT INTO `'.$table."` VALUES\n");
|
|
$i = 1;
|
|
while ($row = $this->db->nextRow($data))
|
|
{
|
|
// this starts a row
|
|
$s = '(';
|
|
foreach ($row AS $field => $value)
|
|
{
|
|
$tmp = "'" . $this->db->escape($value, true) . "',";
|
|
if ($tmp != "'',")
|
|
$s .= $tmp;
|
|
else
|
|
{
|
|
foreach ($lines as $line)
|
|
if (strpos($line, '`'.$field.'`') !== false)
|
|
{
|
|
if (preg_match('/(.*NOT NULL.*)/Ui', $line))
|
|
$s .= "'',";
|
|
else
|
|
$s .= 'NULL,';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$s = rtrim($s, ',');
|
|
|
|
if ($i < $sizeof)
|
|
$s .= "),\n";
|
|
else
|
|
$s .= ");\n";
|
|
|
|
$written += fwrite($fp, $s);
|
|
++$i;
|
|
}
|
|
$time_elapsed = time() - $start_time;
|
|
}
|
|
else
|
|
{
|
|
unset($this->nextParams['backup_table']);
|
|
unset($this->currentParams['backup_table']);
|
|
break;
|
|
}
|
|
}
|
|
while(($time_elapsed < self::$loopBackupDbTime) && ($written < self::$max_written_allowed));
|
|
}
|
|
$found++;
|
|
$time_elapsed = time() - $start_time;
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s table has been saved.'), $table);
|
|
}
|
|
while(($time_elapsed < self::$loopBackupDbTime) && ($written < self::$max_written_allowed));
|
|
|
|
// end of loop
|
|
if (isset($fp))
|
|
{
|
|
fclose($fp);
|
|
unset($fp);
|
|
}
|
|
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupDbList, base64_encode(serialize($tablesToBackup)));
|
|
|
|
if (count($tablesToBackup) > 0)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s tables have been saved.'), $found);
|
|
$this->next = 'backupDb';
|
|
$this->stepDone = false;
|
|
if (count($tablesToBackup))
|
|
{
|
|
$this->next_desc = sprintf($this->l('Database backup: %s table(s) left...'), count($tablesToBackup));
|
|
$this->nextQuickInfo[] = sprintf($this->l('Database backup: %s table(s) left...'), count($tablesToBackup));
|
|
}
|
|
return true;
|
|
}
|
|
if ($found == 0 && !empty($backupfile))
|
|
{
|
|
if (file_exists($backupfile))
|
|
unlink($backupfile);
|
|
$this->nextErrors[] = sprintf($this->l('No valid tables were found to back up. Backup of file %s canceled.'), $backupfile);
|
|
$this->nextQuickInfo[] = sprintf($this->l('No valid tables were found to back up. Backup of file %s canceled.'), $backupfile);
|
|
$this->error = 1;
|
|
$this->next_desc = sprintf($this->l('Error during database backup for file %s.'), $backupfile);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
unset($this->nextParams['backup_loop_limit']);
|
|
unset($this->nextParams['backup_lines']);
|
|
unset($this->nextParams['backup_table']);
|
|
if ($found)
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s tables have been saved.'), $found);
|
|
$this->stepDone = true;
|
|
// reset dbStep at the end of this step
|
|
$this->nextParams['dbStep'] = 0;
|
|
|
|
$this->next_desc = sprintf($this->l('Database backup done in filename %s. Now upgrading files...'), $this->backupName);
|
|
$this->next = 'upgradeFiles';
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public function ajaxProcessBackupFiles()
|
|
{
|
|
if (!$this->getConfig('PS_AUTOUP_BACKUP'))
|
|
{
|
|
$this->stepDone = true;
|
|
$this->next = 'backupDb';
|
|
$this->next_desc = 'File backup skipped.';
|
|
return true;
|
|
}
|
|
|
|
$this->nextParams = $this->currentParams;
|
|
$this->stepDone = false;
|
|
if (empty($this->backupFilesFilename))
|
|
{
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->next_desc = $this->l('Error during backupFiles');
|
|
$this->nextErrors[] = $this->l('[ERROR] backupFiles filename has not been set');
|
|
$this->nextQuickInfo[] = $this->l('[ERROR] backupFiles filename has not been set');
|
|
return false;
|
|
}
|
|
|
|
if (empty($this->nextParams['filesForBackup']))
|
|
{
|
|
// @todo : only add files and dir listed in "originalPrestashopVersion" list
|
|
$filesToBackup = $this->_listFilesInDir($this->prodRootDir, 'backup', false);
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupFileList, base64_encode(serialize($filesToBackup)));
|
|
if (count($this->toBackupFileList))
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s Files to backup.'), count($this->toBackupFileList));
|
|
$this->nextParams['filesForBackup'] = $this->toBackupFileList;
|
|
|
|
// delete old backup, create new
|
|
if (!empty($this->backupFilesFilename) && file_exists($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename))
|
|
unlink($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename);
|
|
|
|
$this->nextQuickInfo[] = sprintf($this->l('backup files initialized in %s'), $this->backupFilesFilename);
|
|
}
|
|
$filesToBackup = unserialize(base64_decode(file_get_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupFileList)));
|
|
|
|
$this->next = 'backupFiles';
|
|
if (count($this->toBackupFileList))
|
|
$this->next_desc = sprintf($this->l('Backup files in progress. %d files left'), count($filesToBackup));
|
|
if (is_array($filesToBackup))
|
|
{
|
|
$res = false;
|
|
if (!self::$force_pclZip && class_exists('ZipArchive', false))
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Using class ZipArchive...');
|
|
$zip_archive = true;
|
|
$zip = new ZipArchive();
|
|
$res = $zip->open($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename, ZIPARCHIVE::CREATE);
|
|
if ($res)
|
|
$res = (isset($zip->filename) && $zip->filename) ? true : false;
|
|
}
|
|
|
|
if(!$res)
|
|
{
|
|
$zip_archive = false;
|
|
$this->nextQuickInfo[] = $this->l('Using class PclZip...');
|
|
// pclzip can be already loaded (server configuration)
|
|
if (!class_exists('PclZip',false))
|
|
require_once(dirname(__FILE__).'/classes/pclzip.lib.php');
|
|
$zip = new PclZip($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename);
|
|
$res = true;
|
|
}
|
|
|
|
if($zip && $res)
|
|
{
|
|
$this->next = 'backupFiles';
|
|
$this->stepDone = false;
|
|
$files_to_add = array();
|
|
$close_flag = true;
|
|
for ($i = 0; $i < self::$loopBackupFiles; $i++)
|
|
{
|
|
if (count($filesToBackup) <= 0)
|
|
{
|
|
$this->stepDone = true;
|
|
$this->status = 'ok';
|
|
$this->next = 'backupDb';
|
|
$this->next_desc = $this->l('All files saved. Now backing up database');
|
|
$this->nextQuickInfo[] = $this->l('All files have been added to archive.', 'AdminSelfUpgrade', true);
|
|
break;
|
|
}
|
|
// filesForBackup already contains all the correct files
|
|
$file = array_shift($filesToBackup);
|
|
|
|
$archiveFilename = ltrim(str_replace($this->prodRootDir, '', $file), DIRECTORY_SEPARATOR);
|
|
$size = filesize($file);
|
|
if ($size < self::$maxBackupFileSize)
|
|
{
|
|
if ($zip_archive)
|
|
{
|
|
$added_to_zip = $zip->addFile($file, $archiveFilename);
|
|
if ($added_to_zip)
|
|
{
|
|
if ($filesToBackup)
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s files left.', 'AdminSelfUpgrade', true), $archiveFilename, count($filesToBackup));
|
|
}
|
|
else
|
|
{
|
|
// if an error occur, it's more safe to delete the corrupted backup
|
|
$zip->close();
|
|
if (file_exists($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename))
|
|
unlink($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename);
|
|
$this->next = 'error';
|
|
$this->error = 1;
|
|
$this->next_desc = sprintf($this->l('Error when trying to add %1$s to archive %2$s.', 'AdminSelfUpgrade', true), $file, $archiveFilename);
|
|
$close_flag = false;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$files_to_add[] = $file;
|
|
if (count($filesToBackup))
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %3$s) added to archive. %2$s files left.' , 'AdminSelfUpgrade', true), $archiveFilename, count($filesToBackup), $size);
|
|
else
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %2$s) added to archive.', 'AdminSelfUpgrade', true), $archiveFilename, $size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %1$s (size: %2$s) has been skipped during backup.', 'AdminSelfUpgrade', true), $archiveFilename, $size);
|
|
$this->nextErrors[] = sprintf($this->l('File %1$s (size: %2$s) has been skipped during backup.', 'AdminSelfUpgrade', true), $archiveFilename, $size);
|
|
}
|
|
}
|
|
|
|
if ($zip_archive && $close_flag && is_object($zip))
|
|
$zip->close();
|
|
elseif(!$zip_archive)
|
|
{
|
|
$added_to_zip = $zip->add($files_to_add, PCLZIP_OPT_REMOVE_PATH, $this->prodRootDir);
|
|
if($added_to_zip)
|
|
$zip->privCloseFd();
|
|
if (!$added_to_zip)
|
|
{
|
|
if (file_exists($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename))
|
|
unlink($this->backupPath.DIRECTORY_SEPARATOR.$this->backupFilesFilename);
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] Error on backup using PclZip: %s.'), $zip->errorInfo(true));
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] Error on backup using PclZip: %s.'), $zip->errorInfo(true));
|
|
$this->next = 'error';
|
|
}
|
|
}
|
|
|
|
file_put_contents($this->autoupgradePath.DIRECTORY_SEPARATOR.$this->toBackupFileList, base64_encode(serialize($filesToBackup)));
|
|
return true;
|
|
}
|
|
else{
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('unable to open archive');
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->stepDone = true;
|
|
$this->next = 'backupDb';
|
|
$this->next_desc = $this->l('All files saved. Now backing up database.');
|
|
return true;
|
|
}
|
|
// 4) save for display.
|
|
}
|
|
|
|
|
|
private function _removeOneSample($removeList)
|
|
{
|
|
if (is_array($removeList) AND count($removeList) > 0)
|
|
{
|
|
if (file_exists($removeList[0]) AND unlink($removeList[0]))
|
|
{
|
|
$item = str_replace($this->prodRootDir, '', array_shift($removeList));
|
|
$this->next = 'removeSamples';
|
|
$this->nextParams['removeList'] = $removeList;
|
|
if(count($removeList) > 0)
|
|
$this->nextQuickInfo[] = sprintf($this->l('%1$s items removed. %2$s items left.'), $item, count($removeList));
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextParams['removeList'] = $removeList;
|
|
$this->nextQuickInfo[] = sprintf($this->l('Error while removing item %1$s, %2$s items left.'), $removeList[0], count($removeList));
|
|
$this->nextErrors[] = sprintf($this->l('Error while removing item %1$s, %2$s items left.'), $removeList[0], count($removeList));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Remove all sample files.
|
|
*
|
|
* @return boolean true if succeed
|
|
*/
|
|
public function ajaxProcessRemoveSamples()
|
|
{
|
|
$this->stepDone = false;
|
|
// remove all sample pics in img subdir
|
|
if (!isset($this->currentParams['removeList']))
|
|
{
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/c', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/cms', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/l', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/m', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/os', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/p', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/s', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/scenes', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/st', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img/su', '.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img', '404.gif');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img', 'favicon.ico');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img', 'logo.jpg');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/img', 'logo_stores.gif');
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/modules/editorial', 'homepage_logo.jpg');
|
|
// remove all override present in the archive
|
|
$this->_listSampleFiles($this->latestPath.'/prestashop/override', '.php');
|
|
|
|
if (count($this->sampleFileList) > 0)
|
|
$this->nextQuickInfo[] = sprintf($this->l('Starting to remove %1$s sample files'), count($this->sampleFileList));
|
|
$this->nextParams['removeList'] = $this->sampleFileList;
|
|
}
|
|
|
|
$resRemove = true;
|
|
for($i = 0; $i < self::$loopRemoveSamples; $i++)
|
|
{
|
|
if (count($this->nextParams['removeList']) <= 0 )
|
|
{
|
|
$this->stepDone = true;
|
|
if ($this->getConfig('skip_backup'))
|
|
{
|
|
$this->next = 'upgradeFiles';
|
|
$this->next_desc = $this->l('All sample files removed. Backup process skipped. Now upgrading files.');
|
|
}
|
|
else
|
|
{
|
|
$this->next = 'backupFiles';
|
|
$this->next_desc = $this->l('All sample files removed. Now backing up files.');
|
|
}
|
|
// break the loop, all sample already removed
|
|
return true;
|
|
}
|
|
$resRemove &= $this->_removeOneSample($this->nextParams['removeList']);
|
|
if (!$resRemove)
|
|
break;
|
|
}
|
|
|
|
return $resRemove;
|
|
}
|
|
|
|
/**
|
|
* download PrestaShop archive according to the chosen channel
|
|
*
|
|
* @access public
|
|
*/
|
|
public function ajaxProcessDownload()
|
|
{
|
|
if (ConfigurationTest::test_fopen() || ConfigurationTest::test_curl())
|
|
{
|
|
if (!is_object($this->upgrader))
|
|
$this->upgrader = new Upgrader();
|
|
// regex optimization
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
$this->upgrader->channel = $this->getConfig('channel');
|
|
$this->upgrader->branch = $matches[1];
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$this->upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$this->upgrader->checkPSVersion(false, array('minor'));
|
|
|
|
if ($this->upgrader->channel == 'private')
|
|
{
|
|
$this->upgrader->link = $this->getConfig('private_release_link');
|
|
$this->upgrader->md5 = $this->getConfig('private_release_md5');
|
|
}
|
|
$this->nextQuickInfo[] = sprintf($this->l('downloading from %s'), $this->upgrader->link);
|
|
$this->nextQuickInfo[] = sprintf($this->l('file will be saved in %s'), $this->getFilePath());
|
|
if (file_exists($this->downloadPath))
|
|
{
|
|
self::deleteDirectory($this->downloadPath, false);
|
|
$this->nextQuickInfo[] = $this->l('download directory has been emptied');
|
|
}
|
|
$report = '';
|
|
$relative_download_path = str_replace(_PS_ROOT_DIR_, '', $this->downloadPath);
|
|
if (ConfigurationTest::test_dir($relative_download_path, false, $report))
|
|
{
|
|
$res = $this->upgrader->downloadLast($this->downloadPath, $this->destDownloadFilename);
|
|
if ($res)
|
|
{
|
|
$md5file = md5_file(realpath($this->downloadPath).DIRECTORY_SEPARATOR.$this->destDownloadFilename);
|
|
if ($md5file == $this->upgrader->md5)
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Download complete.');
|
|
$this->next = 'unzip';
|
|
$this->next_desc = $this->l('Download complete. Now extracting...');
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('Download complete but MD5 sum does not match (%s).'), $md5file);
|
|
$this->nextErrors[] = sprintf($this->l('Download complete but MD5 sum does not match (%s).'), $md5file);
|
|
$this->next = 'error';
|
|
$this->next_desc = $this->l('Download complete but MD5 sum does not match (%s). Operation aborted.');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($this->upgrader->channel == 'private')
|
|
{
|
|
$this->next_desc = $this->l('Error during download. The private key may be incorrect.');
|
|
$this->nextQuickInfo[] = $this->l('Error during download. The private key may be incorrect.');
|
|
$this->nextErrors[] = $this->l('Error during download. The private key may be incorrect.');
|
|
}
|
|
else
|
|
{
|
|
$this->next_desc = $this->l('Error during download');
|
|
$this->nextQuickInfo[] = $this->l('Error during download');
|
|
$this->nextErrors[] = $this->l('Error during download');
|
|
}
|
|
$this->next = 'error';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->next_desc = $this->l('Download directory is not writable.');
|
|
$this->nextQuickInfo[] = $this->l('Download directory is not writable.');
|
|
$this->nextErrors[] = sprintf($this->l('Download directory %s is not writable.'), $this->downloadPath);
|
|
$this->next = 'error';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('You need allow_url_fopen or cURL enabled for automatic download to work.');
|
|
$this->nextErrors[] = $this->l('You need allow_url_fopen or cURL enabled for automatic download to work.');
|
|
$this->next = 'error';
|
|
$this->next_desc = sprintf($this->l('You need allow_url_fopen or cURL enabled for automatic download to work. You can also manually upload it in filepath %s.'), $this->getFilePath());
|
|
}
|
|
}
|
|
|
|
public function buildAjaxResult()
|
|
{
|
|
$return = array();
|
|
|
|
$return['error'] = $this->error;
|
|
$return['stepDone'] = $this->stepDone;
|
|
$return['next'] = $this->next;
|
|
$return['status'] = $this->next == 'error' ? 'error' : 'ok';
|
|
$return['next_desc'] = $this->next_desc;
|
|
|
|
$this->nextParams['config'] = $this->getConfig();
|
|
|
|
foreach($this->ajaxParams as $v)
|
|
if(property_exists($this,$v))
|
|
$this->nextParams[$v] = $this->$v;
|
|
else
|
|
$this->nextQuickInfo[] = sprintf($this->l('[WARNING] Property %s is missing'), $v);
|
|
|
|
$return['nextParams'] = $this->nextParams;
|
|
if (!isset($return['nextParams']['dbStep']))
|
|
$return['nextParams']['dbStep'] = 0;
|
|
|
|
$return['nextParams']['typeResult'] = $this->nextResponseType;
|
|
|
|
$return['nextQuickInfo'] = $this->nextQuickInfo;
|
|
$return['nextErrors'] = $this->nextErrors;
|
|
return Tools14::jsonEncode($return);
|
|
}
|
|
|
|
public function ajaxPreProcess()
|
|
{
|
|
/* PrestaShop demo mode */
|
|
if (defined('_PS_MODE_DEMO_') && _PS_MODE_DEMO_)
|
|
return;
|
|
|
|
/* PrestaShop demo mode*/
|
|
if (!empty($_POST['responseType']) && $_POST['responseType'] == 'json')
|
|
header('Content-Type: application/json');
|
|
|
|
if (!empty($_POST['action']))
|
|
{
|
|
$action = $_POST['action'];
|
|
if (isset(self::$skipAction[$action]))
|
|
{
|
|
$this->next = self::$skipAction[$action];
|
|
$this->nextQuickInfo[] = $this->next_desc = sprintf($this->l('action %s skipped'),$action);
|
|
unset($_POST['action']);
|
|
}
|
|
else if (!method_exists(get_class($this), 'ajaxProcess'.$action))
|
|
{
|
|
$this->next_desc = sprintf($this->l('action "%1$s" not found'), $action);
|
|
$this->next = 'error';
|
|
$this->error = '1';
|
|
}
|
|
}
|
|
|
|
if (!method_exists('Tools', 'apacheModExists') || Tools14::apacheModExists('evasive'))
|
|
sleep(1);
|
|
}
|
|
|
|
private function _getJsErrorMsgs()
|
|
{
|
|
$INSTALL_VERSION = $this->install_version;
|
|
$ret = '
|
|
var txtError = new Array();
|
|
txtError[0] = "'.$this->l('Required field').'";
|
|
txtError[1] = "'.$this->l('Too long!').'";
|
|
txtError[2] = "'.$this->l('Fields are different!').'";
|
|
txtError[3] = "'.$this->l('This email adress is wrong!').'";
|
|
txtError[4] = "'.$this->l('Impossible to send the email!').'";
|
|
txtError[5] = "'.$this->l('Cannot create settings file, if /config/settings.inc.php exists, please give the public write permissions to this file, else please create a file named settings.inc.php in config directory.').'";
|
|
txtError[6] = "'.$this->l('Cannot write settings file, please create a file named settings.inc.php in the "config" directory.').'";
|
|
txtError[7] = "'.$this->l('Impossible to upload the file!').'";
|
|
txtError[8] = "'.$this->l('Data integrity is not valided. Hack attempt?').'";
|
|
txtError[9] = "'.$this->l('Impossible to read the content of a MySQL content file.').'";
|
|
txtError[10] = "'.$this->l('Cannot access a MySQL content file.').'";
|
|
txtError[11] = "'.$this->l('Error while inserting data in the database:').'";
|
|
txtError[12] = "'.$this->l('The password is incorrect (alphanumeric string at least 8 characters).').'";
|
|
txtError[14] = "'.$this->l('A Prestashop database already exists, please drop it or change the prefix.').'";
|
|
txtError[15] = "'.$this->l('This is not a valid file name.').'";
|
|
txtError[16] = "'.$this->l('This is not a valid image file.').'";
|
|
txtError[17] = "'.$this->l('Error while creating the /config/settings.inc.php file.').'";
|
|
txtError[18] = "'.$this->l('Error:').'";
|
|
txtError[19] = "'.$this->l('This PrestaShop database already exists. Please revalidate your authentication informations to the database.').'";
|
|
txtError[22] = "'.$this->l('An error occurred while resizing the picture.').'";
|
|
txtError[23] = "'.$this->l('Database connection is available!').'";
|
|
txtError[24] = "'.$this->l('Database Server is available but database is not found').'";
|
|
txtError[25] = "'.$this->l('Database Server is not found. Please verify the login, password and server fields.').'";
|
|
txtError[26] = "'.$this->l('An error occurred while sending email, please verify your parameters.').'";
|
|
txtError[37] = "'.$this->l('Impossible to write the image /img/logo.jpg. If this image already exists, please delete it.').'";
|
|
txtError[38] = "'.$this->l('The uploaded file exceeds the upload_max_filesize directive in php.ini').'";
|
|
txtError[39] = "'.$this->l('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form').'";
|
|
txtError[40] = "'.$this->l('The uploaded file was only partially uploaded').'";
|
|
txtError[41] = "'.$this->l('No file was uploaded.').'";
|
|
txtError[42] = "'.$this->l('Missing a temporary folder').'";
|
|
txtError[43] = "'.$this->l('Failed to write file to disk').'";
|
|
txtError[44] = "'.$this->l('File upload stopped by extension').'";
|
|
txtError[45] = "'.$this->l('Cannot convert your database\'s data to utf-8.').'";
|
|
txtError[46] = "'.$this->l('Invalid shop name').'";
|
|
txtError[47] = "'.$this->l('Your firstname contains some invalid characters').'";
|
|
txtError[48] = "'.$this->l('Your lastname contains some invalid characters').'";
|
|
txtError[49] = "'.$this->l('Your database server does not support the utf-8 charset.').'";
|
|
txtError[50] = "'.$this->l('Your MySQL server doesn\'t support this engine, please use another one like MyISAM').'";
|
|
txtError[51] = "'.$this->l('The file /img/logo.jpg is not writable, please CHMOD 755 this file or CHMOD 777').'";
|
|
txtError[52] = "'.$this->l('Invalid catalog mode').'";
|
|
txtError[999] = "'.$this->l('No error code available').'";
|
|
//upgrader
|
|
txtError[27] = "'.$this->l('This installer is too old.').'";
|
|
txtError[28] = "'.sprintf($this->l('You already have the %s version.'),$INSTALL_VERSION).'";
|
|
txtError[29] = "'.$this->l('There is no older version. Did you delete or rename the config/settings.inc.php file?').'";
|
|
txtError[30] = "'.$this->l('The config/settings.inc.php file was not found. Did you delete or rename this file?').'";
|
|
txtError[31] = "'.$this->l('Cannot find the SQL upgrade files. Please verify that the /install/upgrade/sql folder is not empty.').'";
|
|
txtError[32] = "'.$this->l('No upgrade is possible.').'";
|
|
txtError[33] = "'.$this->l('Error while loading SQL upgrade file.').'";
|
|
txtError[34] = "'.$this->l('Error while inserting content into the database').'";
|
|
txtError[35] = "'.$this->l('Unfortunately,').'";
|
|
txtError[36] = "'.$this->l('SQL errors have occurred.').'";
|
|
txtError[37] = "'.$this->l('The config/defines.inc.php file was not found. Where did you move it?').'";';
|
|
return $ret;
|
|
}
|
|
|
|
public function displayAjax()
|
|
{
|
|
echo $this->buildAjaxResult();
|
|
}
|
|
|
|
protected function getBackupFilesAvailable()
|
|
{
|
|
$array = array();
|
|
$files = scandir($this->backupPath);
|
|
foreach ($files as $file)
|
|
if ($file[0] != '.')
|
|
{
|
|
if (substr($file, 0, 16) == 'auto-backupfiles')
|
|
$array[] = preg_replace('#^auto-backupfiles_(.*-[0-9a-f]{1,8})\..*$#', '$1', $file);
|
|
}
|
|
|
|
return $array;
|
|
}
|
|
|
|
protected function getBackupDbAvailable()
|
|
{
|
|
$array = array();
|
|
|
|
$files = scandir($this->backupPath);
|
|
|
|
foreach($files as $file)
|
|
if ($file[0] == 'V' && is_dir($this->backupPath.DIRECTORY_SEPARATOR.$file))
|
|
{
|
|
$array[] = $file;
|
|
}
|
|
return $array;
|
|
}
|
|
|
|
protected function _displayRollbackForm()
|
|
{
|
|
$backup_available = array_intersect($this->getBackupDbAvailable(), $this->getBackupFilesAvailable());
|
|
if (!$this->getConfig('PS_AUTOUP_BACKUP') && is_array($backup_available) && count($backup_available) && !in_array($this->backupName, $backup_available))
|
|
$this->backupName = end($backup_available);
|
|
$this->_html .= '
|
|
<fieldset style="margin-top:10px">
|
|
<legend><img src="../img/admin/previous.gif"/>'.$this->l('Rollback').'</legend>
|
|
<div id="rollbackForm">
|
|
<p>
|
|
'.$this->l('After upgrading your shop, you can rollback to the previous database and files. Use this function if your theme or an essential module is not working correctly.').'
|
|
</p>
|
|
<br/>
|
|
<div id="rollbackContainer">
|
|
<a disabled="disabled" class="upgradestep button" href="" id="rollback">'.$this->l('Rollback').'</a>
|
|
</div>
|
|
<br/>
|
|
<div id="restoreBackupContainer">
|
|
'.$this->l('Choose your backup:').'
|
|
<select name="restoreName">
|
|
<option value="0">'.$this->l('-- Choose a backup to restore --').'</option>';
|
|
if (is_array($backup_available) && count($backup_available))
|
|
foreach ($backup_available as $backup_name)
|
|
$this->_html .= '<option value="'.$backup_name.'">'.$backup_name.'</option>';
|
|
$this->_html .= '</select>
|
|
</div>
|
|
<div class="clear"> </div>
|
|
</div>
|
|
</fieldset>';
|
|
}
|
|
|
|
/** this returns fieldset containing the configuration points you need to use autoupgrade
|
|
* @return string
|
|
*/
|
|
private function _displayCurrentConfiguration()
|
|
{
|
|
$current_ps_config = $this->getcheckCurrentPsConfig();
|
|
|
|
$this->_html .= '
|
|
<fieldset id="currentConfigurationBlock" class="width autoupgrade" style="float: left; width: 60%; margin-left: 30px;">
|
|
<legend>'.$this->l('The pre-Upgrade checklist').'</legend>';
|
|
if (!$this->configOk())
|
|
$this->_html .= '<div class="clear"><br></div><p class="warn">'.$this->l('The checklist is not OK. You can only upgrade your shop once all indicators are green.').'</p>';
|
|
|
|
$this->_html .= '<div id="currentConfiguration">
|
|
<p>'.$this->l('Before starting the upgrade process, please make sure this checklist is all green.').'</p>
|
|
<table class="table" cellpadding="0" cellspacing="0">';
|
|
$pic_ok = '<img src="../img/admin/enabled.gif" alt="ok"/>';
|
|
$pic_nok = '<img src="../img/admin/disabled.gif" alt="nok"/>';
|
|
$pic_warn = '<img src="../img/admin/warning.gif" alt="warn"/>';
|
|
// module version : checkAutoupgradeLastVersion
|
|
$this->_html .= '
|
|
<tr>
|
|
<td>'.sprintf($this->l('The 1-click upgrade module is up-to-date (your current version is v%s)'), $this->getModuleVersion()).'
|
|
'.($current_ps_config['module_version_ok'] ? '' : ' '.(version_compare(_PS_VERSION_,'1.5.3.0','>') ? '<strong><a href="index.php?controller=AdminModules&token='.Tools14::getAdminTokenLite('AdminModules').'&update=autoupgrade">'.$this->l('Update').'</a></strong> - ' : '').'<strong><a class="_blank" href="http://addons.prestashop.com/en/administration-tools-prestashop-modules/5496-1-click-upgrade-autoupgrade.html">'.$this->l('Download').'</a><strong> ').'
|
|
</td>
|
|
<td>'.($current_ps_config['module_version_ok'] ? $pic_ok : $pic_nok).'</td>
|
|
</tr>';
|
|
|
|
// root : getRootWritable()
|
|
|
|
$this->_html .= '
|
|
<tr>
|
|
<td>'.$this->l('Your store\'s root directory is writable (with appropriate CHMOD permissions)').'</td>
|
|
<td>'.($current_ps_config['root_writable'] ? $pic_ok : $pic_nok.' '.$this->root_writable_report).'</td>
|
|
</tr>';
|
|
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
$report = '';
|
|
ConfigurationTest::test_dir($admin_dir.DIRECTORY_SEPARATOR.$this->autoupgradeDir, true, $report);
|
|
if ($report)
|
|
$this->_html .= '
|
|
<tr>
|
|
<td>'.$this->l('The "/admin/autoupgrade" directory is writable (appropriate CHMOD permissions)').'</td>
|
|
<td>'.($current_ps_config['admin_au_writable'] ? $pic_ok : $pic_nok.' '.$report).'</td>
|
|
</tr>';
|
|
|
|
//check safe_mod
|
|
if (!$safe_mode = @ini_get('safe_mode'))
|
|
$safe_mode = '';
|
|
$safe_mode = in_array(Tools14::strtolower($safe_mode), array(1, 'on'));
|
|
|
|
$this->_html .= '
|
|
<tr><td>'.$this->l('PHP\'s "Safe mode" option is turned off').'</td>
|
|
<td>'.(!$safe_mode ? $pic_ok : $pic_warn).'</td></tr>';
|
|
|
|
$this->_html .= '
|
|
<tr><td>'.$this->l('PHP\'s "allow_url_fopen" option is turned on, or cURL is installed').'</td>
|
|
<td>'.((ConfigurationTest::test_fopen() || ConfigurationTest::test_curl()) ? $pic_ok : $pic_nok).'</td></tr>';
|
|
|
|
// shop enabled
|
|
$this->_html .= '
|
|
<tr><td>'.$this->l('Your store is in maintenance mode').' '.(!$current_ps_config['shop_deactivated'] ? '<br><form method="post" action="'.$this->currentIndex.'&token='.$this->token.'"><input type="submit" class="button" name="putUnderMaintenance" value="'.$this->l('Click here to put your shop under maintenance').'"></form>' : '').'</td>
|
|
<td>'.($current_ps_config['shop_deactivated'] ? $pic_ok : $pic_nok).'</td></tr>';
|
|
|
|
$this->_html .= '
|
|
<tr><td>'.$this->l('PrestaShop\'s caching features are disabled').'</td>
|
|
<td>'.($current_ps_config['cache_deactivated'] ? $pic_ok : $pic_nok).'</td></tr>';
|
|
|
|
if (version_compare(_PS_VERSION_,'1.5.0.0','<'))
|
|
$this->_html .= '
|
|
<tr><td>'.$this->l('The mobile theme is disabled').'</td>
|
|
<td>'.($current_ps_config['test_mobile'] ? $pic_ok : $pic_nok).'</td></tr>';
|
|
|
|
// for informaiton, display time limit
|
|
$max_exec_time = ini_get('max_execution_time');
|
|
$this->_html .= '
|
|
<tr><td>'.sprintf($this->l('PHP\'s max_execution_time setting has a high value or is disabled entirely (current value: %s)'), ($max_exec_time == 0 ? $this->l('unlimited') : sprintf($this->l('%s seconds'), $max_exec_time))).'</td>
|
|
<td>'.($max_exec_time == 0 ? $pic_ok : $pic_warn).'</td></tr>
|
|
</table>
|
|
<p>'.$this->l('Please also make sure you make a full manual backup of your files and database.').'</p>
|
|
</div>
|
|
</fieldset>';
|
|
}
|
|
|
|
public function divChannelInfos($upgrade_info)
|
|
{
|
|
if ($this->getConfig('channel') == 'private')
|
|
{
|
|
$upgrade_info['link'] = $this->getConfig('private_release_link');
|
|
$upgrade_info['md5'] = $this->getConfig('private_release_md5');
|
|
}
|
|
$content = '<div id="channel-infos" ><br/>';
|
|
if (isset($upgrade_info['branch']))
|
|
{
|
|
$content .= '<div style="clear:both">
|
|
<label class="label-small">'.$this->l('branch:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<span class="available">
|
|
<img src="../img/admin/'.(!empty($upgrade_info['available'])?'enabled':'disabled').'.gif" />'
|
|
.' '.(!empty($upgrade_info['available'])?$this->l('available'):$this->l('unavailable')).'
|
|
</span>
|
|
</div></div>';
|
|
}
|
|
$content .= '<div class="all-infos">';
|
|
if (isset($upgrade_info['version_name']))
|
|
$content .= '<div style="clear:both;">
|
|
<label class="label-small">'.$this->l('Name:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<span class="name">'.$upgrade_info['version_name'].' </span></div>
|
|
</div>';
|
|
if (isset($upgrade_info['version_number']))
|
|
$content .= '<div style="clear:both;">
|
|
<label class="label-small">'.$this->l('Version number:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<span class="version">'.$upgrade_info['version_num'].' </span></div>
|
|
</div>';
|
|
if (!empty($upgrade_info['link']))
|
|
{
|
|
$content .= '<div style="clear:both;">
|
|
<label class="label-small">'.$this->l('URL:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<a class="url" href="'.$upgrade_info['link'].'">'.$upgrade_info['link'].'</a>
|
|
</div>
|
|
</div>';
|
|
}
|
|
if (!empty($upgrade_info['md5']))
|
|
$content .= '<div style="clear:both;">
|
|
<label class="label-small">'.$this->l('MD5 hash:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<span class="md5">'.$upgrade_info['md5'].' </span></div></div>';
|
|
|
|
if (!empty($upgrade_info['changelog']))
|
|
$content .= '<div style="clear:both;">
|
|
<label class="label-small">'.$this->l('Changelog:').'</label>
|
|
<div class="margin-form margin-form-small" style="padding-top:5px">
|
|
<a class="changelog" href="'.$upgrade_info['changelog'].'">'.$this->l('see changelog').'</a>
|
|
</div></div>';
|
|
|
|
$content .= '</div></div>';
|
|
return $content;
|
|
}
|
|
|
|
public function getBlockSelectChannel($channel = 'minor')
|
|
{
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
$content = '';
|
|
$opt_channels = array();
|
|
// Hey ! I'm really using a fieldset element to regroup fields ?! !
|
|
$opt_channels[] = '<option id="useMajor" value="major" '.($channel == 'major'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Major release').'</option>';
|
|
$opt_channels[] = '<option id="useMinor" value="minor" '.($channel == 'minor'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Minor release (recommended)').'</option>';
|
|
$opt_channels[] = '<option id="useRC" value="rc" '.($channel == 'rc'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Release candidates').'</option>';
|
|
$opt_channels[] = '<option id="useBeta" value="beta" '.($channel == 'beta'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Beta releases').'</option>';
|
|
$opt_channels[] = '<option id="useAlpha" value="alpha" '.($channel == 'alpha'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Alpha releases').'</option>';
|
|
$opt_channels[] = '<option id="usePrivate" value="private" '.($channel == 'private'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Private release (require link and MD5 hash)').'</option>';
|
|
$opt_channels[] = '<option id="useArchive" value="archive" '.($channel == 'archive'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Local archive').'</option>';
|
|
$opt_channels[] = '<option id="useDirectory" value="directory" '.($channel == 'directory'?'class="current" selected="selected">* ':'>')
|
|
.$this->l('Local directory').'</option>';
|
|
|
|
$content .= '<label class="label-small">'.$this->l('Channel:').'</label><select name="channel" >';
|
|
$content .= implode('', $opt_channels);
|
|
$content .= '</select>';
|
|
$upgrade_info = $this->getInfoForChannel($channel);
|
|
$content .= $this->divChannelInfos($upgrade_info);
|
|
|
|
$content .= '<div id="for-useMinor" ><div class="margin-form margin-form-small">'.$this->l('This option regroup all stable versions.').'</div></div>';
|
|
$content .= '<div id="for-usePrivate">
|
|
<p><label class="label-small">'.$this->l('Link:').'</label>
|
|
<input size="50" type="text" name="private_release_link" value="'.$this->getConfig('private_release_link').'"/> *
|
|
</p>
|
|
<p><label class="label-small">'.$this->l('Hash key:').'</label>
|
|
<input size="32" type="text" name="private_release_md5" value="'.$this->getConfig('private_release_md5').'"/> *
|
|
</p>
|
|
<p><label class="label-small">'.$this->l('Allow major upgrade:').'</label>
|
|
<input type="checkbox" name="private_allow_major" value="1"'.($this->getConfig('private_allow_major')?' checked="checked"':'').'/>
|
|
</p>
|
|
|
|
</div>';
|
|
|
|
$download = $this->downloadPath.DIRECTORY_SEPARATOR;
|
|
$dir = glob($download.'*.zip');
|
|
$content .= '<div id="for-useArchive">';
|
|
if ($dir !== false && count($dir) > 0)
|
|
{
|
|
$archive_filename = $this->getConfig('archive.filename');
|
|
$content .= '<label class="label-small">'.$this->l('Archive to use:').'</label><div><select name="archive_prestashop" >
|
|
<option value="">'.$this->l('choose an archive').'</option>';
|
|
foreach ($dir as $file)
|
|
$content .= '<option '.($archive_filename ? 'selected="selected"' : '').' value="'.str_replace($download, '', $file).'">'.str_replace($download, '', $file).'</option>';
|
|
$content .= '</select> '
|
|
.$this->l('to upgrade for version').' <input type="text" size="10" name="archive_num"
|
|
value="'.($this->getConfig('archive.version_num')?$this->getConfig('archive.version_num'):'').'" /> *
|
|
</div>';
|
|
}
|
|
else
|
|
$content .= '<div class="warn">'.$this->l('No archive found in your admin/autoupgrade/download directory').'</div>';
|
|
|
|
$content .= '<div class="margin-form">'.$this->l('This option will skip the download step.').'</div></div>';
|
|
// $directory_dirname = $this->getConfig('directory.dirname');
|
|
$content .= '<div id="for-useDirectory">
|
|
<p> '.
|
|
sprintf($this->l('The directory %1$s will be used for upgrading to version '),
|
|
'<b>/admin/autoupgrade/latest/prestashop/</b>' ).
|
|
' <input type="text" size="10" name="directory_num"
|
|
value="'.($this->getConfig('directory.version_num')?$this->getConfig('directory.version_num'):'').'" /> <small>(1.6.0.6 for instance)</small> *
|
|
<br/>
|
|
<p>* '
|
|
.$this->l('This option will skip both download and unzip steps and will use admin/autoupgrade/download/prestashop/ as the source directory.').'</div>
|
|
</p>';
|
|
// backupFiles
|
|
// backupDb
|
|
$content .= '<div style="clear:both;">
|
|
<div class="margin-form" style="">
|
|
<input type="button" class="button" value="'.$this->l('Save').'" name="submitConf-channel" />
|
|
</div>
|
|
</div>';
|
|
return $content;
|
|
}
|
|
|
|
public function getBlockConfigurationAdvanced()
|
|
{
|
|
$content = '
|
|
<div>
|
|
<input type="button" class="button" style="float:right" name="btn_adv" value="'.$this->l('More options (Expert mode)').'"/>
|
|
</div>
|
|
<div style="float: left; margin-top: 13px; display:none;" id="configResult"> </div>
|
|
<div class="clear" id="advanced">
|
|
<h3>'.$this->l('Expert mode').'</h3>
|
|
<h4 style="margin-top: 0px;">'.$this->l('Please select your channel:').'</h4>
|
|
<p>'.$this->l('Channels are offering you different ways to perform an upgrade. You can either upload the new version manually or let the 1-Click Upgrade module download it for you.').'<br />'.
|
|
$this->l('The Alpha, Beta and Private channels give you the ability to upgrade to a non-official or unstable release (for testing purposes only).').'<br />'.
|
|
$this->l('By default, you should use the "Minor release" channel which is offering the latest stable version available.').'</p><br />';
|
|
|
|
$config = $this->getConfig();
|
|
$channel = $config['channel'];
|
|
if (empty($channel))
|
|
$channel = Upgrader::DEFAULT_CHANNEL;
|
|
|
|
$content .= $this->getBlockSelectChannel($channel).'
|
|
</div>';
|
|
|
|
return $content;
|
|
}
|
|
|
|
public function displayDevTools()
|
|
{
|
|
$content = '';
|
|
$content .= '<br class="clear"/>';
|
|
$content .= '<fieldset class="autoupgradeSteps"><legend>'.$this->l('Step').'</legend>';
|
|
$content .= '<h4>'.$this->l('Upgrade steps').' : </h4>';
|
|
$content .= '<div>';
|
|
$content .= '<a id="download" class="upgradestep">download</a>';
|
|
$content .= '<a id="unzip" class="upgradestep">unzip</a>'; // unzip in autoupgrade/latest
|
|
$content .= '<a id="removeSamples" class="upgradestep">removeSamples</a>'; // remove samples (iWheel images)
|
|
$content .= '<a id="backupFiles" class="upgradestep">backupFiles</a>'; // backup files
|
|
$content .= '<a id="backupDb" class="upgradestep">backupDb</a>';
|
|
$content .= '<a id="upgradeFiles" class="upgradestep">upgradeFiles</a>';
|
|
$content .= '<a id="upgradeDb" class="upgradestep">upgradeDb</a>';
|
|
$content .= '<a id="upgradeModules" class="upgradestep">upgradeModules</a>';
|
|
$content .= '<a id="cleanDatabase" class="upgradestep">cleanDb</a>';
|
|
$content .= '<a id="upgradeComplete" class="upgradestep">upgradeComplete</a>';
|
|
$content .= '</div></fieldset>';
|
|
|
|
return $content;
|
|
}
|
|
|
|
private function _displayComparisonBlock()
|
|
{
|
|
$this->_html .= '
|
|
<fieldset id="comparisonBlock">
|
|
<legend>'.$this->l('Version comparison').'</legend>
|
|
<b>'.$this->l('PrestaShop Original version').':</b><br/>
|
|
<span id="checkPrestaShopFilesVersion">
|
|
<img id="pleaseWait" src="'.__PS_BASE_URI__.'img/loader.gif"/>
|
|
</span><br/>
|
|
<b>'.$this->l('Differences between versions').':</b><br/>
|
|
<span id="checkPrestaShopModifiedFiles">
|
|
<img id="pleaseWait" src="'.__PS_BASE_URI__.'img/loader.gif"/>
|
|
</span>
|
|
</fieldset>';
|
|
}
|
|
|
|
private function _displayBlockActivityLog()
|
|
{
|
|
$this->_html .= '
|
|
<fieldset id="activityLogBlock" style="display:none">
|
|
<legend><img src="../img/admin/slip.gif" /> '.$this->l('Activity Log').'</legend>
|
|
<p id="upgradeResultCheck"></p>
|
|
<div id="upgradeResultToDoList" style="width:890px!important;"></div>
|
|
<div id="currentlyProcessing" style="display:none;float:left">
|
|
<h4 id="pleaseWait">'.$this->l('Currently processing').' <img class="pleaseWait" src="'.__PS_BASE_URI__.'img/loader.gif"/></h4>
|
|
<div id="infoStep" class="processing" >'.$this->l('Analyzing the situation...').'</div>
|
|
</div>';
|
|
// this block will show errors and important warnings that happens during upgrade
|
|
$this->_html .= '
|
|
<div id="errorDuringUpgrade" style="display:none;float:right">
|
|
<h4>'.$this->l('Errors').'</h4>
|
|
<div id="infoError" class="processing" ></div>';
|
|
$this->_html .= '
|
|
</div>
|
|
<div class="clear"> </div>
|
|
<div id="quickInfo" class="processing"></div>
|
|
</fieldset>';
|
|
}
|
|
/**
|
|
* _displayBlockUpgradeButton
|
|
* display the summary current version / target vesrion + "Upgrade Now" button with a "more options" button
|
|
*
|
|
* @access private
|
|
* @return void
|
|
*/
|
|
private function _displayBlockUpgradeButton()
|
|
{
|
|
global $cookie;
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
|
|
$this->_html .= '
|
|
<fieldset id="upgradeButtonBlock">
|
|
<legend>'.$this->l('Start your Upgrade').'</legend>
|
|
<div class="blocOneClickUpgrade">';
|
|
if (version_compare(_PS_VERSION_, $this->upgrader->version_num, '=='))
|
|
$this->_html .= '<p>'.$this->l('Congratulations, you are already using the latest version available!').'</p>';
|
|
elseif (version_compare(_PS_VERSION_, $this->upgrader->version_num, '>'))
|
|
$this->_html .= '<p>'.$this->l('You come from the future! You are using a more recent version than the latest available!').'</p>';
|
|
$this->_html .= '<table class="table" cellpadding="0" cellspacing="0"><tr><th>'.$this->l('Your current prestashop version').'</th><td>'._PS_VERSION_.'</td></tr>';
|
|
|
|
$channel = $this->getConfig('channel');
|
|
$this->_html .= '<tr><th>'.sprintf($this->l('Latest official version for %1$s channel.'), $channel).'</th>';
|
|
if (!in_array($channel, array('archive', 'directory')))
|
|
{
|
|
if (!empty($this->upgrader->version_num))
|
|
$this->_html .= '<td><b>'.$this->upgrader->version_name.'</b> '.'('. $this->upgrader->version_num.')</td>';
|
|
}
|
|
else
|
|
$this->_html .= '<td>'.$this->l('N/A').'</td>';
|
|
|
|
$this->_html .= '</tr></table>
|
|
</div>';
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// decide to display "Start Upgrade" or not
|
|
if ($this->configOk())
|
|
{
|
|
if (version_compare(_PS_VERSION_, $this->upgrader->version_num, '<'))
|
|
{
|
|
$show_big_button_new_version = false;
|
|
$this->_html .= '<p class="clear"><a href="" id="upgradeNow" class="button-autoupgrade upgradestep">'.$this->l('Upgrade PrestaShop now !').'</a></p>';
|
|
|
|
// smarty2 uses is a warning only, and will be displayed only if current version is 1.3 or 1.4 and target is <1.5;
|
|
$use_smarty3 = !(Configuration::get('PS_FORCE_SMARTY_2') === '1' || Configuration::get('PS_FORCE_SMARTY_2') === false);
|
|
if ($use_smarty3)
|
|
{
|
|
$srcShopStatus = '../img/admin/enabled.gif';
|
|
$label = $this->l('You use Smarty 3');
|
|
}
|
|
else
|
|
{
|
|
$srcShopStatus = '../img/admin/warning.gif';
|
|
$label = $this->l('Smarty 2 is deprecated in 1.4 and was removed in 1.5. You may need to upgrade your current theme or use a new one.');
|
|
}
|
|
|
|
// if current version is 1.4, we propose to edit now the configuration
|
|
if (version_compare(_PS_VERSION_, '1.4.0.0', '<='))
|
|
{
|
|
$token_preferences = Tools14::getAdminTokenLite('AdminPreferences');
|
|
$this->_html .= '<div class="clear"> </div><b>'.$this->l('Smarty 3 Usage:').'</b> <img src="'.$srcShopStatus.'" />'.$label;
|
|
if (version_compare(_PS_VERSION_, '1.4.0.0', '>') && version_compare(_PS_VERSION_, '1.5.0.0', '<'))
|
|
$this->_html .= '<div class="clear"> </div>
|
|
<a href="index.php?tab=AdminPreferences&token='.$token_preferences.'#PS_FORCE_SMARTY_2" class="button">'
|
|
.$this->l('Edit your Smarty configuration').'</a>';
|
|
$this->_html .= '<div class="clear"> </div>';
|
|
}
|
|
if (!in_array($channel, array('archive', 'directory')))
|
|
{
|
|
if ($this->getConfig('channel') == 'private')
|
|
$this->upgrader->link = $this->getConfig('private_release_link');
|
|
|
|
$this->_html .= '<small><a href="'.$this->upgrader->link.'">'.sprintf($this->l('PrestaShop will be downloaded from %s'), $this->upgrader->link).'</a></small><br/>';
|
|
$this->_html .= '<div class="clear"> </div>';
|
|
$this->_html .= '<small><a href="'.$this->upgrader->changelog.'" target="_blank" >'.$this->l('open changelog in a new window').'</a></small>';
|
|
$this->_html .= '<div class="clear"> </div>';
|
|
}
|
|
else
|
|
$this->_html .= sprintf($this->l('No file will be downloaded (channel %s is used)'), $channel);
|
|
|
|
// if skipActions property is used, we will handle that in the display :)
|
|
if (count(AdminSelfUpgrade::$skipAction) > 0)
|
|
{
|
|
$this->_html .= '<div id="skipAction-list" class="warn" style="display:block;font-weight:normal">
|
|
<img src="../img/admin/warning.gif"/>'
|
|
.$this->l('The following action are automatically replaced')
|
|
.'<ul>';
|
|
foreach(AdminSelfUpgrade::$skipAction as $k => $v)
|
|
$this->_html .= '<li>'
|
|
.sprintf($this->l('%1$s will be replaced by %2$s'), '<b>'.$k.'</b>', '<b>'.$v.'</b>').'</li>';
|
|
$this->_html .= '</ul><p>'.$this->l('To change this behavior, you need to manually edit your php files').'</p>
|
|
</div>';
|
|
}
|
|
}
|
|
else
|
|
$show_big_button_new_version = true;
|
|
}
|
|
else
|
|
$show_big_button_new_version = true;
|
|
|
|
if ($show_big_button_new_version)
|
|
{
|
|
$this->_html .=
|
|
'<div class="clear"></div>
|
|
<a class="button button-autoupgrade"
|
|
href="index.php?tab=AdminSelfUpgrade&token='.$this->token.'&refreshCurrentVersion=1">'.$this->l('Check if a new version is available').'</a>';
|
|
|
|
$this->_html .= '<div><span style="font-style: italic; font-size: 11px;">'.sprintf($this->l('Last check: %s'), Configuration::get('PS_LAST_VERSION_CHECK') ? date('Y-m-d H:i:s', Configuration::get('PS_LAST_VERSION_CHECK')) : $this->l('never')).'</span></div>';
|
|
}
|
|
else
|
|
{
|
|
$this->_html .= '<div class="clear"></div><a class="button button-autoupgrade" href="index.php?tab=AdminSelfUpgrade&token='
|
|
.$this->token
|
|
.'&refreshCurrentVersion=1">'.$this->l('refresh the page').'</a>';
|
|
$this->_html .= '<div>
|
|
<span>'.sprintf($this->l('Last datetime check: %s '), date('Y-m-d H:i:s',Configuration::get('PS_LAST_VERSION_CHECK')))
|
|
.'</span></div>';
|
|
}
|
|
|
|
$this->_html .= $this->getBlockConfigurationAdvanced();
|
|
$this->_html .= '</fieldset>';
|
|
|
|
if ($this->manualMode)
|
|
$this->_html .= $this->displayDevTools();
|
|
|
|
|
|
// information to keep will be in #infoStep
|
|
// temporary infoUpdate will be in #tmpInformation
|
|
}
|
|
|
|
public function display()
|
|
{
|
|
$this->_html .= '<script type="text/javascript">var jQueryVersionPS = parseInt($().jquery.replace(/\./g, ""));</script>
|
|
<script type="text/javascript" src="'.__PS_BASE_URI__.'modules/autoupgrade/js/jquery-1.6.2.min.js"></script>
|
|
<script type="text/javascript">if (jQueryVersionPS >= 162) jq162 = jQuery.noConflict(true);</script>';
|
|
|
|
/* PrestaShop demo mode */
|
|
if (defined('_PS_MODE_DEMO_') && _PS_MODE_DEMO_)
|
|
{
|
|
echo '<div class="error">'.$this->l('This functionality has been disabled.').'</div>';
|
|
return;
|
|
}
|
|
|
|
if (!file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.'ajax-upgradetab.php'))
|
|
{
|
|
echo '<div class="error">'.'<img src="../img/admin/warning.gif" /> '.$this->l('[TECHNICAL ERROR] ajax-upgradetab.php is missing. Please reinstall or reset the module.').'</div>';
|
|
return false;
|
|
}
|
|
/* PrestaShop demo mode*/
|
|
|
|
// in order to not use Tools class
|
|
$upgrader = new Upgrader();
|
|
preg_match('#([0-9]+\.[0-9]+)(?:\.[0-9]+){1,2}#', _PS_VERSION_, $matches);
|
|
$upgrader->branch = $matches[1];
|
|
$channel = $this->getConfig('channel');
|
|
switch ($channel)
|
|
{
|
|
case 'archive':
|
|
$upgrader->channel = 'archive';
|
|
$upgrader->version_num = $this->getConfig('archive.version_num');
|
|
break;
|
|
case 'directory':
|
|
$upgrader->channel = 'directory';
|
|
$upgrader->version_num = $this->getConfig('directory.version_num');
|
|
break;
|
|
default:
|
|
$upgrader->channel = $channel;
|
|
if (isset($_GET['refreshCurrentVersion']))
|
|
{
|
|
// delete the potential xml files we saved in config/xml (from last release and from current)
|
|
$upgrader->clearXmlMd5File(_PS_VERSION_);
|
|
$upgrader->clearXmlMd5File($upgrader->version_num);
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$upgrader->checkPSVersion(true, array('private', 'minor'));
|
|
else
|
|
$upgrader->checkPSVersion(true, array('minor'));
|
|
|
|
Tools14::redirectAdmin($this->currentIndex.'&conf=5&token='.Tools14::getValue('token'));
|
|
}
|
|
else
|
|
{
|
|
if ($this->getConfig('channel') == 'private' && !$this->getConfig('private_allow_major'))
|
|
$upgrader->checkPSVersion(false, array('private', 'minor'));
|
|
else
|
|
$upgrader->checkPSVersion(false, array('minor'));
|
|
}
|
|
}
|
|
|
|
|
|
$this->upgrader = $upgrader;
|
|
|
|
$this->_html .= '<link type="text/css" rel="stylesheet" href="'.__PS_BASE_URI__.'modules/autoupgrade/css/styles.css" />';
|
|
|
|
$this->_html .= '
|
|
<h1>'.$this->l('1-click Upgrade').'</h1>
|
|
<fieldset id="informationBlock" class="information" style="float: left; width: 30%;">
|
|
<legend>'.$this->l('Welcome!').'</legend>
|
|
<p>
|
|
'.$this->l('With the PrestaShop 1-Click Upgrade module, upgrading your store to the latest version available has never been easier!').'<br /><br />
|
|
<span style="color:#CC0000;font-weight:bold">'.$this->l('Please always perform a full manual backup of your files and database before starting any upgrade.').'</span><br />
|
|
'.$this->l('Double-check the integrity of your backup and that you can easily manually roll-back if necessary.').'<br />
|
|
'.$this->l('If you do not know how to proceed, ask your hosting provider.').'
|
|
</p>
|
|
</fieldset>';
|
|
|
|
/* Make sure the user has configured the upgrade options, or set default values */
|
|
$configuration_keys = array('PS_AUTOUP_UPDATE_DEFAULT_THEME' => 1, 'PS_AUTOUP_KEEP_MAILS' => 1, 'PS_AUTOUP_CUSTOM_MOD_DESACT' => 1,
|
|
'PS_AUTOUP_MANUAL_MODE' => 0, 'PS_AUTOUP_PERFORMANCE' => 1, 'PS_DISPLAY_ERRORS' => 0);
|
|
foreach ($configuration_keys as $k => $default_value)
|
|
if (Configuration::get($k) == '')
|
|
Configuration::updateValue($k, $default_value);
|
|
|
|
/* Checks/requirements and "Upgrade PrestaShop now" blocks */
|
|
$this->_displayCurrentConfiguration();
|
|
$this->_html .= '<div class="clear"></div>';
|
|
$this->_displayBlockUpgradeButton();
|
|
|
|
$this->_displayComparisonBlock();
|
|
$this->_displayBlockActivityLog();
|
|
|
|
$this->_displayRollbackForm();
|
|
|
|
$this->_html .= '<br/>';
|
|
$this->_html .= '<form action="'.$this->currentIndex.'&customSubmitAutoUpgrade=1&token='.$this->token.'" method="post" enctype="multipart/form-data">';
|
|
$this->_displayForm('backupOptions',$this->_fieldsBackupOptions,'<a href="#" name="backup-options" id="backup-options">'.$this->l('Backup Options').'</a>', '','database_gear');
|
|
$this->_displayForm('upgradeOptions',$this->_fieldsUpgradeOptions,'<a href="#" name="upgrade-options" id="upgrade-options">'.$this->l('Upgrade Options').'</a>', '','prefs');
|
|
$this->_html .= '</form>';
|
|
|
|
$this->_html .= '<script type="text/javascript" src="'.__PS_BASE_URI__.'modules/autoupgrade/js/jquery.xml2json.js"></script>';
|
|
$this->_html .= '<script type="text/javascript">'.$this->_getJsInit().'</script>';
|
|
echo $this->_html;
|
|
}
|
|
|
|
private function _getJsInit()
|
|
{
|
|
global $cookie;
|
|
$js = '';
|
|
|
|
$token_preferences = Tools14::getAdminTokenLite('AdminPreferences');
|
|
|
|
$js .= '
|
|
function ucFirst(str) {
|
|
if (str.length > 0) {
|
|
return str[0].toUpperCase() + str.substring(1);
|
|
}
|
|
else {
|
|
return str;
|
|
}
|
|
}
|
|
|
|
function cleanInfo(){
|
|
$("#infoStep").html("reset<br/>");
|
|
}
|
|
|
|
function updateInfoStep(msg){
|
|
if (msg)
|
|
{
|
|
$("#infoStep").append(msg+"<div class=\"clear\"></div>");
|
|
$("#infoStep").prop({ scrollTop: $("#infoStep").prop("scrollHeight")},1);
|
|
}
|
|
}
|
|
|
|
function addError(arrError){
|
|
if (typeof(arrError) != "undefined" && arrError.length)
|
|
{
|
|
$("#errorDuringUpgrade").show();
|
|
for(i=0;i<arrError.length;i++)
|
|
$("#infoError").append(arrError[i]+"<div class=\"clear\"></div>");
|
|
// Note : jquery 1.6 make uses of prop() instead of attr()
|
|
$("#infoError").prop({ scrollTop: $("#infoError").prop("scrollHeight")},1);
|
|
}
|
|
}
|
|
|
|
function addQuickInfo(arrQuickInfo){
|
|
if (arrQuickInfo)
|
|
{
|
|
$("#quickInfo").show();
|
|
for(i=0;i<arrQuickInfo.length;i++)
|
|
$("#quickInfo").append(arrQuickInfo[i]+"<div class=\"clear\"></div>");
|
|
// Note : jquery 1.6 make uses of prop() instead of attr()
|
|
$("#quickInfo").prop({ scrollTop: $("#quickInfo").prop("scrollHeight")},1);
|
|
}
|
|
}'."\n";
|
|
|
|
if ($this->manualMode)
|
|
$js .= 'var manualMode = true;'."\n";
|
|
else
|
|
$js .= 'var manualMode = false;'."\n";
|
|
|
|
// relative admin dir
|
|
$admin_dir = trim(str_replace($this->prodRootDir, '', $this->adminDir), DIRECTORY_SEPARATOR);
|
|
// _PS_MODE_DEV_ will be available in js
|
|
if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_)
|
|
$js .= 'var _PS_MODE_DEV_ = true;'."\n";
|
|
|
|
if ($this->getConfig('PS_AUTOUP_BACKUP'))
|
|
$js .= 'var PS_AUTOUP_BACKUP = true;'."\n";
|
|
|
|
$js .= $this->_getJsErrorMsgs();
|
|
|
|
$js .= '
|
|
var firstTimeParams = '.$this->buildAjaxResult().';
|
|
firstTimeParams = firstTimeParams.nextParams;
|
|
firstTimeParams.firstTime = "1";
|
|
|
|
// js initialization : prepare upgrade and rollback buttons
|
|
$(document).ready(function(){
|
|
|
|
$("select[name=channel]").change(function(e){
|
|
$("select[name=channel]").find("option").each(function()
|
|
{
|
|
if ($(this).is(":selected"))
|
|
$("#for-"+$(this).attr("id")).show();
|
|
else
|
|
$("#for-"+$(this).attr("id")).hide();
|
|
});
|
|
|
|
refreshChannelInfos();
|
|
});
|
|
|
|
function refreshChannelInfos()
|
|
{
|
|
val = $("select[name=channel]").find("option:selected").val();
|
|
$.ajax({
|
|
type:"POST",
|
|
url : "'. __PS_BASE_URI__ . $admin_dir.'/autoupgrade/ajax-upgradetab.php",
|
|
async: true,
|
|
data : {
|
|
dir:"'.$admin_dir.'",
|
|
token : "'.$this->token.'",
|
|
tab : "AdminSelfUpgrade",
|
|
action : "getChannelInfo",
|
|
ajaxMode : "1",
|
|
params : { channel : val}
|
|
},
|
|
success : function(res,textStatus,jqXHR)
|
|
{
|
|
if (isJsonString(res))
|
|
res = $.parseJSON(res);
|
|
else
|
|
res = {nextParams:{status:"error"}};
|
|
|
|
answer = res.nextParams.result;
|
|
if (typeof(answer) != "undefined")
|
|
$("#channel-infos").replaceWith(answer.div);
|
|
if (typeof(answer) != "undefined" && answer.available)
|
|
{
|
|
$("#channel-infos .all-infos").show();
|
|
}
|
|
else if (typeof(answer) != "undefined")
|
|
{
|
|
$("#channel-infos").html(answer.div);
|
|
$("#channel-infos .all-infos").hide();
|
|
}
|
|
},
|
|
error: function(res, textStatus, jqXHR)
|
|
{
|
|
if (textStatus == "timeout" && action == "download")
|
|
{
|
|
updateInfoStep("'.$this->l('Your server cannot download the file. Please upload it first by ftp in your admin/autoupgrade directory', 'AdminSelfUpgrade', true).'");
|
|
}
|
|
else
|
|
{
|
|
// technical error : no translation needed
|
|
$("#checkPrestaShopFilesVersion").html("<img src=\"../img/admin/warning.gif\" /> Error Unable to check md5 files");
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
$("div[id|=for]").hide();
|
|
$("select[name=channel]").change();
|
|
});
|
|
|
|
// the following prevents to leave the page at the innappropriate time
|
|
$.xhrPool = [];
|
|
$.xhrPool.abortAll = function()
|
|
{
|
|
$.each(this, function(jqXHR)
|
|
{
|
|
if (jqXHR && (jqXHR.readystate != 4))
|
|
{
|
|
jqXHR.abort();
|
|
}
|
|
});
|
|
}
|
|
$(".upgradestep").click(function(e)
|
|
{
|
|
e.preventDefault();
|
|
// $.scrollTo("#options")
|
|
});
|
|
|
|
// set timeout to 20 minutes (before aborting an ajax request)
|
|
$.ajaxSetup({timeout:1200000});
|
|
|
|
// prepare available button here, without params ?
|
|
prepareNextButton("#upgradeNow",firstTimeParams);
|
|
|
|
/**
|
|
* reset rollbackParams js array (used to init rollback button)
|
|
*/
|
|
$("select[name=restoreName]").change(function(){
|
|
$(this).next().remove();
|
|
// show delete button if the value is not 0
|
|
if($(this).val() != 0)
|
|
{
|
|
$(this).after("<a class=\"button confirmBeforeDelete\" href=\"index.php?tab=AdminSelfUpgrade&token='
|
|
.$this->token
|
|
.'&deletebackup&name="+$(this).val()+"\">'
|
|
.'<img src=\"../img/admin/disabled.gif\" />'.$this->l('Delete').'</a>");
|
|
$(this).next().click(function(e){
|
|
if (!confirm("'.$this->l('Are you sure you want to delete this backup ?', 'AdminSelfUpgrade', true, false).'"))
|
|
e.preventDefault();
|
|
});
|
|
}
|
|
|
|
if ($("select[name=restoreName]").val() != 0)
|
|
{
|
|
$("#rollback").removeAttr("disabled");
|
|
rollbackParams = jQuery.extend(true, {}, firstTimeParams);
|
|
|
|
delete rollbackParams.backupName;
|
|
delete rollbackParams.backupFilesFilename;
|
|
delete rollbackParams.backupDbFilename;
|
|
delete rollbackParams.restoreFilesFilename;
|
|
delete rollbackParams.restoreDbFilenames;
|
|
|
|
// init new name to backup
|
|
rollbackParams.restoreName = $("select[name=restoreName]").val();
|
|
prepareNextButton("#rollback", rollbackParams);
|
|
// Note : theses buttons have been removed.
|
|
// they will be available in a future release (when DEV_MODE and MANUAL_MODE enabled)
|
|
// prepareNextButton("#restoreDb", rollbackParams);
|
|
// prepareNextButton("#restoreFiles", rollbackParams);
|
|
}
|
|
else
|
|
$("#rollback").attr("disabled", "disabled");
|
|
});
|
|
|
|
});
|
|
|
|
function showConfigResult(msg, type){
|
|
if (type == null)
|
|
type = "conf";
|
|
$("#configResult").html("<div class=\""+type+"\">"+msg+"</div>").show();
|
|
if (type == "conf")
|
|
{
|
|
$("#configResult").delay(3000).fadeOut("slow", function() {
|
|
location.reload();
|
|
});
|
|
}
|
|
}
|
|
|
|
// reuse previousParams, and handle xml returns to calculate next step
|
|
// (and the correct next param array)
|
|
// a case has to be defined for each requests that returns xml
|
|
|
|
|
|
function afterUpdateConfig(res)
|
|
{
|
|
params = res.nextParams
|
|
config = params.config
|
|
oldChannel = $("select[name=channel] option.current");
|
|
if (config.channel != oldChannel.val())
|
|
{
|
|
newChannel = $("select[name=channel] option[value="+config.channel+"]");
|
|
oldChannel.removeClass("current");
|
|
oldChannel.html(oldChannel.html().substr(2));
|
|
newChannel.addClass("current");
|
|
newChannel.html("* "+newChannel.html());
|
|
}
|
|
if (res.error == 1)
|
|
showConfigResult(res.next_desc, "error");
|
|
else
|
|
showConfigResult(res.next_desc);
|
|
$("#upgradeNow").unbind();
|
|
$("#upgradeNow").replaceWith("<a class=\"button-autoupgrade\" href=\"'.$this->currentIndex.'&token='.$this->token.'\" >'.$this->l('Click to refresh the page and use the new configuration', 'AdminSelfUpgrade', true).'</a>");
|
|
}
|
|
function startProcess(type){
|
|
|
|
// hide useless divs, show activity log
|
|
$("#informationBlock,#comparisonBlock,#currentConfigurationBlock,#backupOptionsBlock,#upgradeOptionsBlock,#upgradeButtonBlock").slideUp("fast");
|
|
$(".autoupgradeSteps a").addClass("button");
|
|
$("#activityLogBlock").fadeIn("slow");
|
|
|
|
$(window).bind("beforeunload", function(e)
|
|
{
|
|
if (confirm("'.$this->l('An update is currently in progress... Click "OK" to abort.', 'AdminTab', true, false).'"))
|
|
{
|
|
$.xhrPool.abortAll();
|
|
$(window).unbind("beforeunload");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (type == "upgrade")
|
|
{
|
|
e.returnValue = false;
|
|
e.cancelBubble = true;
|
|
if (e.stopPropagation)
|
|
{
|
|
e.stopPropagation();
|
|
}
|
|
if (e.preventDefault)
|
|
{
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function afterUpgradeNow(res)
|
|
{
|
|
startProcess("upgrade");
|
|
$("#upgradeNow").unbind();
|
|
$("#upgradeNow").replaceWith("<span id=\"upgradeNow\" class=\"button-autoupgrade\">'.$this->l('Upgrading PrestaShop', 'AdminSelfUpgrade', true).' ...</span>");
|
|
}
|
|
|
|
function afterUpgradeComplete(res)
|
|
{
|
|
params = res.nextParams
|
|
$("#pleaseWait").hide();
|
|
if (params.warning_exists == "false")
|
|
{
|
|
$("#upgradeResultCheck")
|
|
.addClass("conf")
|
|
.removeClass("fail")
|
|
.html("<p>'.$this->l('Upgrade complete').'</p>")
|
|
.show();
|
|
$("#infoStep").html("<h3>'.$this->l('Upgrade Complete!', 'AdminSelfUpgrade', true).'</h3>");
|
|
}
|
|
else
|
|
{
|
|
params = res.nextParams
|
|
$("#pleaseWait").hide();
|
|
$("#upgradeResultCheck")
|
|
.addClass("fail")
|
|
.removeClass("ok")
|
|
.html("<p>'.$this->l('Upgrade complete, but warning notifications has been found.').'</p>")
|
|
.show("slow");
|
|
$("#infoStep").html("<h3>'.$this->l('Upgrade complete, but warning notifications has been found.', 'AdminSelfUpgrade', true).'</h3>");
|
|
}
|
|
|
|
todo_list = [
|
|
"'.$this->l('Cookies have changed, you will need to log in again once you refreshed the page', 'AdminSelfUpgrade', true).'",
|
|
"'.$this->l('Javascript and CSS files have changed, please clear your browser cache with CTRL-F5', 'AdminSelfUpgrade', true).'",
|
|
"'.$this->l('Please check that your front-office theme is functional (try to create an account, place an order...)', 'AdminSelfUpgrade', true).'",
|
|
"'.$this->l('Product images do not appear in the front-office? Try regenerating the thumbnails in Preferences > Images', 'AdminSelfUpgrade', true).'",
|
|
"'.$this->l('Do not forget to reactivate your shop once you have checked everything!', 'AdminSelfUpgrade', true).'",
|
|
];
|
|
|
|
todo_ul = "<ul>";
|
|
$("#upgradeResultToDoList")
|
|
.addClass("hint clear")
|
|
.html("<h3>'.$this->l('ToDo list:').'</h3>")
|
|
for(var i in todo_list)
|
|
{
|
|
todo_ul += "<li>"+todo_list[i]+"</li>";
|
|
}
|
|
todo_ul += "</ul>";
|
|
$("#upgradeResultToDoList").append(todo_ul)
|
|
$("#upgradeResultToDoList").show();
|
|
|
|
$(window).unbind("beforeunload");
|
|
}
|
|
|
|
function afterError(res)
|
|
{
|
|
params = res.nextParams;
|
|
if (params.next == "")
|
|
$(window).unbind("beforeunload");
|
|
$("#pleaseWait").hide();
|
|
|
|
addQuickInfo(["unbind :) "]);
|
|
}
|
|
|
|
function afterRollback(res)
|
|
{
|
|
startProcess("rollback");
|
|
}
|
|
|
|
function afterRollbackComplete(res)
|
|
{
|
|
params = res.nextParams
|
|
$("#pleaseWait").hide();
|
|
$("#upgradeResultCheck")
|
|
.addClass("ok")
|
|
.removeClass("fail")
|
|
.html("<p>'.$this->l('Restoration complete.').'</p>")
|
|
.show("slow");
|
|
updateInfoStep("<h3>'.$this->l('Restoration complete.').'</h3>");
|
|
$(window).unbind();
|
|
}
|
|
|
|
|
|
function afterRestoreDb(params)
|
|
{
|
|
// $("#restoreBackupContainer").hide();
|
|
}
|
|
|
|
function afterRestoreFiles(params)
|
|
{
|
|
// $("#restoreFilesContainer").hide();
|
|
}
|
|
|
|
function afterBackupFiles(res)
|
|
{
|
|
params = res.nextParams;
|
|
// if (params.stepDone)
|
|
}
|
|
|
|
/**
|
|
* afterBackupDb display the button
|
|
*
|
|
*/
|
|
function afterBackupDb(res)
|
|
{
|
|
params = res.nextParams;
|
|
if (res.stepDone && typeof(PS_AUTOUP_BACKUP) != "undefined" && PS_AUTOUP_BACKUP == true)
|
|
{
|
|
$("#restoreBackupContainer").show();
|
|
$("select[name=restoreName]").children("options").removeAttr("selected");
|
|
$("select[name=restoreName]")
|
|
.append("<option selected=\"selected\" value=\""+params.backupName+"\">"+params.backupName+"</option>")
|
|
$("select[name=restoreName]").change();
|
|
}
|
|
}
|
|
|
|
|
|
function call_function(func){
|
|
this[func].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
}
|
|
|
|
function doAjaxRequest(action, nextParams){
|
|
if (typeof(_PS_MODE_DEV_) != "undefined" && _PS_MODE_DEV_ == true)
|
|
addQuickInfo(["[DEV] ajax request : " + action]);
|
|
$("#pleaseWait").show();
|
|
req = $.ajax({
|
|
type:"POST",
|
|
url : "'. __PS_BASE_URI__.$admin_dir.'/autoupgrade/ajax-upgradetab.php'.'",
|
|
async: true,
|
|
data : {
|
|
dir:"'.$admin_dir.'",
|
|
ajaxMode : "1",
|
|
token : "'.$this->token.'",
|
|
tab : "AdminSelfUpgrade",
|
|
action : action,
|
|
params : nextParams
|
|
},
|
|
beforeSend: function(jqXHR)
|
|
{
|
|
$.xhrPool.push(jqXHR);
|
|
},
|
|
complete: function(jqXHR)
|
|
{
|
|
// just remove the item to the "abort list"
|
|
$.xhrPool.pop();
|
|
// $(window).unbind("beforeunload");
|
|
},
|
|
success : function(res, textStatus, jqXHR)
|
|
{
|
|
$("#pleaseWait").hide();
|
|
try{
|
|
res = $.parseJSON(res);
|
|
}
|
|
catch(e){
|
|
res = {status : "error", nextParams:nextParams};
|
|
alert("'.$this->l('Javascript error (parseJSON) detected for action ', __CLASS__, true, false).'\""+action+"\".'
|
|
.$this->l('Starting restoration...', __CLASS__, true, false).'");
|
|
}
|
|
addQuickInfo(res.nextQuickInfo);
|
|
addError(res.nextErrors);
|
|
updateInfoStep(res.next_desc);
|
|
currentParams = res.nextParams;
|
|
if (res.status == "ok")
|
|
{
|
|
$("#"+action).addClass("done");
|
|
if (res.stepDone)
|
|
$("#"+action).addClass("stepok");
|
|
// if a function "after[action name]" exists, it should be called now.
|
|
// This is used for enabling restore buttons for example
|
|
funcName = "after" + ucFirst(action);
|
|
if (typeof funcName == "string" && eval("typeof " + funcName) == "function")
|
|
call_function(funcName, res);
|
|
|
|
handleSuccess(res, action);
|
|
}
|
|
else
|
|
{
|
|
// display progression
|
|
$("#"+action).addClass("done");
|
|
$("#"+action).addClass("steperror");
|
|
if (action != "rollback"
|
|
&& action != "rollbackComplete"
|
|
&& action != "restoreFiles"
|
|
&& action != "restoreDb"
|
|
&& action != "rollback"
|
|
&& action != "noRollbackFound"
|
|
)
|
|
handleError(res, action);
|
|
else
|
|
alert("'.$this->l('Error detected during', __CLASS__, true, false).' [" + action + "].");
|
|
}
|
|
},
|
|
error: function(jqXHR, textStatus, errorThrown)
|
|
{
|
|
$("#pleaseWait").hide();
|
|
if (textStatus == "timeout")
|
|
{
|
|
if (action == "download")
|
|
updateInfoStep("'.addslashes($this->l('Your server cannot download the file. Please upload it first by ftp in your admin/autoupgrade directory')).'");
|
|
else
|
|
updateInfoStep("[Server Error] Timeout:'.addslashes($this->l('The request exceeded the max_time_limit. Please change your server configuration.')).'");
|
|
}
|
|
else
|
|
updateInfoStep("[Ajax / Server Error for action " + action + "] textStatus: \"" + textStatus + " \" errorThrown:\"" + errorThrown + " \" jqXHR: \" " + jqXHR.responseText + "\"");
|
|
}
|
|
});
|
|
return req;
|
|
};
|
|
|
|
/**
|
|
* prepareNextButton make the button button_selector available, and update the nextParams values
|
|
*
|
|
* @param button_selector $button_selector
|
|
* @param nextParams $nextParams
|
|
* @return void
|
|
*/
|
|
function prepareNextButton(button_selector, nextParams)
|
|
{
|
|
$(button_selector).unbind();
|
|
$(button_selector).click(function(e){
|
|
e.preventDefault();
|
|
$("#currentlyProcessing").show();';
|
|
$js .= '
|
|
action = button_selector.substr(1);
|
|
res = doAjaxRequest(action, nextParams);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* handleSuccess
|
|
* res = {error:, next:, next_desc:, nextParams:, nextQuickInfo:,status:"ok"}
|
|
* @param res $res
|
|
* @return void
|
|
*/
|
|
function handleSuccess(res, action)
|
|
{
|
|
if (res.next != "")
|
|
{
|
|
|
|
$("#"+res.next).addClass("nextStep");
|
|
if (manualMode && (action != "rollback"
|
|
&& action != "rollbackComplete"
|
|
&& action != "restoreFiles"
|
|
&& action != "restoreDb"
|
|
&& action != "rollback"
|
|
&& action != "noRollbackFound"))
|
|
{
|
|
prepareNextButton("#"+res.next,res.nextParams);
|
|
alert("'.sprintf($this->l('Manually go to %s button', __CLASS__, true, false), '"+res.next+"').'");
|
|
}
|
|
else
|
|
{
|
|
// if next is rollback, prepare nextParams with rollbackDbFilename and rollbackFilesFilename
|
|
if ( res.next == "rollback")
|
|
{
|
|
res.nextParams.restoreName = ""
|
|
}
|
|
doAjaxRequest(res.next, res.nextParams);
|
|
// 2) remove all step link (or show them only in dev mode)
|
|
// 3) when steps link displayed, they should change color when passed if they are visible
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Way To Go, end of upgrade process
|
|
addQuickInfo(["'.$this->l('End of process').'"]);
|
|
}
|
|
}
|
|
|
|
// res = {nextParams, next_desc}
|
|
function handleError(res, action)
|
|
{
|
|
// display error message in the main process thing
|
|
// In case the rollback button has been deactivated, just re-enable it
|
|
$("#rollback").removeAttr("disabled");
|
|
// auto rollback only if current action is upgradeFiles or upgradeDb
|
|
if (action == "upgradeFiles" || action == "upgradeDb" || action == "upgradeModules" )
|
|
{
|
|
$(".button-autoupgrade").html("'.$this->l('Operation canceled. Checking for restoration...').'");
|
|
res.nextParams.restoreName = res.nextParams.backupName;
|
|
if (confirm("'.$this->l('Do you want to restore').' " + "'.$this->backupName.'" + " ?"))
|
|
doAjaxRequest("rollback",res.nextParams);
|
|
}
|
|
else
|
|
{
|
|
$(".button-autoupgrade").html("'.$this->l('Operation canceled. An error happened.').'");
|
|
$(window).unbind();
|
|
}
|
|
}';
|
|
// ajax to check md5 files
|
|
$js .= 'function addModifiedFileList(title, fileList, css_class, container)
|
|
{
|
|
subList = $("<ul class=\"changedFileList "+css_class+"\"></ul>");
|
|
|
|
$(fileList).each(function(k,v){
|
|
$(subList).append("<li>"+v+"</li>");
|
|
});
|
|
$(container).append("<h3><a class=\"toggleSublist\" href=\"#\" >"+title+"</a> (" + fileList.length + ")</h3>");
|
|
$(container).append(subList);
|
|
$(container).append("<br/>");
|
|
|
|
}';
|
|
if(!file_exists($this->autoupgradePath.DIRECTORY_SEPARATOR.'ajax-upgradetab.php'))
|
|
$js .= '$(document).ready(function(){
|
|
$("#checkPrestaShopFilesVersion").html("<img src=\"../img/admin/warning.gif\" /> [TECHNICAL ERROR] ajax-upgradetab.php '.$this->l('is missing. please reinstall the module').'");
|
|
})';
|
|
else
|
|
$js .= '
|
|
function isJsonString(str) {
|
|
try {
|
|
typeof(str) != "undefined" && JSON.parse(str);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
$.ajax({
|
|
type:"POST",
|
|
url : "'. __PS_BASE_URI__ . $admin_dir.'/autoupgrade/ajax-upgradetab.php",
|
|
async: true,
|
|
data : {
|
|
dir:"'.$admin_dir.'",
|
|
token : "'.$this->token.'",
|
|
tab : "'.get_class($this).'",
|
|
action : "checkFilesVersion",
|
|
ajaxMode : "1",
|
|
params : {}
|
|
},
|
|
success : function(res,textStatus,jqXHR)
|
|
{
|
|
if (isJsonString(res))
|
|
res = $.parseJSON(res);
|
|
else
|
|
{
|
|
res = {nextParams:{status:"error"}};
|
|
}
|
|
answer = res.nextParams;
|
|
$("#checkPrestaShopFilesVersion").html("<span> "+answer.msg+" </span> ");
|
|
if ((answer.status == "error") || (typeof(answer.result) == "undefined"))
|
|
$("#checkPrestaShopFilesVersion").prepend("<img src=\"../img/admin/warning.gif\" /> ");
|
|
else
|
|
{
|
|
$("#checkPrestaShopFilesVersion").prepend("<img src=\"../img/admin/warning.gif\" /> ");
|
|
$("#checkPrestaShopFilesVersion").append("<a id=\"toggleChangedList\" class=\"button\" href=\"\">'.$this->l('See or hide the list').'</a><br/>");
|
|
$("#checkPrestaShopFilesVersion").append("<div id=\"changedList\" style=\"display:none \"><br/>");
|
|
if(answer.result.core.length)
|
|
addModifiedFileList("'.$this->l('Core file(s)').'", answer.result.core, "changedImportant", "#changedList");
|
|
if(answer.result.mail.length)
|
|
addModifiedFileList("'.$this->l('Mail file(s)').'", answer.result.mail, "changedNotice", "#changedList");
|
|
if(answer.result.translation.length)
|
|
addModifiedFileList("'.$this->l('Translation file(s)').'", answer.result.translation, "changedNotice", "#changedList");
|
|
|
|
$("#toggleChangedList").bind("click",function(e){e.preventDefault();$("#changedList").toggle();});
|
|
$(".toggleSublist").die().live("click",function(e){e.preventDefault();$(this).parent().next().toggle();});
|
|
}
|
|
}
|
|
,
|
|
error: function(res, textStatus, jqXHR)
|
|
{
|
|
if (textStatus == "timeout" && action == "download")
|
|
{
|
|
updateInfoStep("'.$this->l('Your server cannot download the file. Please upload it to your FTP server, and put it in your /[admin]/autoupgrade directory.').'");
|
|
}
|
|
else
|
|
{
|
|
// technical error : no translation needed
|
|
$("#checkPrestaShopFilesVersion").html("<img src=\"../img/admin/warning.gif\" /> Error: Unable to check md5 files");
|
|
}
|
|
}
|
|
})
|
|
$.ajax({
|
|
type:"POST",
|
|
url : "'. __PS_BASE_URI__ . $admin_dir.'/autoupgrade/ajax-upgradetab.php",
|
|
async: true,
|
|
data : {
|
|
dir:"'.$admin_dir.'",
|
|
token : "'.$this->token.'",
|
|
tab : "'.get_class($this).'",
|
|
action : "compareReleases",
|
|
ajaxMode : "1",
|
|
params : {}
|
|
},
|
|
success : function(res,textStatus,jqXHR)
|
|
{
|
|
if (isJsonString(res))
|
|
res = $.parseJSON(res);
|
|
else
|
|
{
|
|
res = {nextParams:{status:"error"}};
|
|
}
|
|
answer = res.nextParams;
|
|
$("#checkPrestaShopModifiedFiles").html("<span> "+answer.msg+" </span> ");
|
|
if ((answer.status == "error") || (typeof(answer.result) == "undefined"))
|
|
$("#checkPrestaShopModifiedFiles").prepend("<img src=\"../img/admin/warning.gif\" /> ");
|
|
else
|
|
{
|
|
$("#checkPrestaShopModifiedFiles").prepend("<img src=\"../img/admin/warning.gif\" /> ");
|
|
$("#checkPrestaShopModifiedFiles").append("<a id=\"toggleDiffList\" class=\"button\" href=\"\">'.$this->l('See or hide the list').'</a><br/>");
|
|
$("#checkPrestaShopModifiedFiles").append("<div id=\"diffList\" style=\"display:none \"><br/>");
|
|
if(answer.result.deleted.length)
|
|
addModifiedFileList("'.$this->l('Theses files will be deleted').'", answer.result.deleted, "diffImportant", "#diffList");
|
|
if(answer.result.modified.length)
|
|
addModifiedFileList("'.$this->l('Theses files will be modified').'", answer.result.modified, "diffImportant", "#diffList");
|
|
|
|
$("#toggleDiffList").bind("click",function(e){e.preventDefault();$("#diffList").toggle();});
|
|
$(".toggleSublist").die().live("click",function(e){
|
|
e.preventDefault();
|
|
// this=a, parent=h3, next=ul
|
|
$(this).parent().next().toggle();
|
|
});
|
|
}
|
|
},
|
|
error: function(res, textStatus, jqXHR)
|
|
{
|
|
if (textStatus == "timeout" && action == "download")
|
|
{
|
|
updateInfoStep("'.$this->l('Your server cannot download the file. Please upload it first by ftp in your admin/autoupgrade directory').'");
|
|
}
|
|
else
|
|
{
|
|
// technical error : no translation needed
|
|
$("#checkPrestaShopFilesVersion").html("<img src=\"../img/admin/warning.gif\" /> Error: Unable to check md5 files");
|
|
}
|
|
}
|
|
})
|
|
});';
|
|
|
|
// advanced/normal mode
|
|
$js .= '
|
|
$("input[name=btn_adv]").click(function(e)
|
|
{
|
|
if ($("#advanced:visible").length)
|
|
switch_to_normal();
|
|
else
|
|
switch_to_advanced();
|
|
});
|
|
|
|
function switch_to_advanced(){
|
|
$("input[name=btn_adv]").val("'.$this->l('Less options', 'AdminTab', true, false).'");
|
|
$("#advanced").show();
|
|
}
|
|
|
|
function switch_to_normal(){
|
|
$("input[name=btn_adv]").val("'.$this->l('More options (Expert mode)', 'AdminTab', true, false).'");
|
|
$("#advanced").hide();
|
|
}
|
|
|
|
$(document).ready(function(){
|
|
'.($this->getConfig('channel') == 'major' ? 'switch_to_normal();' : 'switch_to_advanced();').'
|
|
});
|
|
';
|
|
$js .= '
|
|
$(document).ready(function()
|
|
{
|
|
$("input[name|=submitConf]").bind("click", function(e){
|
|
params = {};
|
|
newChannel = $("select[name=channel] option:selected").val();
|
|
oldChannel = $("select[name=channel] option.current").val();
|
|
oldChannel = "";
|
|
if (oldChannel != newChannel)
|
|
{
|
|
if( newChannel == "major"
|
|
|| newChannel == "minor"
|
|
|| newChannel == "rc"
|
|
|| newChannel == "beta"
|
|
|| newChannel == "alpha" )
|
|
params.channel = newChannel;
|
|
|
|
if(newChannel == "private")
|
|
{
|
|
if (($("input[name=private_release_link]").val() == "") || ($("input[name=private_release_md5]").val() == ""))
|
|
{
|
|
showConfigResult("'.$this->l('Link and MD5 hash cannot be empty').'", "error");
|
|
return false;
|
|
}
|
|
params.channel = "private";
|
|
params.private_release_link = $("input[name=private_release_link]").val();
|
|
params.private_release_md5 = $("input[name=private_release_md5]").val();
|
|
if ($("input[name=private_allow_major]").is(":checked"))
|
|
params.private_allow_major = 1;
|
|
else
|
|
params.private_allow_major = 0;
|
|
}
|
|
if(newChannel == "archive")
|
|
{
|
|
archive_prestashop = $("select[name=archive_prestashop] option:selected").val();
|
|
archive_num = $("input[name=archive_num]").val();
|
|
if (archive_num == "")
|
|
{
|
|
showConfigResult("'.$this->l('You need to enter the version number associated with the archive.').'", "error");
|
|
return false;
|
|
}
|
|
if (archive_prestashop == "")
|
|
{
|
|
showConfigResult("'.$this->l('No archive has been selected.').'", "error");
|
|
return false;
|
|
}
|
|
params.channel = "archive";
|
|
params.archive_prestashop = archive_prestashop;
|
|
params.archive_num = archive_num;
|
|
}
|
|
if(newChannel == "directory")
|
|
{
|
|
params.channel = "directory";
|
|
params.directory_prestashop = $("select[name=directory_prestashop] option:selected").val();
|
|
directory_num = $("input[name=directory_num]").val();
|
|
if (directory_num == "" || directory_num.indexOf(".") == -1)
|
|
{
|
|
showConfigResult("'.$this->l('You need to enter the version number associated with the directory.').'", "error");
|
|
return false;
|
|
}
|
|
params.directory_num = $("input[name=directory_num]").val();
|
|
}
|
|
}
|
|
// note: skipBackup is currently not used
|
|
if ($(this).attr("name") == "submitConf-skipBackup")
|
|
{
|
|
skipBackup = $("input[name=submitConf-skipBackup]:checked").length;
|
|
if (skipBackup == 0 || confirm("'.$this->l('Please confirm that you want to skip the backup.').'"))
|
|
params.skip_backup = $("input[name=submitConf-skipBackup]:checked").length;
|
|
else
|
|
{
|
|
$("input[name=submitConf-skipBackup]:checked").removeAttr("checked");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// note: preserveFiles is currently not used
|
|
if ($(this).attr("name") == "submitConf-preserveFiles")
|
|
{
|
|
preserveFiles = $("input[name=submitConf-preserveFiles]:checked").length;
|
|
if (confirm("'.$this->l('Please confirm that you want to preserve file options.').'"))
|
|
params.preserve_files = $("input[name=submitConf-preserveFiles]:checked").length;
|
|
else
|
|
{
|
|
$("input[name=submitConf-skipBackup]:checked").removeAttr("checked");
|
|
return false;
|
|
}
|
|
}
|
|
res = doAjaxRequest("updateConfig", params);
|
|
});
|
|
});
|
|
';
|
|
return $js;
|
|
}
|
|
|
|
|
|
/**
|
|
* @desc extract a zip file to the given directory
|
|
* @return bool success
|
|
* we need a copy of it to be able to restore without keeping Tools and Autoload stuff
|
|
*/
|
|
private function ZipExtract($from_file, $to_dir)
|
|
{
|
|
if (!is_file($from_file))
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('%s is not a file'), $from_file);
|
|
$this->nextErrors[] = sprintf($this->l('%s is not a file'), $from_file);
|
|
return false;
|
|
}
|
|
|
|
if (!file_exists($to_dir))
|
|
if (!mkdir($to_dir))
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('Unable to create directory %s.'), $to_dir);
|
|
$this->nextErrors[] = sprintf($this->l('Unable to create directory %s.'), $to_dir);
|
|
return false;
|
|
}
|
|
else
|
|
chmod($to_dir, 0775);
|
|
|
|
$res = false;
|
|
if (!self::$force_pclZip && class_exists('ZipArchive', false))
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Using class ZipArchive...');
|
|
$zip = new ZipArchive();
|
|
if ($zip->open($from_file) === true && isset($zip->filename) && $zip->filename)
|
|
{
|
|
$extract_result = true;
|
|
$res = true;
|
|
// We extract file by file, it is very fast
|
|
for ($i = 0; $i < $zip->numFiles; $i++)
|
|
$extract_result &= $zip->extractTo($to_dir, array($zip->getNameIndex($i)));
|
|
|
|
if ($extract_result)
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Archive extracted');
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('zip->extractTo(): unable to use %s as extract destination.'), $to_dir);
|
|
$this->nextErrors[] = sprintf($this->l('zip->extractTo(): unable to use %s as extract destination.'), $to_dir);
|
|
return false;
|
|
}
|
|
}
|
|
elseif(isset($zip->filename) && $zip->filename)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('Unable to open zipFile %s'), $from_file);
|
|
$this->nextErrors[] = sprintf($this->l('Unable to open zipFile %s'), $from_file);
|
|
return false;
|
|
}
|
|
}
|
|
if(!$res)
|
|
{
|
|
if (!class_exists('PclZip', false))
|
|
require_once(_PS_ROOT_DIR_.'/modules/autoupgrade/classes/pclzip.lib.php');
|
|
|
|
$this->nextQuickInfo[] = $this->l('Using class PclZip...');
|
|
|
|
$zip = new PclZip($from_file);
|
|
|
|
if (($file_list = $zip->listContent()) == 0)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] Error on extracting archive using PclZip: %s.'), $zip->errorInfo(true));
|
|
return false;
|
|
}
|
|
|
|
// PCL is very slow, so we need to extract files 500 by 500
|
|
$i = 0;
|
|
$j = 1;
|
|
foreach ($file_list as $file)
|
|
{
|
|
if (!isset($indexes[$i]))
|
|
$indexes[$i] = array();
|
|
$indexes[$i][] = $file['index'];
|
|
if ($j++ % 500 == 0)
|
|
$i++;
|
|
}
|
|
|
|
// replace also modified files
|
|
foreach ($indexes as $index)
|
|
if (($extract_result = $zip->extract(PCLZIP_OPT_BY_INDEX, $index, PCLZIP_OPT_PATH, $to_dir, PCLZIP_OPT_REPLACE_NEWER)) == 0)
|
|
{
|
|
$this->next = 'error';
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] Error on extracting archive using PclZip: %s.'), $zip->errorInfo(true));
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
foreach ($extract_result as $extractedFile)
|
|
{
|
|
$file = str_replace($this->prodRootDir, '', $extractedFile['filename']);
|
|
if ($extractedFile['status'] != 'ok' && $extractedFile['status'] != 'already_a_directory')
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('[ERROR] %s has not been unzipped: '.$extractedFile['status']), $file);
|
|
$this->nextErrors[] = sprintf($this->l('[ERROR] %s has not been unzipped: '.$extractedFile['status']), $file);
|
|
$this->next = 'error';
|
|
}
|
|
else
|
|
$this->nextQuickInfo[] = sprintf('%1$s unzipped into %2$s', $file, str_replace(_PS_ROOT_DIR_, '', $to_dir));
|
|
}
|
|
if ($this->next === 'error')
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private function _listArchivedFiles($zipfile)
|
|
{
|
|
if (file_exists($zipfile))
|
|
{
|
|
$res = false;
|
|
if (!self::$force_pclZip && class_exists('ZipArchive', false))
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Using class ZipArchive...');
|
|
$files = array();
|
|
$zip = new ZipArchive();
|
|
$res = $zip->open($zipfile);
|
|
if ($res)
|
|
$res = (isset($zip->filename) && $zip->filename) ? true : false;
|
|
if ($zip && $res === true){
|
|
for ($i = 0; $i < $zip->numFiles; $i++)
|
|
$files[] = $zip->getNameIndex($i);
|
|
return $files;
|
|
}
|
|
elseif($res)
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('[ERROR] Unable to list archived files');
|
|
return false;
|
|
}
|
|
}
|
|
if (!$res)
|
|
{
|
|
$this->nextQuickInfo[] = $this->l('Using class PclZip...');
|
|
if (!class_exists('PclZip',false))
|
|
require_once(dirname(__FILE__).'/classes/pclzip.lib.php');
|
|
if ($zip = new PclZip($zipfile));
|
|
return $zip->listContent();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* bool _skipFile : check whether a file is in backup or restore skip list
|
|
*
|
|
* @param type $file : current file or directory name eg:'.svn' , 'settings.inc.php'
|
|
* @param type $fullpath : current file or directory fullpath eg:'/home/web/www/prestashop/config/settings.inc.php'
|
|
* @param type $way : 'backup' , 'upgrade'
|
|
*/
|
|
protected function _skipFile($file, $fullpath, $way = 'backup')
|
|
{
|
|
$fullpath = str_replace('\\', '/', $fullpath); // wamp compliant
|
|
$rootpath = str_replace('\\', '/', $this->prodRootDir);
|
|
$admin_dir = str_replace($this->prodRootDir, '', $this->adminDir);
|
|
switch ($way)
|
|
{
|
|
case 'backup':
|
|
if (in_array($file, $this->backupIgnoreFiles))
|
|
return true;
|
|
|
|
foreach ($this->backupIgnoreAbsoluteFiles as $path)
|
|
{
|
|
$path = str_replace(DIRECTORY_SEPARATOR.'admin', DIRECTORY_SEPARATOR.$admin_dir, $path);
|
|
if ($fullpath == $rootpath.$path)
|
|
return true;
|
|
}
|
|
break;
|
|
// restore or upgrade way : ignore the same files
|
|
// note the restore process use skipFiles only if xml md5 files
|
|
// are unavailable
|
|
case 'restore':
|
|
if (in_array($file, $this->restoreIgnoreFiles))
|
|
return true;
|
|
|
|
foreach ($this->restoreIgnoreAbsoluteFiles as $path)
|
|
{
|
|
$path = str_replace(DIRECTORY_SEPARATOR.'admin', DIRECTORY_SEPARATOR.$admin_dir, $path);
|
|
if ($fullpath == $rootpath.$path)
|
|
return true;
|
|
}
|
|
break;
|
|
case 'upgrade':
|
|
// keep mail : will skip only if already exists
|
|
if (!$this->keepMails) /* If set to false, we will not upgrade/replace the "mails" directory */
|
|
{
|
|
if (strpos(str_replace('/', DIRECTORY_SEPARATOR, $fullpath), DIRECTORY_SEPARATOR.'mails'.DIRECTORY_SEPARATOR))
|
|
return true;
|
|
}
|
|
if (in_array($file, $this->excludeFilesFromUpgrade))
|
|
{
|
|
if ($file[0] != '.')
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %s is preserved'), $file);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
foreach ($this->excludeAbsoluteFilesFromUpgrade as $path)
|
|
{
|
|
$path = str_replace(DIRECTORY_SEPARATOR.'admin', DIRECTORY_SEPARATOR.$admin_dir, $path);
|
|
if (strpos($fullpath, $rootpath.$path) !== false)
|
|
{
|
|
$this->nextQuickInfo[] = sprintf($this->l('File %s is preserved'), $fullpath);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
// default : if it's not a backup or an upgrade, do not skip the file
|
|
default:
|
|
return false;
|
|
}
|
|
// by default, don't skip
|
|
return false;
|
|
}
|
|
|
|
public function optionDisplayErrors()
|
|
{
|
|
if ($this->getConfig('PS_DISPLAY_ERRORS'))
|
|
{
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 'on');
|
|
}
|
|
else
|
|
ini_set('display_errors', 'off');
|
|
}
|
|
}
|