diff --git a/admin-dev/tabs/AdminShipping.php b/admin-dev/tabs/AdminShipping.php index f1a637432..43eedcbec 100644 --- a/admin-dev/tabs/AdminShipping.php +++ b/admin-dev/tabs/AdminShipping.php @@ -1,6 +1,6 @@ getShippingMethod(); - $rangeTable = $carrier->getRangeTable(); + $rangeTable = $carrier->getRangeTable(); $carrier->deleteDeliveryPrice($rangeTable); $currentList = Carrier::getDeliveryPriceByRanges($rangeTable, $id_carrier); @@ -104,7 +103,7 @@ class AdminShipping extends AdminTab { $tmpArray = explode('_', $key); - $price = number_format(abs(str_replace(',', '.', $value)), 2, '.', ''); + $price = number_format(abs(str_replace(',', '.', $value)), 6, '.', ''); $current = 0; foreach ($currentList as $item) if ($item['id_zone'] == $tmpArray[1] && $item['id_'.$rangeTable] == $tmpArray[2]) @@ -115,8 +114,8 @@ class AdminShipping extends AdminTab $priceList[] = array( 'id_range_price' => ($shipping_method == Carrier::SHIPPING_METHOD_PRICE) ? (int)$tmpArray[2] : null, 'id_range_weight' => ($shipping_method == Carrier::SHIPPING_METHOD_WEIGHT) ? (int)$tmpArray[2] : null, - 'id_carrier' => (int)$carrier->id, - 'id_zone' => (int)$tmpArray[1], + 'id_carrier' => (int)$carrier->id, + 'id_zone' => (int)$tmpArray[1], 'price' => $price, ); } @@ -218,13 +217,13 @@ class AdminShipping extends AdminTab $id_carrier = (int)$carrierArray[0]['id']; $carrierSelected = new Carrier($id_carrier); } - + echo '

'.$this->l('Fees by carrier, geographical zone, and ranges').'

'.$this->l('Fees').''; - + if (!count($carrierArray)) echo $this->l('You only have free carriers, there is no need to configure your delivery prices.'); else @@ -266,7 +265,7 @@ class AdminShipping extends AdminTab echo ''.$currency->getSign('left').''.$currency->getSign('right').''; echo ''; } - + foreach ($zones AS $zone) { echo ' @@ -284,7 +283,7 @@ class AdminShipping extends AdminTab '; } } - + echo ' '; diff --git a/admin-dev/tabs/AdminStores.php b/admin-dev/tabs/AdminStores.php index 02241d6ef..612c4bdf7 100644 --- a/admin-dev/tabs/AdminStores.php +++ b/admin-dev/tabs/AdminStores.php @@ -1,6 +1,6 @@ context = Context::getContext(); + $this->context = Context::getContext(); $this->table = 'store'; $this->className = 'Store'; $this->lang = false; $this->edit = true; $this->delete = true; - + $this->fieldImageSettings = array('name' => 'image', 'dir' => 'st'); - + $this->_select = 'cl.`name` country, st.`name` state'; $this->_join = ' LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (cl.`id_country` = a.`id_country` AND cl.`id_lang` = '.(int)$this->context->language->id.') LEFT JOIN `'._DB_PREFIX_.'state` st ON (st.`id_state` = a.`id_state`)'; - + $countries = Country::getCountries($this->context->language->id); foreach ($countries AS $country) $this->countriesArray[$country['id_country']] = $country['name']; - + $this->fieldsDisplay = array( 'id_store' => array('title' => $this->l('ID'), 'align' => 'center', 'width' => 25), 'country' => array('title' => $this->l('Country'), 'width' => 100, 'filter_key' => 'cl!name'), @@ -78,7 +78,7 @@ class AdminStores extends AdminTab ); parent::__construct(); } - + protected function postImage($id) { $ret = parent::postImage($id); @@ -90,14 +90,14 @@ class AdminStores extends AdminTab } return $ret; } - + public function displayOptionsList() { parent::displayOptionsList(); - + echo '

'.$this->l('You can also replace the icon representing your store in Google Maps. Go to the Preferences tab, and then the Appearance subtab.').'

'; } - + public function postProcess() { if (isset($_POST['submitAdd'.$this->table])) @@ -152,11 +152,11 @@ class AdminStores extends AdminTab if (!sizeof($this->_errors)) parent::postProcess(); } - + public function displayForm($isMainTab = true) { parent::displayForm(); - + if (!($obj = $this->loadObject(true))) return; echo ' @@ -234,7 +234,7 @@ class AdminStores extends AdminTab
- / + / *

'.$this->l('Store coords, eg. 45.265469 / -47.226478').'

@@ -270,7 +270,7 @@ class AdminStores extends AdminTab

'.$this->l('Store window picture').'

'; echo $this->displayImage($obj->id, _PS_STORE_IMG_DIR_.'/'.$obj->id.'.jpg', 350, NULL, Tools::getAdminToken('AdminStores'.(int)(Tab::getIdFromClassName('AdminStores')).(int)$this->context->employee->id), true); - + echo ' @@ -280,7 +280,7 @@ class AdminStores extends AdminTab '; - + $days = array(); $days[1] = $this->l('Monday'); $days[2] = $this->l('Tuesday'); @@ -289,11 +289,11 @@ class AdminStores extends AdminTab $days[5] = $this->l('Friday'); $days[6] = $this->l('Saturday'); $days[7] = $this->l('Sunday'); - + $hours = $this->getFieldValue($obj, 'hours'); if (!empty($hours)) $hoursUnserialized = unserialize($hours); - + for ($i = 1; $i < 8; $i++) echo ' diff --git a/admin-dev/tabs/AdminUpgrade.php b/admin-dev/tabs/AdminUpgrade.php new file mode 100644 index 000000000..4e3a2da78 --- /dev/null +++ b/admin-dev/tabs/AdminUpgrade.php @@ -0,0 +1,1876 @@ + +* @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'; + + /** + * set to false if the current step is a loop + * + * @var boolean + */ + public $stepDone = true; + public $error ='0'; + public $nextDesc = '.'; + public $nextParams = array(); + public $nextQuickInfo = array(); + public $currentParams = array(); + public $autoupgradePath = ''; + /** + * autoupgradeDir + * + * @var string directory relative to admin dir + */ + public $autoupgradeDir = 'autoupgrade'; + public $latestRootDir = ''; + public $prodRootDir = ''; + 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(); + +/** + * 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 __construct() + { + Tools::displayAsDeprecated(); + @set_time_limit(0); + @ini_set('max_execution_time', '0'); + + $this->init(); + parent::__construct(); + } + + /** + * _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'), + ); + // 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'), + ); + } + } + + /** + * 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 (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')) + { + $this->useSvn = Configuration::get('PS_AUTOUP_USE_SVN'); + } + else + $this->useSvn = false; + + // from $_POST or $_GET + $this->action = Tools::getValue('action'); + $this->currentParams = Tools::getValue('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']; + + $this->backupDbFilename = Configuration::get('UPGRADER_BACKUPDB_FILENAME'); + if(!file_exists($this->backupDbFilename)) + { + $this->backupDbFilename = ''; + Configuration::updateValue('UPGRADER_BACKUPDB_FILENAME',''); + } + $this->backupFilesFilename = Configuration::get('UPGRADER_BACKUPFILES_FILENAME'); + if(!file_exists($this->backupFilesFilename)) + { + $this->backupFilesFilename = ''; + Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME',''); + } + + + $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'; + + /* optional skips */ + $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'); + // 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 (!empty($_POST)) + $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 ...'); + $this->next = 'desactiveShop'; + } + 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(){ + // @TODO : not require_once like that. + $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 ajaxProcessDesactiveShop() + { + $this->ShopActiveValue = Configuration::get('PS_SHOP_ENABLE'); + Configuration::updateValue('PS_SHOP_ENABLE',0); + 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 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'])); + } + } + } + + /** + * model_doUpgrade 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(); + + 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 (isset($this->currentParams['customModule'])) + $_GET['customModule'] = $this->currentParams['customModule']; + + 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)) + { + $this->next = 'restoreFiles'; + $this->status = 'ok'; + $this->nextDesc = $this->l('Files restored, now restoring database.'); + } + else + { + if (!empty($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)) + { + // 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() + { + $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) + { + 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); + + $time = time(); + $this->backupFilesFilename = $this->autoupgradePath . DIRECTORY_SEPARATOR . 'backupfile-'.date('Y-m-d').'-'.$time.'.zip'; + + Configuration::updateValue('UPGRADER_BACKUPFILES_FILENAME', $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; + if (!empty($this->nextParams)) + $return['nextParams'] = $this->nextParams; + else + $return['nextParams'] = array(); + + $return['nextParams']['typeResult'] = $this->nextResponseType; + + $return['nextQuickInfo'] = $this->nextQuickInfo; + return Tools::jsonEncode($return); + } + + /** + * displayConf + * + * @return void + */ + public function displayConf() + { + 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 (Tools::getValue('responseType') == 'json') + header('Content-Type: application/json'); + $action = (Tools::getValue('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" non trouvée '), $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) + { + 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; + + 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)) + echo '
restoreFiles '.sprintf($this->l('click to restore %s'),$this->backupFilesFilename).'

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

'; + + echo '
'; + } + + private function _displayUpgraderForm() + { + $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/enabled.gif'; + $label = $this->l('Active'); + } + else + { + $srcShopStatus = '../img/admin/disabled.gif'; + $label = $this->l('Inactive'); + } + echo ''.$this->l('Shop status').' : '.''.$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) + { + echo ''.$this->l('Upgrade PrestaShop now !').''; + } + else + { + echo '

    '.$this->l('Your shop is already up to date').'

    '; + } + + echo'
    + '; + + echo '
    '; + + + echo '
    '; + + if (defined('_PS_MODE_DEV_') AND _PS_MODE_DEV_) + { + echo '
    '.$this->l('Step').''; + echo '

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

    '; + echo '
    '; + echo 'desactiveShop'; + 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; + // update['name'] = version name + // update['num'] = only the version + // update['link'] = download link + echo '
    '.$this->l('New upgrade module').''; + echo '

    '.$this->l('The tab AdminUpgrade present in 1.4.4.0 and 1.4.4.1 version has been removed and that functions is now available as 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); + echo '

    + ' + .$this->l('Click to remove that tab and activate the autoupgrade module').'

    '; + echo ' +
    '; + $this->displayWarning($this->l('This function is experimental. It\'s highly recommended to make a backup of your files and database before starting the upgrade process.')); + echo ''; + + if ($this->isUpgradeAllowed()) + { + if ($this->useSvn) + echo '

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

    +

    '.$this->l('Your current configuration indicate you want to upgrade your system from the unstable development branch, with no version number. If you upgrade, you will not be able to follow the official release process anymore').'.

    +
    '; + $this->_displayUpgraderForm(); + + echo '
    '; + $this->_displayRollbackForm(); + + echo '
    '; + $this->_displayForm('autoUpgradeOptions',$this->_fieldsAutoUpgrade,''.$this->l('Options').'', '','prefs'); + echo ''; + } + else + { + echo '
    + '.$this->l('Update').''; + echo '

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

    '; + 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 .= ' + +$(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",{}); + prepareNextButton("#rollback",{}); + prepareNextButton("#restoreDb",{}); + prepareNextButton("#restoreFiles",{}); + +}); + +/** + * 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 +}; + +/** + * 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 : "'.str_replace('index','ajax-tab',$currentIndex).'", + async: true, + data : { + dir:"'.$this->adminDir.'", + ajaxMode : "1", + token : "'.$this->token.'", + tab : "AdminUpgrade", + 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 + { + res = $.parseJSON(res); + nextParams = res.nextParams; + } + + if (res.status == "ok") + { + // a + $("#"+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 !!! + if (confirm(res.NextDesc+"\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', '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/AdminTab.php b/classes/AdminTab.php index a795a9dd5..732158bd5 100644 --- a/classes/AdminTab.php +++ b/classes/AdminTab.php @@ -828,7 +828,7 @@ abstract class AdminTabCore $type = (array_key_exists('filter_type', $field) ? $field['filter_type'] : (array_key_exists('type', $field) ? $field['type'] : false)); if (($type == 'date' OR $type == 'datetime') AND is_string($value)) $value = unserialize($value); - $key = isset($tmpTab[1]) ? $tmpTab[0].'.`'.$tmpTab[1].'`' : '`'.$tmpTab[0].'`'; + $key = isset($tmpTab[1]) ? $tmpTab[0].'.'.$tmpTab[1] : $tmpTab[0]; if (array_key_exists('tmpTableFilter', $field)) $sqlFilter = & $this->_tmpTableFilter; elseif (array_key_exists('havingFilter', $field)) @@ -844,7 +844,7 @@ abstract class AdminTabCore if (!Validate::isDate($value[0])) $this->_errors[] = Tools::displayError('\'from:\' date format is invalid (YYYY-MM-DD)'); else - $sqlFilter .= ' AND `'.bqSQL($key).'` >= \''.pSQL(Tools::dateFrom($value[0])).'\''; + $sqlFilter .= ' AND '.bqSQL($key).' >= \''.pSQL(Tools::dateFrom($value[0])).'\''; } if (isset($value[1]) AND !empty($value[1])) @@ -852,7 +852,7 @@ abstract class AdminTabCore if (!Validate::isDate($value[1])) $this->_errors[] = Tools::displayError('\'to:\' date format is invalid (YYYY-MM-DD)'); else - $sqlFilter .= ' AND `'.bqSQL($key).'` <= \''.pSQL(Tools::dateTo($value[1])).'\''; + $sqlFilter .= ' AND '.bqSQL($key).' <= \''.pSQL(Tools::dateTo($value[1])).'\''; } } else diff --git a/classes/CacheFS.php b/classes/CacheFS.php index 453c9fe1b..1dbd232c1 100755 --- a/classes/CacheFS.php +++ b/classes/CacheFS.php @@ -1,6 +1,6 @@ _init(); } - + protected function _init() { $this->_depth = Db::getInstance()->getValue('SELECT value FROM '._DB_PREFIX_.'configuration WHERE name=\'PS_CACHEFS_DIRECTORY_DEPTH\'', false); @@ -45,23 +45,20 @@ class CacheFSCore extends Cache { { $path = $this->getPath(); for ($i = 0; $i < $this->_depth; $i++) - { $path .= $key[$i].'/'; - } - - if (file_put_contents($path.$key, serialize($value))) + if (@file_put_contents($path.$key, serialize($value))) { $this->_keysCached[$key] = true; return $key; } return false; } - + public function setNumRows($key, $value, $expire = 0) { return $this->set($key.'_nrows', $value, $expire); } - + public function getNumRows($key) { return $this->get($key.'_nrows'); @@ -150,8 +147,9 @@ class CacheFSCore extends Cache { public function __destruct() { parent::__destruct(); - file_put_contents($this->getPath().'keysCached', serialize($this->_keysCached)); - file_put_contents($this->getPath().'tablesCached', serialize($this->_tablesCached)); + + @file_put_contents($this->getPath().'keysCached', serialize($this->_keysCached)); + @file_put_contents($this->getPath().'tablesCached', serialize($this->_tablesCached)); } public static function deleteCacheDirectory() @@ -173,7 +171,7 @@ class CacheFSCore extends Cache { self::createCacheDirectories($level_depth - 1, $new_dir); } } - + protected function getPath() { return (defined('_PS_CACHEFS_DIRECTORY_') ? _PS_CACHEFS_DIRECTORY_ : dirname(__FILE__).'/../cache/cachefs/'); diff --git a/classes/Carrier.php b/classes/Carrier.php index 7c9217deb..61a4b89dc 100644 --- a/classes/Carrier.php +++ b/classes/Carrier.php @@ -35,7 +35,7 @@ class CarrierCore extends ObjectModel const CARRIERS_MODULE_NEED_RANGE = 3; const PS_CARRIERS_AND_CARRIER_MODULES_NEED_RANGE = 4; const ALL_CARRIERS = 5; - + const SHIPPING_METHOD_DEFAULT = 0; const SHIPPING_METHOD_WEIGHT = 1; const SHIPPING_METHOD_PRICE = 2; @@ -412,23 +412,23 @@ class CarrierCore extends ObjectModel { if (!Validate::isBool($activeCountries) OR !Validate::isBool($activeCarriers)) die(Tools::displayError()); - + $states = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT s.* FROM `'._DB_PREFIX_.'state` s ORDER BY s.`name` ASC'); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' - SELECT cl.*,c.*, cl.`name` AS country, zz.`name` AS zone FROM `'._DB_PREFIX_.'country` c - LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (c.`id_country` = cl.`id_country` AND cl.`id_lang` = 1) + SELECT cl.*,c.*, cl.`name` AS country, zz.`name` AS zone FROM `'._DB_PREFIX_.'country` c + LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (c.`id_country` = cl.`id_country` AND cl.`id_lang` = 1) INNER JOIN (`'._DB_PREFIX_.'carrier_zone` cz INNER JOIN `'._DB_PREFIX_.'carrier` cr ON ( cr.id_carrier = cz.id_carrier AND cr.deleted = 0 '.($activeCarriers ? 'AND cr.active = 1) ' : ') ').' - LEFT JOIN `'._DB_PREFIX_.'zone` zz ON cz.id_zone = zz.id_zone) ON zz.`id_zone` = c.`id_zone` + LEFT JOIN `'._DB_PREFIX_.'zone` zz ON cz.id_zone = zz.id_zone) ON zz.`id_zone` = c.`id_zone` WHERE 1 '.($activeCountries ? 'AND c.active = 1' : '').' '.(!is_null($containStates) ? 'AND c.`contains_states` = '.(int)($containStates) : '').' ORDER BY cl.name ASC'); - + $countries = array(); foreach ($result AS &$country) $countries[$country['id_country']] = $country; @@ -438,12 +438,12 @@ class CarrierCore extends ObjectModel return $countries; } - + /** * * @param int $id_zone * @param Array $groups group of the customer - * @return Array + * @return Array */ public static function getCarriersForOrder($id_zone, $groups = NULL) { diff --git a/classes/Order.php b/classes/Order.php index 2516c0423..3b8198394 100644 --- a/classes/Order.php +++ b/classes/Order.php @@ -986,14 +986,16 @@ class OrderCore extends ObjectModel return $result; } - public function setCurrentState($id_order_state) + public function setCurrentState($id_order_state, $id_employee) { if (empty($id_order_state)) return false; $history = new OrderHistory(); - $history->id_order = (int)($this->id); - $history->changeIdOrderState((int)$id_order_state, (int)($this->id)); - $res = Db::getInstance()->getRow('SELECT `invoice_number`, `invoice_date`, `delivery_number`, `delivery_date` + $history->id_order = (int)$this->id; + $history->id_employee = (int)$id_employee; + $history->changeIdOrderState((int)$id_order_state, (int)$this->id); + $res = Db::getInstance()->getRow(' + SELECT `invoice_number`, `invoice_date`, `delivery_number`, `delivery_date` FROM `'._DB_PREFIX_.'orders` WHERE `id_order` = '.(int)$this->id); $this->invoice_date = $res['invoice_date']; diff --git a/classes/OrderHistory.php b/classes/OrderHistory.php index 70a9a8a31..7250b095e 100644 --- a/classes/OrderHistory.php +++ b/classes/OrderHistory.php @@ -62,9 +62,9 @@ class OrderHistoryCore extends ObjectModel { $this->validateFields(); - $fields['id_order'] = (int)($this->id_order); - $fields['id_order_state'] = (int)($this->id_order_state); - $fields['id_employee'] = (int)($this->id_employee); + $fields['id_order'] = (int)$this->id_order; + $fields['id_order_state'] = (int)$this->id_order_state; + $fields['id_employee'] = (int)$this->id_employee; $fields['date_add'] = pSQL($this->date_add); return $fields; @@ -143,18 +143,17 @@ class OrderHistoryCore extends ObjectModel LEFT JOIN `'._DB_PREFIX_.'customer` c ON o.`id_customer` = c.`id_customer` LEFT JOIN `'._DB_PREFIX_.'order_state` os ON oh.`id_order_state` = os.`id_order_state` LEFT JOIN `'._DB_PREFIX_.'order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state` AND osl.`id_lang` = o.`id_lang`) - WHERE oh.`id_order_history` = '.(int)($this->id).' - AND os.`send_email` = 1'); + WHERE oh.`id_order_history` = '.(int)($this->id).' AND os.`send_email` = 1'); if (isset($result['template']) AND Validate::isEmail($result['email'])) { $topic = $result['osname']; - $data = array('{lastname}' => $result['lastname'], '{firstname}' => $result['firstname'], '{id_order}' => (int)($this->id_order)); + $data = array('{lastname}' => $result['lastname'], '{firstname}' => $result['firstname'], '{id_order}' => (int)$this->id_order); if ($templateVars) $data = array_merge($data, $templateVars); - $order = new Order((int)($this->id_order)); - $data['{total_paid}'] = Tools::displayPrice((float)($order->total_paid), new Currency((int)($order->id_currency)), false); - $data['{order_name}'] = sprintf("#%06d", (int)($order->id)); + $order = new Order((int)$this->id_order); + $data['{total_paid}'] = Tools::displayPrice((float)$order->total_paid, new Currency((int)$order->id_currency), false); + $data['{order_name}'] = sprintf("#%06d", (int)$order->id); // An additional email is sent the first time a virtual item is validated if ($virtualProducts = $order->getVirtualProducts() AND (!$lastOrderState OR !$lastOrderState->logable) AND $newOrderState = new OrderState($this->id_order_state, Configuration::get('PS_LANG_DEFAULT')) AND $newOrderState->logable) diff --git a/classes/PDF.php b/classes/PDF.php index 5310a71dc..8d5ecd8a4 100644 --- a/classes/PDF.php +++ b/classes/PDF.php @@ -128,6 +128,10 @@ class PDFCore extends PDF_PageGroupCore $this->AddFont($font); $this->AddFont($font, 'B'); } + + /* If the user is using a ISO code no present in the languages, use the first language available instead */ + if (!isset(self::$_pdfparams[self::$_iso]) && isset($languages[0]['iso_code'])) + self::$_iso = strtoupper($languages[0]['iso_code']); } /** @@ -145,9 +149,19 @@ class PDFCore extends PDF_PageGroupCore $conf['PS_SHOP_STATE'] = isset($conf['PS_SHOP_STATE']) ? Tools::iconv('utf-8', self::encoding(), $conf['PS_SHOP_STATE']) : ''; if (file_exists(_PS_IMG_DIR_.'/logo_invoice.jpg')) + { + if ($this->_isPngFile(_PS_IMG_DIR_.'/logo_invoice.jpg')) + $this->Image(_PS_IMG_DIR_.'/logo_invoice.jpg', 10, 8, 0, 15, 'PNG'); + else $this->Image(_PS_IMG_DIR_.'/logo_invoice.jpg', 10, 8, 0, 15); + } else if (file_exists(_PS_IMG_DIR_.'/logo.jpg')) + { + if ($this->_isPngFile(_PS_IMG_DIR_.'/logo.jpg')) + $this->Image(_PS_IMG_DIR_.'/logo.jpg', 10, 8, 0, 15, 'PNG'); + else $this->Image(_PS_IMG_DIR_.'/logo.jpg', 10, 8, 0, 15); + } $this->SetFont(self::fontname(), 'B', 15); $this->Cell(115); @@ -164,6 +178,31 @@ class PDFCore extends PDF_PageGroupCore } /* + * Detect if the file header match a PNG file + * + * @param string $file Filename to check (include full path) + * @return boolean True if the file is a PNG file + */ + private function _isPngFile($file) + { + $pngReferenceHeader = array(137, 80, 78, 71, 13, 10, 26, 10); + $fp = fopen($file, 'r'); + if ($fp) + { + for ($n = 0; $n < 8; $n++) + if (ord(fread($fp, 1)) !== $pngReferenceHeader[$n]) + { + fclose($fp); + return false; + } + } + else + return false; + + return true; + } + + /* * Return the complete Address format */ private function _getCompleteUSAddressFormat($conf) @@ -209,6 +248,7 @@ class PDFCore extends PDF_PageGroupCore "\n".(!empty($conf['PS_SHOP_DETAILS']) ? self::l('Details:').' '.$conf['PS_SHOP_DETAILS'].' - ' : ''). (!empty($conf['PS_SHOP_PHONE']) ? self::l('PHONE:').' '.$conf['PS_SHOP_PHONE'] : ''); } + return $footerText; } diff --git a/classes/PaymentModule.php b/classes/PaymentModule.php index 435fd2743..37b6bebca 100644 --- a/classes/PaymentModule.php +++ b/classes/PaymentModule.php @@ -364,7 +364,7 @@ abstract class PaymentModuleCore extends Module ProductSale::addProductSale((int)$product['id_product'], (int)$product['cart_quantity']); } - if (isset($outOfStock) AND $outOfStock) + if (isset($outOfStock) && $outOfStock && Configuration::get('PS_STOCK_MANAGEMENT')) { $history = new OrderHistory(); $history->id_order = (int)$order->id; diff --git a/classes/Store.php b/classes/Store.php index 289456ab7..d5ba10d6c 100644 --- a/classes/Store.php +++ b/classes/Store.php @@ -79,7 +79,7 @@ class StoreCore extends ObjectModel public $active = true; protected $fieldsRequired = array('id_country', 'name', 'address1', 'city', 'active'); - protected $fieldsSize = array('name' => 128, 'address1' => 128, 'address2' => 128, 'postcode' => 12, 'city' => 64, 'latitude' => 10, 'longitude' => 10, 'hours' => 254, 'phone' => 16, 'fax' => 16, 'email' => 128, 'note' => 65000); + protected $fieldsSize = array('name' => 128, 'address1' => 128, 'address2' => 128, 'postcode' => 12, 'city' => 64, 'latitude' => 12, 'longitude' => 12, 'hours' => 254, 'phone' => 16, 'fax' => 16, 'email' => 128, 'note' => 65000); protected $fieldsValidate = array('id_country' => 'isUnsignedId', 'id_state' => 'isNullOrUnsignedId', 'name' => 'isGenericName', 'address1' => 'isAddress', 'address2' => 'isAddress', 'city' => 'isCityName', 'latitude' => 'isCoordinate', 'longitude' => 'isCoordinate', 'hours' => 'isSerializedArray', 'phone' => 'isPhoneNumber', 'fax' => 'isPhoneNumber', 'note' => 'isCleanHtml', 'email' => 'isEmail', 'active' => 'isBool'); @@ -99,15 +99,15 @@ class StoreCore extends ObjectModel { $this->validateFields(); - $fields['id_country'] = (int)($this->id_country); - $fields['id_state'] = (int)($this->id_state); + $fields['id_country'] = (int)$this->id_country; + $fields['id_state'] = (int)$this->id_state; $fields['name'] = pSQL($this->name); $fields['address1'] = pSQL($this->address1); $fields['address2'] = pSQL($this->address2); $fields['postcode'] = pSQL($this->postcode); $fields['city'] = pSQL($this->city); - $fields['latitude'] = (float)($this->latitude); - $fields['longitude'] = (float)($this->longitude); + $fields['latitude'] = (float)$this->latitude; + $fields['longitude'] = (float)$this->longitude; $fields['hours'] = pSQL($this->hours); $fields['phone'] = pSQL($this->phone); $fields['fax'] = pSQL($this->fax); @@ -115,7 +115,7 @@ class StoreCore extends ObjectModel $fields['email'] = pSQL($this->email); $fields['date_add'] = pSQL($this->date_add); $fields['date_upd'] = pSQL($this->date_upd); - $fields['active'] = (int)($this->active); + $fields['active'] = (int)$this->active; return $fields; } diff --git a/classes/Upgrader.php b/classes/Upgrader.php index 9cf020816..b7568ef41 100644 --- a/classes/Upgrader.php +++ b/classes/Upgrader.php @@ -67,7 +67,8 @@ class UpgraderCore if (empty($this->link)) $this->checkPSVersion(); - if (@copy($this->link, realpath($dest).DIRECTORY_SEPARATOR.$filename)) + $destPath = realpath($dest).DIRECTORY_SEPARATOR.$filename; + if (@copy($this->link, $destPath) && md5_file($destPath) == $this->md5 ) return true; else return false; diff --git a/classes/Validate.php b/classes/Validate.php index 99f3693e2..6af9d2a9c 100644 --- a/classes/Validate.php +++ b/classes/Validate.php @@ -849,7 +849,7 @@ class ValidateCore */ public static function isCoordinate($data) { - return ($data == NULL) OR (bool)(preg_match('/^\-?[0-9]{1,6}\.[0-9]{1,6}$/s', $data)); + return ($data == NULL) OR (bool)(preg_match('/^\-?[0-9]{1,8}\.[0-9]{1,8}$/s', $data)); } /** diff --git a/controllers/front/AuthController.php b/controllers/front/AuthController.php index 0261dd534..ce8e833ad 100644 --- a/controllers/front/AuthController.php +++ b/controllers/front/AuthController.php @@ -83,6 +83,11 @@ class AuthControllerCore extends FrontController $_POST['firstname'] = $_POST['customer_firstname']; if (!Tools::getValue('phone') AND !Tools::getValue('phone_mobile')) $this->errors[] = Tools::displayError('You must register at least one phone number'); + + if (!@checkdate(Tools::getValue('months'), Tools::getValue('days'), Tools::getValue('years')) && !(Tools::getValue('months') == '' && Tools::getValue('days') == '' && Tools::getValue('years') == '')) + $this->errors[] = Tools::displayError('Invalid date of birth'); + $customer->birthday = (empty($_POST['years']) ? '' : (int)$_POST['years'].'-'.(int)$_POST['months'].'-'.(int)$_POST['days']); + $this->errors = array_unique(array_merge($this->errors, $customer->validateController())); /* Preparing address */ $address = new Address(); @@ -123,9 +128,8 @@ class AuthControllerCore extends FrontController $this->errors[] = Tools::displayError('Identification number is incorrect or has already been used.'); elseif (!Country::isNeedDniByCountryId($address->id_country)) $address->dni = NULL; - if (!@checkdate(Tools::getValue('months'), Tools::getValue('days'), Tools::getValue('years')) AND !(Tools::getValue('months') == '' AND Tools::getValue('days') == '' AND Tools::getValue('years') == '')) - $this->errors[] = Tools::displayError('Invalid date of birth'); - if (!sizeof($this->errors)) + + if (!$this->errors) { if (Customer::customerExists(Tools::getValue('email'))) $this->errors[] = Tools::displayError('An account is already registered with this e-mail, please fill in the password or request a new one.'); @@ -135,7 +139,6 @@ class AuthControllerCore extends FrontController $customer->newsletter_date_add = pSQL(date('Y-m-d H:i:s')); } - $customer->birthday = (empty($_POST['years']) ? '' : (int)($_POST['years']).'-'.(int)($_POST['months']).'-'.(int)($_POST['days'])); if (!sizeof($this->errors)) { if (!$country = new Country($address->id_country, Configuration::get('PS_LANG_DEFAULT')) OR !Validate::isLoadedObject($country)) diff --git a/install-dev/classes/ToolsInstall.php b/install-dev/classes/ToolsInstall.php index f75a71604..208c76253 100644 --- a/install-dev/classes/ToolsInstall.php +++ b/install-dev/classes/ToolsInstall.php @@ -115,7 +115,6 @@ class ToolsInstall $result = NULL; try { - if($smtpChecked) { @@ -126,20 +125,15 @@ class ToolsInstall $swift = new Swift($smtp); } else - { $swift = new Swift(new Swift_Connection_NativeMail()); - } $message = new Swift_Message($subject, $content, $type); if ($swift->send($message, $to, $from)) - { $result = true; - } else - { $result = 999; - } + $swift->disconnect(); } catch (Swift_Connection_Exception $e) diff --git a/install-dev/sql/db.sql b/install-dev/sql/db.sql index a4888492f..944f0beb2 100644 --- a/install-dev/sql/db.sql +++ b/install-dev/sql/db.sql @@ -553,7 +553,7 @@ CREATE TABLE `PREFIX_delivery` ( `id_range_price` int(10) unsigned default NULL, `id_range_weight` int(10) unsigned default NULL, `id_zone` int(10) unsigned NOT NULL, - `price` decimal(17,2) NOT NULL, + `price` decimal(20,6) NOT NULL, PRIMARY KEY (`id_delivery`), KEY `id_zone` (`id_zone`), KEY `id_carrier` (`id_carrier`,`id_zone`), @@ -1614,8 +1614,8 @@ CREATE TABLE `PREFIX_store` ( `address2` varchar(128) DEFAULT NULL, `city` varchar(64) NOT NULL, `postcode` varchar(12) NOT NULL, - `latitude` float(10,6) DEFAULT NULL, - `longitude` float(10,6) DEFAULT NULL, + `latitude` decimal(10,8) DEFAULT NULL, + `longitude` decimal(10,8) DEFAULT NULL, `hours` varchar(254) DEFAULT NULL, `phone` varchar(16) DEFAULT NULL, `fax` varchar(16) DEFAULT NULL, diff --git a/install-dev/sql/db_settings_extends.sql b/install-dev/sql/db_settings_extends.sql index 49d07df93..84da2456e 100644 --- a/install-dev/sql/db_settings_extends.sql +++ b/install-dev/sql/db_settings_extends.sql @@ -1120,8 +1120,8 @@ INSERT INTO `PREFIX_profile_lang` (`id_lang`, `id_profile`, `name`) VALUES INSERT INTO `PREFIX_store` (`id_store`, `id_country`, `id_state`, `name`, `address1`, `address2`, `city`, `postcode`, `latitude`, `longitude`, `hours`, `phone`, `fax`, `email`, `note`, `active`, `date_add`, `date_upd`) VALUES (1, 21, 9, 'Dade County', '3030 SW 8th St Miami', '', 'Miami', ' 33135', 25.765005, -80.243797, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 10:53:13', '2010-11-09 10:53:13'), -(2, 21, 9, 'E Fort Lauderdale', '1000 Northeast 4th Ave Fort Lauderdale', '', 'miami', ' 33304', 26.137936, -80.139435, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 10:56:26', '2010-11-09 10:56:26'), -(3, 21, 9, 'Pembroke Pines', '11001 Pines Blvd Pembroke Pines', '', 'miami', '33026', 26.009987, -80.294472, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 10:58:42', '2010-11-09 11:01:11'), +(2, 21, 9, 'E Fort Lauderdale', '1000 Northeast 4th Ave Fort Lauderdale', '', 'Miami', ' 33304', 26.137936, -80.139435, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 10:56:26', '2010-11-09 10:56:26'), +(3, 21, 9, 'Pembroke Pines', '11001 Pines Blvd Pembroke Pines', '', 'Miami', '33026', 26.009987, -80.294472, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 10:58:42', '2010-11-09 11:01:11'), (4, 21, 9, 'Coconut Grove', '2999 SW 32nd Avenue', '', ' Miami', ' 33133', 25.736296, -80.244797, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 11:00:38', '2010-11-09 11:04:52'), (5, 21, 9, 'N Miami/Biscayne', '12055 Biscayne Blvd', '', 'Miami', '33181', 25.886740, -80.163292, 'a:7:{i:0;s:13:"09:00 - 19:00";i:1;s:13:"09:00 - 19:00";i:2;s:13:"09:00 - 19:00";i:3;s:13:"09:00 - 19:00";i:4;s:13:"09:00 - 19:00";i:5;s:13:"10:00 - 16:00";i:6;s:13:"10:00 - 16:00";}', '', '', '', '', 1, '2010-11-09 11:11:28', '2010-11-09 11:11:28'); diff --git a/install-dev/sql/upgrade/1.4.5.0.sql b/install-dev/sql/upgrade/1.4.5.0.sql index 76931c7e7..a9b4883ff 100644 --- a/install-dev/sql/upgrade/1.4.5.0.sql +++ b/install-dev/sql/upgrade/1.4.5.0.sql @@ -3,15 +3,7 @@ SET NAMES 'utf8'; INSERT IGNORE INTO `PREFIX_configuration` (`name`, `value`, `date_add`, `date_upd`) VALUES ('PS_RESTRICT_DELIVERED_COUNTRIES', '0', NOW(), NOW()); -UPDATE `PREFIX_country_lang` -SET `name` = 'United States' -WHERE `name` = 'United State' -AND `id_lang` = ( - SELECT `id_lang` - FROM `PREFIX_lang` - WHERE `iso_code` = 'en' - LIMIT 1 -); +UPDATE `PREFIX_country_lang` SET `name` = 'United States' WHERE `name` = 'United State'; ALTER TABLE `PREFIX_discount` ADD `include_tax` TINYINT(1) NOT NULL DEFAULT '0'; @@ -19,6 +11,11 @@ UPDATE `PREFIX_order_detail` SET `product_price` = `product_price` /( 1-(`group_ DELETE FROM `PREFIX_configuration` WHERE name IN ('PS_LAYERED_BITLY_USERNAME', 'PS_LAYERED_BITLY_API_KEY', 'PS_LAYERED_SHARE') LIMIT 3; +ALTER TABLE `PREFIX_delivery` CHANGE `price` `price` DECIMAL(20, 6) NOT NULL; + +ALTER TABLE `PREFIX_store` CHANGE `latitude` `latitude` DECIMAL(10, 8) NULL DEFAULT NULL; +ALTER TABLE `PREFIX_store` CHANGE `longitude` `longitude` DECIMAL(10, 8) NULL DEFAULT NULL; + INSERT INTO `PREFIX_hook` (`name`, `title`, `description`, `position`, `live_edit`) VALUES ('attributeGroupForm', 'Add fields to the form "attribute group"', 'Add fields to the form "attribute group"', 0, 0), ('afterSaveAttributeGroup', 'On saving attribute group', 'On saving attribute group', 0, 0), @@ -37,4 +34,5 @@ INSERT INTO `PREFIX_hook` (`name`, `title`, `description`, `position`, `live_edi ('attributeForm', 'Add fields to the form "feature value"', 'Add fields to the form "feature value"', 0, 0), ('postProcessAttribute', 'On post-process in admin feature value', 'On post-process in admin feature value', 0, 0), ('afterDeleteAttribute', 'On deleting attribute feature value', 'On deleting attribute feature value', 0, 0), -('afterSaveAttribute', 'On saving attribute feature value', 'On saving attribute feature value', 0, 0); \ No newline at end of file +('afterSaveAttribute', 'On saving attribute feature value', 'On saving attribute feature value', 0, 0); + diff --git a/modules/autoupgrade/Upgrader.php b/modules/autoupgrade/Upgrader.php index 9cf020816..b7568ef41 100644 --- a/modules/autoupgrade/Upgrader.php +++ b/modules/autoupgrade/Upgrader.php @@ -67,7 +67,8 @@ class UpgraderCore if (empty($this->link)) $this->checkPSVersion(); - if (@copy($this->link, realpath($dest).DIRECTORY_SEPARATOR.$filename)) + $destPath = realpath($dest).DIRECTORY_SEPARATOR.$filename; + if (@copy($this->link, $destPath) && md5_file($destPath) == $this->md5 ) return true; else return false; diff --git a/modules/autoupgrade/autoupgrade.php b/modules/autoupgrade/autoupgrade.php index 7ba666a07..70a3ed263 100644 --- a/modules/autoupgrade/autoupgrade.php +++ b/modules/autoupgrade/autoupgrade.php @@ -5,7 +5,7 @@ class Autoupgrade extends Module function __construct() { $this->name = 'autoupgrade'; - $this->tab = 'admin'; + $this->tab = 'administration'; $this->version = 0.1; if (!defined('_PS_ADMIN_DIR_')) @@ -58,10 +58,13 @@ class Autoupgrade extends Module $res &= @mkdir($autoupgradeDir); if(file_exists($autoupgradeDir.DIRECTORY_SEPARATOR.'ajax-upgradetab.php')) $res &= unlink($autoupgradeDir.DIRECTORY_SEPARATOR.'ajax-upgradetab.php'); - $path = dirname(__FILE__).'/'; + if (!defined('_PS_MODULE_DIR_')) + { + define('_PS_MODULE_DIR_', _PS_ROOT_DIR_.'/modules/'); + } - $res &= copy($path.'ajax-upgradetab.php',$autoupgradeDir . DIRECTORY_SEPARATOR . 'ajax-upgradetab.php'); - $res &= copy($path.'logo.gif',_PS_ROOT_DIR_. DIRECTORY_SEPARATOR . 'img/t/AdminSelfUpgrade.gif'); + $res &= copy(_PS_MODULE_DIR_.'autoupgrade/ajax-upgradetab.php',$autoupgradeDir . DIRECTORY_SEPARATOR . 'ajax-upgradetab.php'); + $res &= copy(_PS_MODULE_DIR_.'autoupgrade/logo.gif',_PS_ROOT_DIR_. DIRECTORY_SEPARATOR . 'img/t/AdminSelfUpgrade.gif'); if (!$res OR !Tab::getIdFromClassName('AdminSelfUpgrade') diff --git a/modules/autoupgrade/config.xml b/modules/autoupgrade/config.xml index b27d3b66d..5b8d10540 100644 --- a/modules/autoupgrade/config.xml +++ b/modules/autoupgrade/config.xml @@ -5,7 +5,7 @@ - + 0 1 diff --git a/modules/ebay/config.xml b/modules/ebay/config.xml index 31fd3b958..447645b93 100755 --- a/modules/ebay/config.xml +++ b/modules/ebay/config.xml @@ -2,7 +2,7 @@ ebay - + diff --git a/modules/ebay/eBayRequest.php b/modules/ebay/eBayRequest.php index fdc674c06..8e325a056 100755 --- a/modules/ebay/eBayRequest.php +++ b/modules/ebay/eBayRequest.php @@ -1096,7 +1096,8 @@ class eBayRequest foreach ($this->response->OrderArray->Order as $order) { $name = str_replace(array('_', ',', ' '), array('', '', ' '), (string)$order->ShippingAddress->Name); - $name = explode(' ', $name); + $name = preg_replace('/\-?\d+/', '', $name); + $name = explode(' ', $name, 2); $itemList = array(); for ($i = 0; isset($order->TransactionArray->Transaction[$i]); $i++) { @@ -1110,6 +1111,8 @@ class eBayRequest $tmp = explode('-', (string)$transaction->Item->SKU); if (isset($tmp[1])) $id_product = $tmp[1]; + if (isset($tmp[2])) + $id_product_attribute = $tmp[2]; } if (isset($transaction->Variation->SKU)) { @@ -1160,8 +1163,8 @@ class eBayRequest 'status' => (string)$order->CheckoutStatus->Status, 'date' => substr((string)$order->CreatedTime, 0, 10).' '.substr((string)$order->CreatedTime, 11, 8), 'name' => (string)$order->ShippingAddress->Name, - 'firstname' => $name[0], - 'familyname' => (isset($name[1]) ? $name[1] : $name[0]), + 'firstname' => trim($name[0]), + 'familyname' => (isset($name[1]) ? trim($name[1]) : trim($name[0])), 'address1' => (string)$order->ShippingAddress->Street1, 'address2' => (string)$order->ShippingAddress->Street2, 'city' => (string)$order->ShippingAddress->CityName, diff --git a/modules/ebay/ebay.php b/modules/ebay/ebay.php index f4b480629..f8f0eca5b 100755 --- a/modules/ebay/ebay.php +++ b/modules/ebay/ebay.php @@ -59,7 +59,7 @@ class Ebay extends Module { $this->name = 'ebay'; $this->tab = 'market_place'; - $this->version = '1.2.6'; + $this->version = '1.2.8'; $this->author = 'PrestaShop'; parent::__construct (); $this->displayName = $this->l('eBay'); @@ -656,7 +656,7 @@ class Ebay extends Module success: function(data) { if (data == \'OK\') - window.location.href = \''.Tools::safeOutput($_SERVER['REQUEST_URI']).'&action=validateToken\'; + window.location.href = \'index.php?tab='.Tools::safeOutput($_GET['tab']).'&configure='.Tools::safeOutput($_GET['configure']).'&token='.Tools::safeOutput($_GET['token']).'&tab_module='.Tools::safeOutput($_GET['tab_module']).'&module_name='.Tools::safeOutput($_GET['module_name']).'&action=validateToken\'; else setTimeout ("checkToken()", 5000); } @@ -1111,10 +1111,11 @@ class Ebay extends Module $ad = dirname($_SERVER["PHP_SELF"]); // Display Form + $forbiddenJs = array('textarea', 'script', 'onmousedown', 'onmousemove', 'onmmouseup', 'onmouseover', 'onmouseout', 'onload', 'onunload', 'onfocus', 'onblur', 'onchange', 'onsubmit', 'ondblclick', 'onclick', 'onkeydown', 'onkeyup', 'onkeypress', 'onmouseenter', 'onmouseleave', 'onerror'); $html = '

    '.$this->l('You can customise the template for your products page on eBay').' :

    -
    +
    '.(substr(_PS_VERSION_, 0, 3) == '1.3' ? ' @@ -1498,6 +1499,14 @@ class Ebay extends Module } } + public function findIfCategoryParentIsMultiSku($id_category_ref) + { + $row = Db::getInstance()->getRow('SELECT `id_category_ref_parent`, `is_multi_sku` FROM `'._DB_PREFIX_.'ebay_category` WHERE `id_category_ref` = '.(int)$id_category_ref); + if ($row['id_category_ref_parent'] != $id_category_ref) + return $this->findIfCategoryParentIsMultiSku($row['id_category_ref_parent']); + return $row['is_multi_sku']; + } + private function _syncProducts($productsList) { $fees = 0; @@ -1529,6 +1538,8 @@ class Ebay extends Module // Load default category matched in cache if (!isset($categoryDefaultCache[$product->id_category_default])) $categoryDefaultCache[$product->id_category_default] = Db::getInstance()->getRow('SELECT ec.`id_category_ref`, ec.`is_multi_sku`, ecc.`percent` FROM `'._DB_PREFIX_.'ebay_category` ec LEFT JOIN `'._DB_PREFIX_.'ebay_category_configuration` ecc ON (ecc.`id_ebay_category` = ec.`id_ebay_category`) WHERE ecc.`id_category` = '.(int)$product->id_category_default); + if ($categoryDefaultCache[$product->id_category_default]['is_multi_sku'] != 1) + $categoryDefaultCache[$product->id_category_default]['is_multi_sku'] = $this->findIfCategoryParentIsMultiSku($categoryDefaultCache[$product->id_category_default]['id_category_ref']); // Load Pictures $pictures = array(); diff --git a/modules/mondialrelay/config.xml b/modules/mondialrelay/config.xml index e83e01e83..c4678d8c3 100755 --- a/modules/mondialrelay/config.xml +++ b/modules/mondialrelay/config.xml @@ -2,7 +2,7 @@ mondialrelay - + diff --git a/modules/paypal/api/paypallib.php b/modules/paypal/api/paypallib.php index 91210325a..93339da19 100644 --- a/modules/paypal/api/paypallib.php +++ b/modules/paypal/api/paypallib.php @@ -37,13 +37,13 @@ class PaypalLib extends Paypal unset($response[$k]); } } - if (!Configuration::get('PAYPAL_MODE_DEBUG')) + if (!Configuration::get('PAYPAL_DEBUG_MODE')) $this->_logs = array(); $toExclude = array('TOKEN', 'SUCCESSPAGEREDIRECTREQUESTED', 'VERSION', 'BUILD', 'ACK', 'CORRELATIONID'); $this->_logs[] = ''.$this->l('PayPal response:').''; foreach ($response as $k => $res) { - if (!Configuration::get('PAYPAL_MODE_DEBUG') AND in_array($k, $toExclude)) + if (!Configuration::get('PAYPAL_DEBUG_MODE') AND in_array($k, $toExclude)) continue; $this->_logs[] = $k.' -> '.$res; } diff --git a/modules/paypal/paypal.php b/modules/paypal/paypal.php index 6a609dd8d..b40532982 100644 --- a/modules/paypal/paypal.php +++ b/modules/paypal/paypal.php @@ -886,7 +886,7 @@ class PayPal extends PaymentModule Configuration::updateValue('PAYPAL_API_PASSWORD', trim(Tools::getValue('api_password'))); Configuration::updateValue('PAYPAL_API_SIGNATURE', trim(Tools::getValue('api_signature'))); Configuration::updateValue('PAYPAL_EXPRESS_CHECKOUT', (int)(Tools::isSubmit('paypal_express'))); - Configuration::updateValue('PAYPAL_MODE_DEBUG', (int)(Tools::isSubmit('paypal_debug'))); + Configuration::updateValue('PAYPAL_DEBUG_MODE', (int)(Tools::isSubmit('paypal_debug'))); Configuration::updateValue('PAYPAL_CAPTURE', (int)(Tools::getValue('paypal_capture'))); Configuration::updateValue('PAYPAL_PAYMENT_METHOD', (int)(Tools::getValue('payment_method'))); Configuration::updateValue('PAYPAL_TEMPLATE', Tools::getValue('template_paypal')); diff --git a/modules/shopimporter/ajax.php b/modules/shopimporter/ajax.php index d986a010b..b4adcd446 100644 --- a/modules/shopimporter/ajax.php +++ b/modules/shopimporter/ajax.php @@ -7,7 +7,7 @@ ini_set('display_errors', 'off'); $moduleName = Tools::getValue('moduleName'); -if (!Tools::getValue('ajax') || Tools::getValue('token') != sha1(_COOKIE_KEY_.'ajaxShopImporter') || !ctype_alnum($moduleName)) +if (!Tools::getValue('ajax') || Tools::getValue('token') != sha1(_COOKIE_KEY_.'ajaxShopImporter') || (!empty($moduleName) && !ctype_alnum($moduleName))) die;
      '.$this->l('Sample: 10:00AM - 9:30PM').'