From 87df41c9d66622fcf4a1c40323844d79917cdd59 Mon Sep 17 00:00:00 2001 From: rMalie Date: Wed, 14 Sep 2011 08:29:10 +0000 Subject: [PATCH] // Merge -> revision 8552 git-svn-id: http://dev.prestashop.com/svn/v1/branches/1.5.x@8554 b9a71923-0436-4b27-9f14-aed3839534dd --- admin-dev/tabs/AdminGroups.php | 9 +- admin-dev/tabs/AdminModules.php | 20 +- admin-dev/tabs/AdminUpgrade.php | 2085 ----------------- classes/Category.php | 24 + classes/Tab.php | 6 +- classes/Tools.php | 15 +- modules/autoupgrade/AdminSelfTab.php | 2 +- modules/autoupgrade/AdminSelfUpgrade.php | 273 ++- modules/autoupgrade/SelfModule.php | 2 +- modules/autoupgrade/autoupgrade.php | 20 +- .../blocklayered/blocklayered-url-indexer.php | 3 +- modules/blocklayered/blocklayered.js | 38 +- modules/blocklayered/blocklayered.php | 315 ++- themes/prestashop/category-count.tpl | 4 +- themes/prestashop/category.tpl | 1 + themes/prestashop/lang/de.php | 10 +- themes/prestashop/lang/es.php | 10 +- themes/prestashop/lang/fr.php | 10 +- themes/prestashop/lang/it.php | 10 +- translations/fr/errors.php | 2 +- 20 files changed, 541 insertions(+), 2318 deletions(-) delete mode 100755 admin-dev/tabs/AdminUpgrade.php diff --git a/admin-dev/tabs/AdminGroups.php b/admin-dev/tabs/AdminGroups.php index 9b72edc2e..500003d40 100644 --- a/admin-dev/tabs/AdminGroups.php +++ b/admin-dev/tabs/AdminGroups.php @@ -307,15 +307,14 @@ class AdminGroups extends AdminTab if (!($obj = $this->loadObject())) return; $groupReduction = new GroupReduction(); - if (!$id_category = Tools::getValue('id_category') OR !Validate::isUnsignedId($id_category)) + if (!$id_category = Tools::getValue('id_category') || !Validate::isUnsignedId($id_category)) $this->_errors[] = Tools::displayError('Wrong category ID'); - elseif (!$reduction = Tools::getValue('reductionByCategory') OR !Validate::isPrice($reduction)) + else if (!$reduction = Tools::getValue('reductionByCategory') || !Validate::isPrice($reduction)) $this->_errors[] = Tools::displayError('Invalid reduction (must be a percentage)'); - elseif (Tools::getValue('reductionByCategory') > 100 OR Tools::getValue('reductionByCategory') < 0) + else if (Tools::getValue('reductionByCategory') > 100 || Tools::getValue('reductionByCategory') < 0) $this->_errors[] = Tools::displayError('Reduction value is incorrect'); - elseif (GroupReduction::doesExist((int)($obj->id), $id_category)){ + else if (GroupReduction::doesExist((int)$obj->id, $id_category)) $this->_errors[] = Tools::displayError('A reduction already exists for this category.'); - } else { $category = new Category((int)$id_category); diff --git a/admin-dev/tabs/AdminModules.php b/admin-dev/tabs/AdminModules.php index 1a10c38a7..7a43a9260 100644 --- a/admin-dev/tabs/AdminModules.php +++ b/admin-dev/tabs/AdminModules.php @@ -350,16 +350,18 @@ class AdminModules extends AdminTab unset(Context::getContext()->tmpOldShop); } } - if ($key != 'configure' AND isset($_GET['bpay'])) + if ($key != 'configure' && isset($_GET['bpay'])) Tools::redirectAdmin('index.php?tab=AdminPayment&token='.Tools::getAdminToken('AdminPayment'.(int)(Tab::getIdFromClassName('AdminPayment')).(int)$this->context->employee->id)); } - if (sizeof($module_errors)) + if (count($module_errors)) { - $htmlError = ''; - $this->_errors[] = Tools::displayError('The following module(s) were not installed successfully:').$htmlError; + // If error during module installation, no redirection + $html_error = ''; + + $this->_errors[] = sprintf(Tools::displayError('The following module(s) were not installed successfully: %s'), $html_error); } } if ($return) @@ -367,7 +369,7 @@ class AdminModules extends AdminTab } } - function extractArchive($file) + public function extractArchive($file) { $success = false; if (substr($file, -4) == '.zip') @@ -391,7 +393,7 @@ class AdminModules extends AdminTab public function display() { - if (!isset($_GET['configure']) AND !isset($_GET['delete']) OR sizeof($this->_errors) ) + if (!isset($_GET['configure']) && !isset($_GET['delete']) || count($this->_errors)) $this->displayList(); } diff --git a/admin-dev/tabs/AdminUpgrade.php b/admin-dev/tabs/AdminUpgrade.php deleted file mode 100755 index 7116eaabd..000000000 --- a/admin-dev/tabs/AdminUpgrade.php +++ /dev/null @@ -1,2085 +0,0 @@ - -* @copyright 2007-2011 PrestaShop SA -* @version Release: $Revision$ -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -require_once(_PS_ADMIN_DIR_.'/tabs/AdminPreferences.php'); - -class AdminUpgrade extends AdminPreferences -{ - public $ajax = false; - public $nextResponseType = 'json'; // json, xml - public $next = 'N/A'; - public $isModule = false; - - /** - * set to false if the current step is a loop - * - * @var boolean - */ - public $stepDone = true; - public $status = true; - public $error ='0'; - public $nextDesc = '.'; - public $nextParams = array(); - public $nextQuickInfo = array(); - public $currentParams = array(); - /** - * @var array theses values will be automatically added in "nextParams" - * if their properties exists - */ - public $ajaxParams = array( - // autoupgrade options - 'dontBackupImages', - 'keepDefaultTheme', - 'keepTrad', - 'manualMode', - 'desactivateCustomModule', - - // - 'backupDbFilename', - 'backupFilesFilename', - - - ); - public $autoupgradePath = null; - /** - * autoupgradeDir - * - * @var string directory relative to admin dir - */ - public $autoupgradeDir = 'autoupgrade'; - public $latestRootDir = ''; - public $prodRootDir = ''; - public $adminDir = ''; - public $rootWritable = false; - public $svnDir = 'svn'; - public $destDownloadFilename = 'prestashop.zip'; - public $toUpgradeFileList = array(); - public $backupFileList = array(); - public $sampleFileList = array(); - private $backupIgnoreFiles = array(); - private $backupIgnoreAbsoluteFiles = array(); - private $excludeFilesFromUpgrade = array(); - private $excludeAbsoluteFilesFromUpgrade = array(); - - private $backupFilesFilename = ''; - private $backupDbFilename = ''; - -/** - * int loopBackupFiles : if your server has a low memory size, lower this value - * @TODO remove the static, add a const, and use it like this : min(AdminUpgrade::DEFAULT_LOOP_ADD_FILE_TO_ZIP,Configuration::get('LOOP_ADD_FILE_TO_ZIP'); - */ - public static $loopBackupFiles = 1000; -/** - * int loopUpgradeFiles : if your server has a low memory size, lower this value - */ - public static $loopUpgradeFiles = 1000; -/** - * intloopRemoveSamples : if your server has a low memory size, lower this value - */ - public static $loopRemoveSamples = 1000; - -// public static $skipAction = array('unzip'=>'listSampleFiles'); - public static $skipAction; - public $useSvn; - - protected $_includeContainer = false; - - 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) - 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; - - $cookiePath = __PS_BASE_URI__.str_replace($this->prodRootDir,'',trim($this->adminDir,'/')); - setcookie('id_employee', $id_employee, time()+3600, $cookiePath); - setcookie('id_tab', $this->id, time()+3600, $cookiePath); - setcookie('autoupgrade', $this->encrypt($id_employee), time()+3600, $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'); - - $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(); - else - $this->id = $_COOKIE['id_tab']; - } - - protected function l($string, $class = 'AdminTab', $addslashes = FALSE, $htmlentities = TRUE) - { - if($this->isModule) - { - $currentClass = get_class($this); - // need to be called in order to populate $classInModule - return SelfModule::findTranslation('autoupgrade', $string, 'AdminSelfUpgrade'); - } - else - return parent::l($string, $class, $addslashes, $htmlentities); - } - - /** - * _setFields function to set fields (only when we need it). - * - * @return void - */ - private function _setFields() - { - $this->_fieldsAutoUpgrade['PS_AUTOUP_DONT_SAVE_IMAGES'] = array( - 'title' => $this->l('Don\'t save images'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc'=>$this->l('You can exclude the image directory from backup if you already saved it by another method (not recommended)'), - ); - - $this->_fieldsAutoUpgrade['PS_AUTOUP_KEEP_DEFAULT_THEME'] = array( - 'title' => $this->l('Keep theme "prestashop"'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc'=>$this->l('If you have customized PrestaShop default theme, you can protect it from upgrade (not recommended)'), - ); - - $this->_fieldsAutoUpgrade['PS_AUTOUP_KEEP_TRAD'] = array( - 'title' => $this->l('Keep translations'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc'=>$this->l('If set too yes, you will keep all your translations'), - ); - - $this->_fieldsAutoUpgrade['PS_AUTOUP_CUSTOM_MOD_DESACT'] = array( - 'title' => $this->l('Desactivate custom modules'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc'=>$this->l('If you don\'t desactivate your modules, you can have some compatibility problem and the Modules page might not load correctly.'), - ); - // allow manual mode only for dev - if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) - $this->_fieldsAutoUpgrade['PS_AUTOUP_MANUAL_MODE'] = array( - 'title' => $this->l('Manual mode'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc'=>$this->l('Check this if you want to stop after each step'), - ); - - if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ AND function_exists('svn_checkout')) - { - $this->_fieldsAutoUpgrade['PS_AUTOUP_USE_SVN'] = array( - 'title' => $this->l('Use Subversion'), 'cast' => 'intval', 'validation' => 'isBool', - 'type' => 'bool', 'desc' => $this->l('check this if you want to use unstable svn instead of official release'), - ); - } - } - - public function configOk() - { - $allowed = (ConfigurationTest::test_fopen() && $this->rootWritable); - $allowed &= !Configuration::get('PS_SHOP_ENABLE'); - - return $allowed; - } - /** - * isUpgradeAllowed checks if all server configuration is valid for upgrade - * - * @return void - */ - public function isUpgradeAllowed() - { - $allowed = (ConfigurationTest::test_fopen() && $this->rootWritable); - - if (!defined('_PS_MODE_DEV_') OR !_PS_MODE_DEV_) - $allowed &= $this->upgrader->autoupgrade; - - return $allowed; - } - - /** - * 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_; - - // test writable recursively - if ($this->isModule) - { - require_once('ConfigurationTest.php'); - if(!class_exists('ConfigurationTest', false) AND class_exists('ConfigurationTestCore')) - eval('class ConfigurationTest extends ConfigurationTestCore{}'); - } - if (ConfigurationTest::test_dir($this->prodRootDir,true)) - $this->rootWritable = true; - - // checkPSVersion will be not - $this->upgrader = new Upgrader(true); - $this->upgrader->checkPSVersion(); - // If you have defined this somewhere, you know what you do - if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ AND function_exists('svn_checkout')) - { - if (!$this->isModule OR class_exists('Configuration',false)) - $this->useSvn = Configuration::get('PS_AUTOUP_USE_SVN'); - } - else - $this->useSvn = false; - - // from $_POST or $_GET - $this->action = empty($_REQUEST['action'])?null:$_REQUEST['action']; - $this->currentParams = empty($_REQUEST['params'])?null:$_REQUEST['params']; - - // 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 (class_exists('Configuration',false)) - { - $time = time(); - $this->backupDbFilename = Configuration::get('UPGRADER_BACKUPDB_FILENAME'); - if(!file_exists($this->backupDbFilename)) - { - // If not exists, the filename is generated by Backup.php - $this->backupDbFilename = ''; - Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME', $this->backupDbFilename); - } - - $this->backupFilesFilename = Configuration::get('UPGRADER_BACKUPFILES_FILENAME'); - if(!file_exists($this->backupFilesFilename)) - { - $this->backupFilesFilename = $this->autoupgradePath . DIRECTORY_SEPARATOR . 'backupfile-'.date('Y-m-d').'-'.$time.'.zip'; - Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME', $this->backupFilesFilename); - } - } - else{ - // backupDbFilename should never be empty - $this->backupDbFilename = $this->currentParams['backupDbFilename']; - // backupFilesFilename should never etc. - $this->backupFilesFilename = $this->currentParams['backupFilesFilename']; - } - $this->autoupgradePath = $this->adminDir.DIRECTORY_SEPARATOR.$this->autoupgradeDir; - - if (!file_exists($this->autoupgradePath)) - if (!@mkdir($this->autoupgradePath,0777)) - $this->_errors[] = Tools::displayError(sprintf($this->l('unable to create directory %s'),$this->autoupgradePath)); - - $latest = $this->autoupgradePath.DIRECTORY_SEPARATOR.'latest'; - if (!file_exists($latest)) - if (!@mkdir($latest,0777)) - $this->_errors[] = Tools::displayError(sprintf($this->l('unable to create directory %s'),$latest)); - - $this->latestRootDir = $latest.DIRECTORY_SEPARATOR.'prestashop'; - $this->adminDir = str_replace($this->prodRootDir,'',$this->adminDir); - // @TODO future option - // $this->testRootDir = $this->autoupgradePath.DIRECTORY_SEPARATOR.'test'; - - /* option */ - if (class_exists('Configuration',false)) - { - $this->dontBackupImages = Configuration::get('PS_AUTOUP_DONT_SAVE_IMAGES'); - $this->keepDefaultTheme = Configuration::get('PS_AUTOUP_KEEP_DEFAULT_THEME'); - $this->keepTrad = Configuration::get('PS_AUTOUP_KEEP_TRAD'); - $this->manualMode = Configuration::get('PS_AUTOUP_MANUAL_MODE'); - $this->desactivateCustomModule = Configuration::get('PS_AUTOUP_CUSTOM_MOD_DESACT'); - } - else - { - $this->dontBackupImages = $this->currentParams['dontBackupImages']; - $this->keepDefaultTheme = $this->currentParams['keepDefaultTheme']; - $this->keepTrad = $this->currentParams['keepTrad']; - $this->manualMode = $this->currentParams['manualMode']; - $this->desactivateCustomModule = $this->current['desactivateCustomModule']; - } - // We can add any file or directory in the exclude dir : theses files will be not removed or overwritten - // @TODO cache should be ignored recursively, but we have to reconstruct it after upgrade - // - compiled from smarty - // - .svn - $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty_v2/compile"; - $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty_v2/cache"; - $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty/compile"; - $this->backupIgnoreAbsoluteFiles[] = "/tools/smarty/cache"; - - $this->excludeFilesFromUpgrade[] = '.'; - $this->excludeFilesFromUpgrade[] = '..'; - $this->excludeFilesFromUpgrade[] = '.svn'; - $this->excludeFilesFromUpgrade[] = 'install'; - $this->excludeFilesFromUpgrade[] = 'settings.inc.php'; - $this->excludeFilesFromUpgrade[] = 'autoupgrade'; - $this->backupIgnoreFiles[] = '.'; - $this->backupIgnoreFiles[] = '..'; - $this->backupIgnoreFiles[] = '.svn'; - $this->backupIgnoreFiles[] = 'autoupgrade'; - - if ($this->dontBackupImages) - $this->backupIgnoreAbsoluteFiles[] = "/img"; - - - if ($this->keepDefaultTheme) - $this->excludeAbsoluteFilesFromUpgrade[] = "/themes/prestashop"; - - if ($this->keepTrad) - $this->excludeFilesFromUpgrade[] = "translations"; - } - - /** - * getFilePath return the path to the zipfile containing prestashop. - * - * @return void - */ - private function getFilePath() - { - return $this->autoupgradePath.DIRECTORY_SEPARATOR.$this->destDownloadFilename; - } - - public function postProcess() - { - $this->_setFields(); - - if (sizeof($_POST)>0) - { - $this->_postConfig($this->_fieldsAutoUpgrade); - } - } - - public function ajaxProcessUpgradeComplete() - { - $this->nextDesc = $this->l('Upgrade process done. Congratulations ! You can now reactive your shop.'); - $this->next = ''; - } - - public function ajaxProcessUpgradeNow() - { - $this->nextDesc = $this->l('Starting upgrade ...'); - - if ($this->useSvn) - { - $this->next = 'svnCheckout'; - $this->nextDesc = $this->l('switching to svn checkout (useSvn set to true)'); - } - else - { - $this->next = 'download'; - $this->nextDesc = $this->l('Shop desactivated. Now downloading (this can takes some times )...'); - } - } - - public function ajaxProcessSvnExport() - { - if ($this->useSvn) - { - // first of all, delete the content of the latest root dir just in case - if (is_dir($this->latestRootDir)) - Tools::deleteDirectory($this->latestRootDir, false); - - if (!file_exists($this->latestRootDir)) - { - @mkdir($this->latestRootDir); - } - - if (svn_export($this->autoupgradePath . DIRECTORY_SEPARATOR . $this->svnDir, $this->latestRootDir)) - { - - // export means svn means install-dev and admin-dev. - // let's rename admin to the correct admin dir - // and rename install-dev to install - $adminDir = str_replace($this->prodRootDir, '', $this->adminDir); - rename($this->latestRootDir.DIRECTORY_SEPARATOR.'install-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.'install'); - rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin-dev', $this->latestRootDir.DIRECTORY_SEPARATOR.$adminDir); - - // Unsetting to force listing - unset($this->nextParams['removeList']); - $this->next = "removeSamples"; - $this->nextDesc = $this->l('Export svn complete. removing sample files...'); - return true; - } - else - { - $this->next = 'error'; - $this->nextDesc = $this->l('error when svn export '); - } - } - } - - public function ajaxProcessUnzip(){ - if ($this->isModule AND !class_exists('Tools',false)) - require_once('Tools.php'); - - $filepath = $this->getFilePath(); - $destExtract = $this->autoupgradePath.DIRECTORY_SEPARATOR.'latest'; - if (file_exists($destExtract)) - Tools::deletedirectory($destExtract); - - if (Tools::ZipExtract($filepath,$destExtract)) - { - $adminDir = str_replace($this->prodRootDir, '', $this->adminDir); - rename($this->latestRootDir.DIRECTORY_SEPARATOR.'admin', $this->latestRootDir.DIRECTORY_SEPARATOR.$adminDir); - // Unsetting to force listing - unset($this->nextParams['removeList']); - $this->next = "removeSamples"; - $this->nextDesc = $this->l('Extract complete. removing sample files...'); - return true; - } - else{ - $this->next = "error"; - $this->nextDesc = sprintf($this->l('unable to extract %1$s into %2$s ...'),$filepath,$destExtract); - return true; - } - } - - - /** - * _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) - * - * @TODO maybe $regex instead of $fileext ? - * @param string $dir directory to look in - * @param string $fileext suffixe filename - * @return void - */ - private function _listSampleFiles($dir, $fileext = '.jpg'){ - $res = true; - $dir = rtrim($dir,'/').DIRECTORY_SEPARATOR; - - $toDel = scandir($dir); - // copied (and kind of) adapted from AdminImages.php - foreach ($toDel AS $file) - { - if ($file!='.' AND $file != '..' AND $file != '.svn') - { - - if (preg_match('#'.preg_quote($fileext,'#').'$#i',$file)) - { - $this->sampleFileList[] = $dir.$file; - } - else if (is_dir($dir.$file)) - { - $res &= $this->_listSampleFiles($dir.$file); - } - } - } - return $res; - } - - public function _listBackupFiles($dir) - { - $allFiles = scandir($dir); - foreach ($allFiles as $file) - { - $fullPath = $dir.DIRECTORY_SEPARATOR.$file; - - if (!$this->_skipFile($file, $fullPath,'backup')) - { - if (is_dir($fullPath)) - $this->_listBackupFiles($fullPath); - else - $this->backupFileList[] = $fullPath; - } - else - $this->backupIgnoreFiles[] = $fullPath; - - } - } - - public function _listFilesToUpgrade($dir) - { - $allFiles = scandir($dir); - foreach ($allFiles as $file) - { - $fullPath = $dir.DIRECTORY_SEPARATOR.$file; - - if (!$this->_skipFile($file, $fullPath, "upgrade")) - { - if (is_dir($fullPath)) - { - // if is_dir, we will create it :)e it :) - $this->toUpgradeFileList[] = $fullPath; - if (strpos($dir.DIRECTORY_SEPARATOR.$file, 'install') === false) - { - $this->_listFilesToUpgrade($fullPath); - } - } - else - $this->toUpgradeFileList[] = $fullPath; - } - } - - $this->nextParams['filesToUpgrade'] = $this->toUpgradeFileList; - } - - - public function ajaxProcessUpgradeFiles(){ - // @TODO : - $this->nextParams = $this->currentParams; - if (!isset($this->nextParams['filesToUpgrade'])) - $this->_listFilesToUpgrade($this->latestRootDir); - - // later we could choose between _PS_ROOT_DIR_ or _PS_TEST_DIR_ - $this->destUpgradePath = $this->prodRootDir; - - // upgrade files one by one like for the backup - // with a 1000 loop because it's funny - // @TODO : - // foreach files in latest, copy - $this->next = 'upgradeFiles'; - if (!is_array($this->nextParams['filesToUpgrade'])) - { - error($this->nextParams); - $this->next = 'error'; - $this->nextDesc = $this->l('filesToUpgrade is not an array'); - $this->nextQuickInfo[] = $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;$inextParams['filesToUpgrade'])<=0) - { - $this->next = 'upgradeDb'; - $this->nextDesc = $this->l('All files upgraded. Now upgrading database'); - $this->nextResponseType = 'xml'; - break; - } - - //$file = array_shift($this->nextParams['filesToUpgrade']); - $file = array_shift($this->nextParams['filesToUpgrade']); - if (!$this->upgradeThisFile($file)) - { - // put the file back to the begin of the list - $totalFiles = array_unshift($this->nextParams['filesToUpgrade'],$file); - $this->next = 'error'; - $this->nextQuickInfo[] = sprintf($this->l('error when trying to upgrade %s'),$file); - break; - } - else{ - // @TODO : maybe put several files at the same times ? - $this->nextDesc = sprintf($this->l('%2$s files left to upgrade.'),$file,sizeof($this->nextParams['filesToUpgrade'])); - } - } - } - - /** - * _modelDoUpgrade prepare the call to doUpgrade.php file (like model.php) - * - * @return void - */ - public function _modelDoUpgrade() - { - // a. set logger - // it will be used later - global $logger; - $logger = new FileLogger(); - if (function_exists('date_default_timezone_set')) - date_default_timezone_set('Europe/Paris'); - // use autoupgrade as log dir - $logger->setFilename($this->latestRootDir.'/'.date('Ymd').'_autoupgrade.log'); - - // init env. - @set_time_limit(0); - @ini_set('max_execution_time', '0'); - // setting the memory limit to 128M only if current is lower - $memory_limit = ini_get('memory_limit'); - if (substr($memory_limit,-1) != 'G' - AND ((substr($memory_limit,-1) == 'M' AND substr($memory_limit,0,-1) < 128) - OR 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']) || $_SERVER['REQUEST_URI'] == '') - $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME']; - - if ($tmp = strpos($_SERVER['REQUEST_URI'], '?')) - $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $tmp); - - $_SERVER['REQUEST_URI'] = str_replace('//', '/', $_SERVER['REQUEST_URI']); - - /////////////////////// - // Copy from model.php - /////////////////////// - $upgrader = $this->upgrader; - $upgrader->checkPSVersion(true); - - define('INSTALL_VERSION', $upgrader->version_num); - // now the install dir to use is in a subdirectory of the admin dir - define('INSTALL_PATH', realpath($this->latestRootDir.DIRECTORY_SEPARATOR.'install')); - - define('PS_INSTALLATION_IN_PROGRESS', true); - // Note : we don't need ToolsInstall.php - // include_once(INSTALL_PATH.'/classes/ToolsInstall.php'); - - 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)))); - - // Note : INSTALLER__PS_BASE_URI_ABSOLUTE is not used for upgrade - // define('INSTALLER__PS_BASE_URI_ABSOLUTE', 'http://'.ToolsInstall::getHttpHost(false, true).INSTALLER__PS_BASE_URI); - - // XML Header - header('Content-Type: text/xml'); - require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'doUpgrade.php'); - - ////////////////////////////// - // End of copy from model.php - ////////////////////////////// - - } - - public function ajaxProcessUpgradeDb(){ - // @TODO : 1/2/3 have to be done at the beginning !!!!!!!!!!!!!!!!!!!!!! - - // use something like actual in install-dev - // Notice : xml used here ... - - // 1) confirm version is correct(DB) - // install/model.php?method=getVersionFromDb&language=0 - // later - - // 2) confirm config is correct (r/w rights) - // install/model.php?method=checkConfig&firsttime=0 - // later - - // 3) save current activated modules in nextParams, or don't desactivate them ? - // @TODO - // 4) upgrade - // install/model.php?_=1309193641470&method=doUpgrade&customModule=desactivate - if (!empty($this->currentParams['desactivateCustomModule'])) - $_GET['customModule'] = 'desactivate'; - - if (!$this->_modelDoUpgrade()) - { - $this->next = 'error'; - $this->nextDesc = $this->l('error during upgrade Db'); - } - - // 5) compare activated modules and reactivate them - // @TODO - - } - - - /** - * upgradeThisFile - * - * @param mixed $file - * @return void - */ - public function upgradeThisFile($file) - { - // @TODO : later, we could handle customization with some kind of diff functions - // for now, just copy $file in str_replace($this->latestRootDir,_PS_ROOT_DIR_) - // $file comes from scandir function, no need to lost time and memory with file_exists() - if ($this->_skipFile('', $file,'upgrade')) - { - $this->nextQuickInfo[] = $this->l('%s ignored'); - return true; - } - else - { - $dest = str_replace($this->latestRootDir, $this->destUpgradePath,$file); - - if (is_dir($file)) - { - if (!file_exists($dest)) - { - if (@mkdir($dest)) - { - $this->nextQuickInfo[] = sprintf($this->l('created dir %2$s. %3$s files left to upgrade.'),$file, $dest, sizeof($this->nextParams['filesToUpgrade'])); - return true; - } - else - { - $this->next = 'error'; - $this->nextQuickInfo[] = sprintf($this->l('error when creating directory %s'),$dest); - $this->nextDesc = sprintf($this->l('error when creating directory %s'),$dest); - return false; - } - } - else - { - // directory already exists - return true; - } - } - else - { - if (copy($file,$dest)) - { - $this->nextQuickInfo[] = sprintf($this->l('copied %1$s in %2$s. %3$s files left to upgrade.'),$file, $dest, sizeof($this->nextParams['filesToUpgrade'])); - return true; - } - else - { - $this->next = 'error'; - $this->nextQuickInfo[] = sprintf($this->l('error for copy %1$s in %2$s'),$file,$dest); - $this->nextDesc = sprintf($this->l('error for copy %1$s in %2$s'),$file,$dest); - return false; - } - } - } - - } - - public function ajaxProcessRollback() - { - // 1st, need to analyse what was wrong. - - $this->nextParams = $this->currentParams; - if (!empty($this->backupFilesFilename) AND file_exists($this->backupFilesFilename)) - { - $this->next = 'restoreFiles'; - $this->status = 'ok'; - $this->nextDesc = $this->l('Files restored, now restoring database.'); - } - else - { - if (!empty($this->backupDbFilename) AND file_exists($this->backupDbFilename)) - { - $this->next = 'restoreDb'; - $this->status = 'ok'; - $this->nextDesc = $this->l('Database restored'); - } - else - { - // 2nd case if upgradeFiles made an error - // 3rd case if no upgrade has been done - // all theses cases are handled by the method ajaxRequestRollback() - $this->next = ''; // next is empty : nothing next :) - $this->status = 'ok'; - $this->nextDesc = $this->l('All your site is restored... '); - } - } - } - - /** - * ajaxProcessRestoreFiles restore the previously saved files. - * - * @return boolean true if succeed - */ - public function ajaxProcessRestoreFiles() - { - // @TODO : workaround max_execution_time / ajax batch unzip - if (!empty($this->backupFilesFilename) AND file_exists($this->backupFilesFilename)) - { - // cleanup current PS tree - $list = $this->_listArchivedFiles(); - if (count($list) > 0) - { - $this->_cleanUp($this->prodRootDir.'/'); - $this->nextQuickInfo[] = $this->l('root directory cleaned.'); - - $filepath = $this->backupFilesFilename; - $destExtract = $this->prodRootDir; - - if (self::ZipExtract($filepath, $destExtract)) - { - // once it's restored, delete the file ! - unlink($this->backupFilesFilename); - Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME', ''); - if (!empty($this->backupDbFilename)) - { - $this->nextDesc = $this->l('Files restored. No database backup found. Restoration done.'); - $this->next = ''; - } - else - { - $this->nextDesc = $this->l('Files restored.'); - $this->next = 'rollback'; - } - return true; - } - else - { - $this->next = "error"; - $this->nextDesc = sprintf($this->l('unable to extract $1$s into %2$s .'), $filepath, $destExtract); - return false; - } - } - } - else - { - $this->next = 'error'; - $this->nextDesc = $this->l('no known backup. nothing to restore.'); - return false; - } - } - - /** - * try to restore db backup file - * @return type : hey , what you expect ? well mysql errors array ..... - * @TODO : maybe this could be in the Backup class - */ - public function ajaxProcessRestoreDb() - { - $exts = explode('.', $this->backupDbFilename); - $fileext = $exts[count($exts)-1]; - $requests = array(); - $errors = array(); - $content = ''; - switch ($fileext) - { - case 'bz': - case 'bz2': - if ($fp = bzopen($this->backupDbFilename, 'r')) - { - while(!feof($fp)) - $content .= bzread($fp, filesize($this->backupDbFilename)); - bzclose($fp); - } - break; - case 'gz': - if ($fp = gzopen($this->backupDbFilename, 'r')) - { - while(!feof($fp)) - $content = gzread($fp, filesize($this->backupDbFilename)); - gzclose($fp); - } - break; - // default means sql ? - default : - if ($fp = fopen($this->backupDbFilename, 'r')) - { - while(!feof($fp)) - $content = fread($fp, filesize($this->backupDbFilename)); - fclose($fp); - } - } - - if ($content=='') - return false; - - // preg_match_all is better than preg_split (what is used in doUpgrade.php) - // This way we avoid extra blank lines - // option s (PCRE_DOTALL) added - // @TODO need to check if a ";" in description could block that (I suppose it can at the end of a line) - preg_match_all('/.*;[\n]\+/s', $content, $requests); - /* @TODO maybe improve regex pattern ... */ - $db = Db::getInstance(); - if (count($requests)>0) - { - foreach ($requests as $request) - if (!empty($request)) - if (!$db->Execute($request)) - $this->nextQuickInfo[] = $db->getMsgError(); - - // once it's restored, delete the file ! - unlink($this->backupDbFilename); - Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME',''); - } - else - $this->nextQuickInfo[] = $this->l('Nothing to restore (no request found)'); - - $this->next = 'rollback'; - $this->nextDesc = 'Database restore done.'; - } - - public function ajaxProcessBackupDb() - { - if(!class_exists('ObjectModel',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/ObjectModel.php'); - if(!class_exists('ObjectModel',false)) - eval('Class ObjectModel extends ObjectModelCore{}'); - } - - if(!class_exists('Language',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/Language.php'); - if(!class_exists('Language',false)) - eval('Class Language extends LanguageCore{}'); - } - if(!class_exists('Validate',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/Validate.php'); - if(!class_exists('Validate',false)) - eval('Class Validate extends ValidateCore{}'); - } - if(!class_exists('Db',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/Db.php'); - if(!class_exists('Db',false)) - eval('abstract Class Db extends DbCore{}'); - } - if(!class_exists('MySQL',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/MySQL.php'); - if(!class_exists('MySQL',false)) - eval('Class MySQL extends MySQLCore{}'); - } - if(!class_exists('Configuration',false)) - { - require_once(_PS_ROOT_DIR_.'/classes/Configuration.php'); - if(!class_exists('Configuration',false)) - eval('Class Configuration extends ConfigurationCore{}'); - } - if(!class_exists('Backup',false)) - { - require_once('Backup.php'); - if(!class_exists('ObjectModel',false)) - eval('Class ObjectModel extends ObjectModelCore{}'); - } - - if(!defined('_PS_MAGIC_QUOTES_GPC_')) - define('_PS_MAGIC_QUOTES_GPC_', get_magic_quotes_gpc()); - if(!defined('_PS_MYSQL_REAL_ESCAPE_STRING_')) - define('_PS_MYSQL_REAL_ESCAPE_STRING_', function_exists('mysql_real_escape_string')); - - $backup = new Backup(); - // for backup db, use autoupgrade directory - // @TODO : autoupgrade must not be static - $backup->setCustomBackupPath('autoupgrade'); - // maybe for big tables we should save them in more than one file ? - $res = $backup->add(); - if ($res) - { - $this->nextParams['backupDbFilename'] = $backup->id; - // We need to load configuration to use it ... - Configuration::loadConfiguration(); - Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME', $backup->id); - - $this->next = 'upgradeFiles'; - $this->nextDesc = sprintf($this->l('Database backup done in %s. Now updating files'),$backup->id); - } - // if an error occur, we assume the file is not saved - } - - public function ajaxProcessBackupFiles() - { - $this->nextParams = $this->currentParams; - $this->stepDone = false; - ///////////////////// - - if (!isset($this->nextParams['filesForBackup'])) - { - $list = $this->_listBackupFiles($this->prodRootDir); - $this->nextQuickInfo[] = sprintf($this->l('%s Files to backup.'), sizeof($this->backupFileList)); - $this->nextParams['filesForBackup'] = $this->backupFileList; - - // delete old backup, create new - if (file_exists($this->backupFilesFilename)) - unlink($this->backupFilesFilename); - - $this->nextQuickInfo[] = sprintf($this->l('backup files initialized in %s'), $this->backupFilesFilename); - } - - ///////////////////// - $this->next = 'backupFiles'; - // @TODO : display % instead of this - $this->nextDesc = sprintf($this->l('Backup files in progress. %s files left'), sizeof($this->nextParams['filesForBackup'])); - if (is_array($this->nextParams['filesForBackup'])) - { - // @TODO later - // 1) calculate crc32 of next file - // 2) use the provided xml with crc32 calculated from previous versions ? - // or simply use the latest dir ? - //$current = crc32(file_get_contents($file)); - //$file = $this->nextParams['filesForBackup'][0]; - //$latestFile = str_replace(_PS_ROOT_DIR_,$this->latestRootDir,$file); - - // if (file_exists($latestFile)) - // $latest = crc32($latestFile); - // else - // $latest = ''; - - $zip = new ZipArchive(); - if ($zip->open($this->backupFilesFilename, ZIPARCHIVE::CREATE)) - { - $this->next = 'backupFiles'; - // @TODO all in one time will be probably too long - // 1000 ok during test, but 10 by 10 to be sure - $this->stepok = false; - // @TODO min(self::$loopBackupFiles, sizeof()) - for($i=0;$inextParams['filesForBackup'])<=0) - { - $this->stepok = true; - $this->status = 'ok'; - $this->next = 'backupDb'; - $this->nextDesc = $this->l('All files saved. Now backup Database'); - $this->nextQuickInfo[] = $this->l('all files have been added to archive.'); - break; - } - // filesForBackup already contains all the correct files - $file = array_shift($this->nextParams['filesForBackup']); - $archiveFilename = str_replace($this->prodRootDir,'',$file); - // @TODO : maybe put several files at the same times ? - if ($zip->addFile($file,$archiveFilename)) - $this->nextQuickInfo[] = sprintf($this->l('%1$s added to archive. %2$s left.'),$file, sizeof($this->nextParams['filesForBackup'])); - else - { - // if an error occur, it's more safe to delete the corrupted backup - if (file_exists($this->backupFilesFilename)) - unlink($this->backupFilesFilename); - $this->next = 'error'; - $this->nextDesc = sprintf($this->l('error when trying to add %1$s to archive %2$s.'),$file, $backupFilePath); - break; - } - } - $zip->close(); - return true; - } - else{ - $this->next = 'error'; - $this->nextDesc = $this->l('unable to open archive'); - return false; - } - } - else - { - $this->next = 'backupDb'; - $this->nextDesc = 'All files saved. Now backup Database'; - return true; - } - // 4) save for display. - } - - - private function _removeOneSample($removeList) - { - if (is_array($removeList) AND sizeof($removeList)>0) - { - if (file_exists($removeList[0]) AND unlink($removeList[0])) - { - $item = array_shift($removeList); - $this->next = 'removeSamples'; - $this->nextParams['removeList'] = $removeList; - $this->nextQuickInfo[] = sprintf($this->l('%1$s removed. %2$s items left'), $item, sizeof($removeList)); - } - else - { - $this->next = 'error'; - $this->nextParams['removeList'] = $removeList; - $this->nextQuickInfo[] = sprintf($this->l('error when removing %1$s, %2$s items left'), $removeList[0], sizeof($removeList)); - return false; - } - } - return true; - } - - public function ajaxProcessRemoveSamples(){ - $this->stepDone = false; - // @TODO : list exaustive list of files to remove : - // all images from img dir exept admin ? - // all images like logo, favicon, ?. - // all custom image from modules ? - // all custom image from theme ? - if (!isset($this->currentParams['removeList'])) - { - $this->_listSampleFiles($this->autoupgradePath.'/latest/prestashop/img', 'jpg'); - $this->_listSampleFiles($this->autoupgradePath.'/latest/prestashop/modules/editorial/', 'homepage_logo.jpg'); - // @TODO handle this bad thing - $this->nextQuickInfo[] = sprintf($this->l('Starting to remove %1$s sample files'), sizeof($this->sampleFileList)); - $this->nextParams['removeList'] = $this->sampleFileList; - } - - - // @TODO : removing @, adding if file_exists -// @unlink(_PS_ROOT_DIR_.'modules'.DIRECTORY_SEPARATOR.'editorial'.DIRECTORY_SEPARATOR.'editorial.xml'); -// @unlink(_PS_ROOT_DIR_.'modules'.DIRECTORY_SEPARATOR.'editorial'.DIRECTORY_SEPARATOR.'homepage_logo.jpg'); // homepage custom ? -// @unlink(_PS_ROOT_DIR_.'img'.DIRECTORY_SEPARATOR.'logo.jpg'); -// @unlink(_PS_ROOT_DIR_.'img'.DIRECTORY_SEPARATOR.'favicon.ico'); - $resRemove = true; - for($i=0;$inextParams['removeList']) <= 0 ) - { - $this->stepDone = true; - $this->next = 'backupFiles'; - $this->nextDesc = $this->l('All sample files removed. Now backup files.'); - // break the loop, all sample already removed - return true; - } - $resRemove &= $this->_removeOneSample($this->nextParams['removeList']); - if (!$resRemove) - break; - } - - return $resRemove; - } - - public function ajaxProcessSvnCheckout() - { - $this->nextParams = $this->currentParams; - if ($this->useSvn){ - $svnLink = 'http://svn.prestashop.com/trunk'; - $dest = $this->autoupgradePath . DIRECTORY_SEPARATOR . $this->svnDir; - - $svnStatus = svn_status($dest); - if (is_array($svnStatus)) - { - if (sizeof($svnStatus) == 0) - { - $this->next = 'svnExport'; - $this->nextDesc = sprintf($this->l('working copy already %s up-to-date. now exporting it into latest dir'),$dest); - } - else - { - // we assume no modification has been done - // @TODO a svn revert ? - if ($svnUpdate = svn_update($dest)) - { - $this->next = 'svnExport'; - $this->nextDesc = sprintf($this->l('SVN Update done for working copy %s . now exporting it into latest...'),$dest); - } - } - } - else - { - // no valid status found - // @TODO : is 0777 good idea ? - if (!file_exists($dest)) - if (!@mkdir($dest,0777)) - { - $this->next = 'error'; - $this->nextDesc = sprintf($this->l('unable to create directory %s'),$dest); - return false; - } - - if (svn_checkout($svnLink, $dest)) - { - $this->next = 'svnExport'; - $this->nextDesc = sprintf($this->l('SVN Checkout done from %s . now exporting it into latest...'),$svnLink); - return true; - } - else - { - $this->next = 'error'; - $this->nextDesc = $this->l('SVN Checkout error...'); - } - } - } - else - { - $this->next = 'error'; - $this->nextDesc = $this->l('not allowed to use svn'); - } - } - - public function ajaxProcessDownload() - { - if (@ini_get('allow_url_fopen')) - { - $res = $this->upgrader->downloadLast($this->autoupgradePath,$this->destDownloadFilename); - if ($res){ - $this->next = 'unzip'; - $this->nextDesc = $this->l('Download complete. Now extracting'); - } - else - { - $this->next = 'error'; - $this->nextDesc = $this->l('Error during download'); - } - } - else - { - // @TODO : ftp mode - $this->next = 'error'; - $this->nextDesc = sprintf($this->l('you need allow_url_fopen for automatic download. You can also manually upload it in %s'),$this->autoupgradePath.$this->destDownloadFilename); - } - } - - public function buildAjaxResult() - { - $return['error'] = $this->error; - $return['stepDone'] = $this->stepDone; - $return['next'] = $this->next; - $return['status'] = $this->next == 'error' ? 'error' : 'ok'; - $return['nextDesc'] = $this->nextDesc; - - foreach($this->ajaxParams as $v) - if(property_exists($this,$v)) - $this->nextParams[$v] = $this->$v; - - $return['nextParams'] = $this->nextParams; - - $return['nextParams']['typeResult'] = $this->nextResponseType; - - $return['nextQuickInfo'] = $this->nextQuickInfo; - return Tools::jsonEncode($return); - } - - /** - * displayConf - * - * @return void - */ - public function displayConf() - { - if(!$this->isModule) - { - if (version_compare(_PS_VERSION_,'1.4.4.0','<') AND false) - $this->_errors[] = Tools::displayError('This class depends of several files modified in 1.4.4.0 version and should not be used in an older version'); - } - parent::displayConf(); - - } - - public function ajaxPreProcess() - { - if (!empty($_POST['responseType']) AND $_POST['responseType'] == 'json') - header('Content-Type: application/json'); - - if(!empty($_POST['action'])) - { - $action = $_POST['action']; - if (isset(self::$skipAction[strtolower($action)])) - { - $this->next = self::$skipAction[$action]; - $this->nextDesc = sprintf($this->l('action %s skipped'),$action); - $this->nextQuickInfo[] = sprintf($this->l('action %s skipped'),$action); - unset($_POST['action']); - } - else if (!method_exists(get_class($this), 'ajaxProcess'.$action)) - { - $this->nextDesc = sprintf($this->l('action "%1$s" not found'), $action); - $this->next = 'error'; - $this->error = '1'; - } - } - - if ($this->apacheModExists('mod_evasive')) - sleep(1); - } - /** - * apacheModExists return true if the apache module $name is loaded - * @TODO move this method in class Information (when it will exist) - * - * @param string $name module name - * @return boolean true if exists - */ - function apacheModExists($name) - { - if(function_exists('apache_get_modules')) - { - static $apacheModuleList = null; - - if (!is_array($apacheModuleList)) - $apacheModuleList = apache_get_modules(); - - // we need strpos (example can be evasive20 - foreach($apacheModuleList as $module) - if (strpos($name, $module)!==false) - return true; - } - else{ - // If apache_get_modules does not exists, - // one solution should be parsing httpd.conf, - // but we could simple parse phpinfo(INFO_MODULES) return string - ob_start(); - phpinfo(INFO_MODULES); - $phpinfo = ob_get_contents(); - ob_end_clean(); - if (strpos($phpinfo, $module) !== false) - return true; - } - - return false; - } - - private function _getJsErrorMsgs() - { - $INSTALL_VERSION = $this->upgrader->version_num; - $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('Can\'t 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('Can\'t write settings file, please create a file named settings.inc.php in 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('Impossible the access the 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('Can\'t find the sql upgrade files. Please verify that the /install/sql/upgrade 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(); - } - - private function _displayRollbackForm() - { - echo '
'.$this->l('Rollback').' -
'; - if (empty($this->backupFilesFilename) AND empty($this->backupDbFilename)) - echo $this->l('No rollback available'); - else if (!empty($this->backupFilesFilename) OR !empty($this->backupDbFilename)) - { - echo '
'; - } - if (!empty($this->backupFilesFilename) AND file_exists($this->backupFilesFilename)) - echo '
restoreFiles '.sprintf($this->l('click to restore %s'),$this->backupFilesFilename).'

'; - if (!empty($this->backupDbFilename) AND file_exists($this->backupDbFilename)) - echo '
restoreDb '.sprintf($this->l('click to restore %s'), $this->backupDbFilename).'

'; - - echo '
'; - } - - private function _displayUpgraderForm() - { - global $cookie; - $pleaseUpdate = $this->upgrader->checkPSVersion(); - - echo '
'; - echo ''.$this->l('Your current configuration').''; - echo ''.$this->l('Root directory').' : '.$this->prodRootDir.'

'; - - if ($this->rootWritable) - $srcRootWritable = '../img/admin/enabled.gif'; - else - $srcRootWritable = '../img/admin/disabled.gif'; - echo ''.$this->l('Root directory status').' : '.' '.($this->rootWritable?$this->l('fully writable'):$this->l('not writable recursively')).'

'; - - if ($this->upgrader->needUpgrade) - { - if ($this->upgrader->autoupgrade) - $srcAutoupgrade = '../img/admin/enabled.gif'; - else - $srcAutoupgrade = '../img/admin/disabled.gif'; - echo ''.$this->l('Autoupgrade allowed').' : '.' '.($this->upgrader->autoupgrade?$this->l('This release allow autoupgrade.'):$this->l('This release does not allow autoupgrade')).'.

'; - } - - if (Configuration::get('PS_SHOP_ENABLE')) - { - $srcShopStatus = '../img/admin/disabled.gif'; - $label = $this->l('No'); - } - else - { - $srcShopStatus = '../img/admin/enabled.gif'; - $label = $this->l('Yes'); - } - echo ''.$this->l('Shop desactivated').' : '.''.$label.'

'; - - $max_exec_time = ini_get('max_execution_time'); - if ($max_exec_time == 0) - $srcExecTime = '../img/admin/enabled.gif'; - else - $srcExecTime = '../img/admin/warning.gif'; - echo ''.$this->l('PHP time limit').' : '.''.($max_exec_time == 0?$this->l('disabled'):$max_exec_time.' '.$this->l('seconds')).'

'; - - if ($this->rootWritable) - $srcRootWritable = '../img/admin/enabled.gif'; - else - $srcRootWritable = '../img/admin/disabled.gif'; - echo ''.$this->l('Root directory').' : '.' '.($this->rootWritable?$this->l('writable recursively'):$this->l('not writable recursively')).'.

'; - - echo ''.$this->l('Modify your options').''; - echo '
'; - - echo '
'; - - echo '
'.$this->l('Update').''; - - - echo '
-

'.sprintf($this->l('Your current prestashop version : %s '),_PS_VERSION_).'

'; - echo '

'.sprintf($this->l('Last version is %1$s (%2$s) '), $this->upgrader->version_name, $this->upgrader->version_num).'

'; - - // @TODO : this should be checked when init() - if ($this->isUpgradeAllowed()) { - if ($pleaseUpdate) { - echo '
  • information '.$this->l('Latest Prestashop version available is:').' '.$pleaseUpdate['name'].'
  • '; - } -// echo ''; -// echo ''; - echo '
    '; - if ($this->upgrader->needUpgrade) - { - if($this->configOk()) - echo ''.$this->l('Upgrade PrestaShop now !').''; - else - echo $this->displayWarning('Your current configuration does not allow upgrade.'); - } - else - { - echo ''.$this->l('Your shop is already up to date.').' '; - } - echo ''.sprintf($this->l('last datetime check : %s '),date('Y-m-d H:i:s',Configuration::get('PS_LAST_VERSION_CHECK'))).' - '.$this->l('Please click to refresh').' - '; - - echo'
    - '; - - echo '
    '; - - - echo '
    '; - - if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) - { - echo '
    '.$this->l('Step').''; - echo '

    '.$this->l('Upgrade steps').'

    '; - echo '
    '; - echo 'download'; - echo 'unzip'; // unzip in autoupgrade/latest - echo 'removeSamples'; // remove samples (iWheel images) - echo 'backupFiles'; // backup files - echo 'backupDb'; - echo 'upgradeFiles'; - echo 'upgradeDb'; - echo '
    '; - - if (defined('_PS_ALLOW_UPGRADE_UNSTABLE_') AND _PS_ALLOW_UPGRADE_UNSTABLE_ ) - { - echo '

    Development tools

    '; - } - } - - echo '
    '; - echo'
    quick info
    '; - // for upgradeDb - echo '

    '; - echo '

    '; - } - else - echo '

    '.$this->l('Your current configuration does not allow upgrade.').'

    '; - - echo '
    '; -/* echo '
    - Error -
    no error yet
    -
    '; - * - */ - // information to keep will be in #infoStep - // temporary infoUpdate will be in #tmpInformation - echo ''; - } - - public function display() - { - global $cookie, $currentIndex; - echo '
    '.$this->l('Upgrade').''; - if(is_dir('autoupgrade')) - { - echo '

    '.$this->l('To make an upgrade, you need to activate the autoupgrade module').'

    '; - $tokenModule = Tools::getAdminToken('AdminModules'.(int)(Tab::getIdFromClassName('AdminModules')).(int)$cookie->id_employee); - $tokenAdminTabs = Tools::getAdminToken('AdminTabs'.(int)(Tab::getIdFromClassName('AdminTabs')).(int)$cookie->id_employee); - $tokenAdminTools = Tools::getAdminToken('AdminTools'.(int)(Tab::getIdFromClassName('AdminTools')).(int)$cookie->id_employee); - if (!$idTab = Tab::getIdFromClassName('AdminSelfUpgrade')) - { - echo '

    - ' - .$this->l('Activate the module').'

    '; - } - else{ - $tokenSelfUpgrade = Tools::getAdminToken('AdminSelfUpgrade'.(int)(Tab::getIdFromClassName('AdminSelfUpgrade')).(int)$cookie->id_employee); - echo ' ' - .$this->l('Use the autoupgrade module').'

    '; - } - echo ''; - } - else{ - echo "please download autoupgrade at this url"; - } - echo '
    '; - } - - private function _getJsInit() - { - global $currentIndex; - $js = ''; - $js .= ' -function ucFirst(str) { - if (str.length > 0) { - return str[0].toUpperCase() + str.substring(1); -} - else { - return str; - } -} - -function cleanInfo(){ - $("#infoStep").html("reset
    "); -} - -function updateInfoStep(msg){ - if (msg) - { - $("#infoStep").html(msg); - $("#infoStep").attr({ scrollTop: $("#infoStep").attr("scrollHeight") }); - } -} - -function addError(msg){ - if (msg) - $("#errorWindow").html(msg); -} - -function addQuickInfo(arrQuickInfo){ - if (arrQuickInfo) - { - $("#quickInfo").show(); - for(i=0;i"); - - $("#quickInfo").attr({ scrollTop: $("#quickInfo").attr("scrollHeight") }); - } -}'; - - if ($this->manualMode) - $js .= 'var manualMode = true;'; - else - $js .= 'var manualMode = false;'; - - $js .= ' -var firstTimeParams = '.$this->buildAjaxResult().'; -firstTimeParams = firstTimeParams.nextParams; - -$(document).ready(function(){ - $(".upgradestep").click(function(e) - { - e.preventDefault(); - // $.scrollTo("#options") - }); - - // more convenient to have that param for handling success and error - var requestParams; - - // set timeout to 5 minutes (download can be long)? - $.ajaxSetup({timeout:300000}); - - - // prepare available button here, without params ? - prepareNextButton("#upgradeNow",firstTimeParams); - prepareNextButton("#rollback",firstTimeParams); - prepareNextButton("#restoreDb",firstTimeParams); - prepareNextButton("#restoreFiles",firstTimeParams); - -}); - -/** - * parseXMLResult is used to handle the return value of the doUpgrade method - * - */ -function parseXMLResult(xmlRet) -{ - ret = $(xmlRet); - ret = ret.find("action")[0]; - if (ret.getAttribute("result") == "ok") - { - $("#dbResultCheck") - .addClass("ok") - .removeClass("fail") - .html("

    '.$this->l('upgrade complete. Please check your front-office (try to make an order, check theme)').'

    ") - .show("slow"); - $("#dbCreateResultCheck") - .hide("slow"); - - // difference with the original function - ret = {next:"upgradeComplete",nextParams:{typeResult:"json"},status:"ok"}; - - } - else - { - $("#dbResultCheck") - .addClass("fail") - .removeClass("ok") - .html(txtError[parseInt(ret.getAttribute("error"))]) - .show("slow"); - $("#dbCreateResultCheck") - .hide("slow"); - - // propose rollback if there is an error - if (confirm(txtError[parseInt(ret.getAttribute("error"))]+"\r\n\r\n'.$this->l('Do you want to rollback ?').'")) - ret = {next:"rollback",nextParams:{typeResult:"json"},status:"error"}; - } - - return ret -}; - -function afterUpgradeComplete() -{ - $("#pleaseWait").hide(); - $("#infoStep").html("

    '.$this->l('Upgrade Complete ! ').'

    "); -} -/** - * afterBackupDb display the button - * - */ -function afterBackupDb() -{ - $("#restoreDbContainer").html("restoreDb '.$this->l('click to restore database').'"); - prepareNextButton("#restoreDb",{}); -} - -function afterRestoreDb() -{ - $("#restoreDbContainer").html(""); -} - -function afterRestoreFiles() -{ - $("#restoreFilesContainer").html(""); -} - -function afterBackupFiles() -{ - $("#restoreFilesContainer").html("
    restoreFiles '.$this->l('click to restore files').'"); - prepareNextButton("#restoreFiles",{}); - -} - -function doAjaxRequest(action, nextParams){ - req = $.ajax({ - type:"POST", - url : "'.($this->isModule? __PS_BASE_URI__ . trim($this->adminDir,'/').'/autoupgrade/ajax-upgradetab.php' : str_replace('index','ajax-tab',$currentIndex)).'", - async: true, - data : { - dir:"'.trim($this->adminDir,'/').'", - ajaxMode : "1", - token : "'.$this->token.'", - tab : "'.get_class($this).'", - action : action, - params : nextParams - }, - success : function(res,textStatus,jqXHR) - { - if(eval("typeof nextParams") == "undefined") - { - nextParams = {typeResult : "json"}; - } - - if (nextParams.typeResult == "xml") - { - xmlRes = parseXMLResult(res); - res = {}; - res.next = xmlRes.next; - // if xml, we keep the next params - nextParams = myNext; - res.status = xmlRes.status; - } - else - { - try{ - res = $.parseJSON(res); - nextParams = res.nextParams; - } - catch(e){ - res = {status : "error"}; - alert("error during "+action); - /* - nextParams = { - error:"0", - next:"cancelUpgrade", - nextDesc:"Error detected during ["+action+"] step, reverting...", - nextQuickInfo:[], - status:"ok", - "stepDone":true - } - */ - } - } - - if (res.status == "ok") - { - $("#"+action).addClass("done"); - if (res.stepDone) - $("#"+action).addClass("stepok"); - - // if a function "after[action name]" exists, it should be called. - // This is used for enabling restore buttons for example - funcName = "after"+ucFirst(action); - if (typeof funcName == "string" && - eval("typeof " + funcName) == "function") { - - eval(funcName+"()"); - } - - handleSuccess(res,nextParams.typeResult); - } - else - { - // display progression - $("#"+action).addClass("done"); - $("#"+action).addClass("steperror"); - handleError(res); - } - }, - error: function(res,textStatus,jqXHR) - { - if (textStatus == "timeout" && action == "download") - { - updateInfoStep("'.$this->l('Your server can\'t download the file. Please upload it first by ftp in your admin/autoupgrade directory').'"); - } - else - { - //console.log(res); - //console.log(jqXHR); - updateInfoStep("[Server Error] Status message : " + textStatus); - } - } - }); - }; - -/** - * 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) -{ -// myNext; - myNext = nextParams; - $(button_selector).unbind(); - $(button_selector).click(function(e){ - e.preventDefault(); - $("#currentlyProcessing").show(); -'; - if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) - $js .= 'addQuickInfo(["[DEV] request : "+$(this).attr("id")]);'; - $js .= ' - action = button_selector.substr(1); - res = doAjaxRequest(action, nextParams); - }); -} - -/** - * handleSuccess - * res = {error:, next:, nextDesc:, nextParams:, nextQuickInfo:,status:"ok"} - * @param res $res - * @return void - */ -function handleSuccess(res) -{ - updateInfoStep(res.nextDesc); - if (res.next != "") - { - addQuickInfo(res.nextQuickInfo); - - $("#"+res.next).addClass("nextStep"); - if (manualMode) - { - prepareNextButton("#"+res.next,res.nextParams); - alert("manually go to "+res.next+" button "); - } - else - { - // @TODO : - // 1) instead of click(), call a function. - 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 - } - } - else - { - // Way To Go, end of upgrade process - addQuickInfo(["End of upgrade process"]); - } -} - -// res = {nextParams, NextDesc} -function handleError(res) -{ - // display error message in the main process thing - updateInfoStep(res.nextDesc); - addQuickInfo(res.nextQuickInfo); - // In case the rollback button has been desactivated, just re-enable it - prepareNextButton("#rollback",res.nextParams); - // ask if you want to rollback - // TODO : be sure there is useful infos - addQuickInfo(res); - if (confirm(res+"\r\r'.$this->l('Do you want to rollback ?').'")) - { - if (manualMode) - alert("'.$this->l('Please go manually go to rollback button').'"); - else - { - $("#rollback").click(); - } - - } -} -'; - return $js; - } - private function _cleanUp($path) - { - // as we need theses files for restore operation, we can't remove them. - // They will be overwritten - $skipDirs = array('backups', 'pclzip', 'autoupgrade', '.', '..', '.svn'); - $skipFiles = array('autoload.php', 'init.php', 'settings.inc.php', 'config.inc.php', 'Tools.php', 'AdminUpgrade.php'); - $skipFiles[] = $this->isModule?'ajax-upgradetab.php':'ajax-tab.php'; - if (is_dir($path)) - { - $fp = opendir($path); - while ($file = readdir($fp)) - { - if (!in_array($file, $skipDirs) AND !$this->_skipFile('', $path.$file, 'backup')) - { - $fullpath = $path.$file; - if (is_dir($fullpath)) - $this->_cleanUp($fullpath.'/'); - else - { - if (!in_array($file, $skipFiles)) - { - unlink($fullpath); - } - } - } - } - closedir($fp); - /* fortunately not empty dir won't be removed by the following */ - @rmdir($path); - } - else - if (!$this->_skipFile($file, '', 'backup')) unlink($path); - - return true; - } - - /** - * @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 static function ZipExtract($fromFile, $toDir) - { - if (!file_exists($toDir)) - if (!@mkdir($toDir,0777)) - { - $this->next = 'error'; - $this->nextDesc = sprintf($this->l('unable to create directory %s'),$toDir); - return false; - } - - if (class_exists('ZipArchive', false)) - { - $zip = new ZipArchive(); - if ($zip->open($fromFile) === true AND $zip->extractTo($toDir) AND $zip->close()) - return true; - return false; - } - else - { - - if (!class_exists('PclZip',false)) - require_once($this->prodRootDir.'/tools/pclzip/pclzip.lib.php'); - - $zip = new PclZip($fromFile); - $list = $zip->extract(PCLZIP_OPT_PATH, $toDir); - foreach ($list as $extractedFile) - if ($extractedFile['status'] != 'ok') - return false; - - return true; - } - } - - private function _listArchivedFiles() - { - if (!empty($this->nextParams['backupFilesFilepath'])) - { - if (class_exists('ZipArchive', false)) - { - $files=array(); - if ($zip = zip_open($this->currentParams['backupFilesFilepath'])) - { - while ($entry=zip_read($zip)) - $files[] = zip_entry_name($entry); - - zip_close($zip); - } - } - else - { - require_once($this->prodRootDir.'/tools/pclzip/pclzip.lib.php'); - if ($zip = new PclZip($this->currentParams['backupFilesFilepath'])) - 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/img' - * @param type $way : 'backup' , 'upgrade' - */ - private function _skipFile($file,$fullpath,$way='backup') - { - $fullpath = str_replace('\\','/', $fullpath); // wamp compliant - $rootpath = str_replace('\\','/', $this->prodRootDir); - switch ($way) - { - case 'backup': - if (in_array($file, $this->backupIgnoreFiles)) - return true; - - foreach($this->backupIgnoreAbsoluteFiles as $path) - if ($file == 'img') - if (strpos($fullpath, $rootpath.$path) !== false) - return true; - break; - - case 'upgrade': - if (in_array($file, $this->excludeFilesFromUpgrade)) - return true; - - foreach ($this->excludeAbsoluteFilesFromUpgrade as $path) - if (strpos($fullpath, $rootpath.$path) !== false) - return true; - break; - // default : if it's not a backup or an upgrade, juste skip the file - default: - return false; - } - } -} - diff --git a/classes/Category.php b/classes/Category.php index fb6e23512..aadf827e0 100644 --- a/classes/Category.php +++ b/classes/Category.php @@ -191,7 +191,10 @@ class CategoryCore extends ObjectModel $this->position = self::getLastPosition((int)$this->id_parent); $ret = parent::update($nullValues); if (!isset($this->doNotRegenerateNTree) OR !$this->doNotRegenerateNTree) + { self::regenerateEntireNtree(); + $this->recalculateLevelDepth($this->id_category); + } Module::hookExec('categoryUpdate', array('category' => $this)); return $ret; } @@ -395,6 +398,27 @@ class CategoryCore extends ObjectModel Db::getInstance()->Execute('UPDATE '._DB_PREFIX_.'category SET nleft = '.(int)$left.', nright = '.(int)$right.' WHERE id_category = '.(int)$id_category.' LIMIT 1'); } + /** + * Re-calculate the levels of all childs + */ + public function recalculateLevelDepth($id_category) + { + /* Gets all childs */ + $categories = Db::getInstance()->ExecuteS('SELECT id_category, id_parent, level_depth FROM '._DB_PREFIX_.'category + WHERE id_parent = '.$id_category); + $level = Db::getInstance()->getRow('SELECT level_depth FROM '._DB_PREFIX_.'category + WHERE id_category = '.$id_category); + /* Update level of depth for all childs */ + foreach ($categories as $sub_category) + { + Db::getInstance()->Execute('UPDATE '._DB_PREFIX_.'category + SET level_depth = '.($level['level_depth'] + 1).' + WHERE id_category = '.$sub_category['id_category']); + /* Recursive call */ + $this->recalculateLevelDepth($sub_category['id_category']); + } + } + /** * Return available categories * diff --git a/classes/Tab.php b/classes/Tab.php index 9285e1858..c0488db75 100644 --- a/classes/Tab.php +++ b/classes/Tab.php @@ -74,7 +74,11 @@ class TabCore extends ObjectModel { $this->position = self::getNbTabs($this->id_parent) + 1; if (parent::add($autodate, $nullValues)) + { + // refresh cache when adding new tab + self::$_getIdFromClassName[$this->class_name] = $this->id; return self::initAccess($this->id); + } return false; } @@ -235,5 +239,3 @@ class TabCore extends ObjectModel return true; } } - - diff --git a/classes/Tools.php b/classes/Tools.php index df90b4798..5dca608f7 100644 --- a/classes/Tools.php +++ b/classes/Tools.php @@ -665,9 +665,12 @@ class ToolsCore { if (empty($row['meta_description'])) $row['meta_description'] = strip_tags($row['description']); - $row['meta_title'] .= $row['name'] . (!empty($page_number) ? ' ('.$page_number.')' : ''); - $row['meta_title'] .= ' - '.Configuration::get('PS_SHOP_NAME'); - return self::completeMetaTags($row, $row['meta_title']); + if (!empty($row['meta_title'])) + $row['meta_title'] = $row['meta_title'].(!empty($page_number) ? ' ('.$page_number.')' : '').' - '.Configuration::get('PS_SHOP_NAME'); + else + $row['meta_title'] = $row['name'].(!empty($page_number) ? ' ('.$page_number.')' : '').' - '.Configuration::get('PS_SHOP_NAME'); + + return self::completeMetaTags($row, $row['name']); } } @@ -764,11 +767,11 @@ class ToolsCore if (!$context) $context = Context::getContext(); - if ($metaTags['meta_title'] == NULL) + if (empty($metaTags['meta_title'])) $metaTags['meta_title'] = $defaultValue.' - '.Configuration::get('PS_SHOP_NAME'); - if ($metaTags['meta_description'] == NULL) + if (empty($metaTags['meta_description'])) $metaTags['meta_description'] = Configuration::get('PS_META_DESCRIPTION', $context->language->id) ? Configuration::get('PS_META_DESCRIPTION', $context->language->id) : ''; - if ($metaTags['meta_keywords'] == NULL) + if (empty($metaTags['meta_keywords'])) $metaTags['meta_keywords'] = Configuration::get('PS_META_KEYWORDS', $context->language->id) ? Configuration::get('PS_META_KEYWORDS', $context->language->id) : ''; return $metaTags; } diff --git a/modules/autoupgrade/AdminSelfTab.php b/modules/autoupgrade/AdminSelfTab.php index 44549e354..ef80165c5 100644 --- a/modules/autoupgrade/AdminSelfTab.php +++ b/modules/autoupgrade/AdminSelfTab.php @@ -2160,7 +2160,7 @@ abstract class AdminSelfTab global $currentIndex, $smarty; $languages = Language::getLanguages(false); - if (function_exists('Tools','clearCache')) + if (method_exists('Tools','clearCache')) Tools::clearCache($smarty); /* Check required fields */ diff --git a/modules/autoupgrade/AdminSelfUpgrade.php b/modules/autoupgrade/AdminSelfUpgrade.php index fc32ef3ea..049556f11 100644 --- a/modules/autoupgrade/AdminSelfUpgrade.php +++ b/modules/autoupgrade/AdminSelfUpgrade.php @@ -65,6 +65,8 @@ if(!class_exists('Tools',false)) eval('class Tools extends Tools14{}'); class AdminSelfUpgrade extends AdminSelfTab { + public $svn_link = 'http://svn.prestashop.com/trunk'; + public $ajax = false; public $nextResponseType = 'json'; // json, xml public $next = 'N/A'; @@ -140,7 +142,10 @@ class AdminSelfUpgrade extends AdminSelfTab */ public static $loopRemoveSamples = 1000; -// public static $skipAction = array('unzip'=>'listSampleFiles'); + /* usage : key = the step you want to ski + * value = the next step you want instead + * example : public static $skipAction = array('download'=>'upgradeFiles'); + */ public static $skipAction; public $useSvn; @@ -312,7 +317,7 @@ class AdminSelfUpgrade extends AdminSelfTab // checkPSVersion will be not $this->upgrader = new Upgrader(); $this->upgrader->checkPSVersion(); - $this->currentParams['install_version'] = $this->upgrader->version_num; + $this->nextParams['install_version'] = $this->upgrader->version_num; if ($this->upgrader->autoupgrade_module) $this->standalone = true; @@ -668,23 +673,8 @@ $this->standalone = true; file_put_contents($this->nextParams['filesToUpgrade'],serialize($filesToUpgrade)); } - /** - * _modelDoUpgrade prepare the call to doUpgrade.php file (like model.php) - * - * @return void - */ - public function _modelDoUpgrade() + public function _modelDo($method) { - // a. set logger - // it will be used later - global $logger; - $logger = new FileLogger(); - if (function_exists('date_default_timezone_set')) - date_default_timezone_set('Europe/Paris'); - // use autoupgrade as log dir - $logger->setFilename($this->latestRootDir.'/'.date('Ymd').'_autoupgrade.log'); - - // init env. @set_time_limit(0); @ini_set('max_execution_time', '0'); // setting the memory limit to 128M only if current is lower @@ -695,78 +685,124 @@ $this->standalone = true; ){ @ini_set('memory_limit','128M'); } + require_once($this->prodRootDir.'/config/autoload.php'); /* Redefine REQUEST_URI if empty (on some webservers...) */ if (!isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI'] == '') $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME']; - if ($tmp = strpos($_SERVER['REQUEST_URI'], '?')) $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $tmp); - $_SERVER['REQUEST_URI'] = str_replace('//', '/', $_SERVER['REQUEST_URI']); - /////////////////////// - // Copy from model.php - /////////////////////// - if (!is_object($this->upgrader)) - $this->upgrader = new Upgrader(); - - $upgrader = $this->upgrader; - - $upgrader->checkPSVersion(); - define('INSTALL_VERSION', $this->currentParams['install_version']); - // now the install dir to use is in a subdirectory of the admin dir define('INSTALL_PATH', realpath($this->latestRootDir.DIRECTORY_SEPARATOR.'install')); - define('PS_INSTALLATION_IN_PROGRESS', true); - // Note : we don't need ToolsInstall.php - // include_once(INSTALL_PATH.'/classes/ToolsInstall.php'); + define('PS_INSTALLATION_IN_PROGRESS', true); + require_once(INSTALL_PATH.'/classes/ToolsInstall.php'); 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)))); - - // Note : INSTALLER__PS_BASE_URI_ABSOLUTE is not used for upgrade - // define('INSTALLER__PS_BASE_URI_ABSOLUTE', 'http://'.ToolsInstall::getHttpHost(false, true).INSTALLER__PS_BASE_URI); + define('INSTALLER__PS_BASE_URI_ABSOLUTE', 'http://'.ToolsInstall::getHttpHost(false, true).INSTALLER__PS_BASE_URI); // XML Header header('Content-Type: text/xml'); - require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'doUpgrade.php'); - - ////////////////////////////// - // End of copy from model.php - ////////////////////////////// - - } + // Switching method + if (in_array($method, array('doUpgrade', 'createDB', 'checkShopInfos'))) + { + global $logger; + $logger = new FileLogger(); + $logger->setFilename($this->prodRootDir.DIRECTORY_SEPARATOR.'log'.DIRECTORY_SEPARATOR.@date('Ymd').'_installation.log'); + } + switch ($method) + { + case 'checkConfig' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'checkConfig.php'); + die(); + break; + + case 'checkDB' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'checkDB.php'); + break; + + case 'createDB' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'createDB.php'); + break; + + case 'checkMail' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'checkMail.php'); + break; + + case 'checkShopInfos' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'checkShopInfos.php'); + break; + + case 'doUpgrade' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'doUpgrade.php'); + break; + + case 'getVersionFromDb' : + require_once(INSTALL_PATH.DIRECTORY_SEPARATOR.'xml'.DIRECTORY_SEPARATOR.'getVersionFromDb.php'); + break; + } + } public function ajaxProcessUpgradeDb(){ + // @TODO : 1/2/3 have to be done at the beginning !!!!!!!!!!!!!!!!!!!!!! + $this->nextParams = $this->currentParams; // use something like actual in install-dev // Notice : xml used here ... - + if (!isset($this->currentParams['upgradeDbStep'])) + { + $this->nextParams['upgradeDbStep'] = 1; + $this->next = 'upgradeDb'; + $this->nextDesc = 'upgrading database'; + $this->nextResponseType = 'xml'; + } + else + switch ($this->currentParams['upgradeDbStep']) + { + default: + $this->next = 'upgradeComplete'; + $this->nextResponseType = 'json'; + return true; + // $this->_model('checkConfig'); + break; // 1) confirm version is correct(DB) // install/model.php?method=getVersionFromDb&language=0 - // later - + case '1': + $this->_modelDo('getVersionFromDb'); + break; // 2) confirm config is correct (r/w rights) // install/model.php?method=checkConfig&firsttime=0 - // later - // 3) save current activated modules in nextParams, or don't desactivate them ? - // @TODO - // 4) upgrade - // install/model.php?_=1309193641470&method=doUpgrade&customModule=desactivate - if (!empty($this->currentParams['desactivateCustomModule'])) - $_GET['customModule'] = 'desactivate'; - if (!$this->_modelDoUpgrade()) + case '2': + if(!$this->_modelDo('checkConfig')) { $this->next = 'error'; - $this->nextDesc = $this->l('error during upgrade Db'); + $this->nextDesc = $this->l('error when checking configuration'); } + break; + + case '3': + if (!$this->_modelDo('doUpgrade')) + { + $this->next = 'error'; + $this->nextDesc = $this->l('error during upgrade Db. You may need to restore your database'); + } + break; + + case '4': + $this->next = 'upgradeComplete'; + $this->nextResponseType = 'json'; + $this->nextDesc = $this->l('Way to go ! Upgrade complete.'); + break; + } // 5) compare activated modules and reactivate them // @TODO + return true; } @@ -1226,7 +1262,6 @@ $this->standalone = true; { $this->nextParams = $this->currentParams; if ($this->useSvn){ - $svnLink = 'http://svn.prestashop.com/trunk'; $dest = $this->autoupgradePath . DIRECTORY_SEPARATOR . $this->svnDir; $svnStatus = svn_status($dest); @@ -1260,10 +1295,10 @@ $this->standalone = true; return false; } - if (svn_checkout($svnLink, $dest)) + if (svn_checkout($this->svn_link, $dest)) { $this->next = 'svnExport'; - $this->nextDesc = sprintf($this->l('SVN Checkout done from %s . now exporting it into latest...'),$svnLink); + $this->nextDesc = sprintf($this->l('SVN Checkout done from %s . now exporting it into latest...'),$this->svn_link); return true; } else @@ -1661,8 +1696,6 @@ echo ''; // update['link'] = download link // @TODO - if ($this->isUpgradeAllowed()) - { $this->createCustomToken(); if ($this->useSvn) echo '

    '.$this->l('Unstable upgrade').'

    @@ -1683,15 +1716,8 @@ echo ''; '; } + echo ''; echo ''; - } - else - { - echo '
    - '.$this->l('Update').''; - echo '

    '.$this->l('You currently don\'t need to use this feature.').'

    '; - echo '
    '; - } } @@ -1771,24 +1797,67 @@ $(document).ready(function(){ /** * parseXMLResult is used to handle the return value of the doUpgrade method - * + * @xmlRet xml return value + * @var previousParams contains the precedent post values (to conserve post datas during upgrade db process) */ -function parseXMLResult(xmlRet) -{ - ret = $(xmlRet); - ret = ret.find("action")[0]; - if (ret.getAttribute("result") == "ok") - { - $("#dbResultCheck") - .addClass("ok") - .removeClass("fail") - .html("

    '.$this->l('upgrade complete. Please check your front-office (try to make an order, check theme)').'

    ") - .show("slow"); - $("#dbCreateResultCheck") - .hide("slow"); - // as xml is only after upgradeDb, the next step is always upgradeComplete - ret = {next:"upgradeComplete",nextParams:{typeResult:"json"},status:"ok"}; +function checkConfig(res) +{ + testRequiredList = $(res.testList[0].test); + configIsOk = true; + + testRequiredList.each(function() + { + result = $(this).attr("result"); + if (result == "fail") configIsOk = false; + }); + + if (!configIsOk) + { + alert("Configuration install problem"); + return "fail"; + } + else + return "ok"; +} + +function handleXMLResult(xmlRet, previousParams) +{ + // use xml2json and put the result in the global var + // this will be used in after** javascript functions + resGlobal = $.xml2json(xmlRet); + + switch(previousParams.upgradeDbStep) + { + case 0: // getVersionFromDb + result = "ok"; + break; + case 1: // getVersionFromDb + result = resGlobal.result; + break; + case 2: // checkConfig + result = checkConfig(resGlobal); + break; + case 3: // doUpgrade: + result = resGlobal.result; + break; + case 4: // upgradeComplete + result = resGlobal.result; + break; + } + + if (result == "ok") + { + nextParams = previousParams; + nextParams.upgradeDbStep = previousParams.upgradeDbStep+1; + if(nextParams.upgradeDbStep >= 4) + { + resGlobal.next = "upgradeComplete"; + nextParams.typeResult = "json"; + } + else + resGlobal.next = "upgradeDb"; + resGlobal = {next:resGlobal.next,nextParams:nextParams,status:"ok"}; } else @@ -1796,22 +1865,35 @@ function parseXMLResult(xmlRet) $("#dbResultCheck") .addClass("fail") .removeClass("ok") - .html(txtError[parseInt(ret.getAttribute("error"))]) .show("slow"); $("#dbCreateResultCheck") .hide("slow"); // propose rollback if there is an error - if (confirm(txtError[parseInt(ret.getAttribute("error"))]+"\r\n\r\n'.$this->l('Do you want to rollback ?').'")) - ret = {next:"rollback",nextParams:{typeResult:"json"},status:"error"}; + if (confirm("An error happen\r\n'.$this->l('Do you want to rollback ?').'")) + resGlobal = {next:"rollback",nextParams:{typeResult:"json"},status:"error"}; } - return ret + return resGlobal; }; +var resGlobal = {}; +function afterUpgradeDb() +{ + // console.info("inside afterUpgradeDb"); + // console.log(resGlobal); + +} function afterUpgradeComplete() { $("#pleaseWait").hide(); + $("#dbResultCheck") + .addClass("ok") + .removeClass("fail") + .html("

    '.$this->l('upgrade complete. Please check your front-office (try to make an order, check theme)').'

    ") + .show("slow"); + $("#dbCreateResultCheck") + .hide("slow"); $("#infoStep").html("

    '.$this->l('Upgrade Complete ! ').'

    "); } /** @@ -1865,12 +1947,12 @@ function doAjaxRequest(action, nextParams){ if (nextParams.typeResult == "xml") { - xmlRes = parseXMLResult(res); - res = {}; - res.next = xmlRes.next; + res = handleXMLResult(res,nextParams); + // res.next = xmlRes; // if xml, we keep the next params - nextParams = myNext; - res.status = xmlRes.status; + // nextParams = xmlRes; + // console.info(nextParams); + // res.status = xmlRes.status; } else { @@ -1905,7 +1987,6 @@ function doAjaxRequest(action, nextParams){ funcName = "after"+ucFirst(action); if (typeof funcName == "string" && eval("typeof " + funcName) == "function") { - eval(funcName+"()"); } @@ -1927,8 +2008,6 @@ function doAjaxRequest(action, nextParams){ } else { - //console.log(res); - //console.log(jqXHR); updateInfoStep("[Server Error] Status message : " + textStatus); } } diff --git a/modules/autoupgrade/SelfModule.php b/modules/autoupgrade/SelfModule.php index e0da70cbe..b14ff6ed7 100644 --- a/modules/autoupgrade/SelfModule.php +++ b/modules/autoupgrade/SelfModule.php @@ -393,7 +393,7 @@ abstract class SelfModule { self::$classInModule[$currentClass] = substr(dirname($filePath), strlen($realpathModuleDir)+1); - $id_lang = (int)($cookie->id_lang); + $id_lang = (!isset($cookie) OR !is_object($cookie)) ? (int)(Configuration::get('PS_LANG_DEFAULT')) : (int)($cookie->id_lang); $file = _PS_MODULE_DIR_.self::$classInModule[$currentClass].'/'.Language::getIsoById($id_lang).'.php'; if (file_exists($file) AND include_once($file)) $_MODULES = !empty($_MODULES) ? array_merge($_MODULES, $_MODULE) : $_MODULE; diff --git a/modules/autoupgrade/autoupgrade.php b/modules/autoupgrade/autoupgrade.php index bc83318bb..5f193fe5f 100644 --- a/modules/autoupgrade/autoupgrade.php +++ b/modules/autoupgrade/autoupgrade.php @@ -64,7 +64,6 @@ class Autoupgrade extends Module if (!$res OR !Tab::getIdFromClassName('AdminSelfUpgrade') - OR !(Hook::get('backOfficeHeader') AND !$this->registerHook('backOfficeHeader')) OR !parent::install() ) return false; @@ -79,26 +78,21 @@ class Autoupgrade extends Module if(file_exists(_PS_ADMIN_DIR_.DIRECTORY_SEPARATOR.'tabs'.'AdminUpgrade.php')) { // Should we create the correct AdminUpgrade tab (not the module) - $tab = new Tab(); - $tab->class_name = 'AdminUpgrade'; - $tab->module = false; - $tab->id_parent = 9; - $tab->name = array_fill(1,sizeof(Language::getLanguages(false)), 'Upgrade'); - $res = $tab->save(); + if($idOldTab = Tab::getIdFromClassName('AdminUpgrade')) + { + $tab = new Tab($idOldTab); + $res &= $tab->delete(); + } + $res &= unlink(_PS_ADMIN_DIR_.DIRECTORY_SEPARATOR.'tabs'.'AdminUpgrade.php'); } if (file_exists(_PS_ADMIN_DIR_.DIRECTORY_SEPARATOR.'autoupgrade'.DIRECTORY_SEPARATOR.'ajax-upgradetab.php')) $res &= @unlink(_PS_ADMIN_DIR_.DIRECTORY_SEPARATOR.'autoupgrade'.DIRECTORY_SEPARATOR.'ajax-upgradetab.php'); - if($res OR !parent::uninstall()) + if (!$res OR !parent::uninstall()) return false; return true; } - public function hookBackOfficeHeader($params) - { - echo ''; } - -} diff --git a/modules/blocklayered/blocklayered-url-indexer.php b/modules/blocklayered/blocklayered-url-indexer.php index f9cb401a0..4613b6bf6 100644 --- a/modules/blocklayered/blocklayered-url-indexer.php +++ b/modules/blocklayered/blocklayered-url-indexer.php @@ -8,4 +8,5 @@ if (substr(Tools::encrypt('blocklayered/index'),0,10) != Tools::getValue('token' die('Bad token'); $blockLayered = new BlockLayered(); -echo $blockLayered->indexUrl((int)Tools::getValue('id_category'), (int)Tools::getValue('truncate')); \ No newline at end of file +$cursor = Tools::jsonDecode(Tools::getValue('cursor', '{}'), true); +echo $blockLayered->indexUrl($cursor, (int)Tools::getValue('ajax'), (int)Tools::getValue('truncate')); \ No newline at end of file diff --git a/modules/blocklayered/blocklayered.js b/modules/blocklayered/blocklayered.js index 325d6d49d..fb7c74451 100644 --- a/modules/blocklayered/blocklayered.js +++ b/modules/blocklayered/blocklayered.js @@ -81,10 +81,13 @@ function initSliders() function initLayered() { initSliders(); - var params = document.location.toString().split('#'); + var params = document.location.toString(); + params = friendlyUrl(params, 'long'); + params = params.split('#'); params.shift(); $(params).each(function(it, val) { + allowReload = true; if (val.split('=')[0] == 'price' || val.split('=')[0] == 'weight') { $("#layered_"+val.split('=')[0]+"_slider").slider('values', 0, val.split('=')[1].split('_')[0]); @@ -102,6 +105,7 @@ function updatelink(link) { baseUrl = link.split('#'); linkFilterUpdate = baseUrl[0]+getValueSelected(); + linkFilterUpdate = friendlyUrl(linkFilterUpdate, 'short'); return linkFilterUpdate; } @@ -126,6 +130,32 @@ function getValueSelected(){ return checkboxChecked; } +function friendlyUrl(link, encode) +{ + var friendlyTab = { + 'layered_condition_' : 'cond_', + 'layered_id_attribute_group_' : 'g_', + 'id_category_layered=' : 'c=', + 'layered_manufacturer_' : 'm_', + 'layered_id_feature_' : 'f_', + 'layered_category_' : 'cat_', + }; + + if(encode == 'short'){ + $.each(friendlyTab, function(key, value) { + Expression = new RegExp(key,'g'); + link = link.replace(Expression, value); + }); + }else{ + $.each(friendlyTab, function(key, value) { + Expression = new RegExp(value,'g'); + link = link.replace(Expression, key); + }); + } + + return link; +} + function paginationButton() { $('#pagination li').not('.current, .disabled').each( function () { var nbPage = 0; @@ -188,6 +218,12 @@ function openCloseFilter() function reloadContent(params_plus) { + if (typeof(allowReload) == 'undefined') + { + allowReload = true; + return; + } + window.location = updatelink( window.location.href); for(i = 0; i < ajaxQueries.length; i++) ajaxQueries[i].abort(); diff --git a/modules/blocklayered/blocklayered.php b/modules/blocklayered/blocklayered.php index 91cb92594..000452c53 100644 --- a/modules/blocklayered/blocklayered.php +++ b/modules/blocklayered/blocklayered.php @@ -138,7 +138,7 @@ class BlockLayered extends Module /* * Url indexation */ - public function indexUrl($idCategory = null, $truncate = true) + public function indexUrl($cursor = array(), $ajax = false, $truncate = true) { if($truncate) Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_friendly_url'); @@ -177,8 +177,8 @@ class BlockLayered extends Module if (!isset($attributeValues[$attribute['id_lang']][$filter['id_category']]['c'.$attribute['id_name']])) $attributeValues[$attribute['id_lang']][$filter['id_category']]['c'.$attribute['id_name']] = array(); $attributeValues[$attribute['id_lang']][$filter['id_category']]['c'.$attribute['id_name']][] = array('name' => $attribute['name'], - 'id_name' => 'c'.$attribute['id_name'], 'value' => $attribute['value'], 'id_value' => $attribute['id_value'], - 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); + 'id_name' => 'c'.$attribute['id_name'], 'value' => $attribute['value'], 'id_value' => $attribute['id_value'].'_'.$attribute['id_name'], + 'id_id_value' => $attribute['id_value'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } break; @@ -218,30 +218,101 @@ class BlockLayered extends Module $attributeValues[$category['id_lang']] = array(); if (!isset($attributeValues[$category['id_lang']][$filter['id_category']])) $attributeValues[$category['id_lang']][$filter['id_category']] = array(); - if (!isset($attributeValues[$category['id_lang']][$filter['id_category']]['cat'.$category['id_category']])) - $attributeValues[$category['id_lang']][$filter['id_category']]['cat'.$category['id_category']] = array(); - $attributeValues[$category['id_lang']][$filter['id_category']]['cat'.$category['id_category']][] = array('name' => $this->l('Categories'), + if (!isset($attributeValues[$category['id_lang']][$filter['id_category']]['category'])) + $attributeValues[$category['id_lang']][$filter['id_category']]['category'] = array(); + $attributeValues[$category['id_lang']][$filter['id_category']]['category'][] = array('name' => $this->l('Categories'), 'id_name' => null, 'value' => $category['name'], 'id_value' => $category['id_category'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } - $filter['id_category']; break; case 'manufacturer': - // @TODO + $manufacturers = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' + SELECT m.name as name,l.id_lang as id_lang, id_manufacturer + FROM '._DB_PREFIX_.'manufacturer m , '._DB_PREFIX_.'lang l + '); + + foreach ($manufacturers as $manufacturer) + { + if (!isset($attributeValues[$manufacturer['id_lang']])) + $attributeValues[$manufacturer['id_lang']] = array(); + if (!isset($attributeValues[$manufacturer['id_lang']][$filter['id_category']])) + $attributeValues[$manufacturer['id_lang']][$filter['id_category']] = array(); + if (!isset($attributeValues[$manufacturer['id_lang']][$filter['id_category']]['manufacturer'])) + $attributeValues[$manufacturer['id_lang']][$filter['id_category']]['manufacturer'] = array(); + $attributeValues[$manufacturer['id_lang']][$filter['id_category']]['manufacturer'][] = array('name' => $this->translateWord('Manufacturer', $manufacturer['id_lang']), + 'id_name' => null, 'value' => $manufacturer['name'], 'id_value' => $manufacturer['id_manufacturer'], + 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); + } break; - case 'avaibility': - // @TODO + case 'quantity': + foreach (array (0 => $this->translateWord('Not available',(int)$filter['id_lang']), 1 => $this->translateWord('In stock', (int)$filter['id_lang'])) + as $key => $quantity) + $attributeValues[$filter['id_lang']][$filter['id_category']]['quantity'][] = array('name' => $this->translateWord('Availability', (int)$filter['id_lang']), + 'id_name' => null, 'value' => $quantity, 'id_value' => $key, 'id_id_value' => 0, + 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); + break; + + case 'condition': + foreach (array('new' => $this->translateWord('New', (int)$filter['id_lang']), 'used' => $this->translateWord('Used', (int)$filter['id_lang']), + 'refurbished' => $this->translateWord('Refurbished', (int)$filter['id_lang'])) + as $key => $condition) + $attributeValues[$filter['id_lang']][$filter['id_category']]['condition'][] = array('name' => $this->translateWord('Condition', (int)$filter['id_lang']), + 'id_name' => null, 'value' => $condition, 'id_value' => $key, + 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); break; } - // Foreach langs - foreach ($attributeValues as $id_lang => $tmp1) - { - // Foreach categories - foreach ($tmp1 as $id_category => $tmp2) + $maxExecutionTime = ini_get('max_execution_time') * 0.9; // 90% of safety margin + if ($maxExecutionTime > 5) + $maxExecutionTime = 5; + $startTime = microtime(true); + $memoryLimit = (Tools::getMemoryLimit() * 0.9); + + if (empty($cursor)) + { + $cursor = array( + 'attribute_values' => 0, + 'tmp1' => 0, + 'possibility' => 0, + 'total' => 0 + ); + + if ($ajax) { + // Calculation, to eval progression + $nbPosibilities = 0; + foreach ($attributeValues as $idLang => $tmp1) + foreach ($tmp1 as $key => $tmp2) + { + $nbPosibilitiesTmp = 1; + foreach ($tmp2 as $name) + { + $count = count($name)+1; + $nbPosibilitiesTmp *= $count; + } + $nbPosibilities += $nbPosibilitiesTmp; + } + $cursor['nb_posibilities'] = $nbPosibilities; + } + } + + + // Foreach langs + $attributeValuesKeys = array_keys($attributeValues); + for (;$cursor['attribute_values'] < count($attributeValuesKeys); $cursor['attribute_values']++) + { + $id_lang = $attributeValuesKeys[$cursor['attribute_values']]; + $tmp1 = &$attributeValues[$id_lang]; + + // Foreach categories + $tmp1Keys = array_keys($tmp1); + for(; $cursor['tmp1'] < count($tmp1Keys); $cursor['tmp1']++) + { + $id_category = $tmp1Keys[$cursor['tmp1']]; + $tmp2 = &$tmp1[$id_category]; + $cursors = array_fill(0, count($tmp2), 0); $limits = array(); $nbName = count($tmp2); @@ -257,53 +328,112 @@ class BlockLayered extends Module } // Loop all url posibilities - for ($i = 1; $i < $nbPosibilities; $i++) + for (; $cursor['possibility'] < $nbPosibilities; $cursor['possibility']++) { + if ($memoryLimit < memory_get_peak_usage() OR (microtime(true) - $startTime) > $maxExecutionTime) + { + if ($ajax) + return Tools::jsonEncode(array('cursor' => Tools::jsonEncode($cursor))); + Tools::file_get_contents(Tools::getProtocol().Tools::getHttpHost().'/modules/blocklayered/blocklayered-url-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&cursor='.Tools::jsonEncode($cursor)); + return 1; + } + + $cursor['total']++; // generate all parameters posibilities $a = 1; - foreach ($cursors as $position => $cursor) + foreach ($cursors as $position => $cursorP) { // Get all possible combination (one by group) // 0 means no combinations selected in the group - $cursors[$position] = (($i / ($a)) % $limits[$position]); + $cursors[$position] = (($cursor['possibility'] / ($a)) % $limits[$position]); $a *= $limits[$position]; } - $link = ''; $selectedFilters = array('category' => array()); // Generate url with selected filters - foreach ($cursors as $position => $cursor) + foreach ($cursors as $position => $cursorP) { - if ($cursor != 0) + if ($cursorP != 0) { - $link .= '/'.Tools::link_rewrite($tmp2[$position][$cursor-1]['name'].'-'.$tmp2[$position][$cursor-1]['value']); - if (!isset($selectedFilters[$tmp2[$position][$cursor-1]['type']])) - $selectedFilters[$tmp2[$position][$cursor-1]['type']] = array(); - $selectedFilters[$tmp2[$position][$cursor-1]['type']][$tmp2[$position][$cursor-1]['id_value']] = $tmp2[$position][$cursor-1]['id_value']; + $link .= '/'.Tools::link_rewrite($tmp2[$position][$cursorP-1]['name'].'-'.$tmp2[$position][$cursorP-1]['value']); + if (!isset($selectedFilters[$tmp2[$position][$cursorP-1]['type']])) + $selectedFilters[$tmp2[$position][$cursorP-1]['type']] = array(); + if (!isset($tmp2[$position][$cursorP-1]['id_id_value'])) + $tmp2[$position][$cursorP-1]['id_id_value'] = $tmp2[$position][$cursorP-1]['id_value']; + $selectedFilters[$tmp2[$position][$cursorP-1]['type']][$tmp2[$position][$cursorP-1]['id_id_value']] = $tmp2[$position][$cursorP-1]['id_value']; } } $urlKey = md5($link); - $idLayeredFriendlyUrl = Db::getInstance()->getValue('SELECT id_layered_friendly_url FROM `'._DB_PREFIX_.'layered_friendly_url` WHERE `url_key` = \''.$urlKey.'\''); + $idLayeredFriendlyUrl = Db::getInstance()->getValue('SELECT id_layered_friendly_url FROM `'._DB_PREFIX_.'layered_friendly_url` WHERE `id_lang` = '.$id_lang.' AND `url_key` = \''.$urlKey.'\''); if ($idLayeredFriendlyUrl == false) { Db::getInstance()->AutoExecute(_DB_PREFIX_.'layered_friendly_url', array('url_key' => $urlKey, 'data' => serialize($selectedFilters), 'id_lang' => $id_lang), 'INSERT'); $idLayeredFriendlyUrl = Db::getInstance()->Insert_ID(); } } + $cursor['possibility'] = 0; } + $cursor['tmp1'] = 0; } + if ($ajax) + return '{"result": 1}'; + else return 1; } + public function translateWord($string, $id_lang ) + { + static $_MODULES = array(); + global $_MODULE; + + $file = _PS_MODULE_DIR_.$this->name.'/'.Language::getIsoById($id_lang).'.php'; + + if (!array_key_exists($id_lang,$_MODULES)) + { + if (!file_exists($file)) + return $string; + include $file; + $_MODULES[$id_lang] = $_MODULE; + } + + $string = str_replace('\'', '\\\'', $string); + + // set array key to lowercase for 1.3 compatibility + $_MODULES[$id_lang] = array_change_key_case($_MODULES[$id_lang]); + $currentKey = '<{'.strtolower( $this->name).'}'.strtolower(_THEME_NAME_).'>'.strtolower($this->name).'_'.md5($string); + $defaultKey = '<{'.strtolower( $this->name).'}prestashop>'.strtolower($this->name).'_'.md5($string); + + if (isset($_MODULES[$id_lang][$currentKey])) + $ret = stripslashes($_MODULES[$id_lang][$currentKey]); + elseif (isset($_MODULES[$id_lang][Tools::strtolower($currentKey)])) + $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($currentKey)]); + elseif (isset($_MODULES[$id_lang][$defaultKey])) + $ret = stripslashes($_MODULES[$id_lang][$defaultKey]); + elseif (isset($_MODULES[$id_lang][Tools::strtolower($defaultKey)])) + $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($defaultKey)]); + else + $ret = stripslashes($string); + + return str_replace('"', '"', $ret); + } + public function hookProductListAssign($params) { + global $smarty; if (!Configuration::get('PS_LAYERED_INDEXED')) return; $params['hookExecuted'] = true; $params['catProducts'] = array(); $selectedFilters = $this->getSelectedFilters(); + $filterBlock = self::getFilterBlock($selectedFilters); + $title = ''; + if (is_array($filterBlock['title_values'])) + foreach ($filterBlock['title_values'] as $key => $val) + $title .= ' – '.$key.' '.implode('/', $val); + + $smarty->assign('categoryNameComplement', $title); $this->getProducts($selectedFilters, $params['catProducts'], $params['nbProducts'], $p, $n, $pages_nb, $start, $stop, $range); } @@ -385,7 +515,6 @@ class BlockLayered extends Module
    '; } - /* * $cursor $cursor in order to restart indexing from the last state */ @@ -591,9 +720,35 @@ class BlockLayered extends Module public function hookHeader($params) { + global $smarty, $cookie; + if (Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)) == 1) return; + $idLang = (int)$cookie->id_lang; + $category = new Category((int)Tools::getValue('id_category')); + $categoryMetas = Tools::getMetaTags($idLang, ''); + $categoryTitle = (empty($category->meta_title[$idLang])?$category->name[$idLang]:$category->meta_title[$idLang]); + + // Generate meta title and meta description + $selectedFilters = $this->getSelectedFilters(); + $filterBlock = self::getFilterBlock($selectedFilters); + $title = ''; + if (is_array($filterBlock['title_values'])) + foreach ($filterBlock['title_values'] as $key => $val) + $title .= $key.' '.implode('/', $val).' – '; + $title = rtrim($title, ' – '); + $metaComplement = ucfirst(strtolower($title)); + $metaKeyWordsComplement = str_replace(' – ', ', ', strtolower($title)); + + if (!empty($metaComplement)) + { + $smarty->assign('meta_title', str_replace(' - '.Configuration::get('PS_SHOP_NAME'), ' – '.$metaComplement.' - '.Configuration::get('PS_SHOP_NAME'), $categoryMetas['meta_title'])); + $smarty->assign('meta_description', rtrim($categoryTitle.' – '.$metaComplement.' – '.$categoryMetas['meta_description'], ' – ')); + } + if (!empty($metaKeyWordsComplement)) + $smarty->assign('meta_keywords', rtrim($categoryTitle.', '.$metaKeyWordsComplement.', '.$categoryMetas['meta_keywords'], ', ')); + Tools::addJS(($this->_path).'blocklayered.js'); Tools::addJS(_PS_JS_DIR_.'jquery/jquery-ui-1.8.10.custom.min.js'); Tools::addCSS(_PS_CSS_DIR_.'jquery-ui-1.8.10.custom.css', 'all'); @@ -795,7 +950,7 @@ class BlockLayered extends Module