* @copyright 2007-2011 PrestaShop SA * @version Release: $Revision: 9790 $ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ class AdminModulesControllerCore extends AdminController { /* ** @var array map with $_GET keywords and their callback */ private $map = array( 'install' => 'install', 'uninstall' => 'uninstall', 'configure' => 'getContent', 'delete' => 'delete' ); private $list_modules_categories = array(); private $list_partners_modules = array(); private $list_natives_modules = array(); private $nb_modules_total = 0; private $nb_modules_installed = 0; private $nb_modules_activated = 0; private $serial_modules = ''; private $modules_authors = array(); private $id_employee; private $iso_default_country; private $filter_configuration = array(); private $xml_modules_list = 'api.prestashop.com/xml/modules_list.xml'; private $addons_url = 'api.addons.prestashop.com'; private $logged_on_addons = false; private $cache_file_modules_list = '/config/xml/modules_list.xml'; private $cache_file_default_country_modules_list = '/config/xml/default_country_modules_list.xml'; private $cache_file_customer_modules_list = '/config/xml/customer_modules_list.xml'; /* ** Admin Modules Controller Constructor ** Init list modules categories ** Load id employee ** Load filter configuration ** Load cache file */ public function __construct() { parent::__construct(); include_once(_PS_ADMIN_DIR_.'/../tools/tar/Archive_Tar.php'); // Set the modules categories $this->list_modules_categories['administration']['name'] = $this->l('Administration'); $this->list_modules_categories['advertising_marketing']['name'] = $this->l('Advertising & Marketing'); $this->list_modules_categories['analytics_stats']['name'] = $this->l('Analytics & Stats'); $this->list_modules_categories['billing_invoicing']['name'] = $this->l('Billing & Invoicing'); $this->list_modules_categories['checkout']['name'] = $this->l('Checkout'); $this->list_modules_categories['content_management']['name'] = $this->l('Content Management'); $this->list_modules_categories['export']['name'] = $this->l('Export'); $this->list_modules_categories['emailing']['name'] = $this->l('E-mailing'); $this->list_modules_categories['front_office_features']['name'] = $this->l('Front Office Features'); $this->list_modules_categories['i18n_localization']['name'] = $this->l('I18n & Localization'); $this->list_modules_categories['merchandizing']['name'] = $this->l('Merchandizing'); $this->list_modules_categories['migration_tools']['name'] = $this->l('Migration Tools'); $this->list_modules_categories['payments_gateways']['name'] = $this->l('Payments & Gateways'); $this->list_modules_categories['payment_security']['name'] = $this->l('Payment Security'); $this->list_modules_categories['pricing_promotion']['name'] = $this->l('Pricing & Promotion'); $this->list_modules_categories['quick_bulk_update']['name'] = $this->l('Quick / Bulk update'); $this->list_modules_categories['search_filter']['name'] = $this->l('Search & Filter'); $this->list_modules_categories['seo']['name'] = $this->l('SEO'); $this->list_modules_categories['shipping_logistics']['name'] = $this->l('Shipping & Logistics'); $this->list_modules_categories['slideshows']['name'] = $this->l('Slideshows'); $this->list_modules_categories['smart_shopping']['name'] = $this->l('Smart Shopping'); $this->list_modules_categories['market_place']['name'] = $this->l('Market Place'); $this->list_modules_categories['social_networks']['name'] = $this->l('Social Networks'); $this->list_modules_categories['others']['name'] = $this->l('Other Modules'); // Set Id Employee, Iso Default Country and Filter Configuration $this->id_employee = (int)$this->context->employee->id; $this->iso_default_country = $this->context->country->iso_code; $this->filter_configuration = Configuration::getMultiple(array( 'PS_SHOW_TYPE_MODULES_'.(int)$this->id_employee, 'PS_SHOW_COUNTRY_MODULES_'.(int)$this->id_employee, 'PS_SHOW_INSTALLED_MODULES_'.(int)$this->id_employee, 'PS_SHOW_ENABLED_MODULES_'.(int)$this->id_employee, 'PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, )); // Load cache file modules list (natives and partners modules) $xmlModules = false; if (file_exists(_PS_ROOT_DIR_.$this->cache_file_modules_list)) $xmlModules = @simplexml_load_file(_PS_ROOT_DIR_.$this->cache_file_modules_list); if ($xmlModules) foreach ($xmlModules->children() as $xmlModule) foreach ($xmlModule->children() as $module) foreach ($module->attributes() as $key => $value) { if ($xmlModule->attributes() == 'native' && $key == 'name') $this->list_natives_modules[] = (string)$value; if ($xmlModule->attributes() == 'partner' && $key == 'name') $this->list_partners_modules[] = (string)$value; } // Check if logged on Addons if (isset($this->context->cookie->username_addons) && isset($this->context->cookie->password_addons) && !empty($this->context->cookie->username_addons) && !empty($this->context->cookie->password_addons)) $this->logged_on_addons = true; } /* ** Ajax Request Methods ** ** if modules_list.xml is outdated, ** this function will re-upload it from prestashop.com ** ** @return null */ public function isFresh($file, $timeout = 604800000) { if (file_exists(_PS_ROOT_DIR_.$file)) return ((time() - filemtime(_PS_ROOT_DIR_.$file)) < $timeout); else return false; } public function refresh($file_to_refresh, $external_file) { $content = Tools::file_get_contents($external_file); if ($content) return file_put_contents(_PS_ROOT_DIR_.$file_to_refresh, $content); return false; } public function addonsRequest($request, $params = array()) { // Config for each request if ($request == 'native') { // Define protocol accepted and post data values for this request $protocolsList = array('https://' => 443, 'http://' => 80); $postData = 'version=151&method=listing&action=native&iso_code='.strtolower(Configuration::get('PS_LOCALE_COUNTRY')); } if ($request == 'customer') { // Define protocol accepted and post data values for this request $protocolsList = array('https://' => 443); $postData = 'version=151&method=listing&action=customer&username='.pSQL(trim($this->context->cookie->username_addons)).'&password='.pSQL(trim($this->context->cookie->password_addons)); } if ($request == 'check_customer') { // Define protocol accepted and post data values for this request $protocolsList = array('https://' => 443); $postData = 'version=151&method=check_customer&username='.pSQL($params['username_addons']).'&password='.pSQL($params['password_addons']); } if ($request == 'module') { // Define protocol accepted and post data values for this request if (isset($params['username_addons']) && isset($params['password_addons'])) { $protocolsList = array('https://' => 443); $postData = 'version=151&method=module&id_module='.pSQL($params['id_module']).'&username='.pSQL($params['username_addons']).'&password='.pSQL($params['password_addons']); } else { $protocolsList = array('https://' => 443, 'http://' => 80); $postData = 'version=151&method=module&id_module='.pSQL($params['id_module']); } } // Make the request if (is_callable('curl_exec') && count($protocolsList) > 0) { foreach ($protocolsList as $protocol => $port) { // Curl Request $ch = curl_init($protocol.$this->addons_url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 3); curl_setopt($ch, CURLOPT_PORT, $port); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); $content = curl_exec($ch); // If content returned, we cache it if ($content) return $content; } } // No content, return false return false; } public function ajaxProcessRefreshModuleList() { // Refresh modules_list.xml every week if (!$this->isFresh($this->cache_file_modules_list, 604800)) { if ($this->refresh($this->cache_file_modules_list, 'https://'.$this->xml_modules_list)) $this->status = 'refresh'; else if ($this->refresh($this->cache_file_modules_list, 'http://'.$this->xml_modules_list)) $this->status = 'refresh'; else $this->status = 'error'; } else $this->status = 'cache'; // If logged to Addons Webservices, refresh default country native modules list every day if ($this->status != 'error') { if (!$this->isFresh($this->cache_file_default_country_modules_list, 86400)) { if (file_put_contents(_PS_ROOT_DIR_.$this->cache_file_default_country_modules_list, $this->addonsRequest('native'))) $this->status = 'refresh'; else $this->status = 'error'; } else $this->status = 'cache'; } // If logged to Addons Webservices, refresh customer modules list every day if ($this->logged_on_addons && $this->status != 'error') { if (!$this->isFresh($this->cache_file_customer_modules_list, 60)) { if (file_put_contents(_PS_ROOT_DIR_.$this->cache_file_customer_modules_list, $this->addonsRequest('customer'))) $this->status = 'refresh'; else $this->status = 'error'; } else $this->status = 'cache'; } } public function displayAjaxRefreshModuleList() { echo Tools::jsonEncode(array('status' => $this->status)); } public function ajaxProcessLogOnAddonsWebservices() { $content = $this->addonsRequest('check_customer', array('username_addons' => pSQL(trim(Tools::getValue('username_addons'))), 'password_addons' => pSQL(trim(Tools::getValue('password_addons'))))); $xml = @simplexml_load_string($content, null, LIBXML_NOCDATA); if (!$xml) die('KO'); $result = strtoupper((string)$xml->success); if (!in_array($result, array('OK', 'KO'))) die ('KO'); if ($result == 'OK') { $this->context->cookie->username_addons = pSQL(trim(Tools::getValue('username_addons'))); $this->context->cookie->password_addons = pSQL(trim(Tools::getValue('password_addons'))); } die($result); } public function ajaxProcessReloadModulesList() { if (Tools::getValue('filterCategory')) Configuration::updateValue('PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, Tools::getValue('filterCategory')); if (Tools::getValue('unfilterCategory')) Configuration::updateValue('PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, ''); $this->initContent(); $this->context->smarty->display('controllers/modules/list.tpl'); exit; } public function ajaxProcessSetFilter() { $this->setFilterModules(Tools::getValue('module_type'), Tools::getValue('country_module_value'), Tools::getValue('module_install'), Tools::getValue('module_status')); die('OK'); } public function ajaxProcessSaveFavoritePreferences() { $action = Tools::getValue('action_pref'); $value = Tools::getValue('value_pref'); $module = Tools::getValue('module_pref'); $id_module_preference = (int)Db::getInstance()->getValue('SELECT `id_module_preference` FROM `'._DB_PREFIX_.'module_preference` WHERE `id_employee` = '.(int)$this->id_employee.' AND `module` = \''.pSQL($module).'\''); if ($id_module_preference > 0) { if ($action == 'i') $update = array('interest' => ($value == '' ? null : (int)$value)); if ($action == 'f') $update = array('favorite' => ($value == '' ? null : (int)$value)); Db::getInstance()->update('module_preference', $update, '`id_employee` = '.(int)$this->id_employee.' AND `module` = \''.pSQL($module).'\'', 0, true); } else { $insert = array('id_employee' => (int)$this->id_employee, 'module' => pSQL($module), 'interest' => null, 'favorite' => null); if ($action == 'i') $insert['interest'] = ($value == '' ? null : (int)$value); if ($action == 'f') $insert['favorite'] = ($value == '' ? null : (int)$value); Db::getInstance()->insert('module_preference', $insert, true); } die('OK'); } /* ** Get current URL ** ** @param array $remove List of keys to remove from URL ** @return string */ protected function getCurrentUrl($remove = array()) { $url = $_SERVER['REQUEST_URI']; if (!$remove) return $url; if (!is_array($remove)) $remove = array($remove); $url = preg_replace('#(?<=&|\?)('.implode('|', $remove).')=.*?(&|$)#i', '', $url); $len = strlen($url); if ($url[$len - 1] == '&') $url = substr($url, 0, $len - 1); return $url; } protected function extractArchive($file, $redirect = true) { $success = false; if (substr($file, -4) == '.zip') { if (Tools::ZipExtract($file, _PS_MODULE_DIR_)) $success = true; else $this->errors[] = Tools::displayError('Error while extracting module (file may be corrupted).'); } else { $archive = new Archive_Tar($file); if ($archive->extract(_PS_MODULE_DIR_)) $success = true; else $this->errors[] = Tools::displayError('Error while extracting module (file may be corrupted).'); } @unlink($file); if ($success && $redirect) Tools::redirectAdmin(self::$currentIndex.'&conf=8'.'&token='.$this->token); } protected function recursiveDeleteOnDisk($dir) { if (strpos(realpath($dir), realpath(_PS_MODULE_DIR_)) === false) return; if (is_dir($dir)) { $objects = scandir($dir); foreach ($objects as $object) if ($object != '.' && $object != '..') { if (filetype($dir.'/'.$object) == 'dir') $this->recursiveDeleteOnDisk($dir.'/'.$object); else unlink($dir.'/'.$object); } reset($objects); rmdir($dir); } } /* ** Filter Configuration Methods ** Set and reset filter configuration */ protected function setFilterModules($module_type, $country_module_value, $module_install, $module_status) { Configuration::updateValue('PS_SHOW_TYPE_MODULES_'.(int)$this->id_employee, $module_type); Configuration::updateValue('PS_SHOW_COUNTRY_MODULES_'.(int)$this->id_employee, $country_module_value); Configuration::updateValue('PS_SHOW_INSTALLED_MODULES_'.(int)$this->id_employee, $module_install); Configuration::updateValue('PS_SHOW_ENABLED_MODULES_'.(int)$this->id_employee, $module_status); } protected function resetFilterModules() { Configuration::updateValue('PS_SHOW_TYPE_MODULES_'.(int)$this->id_employee, 'allModules'); Configuration::updateValue('PS_SHOW_COUNTRY_MODULES_'.(int)$this->id_employee, 0); Configuration::updateValue('PS_SHOW_INSTALLED_MODULES_'.(int)$this->id_employee, 'installedUninstalled'); Configuration::updateValue('PS_SHOW_ENABLED_MODULES_'.(int)$this->id_employee, 'enabledDisabled'); Configuration::updateValue('PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, ''); } /* ** Post Process Filter ** */ public function postProcessFilterModules() { $this->setFilterModules(Tools::getValue('module_type'), Tools::getValue('country_module_value'), Tools::getValue('module_install'), Tools::getValue('module_status')); Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token); } public function postProcessResetFilterModules() { $this->resetFilterModules(); Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token); } public function postProcessFilterCategory() { // Save configuration and redirect employee Configuration::updateValue('PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, Tools::getValue('filterCategory')); Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token); } public function postProcessUnfilterCategory() { // Save configuration and redirect employee Configuration::updateValue('PS_SHOW_CAT_MODULES_'.(int)$this->id_employee, ''); Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token); } /* ** Post Process Module CallBack ** */ public function postProcessReset() { if ($this->tabAccess['edit'] === '1') { $module = Module::getInstanceByName(Tools::getValue('module_name')); if (Validate::isLoadedObject($module)) { if (!$module->getPermission('configure')) $this->errors[] = Tools::displayError('You do not have the permission to use this module'); else { if ($module->uninstall()) if ($module->install()) Tools::redirectAdmin(self::$currentIndex.'&conf=21'.'&token='.$this->token.'&tab_module='.$module->tab.'&module_name='.$module->name.'&anchor=anchor'.ucfirst($module->name)); else $this->errors[] = Tools::displayError('Cannot install module'); else $this->errors[] = Tools::displayError('Cannot uninstall module'); } } else $this->errors[] = Tools::displayError('Cannot load module object'); } else $this->errors[] = Tools::displayError('You do not have permission to add here.'); } public function postProcessDownload() { // PrestaShop demo mode if (_PS_MODE_DEMO_) { $this->errors[] = Tools::displayError('This functionnality has been disabled.'); return; } // Try to upload and unarchive the module if ($this->tabAccess['add'] === '1') { if (!isset($_FILES['file']['tmp_name']) || empty($_FILES['file']['tmp_name'])) $this->errors[] = $this->l('no file selected'); elseif (substr($_FILES['file']['name'], -4) != '.tar' && substr($_FILES['file']['name'], -4) != '.zip' && substr($_FILES['file']['name'], -4) != '.tgz' && substr($_FILES['file']['name'], -7) != '.tar.gz') $this->errors[] = Tools::displayError('Unknown archive type'); elseif (!@copy($_FILES['file']['tmp_name'], _PS_MODULE_DIR_.$_FILES['file']['name'])) $this->errors[] = Tools::displayError('An error occurred while copying archive to module directory.'); else $this->extractArchive(_PS_MODULE_DIR_.$_FILES['file']['name']); } else $this->errors[] = Tools::displayError('You do not have permission to add here.'); } public function postProcessEnable() { if ($this->tabAccess['edit'] === '1') { $module = Module::getInstanceByName(Tools::getValue('module_name')); if (Validate::isLoadedObject($module)) { if (!$module->getPermission('configure')) $this->errors[] = Tools::displayError('You do not have the permission to use this module'); else { if (Tools::getValue('enable')) $module->enable(); else $module->disable(); Tools::redirectAdmin($this->getCurrentUrl('enable')); } } else $this->errors[] = Tools::displayError('Cannot load module object'); } else $this->errors[] = Tools::displayError('You do not have permission to add here.'); } public function postProcessDelete() { if ($this->tabAccess['delete'] === '1') { if (Tools::getValue('module_name') != '') { $module = Module::getInstanceByName(Tools::getValue('module_name')); if (Validate::isLoadedObject($module) && !$module->getPermission('configure')) $this->errors[] = Tools::displayError('You do not have the permission to use this module'); else { $moduleDir = _PS_MODULE_DIR_.str_replace(array('.', '/', '\\'), array('', '', ''), Tools::getValue('module_name')); $this->recursiveDeleteOnDisk($moduleDir); Tools::redirectAdmin(self::$currentIndex.'&conf=22&token='.$this->token.'&tab_module='.Tools::getValue('tab_module').'&module_name='.Tools::getValue('module_name')); } } } else $this->errors[] = Tools::displayError('You do not have permission to delete here.'); } public function postProcessCallback() { $return = false; foreach ($this->map as $key => $method) { $modules = Tools::getValue($key); if (strpos($modules, '|')) $modules = explode('|', $modules); else $modules = empty($modules) ? false : array($modules); $module_errors = array(); if ($modules) foreach ($modules as $name) { // If Addons module, download and unzip it before installing it if (!is_dir('../modules/'.$name.'/')) { $filesList = array( array('type' => 'addonsNative', 'file' => $this->cache_file_default_country_modules_list, 'loggedOnAddons' => 0), array('type' => 'addonsBought', 'file' => $this->cache_file_customer_modules_list, 'loggedOnAddons' => 1), ); foreach ($filesList as $f) if (file_exists(_PS_ROOT_DIR_.$f['file'])) { $file = $f['file']; $content = Tools::file_get_contents(_PS_ROOT_DIR_.$file); $xml = @simplexml_load_string($content, null, LIBXML_NOCDATA); foreach ($xml->module as $modaddons) if ($name == $modaddons->name && isset($modaddons->id) && ($this->logged_on_addons || $f['loggedOnAddons'] == 0)) { if ($f['loggedOnAddons'] == 0) if (file_put_contents('../modules/'.$modaddons->name.'.zip', $this->addonsRequest('module', array('id_module' => pSQL($modaddons->id))))) $this->extractArchive('../modules/'.$modaddons->name.'.zip', false); if ($f['loggedOnAddons'] == 1 && $this->logged_on_addons) if (file_put_contents('../modules/'.$modaddons->name.'.zip', $this->addonsRequest('module', array('id_module' => pSQL($modaddons->id), 'username_addons' => pSQL(trim($this->context->cookie->username_addons)), 'password_addons' => pSQL(trim($this->context->cookie->password_addons)))))) $this->extractArchive('../modules/'.$modaddons->name.'.zip', false); } } } // Check potential error if (!($module = Module::getInstanceByName(urldecode($name)))) $this->errors[] = $this->l('module not found'); elseif ($key == 'install' && $this->tabAccess['add'] !== '1') $this->errors[] = Tools::displayError('You do not have permission to install a module.'); elseif ($key == 'uninstall' && ($this->tabAccess['delete'] !== '1' || !$module->getPermission('configure'))) $this->errors[] = Tools::displayError('You do not have permission to delete this module.'); elseif ($key == 'configure' && ($this->tabAccess['edit'] !== '1' || !$module->getPermission('configure'))) $this->errors[] = Tools::displayError('You do not have permission to configure this module.'); elseif ($key == 'install' && Module::isInstalled($module->name)) $this->errors[] = Tools::displayError('This module is already installed:').' '.$module->name; elseif ($key == 'uninstall' && !Module::isInstalled($module->name)) $this->errors[] = Tools::displayError('This module is already uninstalled:').' '.$module->name; else { // If we install a module, force temporary global context for multishop if (Shop::isFeatureActive() && Context::shop() != Shop::CONTEXT_ALL) { // If we install a module, force temporary global context for multishop if (Shop::isFeatureActive() && Context::shop() != Shop::CONTEXT_ALL && $method != 'getContent') { Context::getContext()->tmpOldShop = clone(Context::getContext()->shop); Context::getContext()->shop = new Shop(); Configuration::updateValue('RSS_FEED_TITLE', 'lol'); } } //retrocompatibility if (Tools::getValue('controller') != '') $_POST['tab'] = Tools::safeOutput(Tools::getValue('controller')); // We check if method of module exists if (!method_exists($module, $method)) throw new PrestaShopException('Method of module can\'t be found'); // Get the return value of current method $echo = $module->{$method}(); // If the method called is "configure" (getContent method), we show the html code of configure page if ($key == 'configure' && Module::isInstalled($module->name)) { $backlink = self::$currentIndex.'&token='.$this->token.'&tab_module='.$module->tab.'&module_name='.$module->name; $hooklink = 'index.php?tab=AdminModulesPositions&token='.Tools::getAdminTokenLite('AdminModulesPositions').'&show_modules='.(int)$module->id; $tradlink = 'index.php?tab=AdminTranslations&token='.Tools::getAdminTokenLite('AdminTranslations').'&type=modules&lang='; $toolbar = '
| '.$this->l('Module').' '.$module->name.' | '.$this->l('Back').' | '.$this->l('Manage hooks').' | '.$this->l('Manage translations:').' ';
foreach (Language::getLanguages(false) as $language)
$toolbar .= ' ';
$toolbar .= ' |
|---|---|---|---|
| active) ? 'checked="checked"' : '').' '.$activateOnclick.' /> '.$this->l('Activate module for').' '; if ($this->context->shop->getContextType() == Shop::CONTEXT_SHOP) $toolbar .= 'shop '.$this->context->shop->name.''; elseif ($this->context->shop->getContextType() == Shop::CONTEXT_GROUP) $toolbar .= 'all shops of group shop '.$this->context->shop->getGroup()->name.''; else $toolbar .= 'all shops'; $toolbar .= ' | |||