* @copyright 2007-2019 ETS-Soft * @license Valid for 1 website (or project) for each purchase of license * International Registered Trademark & Property of ETS-Soft */ if (!defined('_PS_VERSION_')) exit; include_once(dirname(__FILE__) . '/cache/temp'); if (version_compare(_PS_VERSION_, '1.7', '>=')) { interface WidgetCaptcha extends PrestaShop\PrestaShop\Core\Module\WidgetInterface { } } else { interface WidgetCaptcha { } } class Ets_advancedcaptcha extends Module implements WidgetCaptcha { const SEND_CONFIRMATION_EMAIL = 'CONTACTFORM_SEND_CONFIRMATION_EMAIL'; const SEND_NOTIFICATION_EMAIL = 'CONTACTFORM_SEND_NOTIFICATION_EMAIL'; const PREFIX_CODE = 'pa_'; const CACERT_LOCATION = 'https://curl.haxx.se/ca/cacert.pem'; public static $hooks = array( 'displayPaCaptcha', 'displayHeader', 'displayCustomerAccountForm', 'displayBackOfficeHeader', 'displayOverrideTemplate', 'displayReassurance', 'displayPaCaptchaHelp' ); public static $pages = array('contact', 'authentication', 'order', 'order-opc', 'orderopc', 'product', 'password'); public $_html = ''; public $is17; public $is16; public $_errors = array(); protected $contact; protected $customer_thread; public $link_capcha; public $trans; public $position = array(); public $captchaType = array(); public $configs = array(); public $overrideDir = array(); public function __construct() { $this->name = 'ets_advancedcaptcha'; $this->tab = 'front_office_features'; $this->version = '1.1.5'; $this->author = 'ETS-Soft'; $this->need_instance = 0; $this->bootstrap = true; $this->module_key = '23c752bc1234e5c89322801b5d4a9117'; parent::__construct(); $this->displayName = $this->l('CAPTCHA - reCAPTCHA'); $this->description = $this->l('Protect your store from spam messages and spam user accounts'); if (version_compare(_PS_VERSION_, '1.5.6.0', '>') || version_compare(_PS_VERSION_, '1.5.0.0', '<')) { $this->ps_versions_compliancy = array('min' => '1.5.0.0', 'max' => _PS_VERSION_); } $this->is17 = version_compare(_PS_VERSION_, '1.7.0', '>='); $this->is16 = version_compare(_PS_VERSION_, '1.6.0', '>='); $this->shortlink = 'https://mf.short-link.org/'; //ajax. if(Tools::getValue('configure')==$this->name && Tools::isSubmit('othermodules')) { $this->displayRecommendedModules(); } if ($this->is17) { $this->overrideDir = array('form', 'ps_emailsubscription', 'ps_emailalerts'); } else { if (version_compare(_PS_VERSION_, '1.6.1', '>=')) $this->overrideDir = array('front', 'blocknewsletter', 'mailalerts'); else $this->overrideDir = array('front'); } $this->position = array( 'con' => array( 'id_option' => 'contact', 'name' => $this->l('Contact form (Recommended)'), ), 'reg' => array( 'id_option' => 'register', 'name' => $this->l('Registration form (Recommended)'), ), 'log' => array( 'id_option' => 'login', 'name' => $this->l('Login form'), ), 'new' => array( 'id_option' => 'newsletter', 'name' => $this->l('Newsletter subscription form'), ), 'out' => array( 'id_option' => 'out_of_stock', 'name' => $this->l('Out of product alert form'), ), 'pwd' => array( 'id_option' => 'pwd_recovery', 'name' => $this->l('Forgot your password form'), ), ); if (($class = ($this->is17 ? 'ps_emailalerts' : 'mailalerts')) && (($prev_version = version_compare(_PS_VERSION_, '1.6.1', '<')) || !Module::isEnabled($class))) { unset($this->position['out']); $this->captchaPos('out_of_stock', $class); } if (($class = ($this->is17 ? 'ps_emailsubscription' : 'blocknewsletter')) && (isset($prev_version) && $prev_version || !Module::isEnabled($class))) { unset($this->position['new']); $this->captchaPos('newsletter', $class); } $this->captchaType = array( 'google' => array( 'id_option' => 'google', 'name' => $this->l('Google reCAPTCHA - V2'), 'img' => 'google.png', ), 'google_v3' => array( 'id_option' => 'google_v3', 'name' => $this->l('Google reCAPTCHA - V3'), 'img' => 'google_v3.png', ), 'colorful' => array( 'id_option' => 'colorful', 'name' => $this->l('Image captcha - Easy level'), 'img' => 'colorful.png', ), 'basic' => array( 'id_option' => 'basic', 'name' => $this->l('Image captcha - Medium level'), 'img' => 'basic.png', ), 'complex' => array( 'id_option' => 'complex', 'name' => $this->l('Image captcha - Difficult level'), 'img' => 'complex.png', ), ); //order opc. if (!$this->is17 && (int)Configuration::get('PS_ORDER_PROCESS_TYPE')) { unset($this->captchaType['google']); if (Configuration::get('PA_CAPTCHA_TYPE') == 'google') { ConfigurationCore::updateValue('PA_CAPTCHA_TYPE', 'colorful'); } unset($this->position['log']); $this->captchaPos('login'); } //configs. $this->configs = array( 'PA_CAPTCHA_POSITION' => array( 'label' => $this->l('Select forms to enable captcha'), 'type' => 'pa_checkbox', 'values' => $this->position, 'default' => 'register,contact', 'tab' => 'captcha', ), 'PA_CAPTCHA_TYPE' => array( 'label' => $this->l('Captcha type'), 'type' => 'pa_img_radio', 'required' => true, 'values' => $this->captchaType, 'default' => 'colorful', 'tab' => 'captcha', ), 'PA_GOOGLE_CAPTCHA_SITE_KEY' => array( 'label' => $this->l('Site key'), 'type' => 'text', 'required' => true, 'col' => '4', 'tab' => 'captcha', ), 'PA_GOOGLE_CAPTCHA_SECRET_KEY' => array( 'label' => $this->l('Secret key'), 'type' => 'text', 'required' => true, 'col' => '4', 'tab' => 'captcha', ), 'PA_GOOGLE_V3_CAPTCHA_SITE_KEY' => array( 'label' => $this->l('Site key'), 'type' => 'text', 'required' => true, 'col' => '4', 'tab' => 'captcha', ), 'PA_GOOGLE_V3_CAPTCHA_SECRET_KEY' => array( 'label' => $this->l('Secret key'), 'type' => 'text', 'required' => true, 'col' => '4', 'tab' => 'captcha', ), 'PA_CAPTCHA_TMP_CONTACT' => array( 'label' => $this->l('Disable template overrides contact form'), 'type' => 'switch', 'default' => '0', 'unset' => $this->is17 ? 1 : 0, 'desc' => $this->l('Enable this to use contact-form.tpl file of your theme (keep your custom contact form design and its translation). You will need to add a custom hook to your contact-form.tpl file MANUALLY.'), 'tab' => 'captcha', ), 'PA_CAPTCHA_TMP_LOGIN' => array( 'label' => $this->l('Disable template overrides Login form'), 'type' => 'switch', 'default' => '0', 'unset' => $this->is17 ? 1 : 0, 'desc' => $this->l('Enable this to use authentication.tpl file of your theme (keep your custom login form design and its translation). You will need to add a custom hook to your authentication.tpl file MANUALLY.'), 'tab' => 'captcha', ), 'PA_CAPTCHA_TMP_RE_PASSWORD' => array( 'label' => $this->l('Disable template overrides Forgot your password form'), 'type' => 'switch', 'default' => '0', 'unset' => $this->is17 ? 1 : 0, 'desc' => $this->l('Enable this to use password.tpl file of your theme (keep your custom password recovery form design and its translation). You will need to add a custom hook to your password.tpl file MANUALLY.'), 'tab' => 'captcha', ), 'PA_CAPTCHA_OFF_CUSTOMER_LOGIN' => array( 'label' => $this->l('Disable captcha for logged in customer'), 'type' => 'switch', 'default' => '1', 'tab' => 'captcha', ), 'PA_CAPTCHA_IP_BLACKLIST' => array( 'label' => $this->l('IP blacklist (IPs to block)'), 'type' => 'textarea', 'desc' => $this->l('Enter exact IP or IP pattern using "*", each IP/IP pattern on a line. For example: 69.89.31.226, 69.89.31.*, *.226, etc. '), 'rows' => 10, 'col' => 4, 'tab' => 'captcha', ), 'PA_CAPTCHA_EMAIL_BLACKLIST' => array( 'label' => $this->l('Email blacklist (emails to block)'), 'type' => 'textarea', 'desc' => $this->l('Enter exact email address or email pattern using "*", each email/email pattern on a line. For example: example@mail.ru,*@mail.ru, *@qq.com, etc.'), 'rows' => 10, 'col' => 4, 'tab' => 'captcha', ) ); } /** * @param $key * @param $class * @return bool */ public function captchaPos($key, $class = '') { if ($class && $this->overrideDir) { $ik = 0; foreach ($this->overrideDir as $overrideClass) { if ($overrideClass == $class) unset($this->overrideDir[$ik]); $ik++; } } if (!($result = Configuration::get('PA_CAPTCHA_POSITION'))) return false; $positions = explode(',', $result); $override = _PS_OVERRIDE_DIR_ . 'modules' . DIRECTORY_SEPARATOR . $class . DIRECTORY_SEPARATOR . $class . '.php'; $values = array(); foreach ($positions as $position) { if ($key != $position || $class && @file_exists($override)) $values[] = $position; } return Configuration::updateValue('PA_CAPTCHA_POSITION', ($values ? implode(',', $values) : ''), true); } /** * @return bool */ public function overrideClass() { $dst = _PS_ROOT_DIR_ . '/override'; if (!@file_exists($dst)) return true; $src = dirname(__FILE__) . '/override'; if (glob($src . DIRECTORY_SEPARATOR . '*')) { $this->recurseCopy($src, $dst); } $this->generateIndex(); } /** * @param $src * @param $dst * @return bool */ public function recurseCopy($src, $dst) { if (!@file_exists($src)) return true; if (!@is_dir($dst) && in_array(basename($dst, '.php'), $this->overrideDir)) @mkdir($dst); $dir = opendir($src); while (false !== ($file = readdir($dir))) { if (($file != '.') && ($file != '..') && basename($src . DIRECTORY_SEPARATOR . $file, '.php') != 'index') { if (is_dir($src . DIRECTORY_SEPARATOR . $file)) { $this->recurseCopy($src . DIRECTORY_SEPARATOR . $file, $dst . DIRECTORY_SEPARATOR . $file); } elseif (!@file_exists($dst . DIRECTORY_SEPARATOR . $file)) { @file_put_contents($dst . DIRECTORY_SEPARATOR . $file, ''); } } } closedir($dir); } /** * @return bool */ public function registerHooks() { $res = true; if (self::$hooks) { foreach (self::$hooks as $hook) $res &= $this->registerHook($hook); } return $res; } /** * @see Module::install() */ public function install() { $this->overrideClass(); return parent::install() && $this->registerHooks() && $this->installConfig() && $this->configGDPR(); } public function configGDPR($install = true) { if (Module::isInstalled('psgdpr') && $this->id) { $id_module = Db::getInstance()->getValue('SELECT id_module FROM `' . _DB_PREFIX_ . 'psgdpr_consent` psgdpr WHERE id_module = ' . (int)$this->id); if (!$id_module && $install) { Db::getInstance()->execute(" INSERT INTO `" . _DB_PREFIX_ . "psgdpr_consent` (id_module, active, error, error_message, date_add, date_upd) VALUES(" . (int)$this->id . ", 1, '', '', '" . date('Y-m-d H:i:s') . "', '" . date('Y-m-d H:i:s') . "')" ); } if ($id_module && !$install) { Db::getInstance()->execute("DELETE FROM `" . _DB_PREFIX_ . "psgdpr_consent` WHERE id_module = " . (int)$this->id); } } return true; } /** * @see Module::uninstall() */ public function uninstall() { return parent::uninstall() && $this->uninstallConfig() && $this->clearLogInstall() && $this->configGDPR(false); } /** * @param bool $upgrade * @return bool */ public function installConfig($upgrade = false) { $languages = Language::getLanguages(false); if ($this->configs) { foreach ($this->configs as $key => $config) { if (isset($config['lang']) && $config['lang']) { $values = array(); foreach ($languages as $lang) { $values[$lang['id_lang']] = isset($config['default']) ? $config['default'] : ''; } if ($upgrade && !Configuration::hasKey($key) || !$upgrade) { Configuration::updateValue($key, $values, true); } } else if ($upgrade && !Configuration::hasKey($key) || !$upgrade) { Configuration::updateValue($key, isset($config['default']) ? $config['default'] : '', true); } } } if (!$upgrade) { Configuration::updateValue('PS_DISABLE_OVERRIDES', 0); } return true; } /** * @return bool */ protected function uninstallConfig() { if ($this->configs) { foreach ($this->configs as $key => $config) { Configuration::deleteByName($key); } unset($config); } return true; } /** * */ public function hookDisplayBackOfficeHeader() { if (Tools::strtolower(trim(Tools::getValue('controller'))) == 'adminmodules' && Tools::getValue('configure') == $this->name) { $this->context->controller->addCss(array( $this->_path . 'views/css/admin.css', $this->_path . 'views/css/font-awesome.min.css', $this->_path . 'views/css/other.css', ), 'all'); } } public function displayRecommendedModules() { $cacheDir = dirname(__file__) . '/../../cache/'.$this->name.'/'; $cacheFile = $cacheDir.'module-list.xml'; $cacheLifeTime = 24; $cacheTime = (int)Configuration::getGlobalValue('ETS_MOD_CACHE_'.$this->name); $profileLinks = array( 'en' => 'https://addons.prestashop.com/en/207_ets-soft', 'fr' => 'https://addons.prestashop.com/fr/207_ets-soft', 'it' => 'https://addons.prestashop.com/it/207_ets-soft', 'es' => 'https://addons.prestashop.com/es/207_ets-soft', ); if(!is_dir($cacheDir)) { @mkdir($cacheDir, 0755,true); if ( @file_exists(dirname(__file__).'/index.php')){ @copy(dirname(__file__).'/index.php', $cacheDir.'index.php'); } } if(!file_exists($cacheFile) || !$cacheTime || time()-$cacheTime > $cacheLifeTime * 60 * 60) { if(file_exists($cacheFile)) @unlink($cacheFile); if($xml = self::file_get_contents($this->shortlink.'ml.xml')) { $xmlData = @simplexml_load_string($xml); if($xmlData && (!isset($xmlData->enable_cache) || (int)$xmlData->enable_cache)) { @file_put_contents($cacheFile,$xml); Configuration::updateGlobalValue('ETS_MOD_CACHE_'.$this->name,time()); } } } else $xml = Tools::file_get_contents($cacheFile); $modules = array(); $categories = array(); $categories[] = array('id'=>0,'title' => $this->l('All categories')); $enabled = true; $iso = Tools::strtolower($this->context->language->iso_code); $moduleName = $this->displayName; $contactUrl = ''; if($xml && ($xmlData = @simplexml_load_string($xml))) { if(isset($xmlData->modules->item) && $xmlData->modules->item) { foreach($xmlData->modules->item as $arg) { if($arg) { if(isset($arg->module_id) && (string)$arg->module_id==$this->name && isset($arg->{'title'.($iso=='en' ? '' : '_'.$iso)}) && (string)$arg->{'title'.($iso=='en' ? '' : '_'.$iso)}) $moduleName = (string)$arg->{'title'.($iso=='en' ? '' : '_'.$iso)}; if(isset($arg->module_id) && (string)$arg->module_id==$this->name && isset($arg->contact_url) && (string)$arg->contact_url) $contactUrl = $iso!='en' ? str_replace('/en/','/'.$iso.'/',(string)$arg->contact_url) : (string)$arg->contact_url; $temp = array(); foreach($arg as $key=>$val) { if($key=='price' || $key=='download') $temp[$key] = (int)$val; elseif($key=='rating') { $rating = (float)$val; if($rating > 0) { $ratingInt = (int)$rating; $ratingDec = $rating-$ratingInt; $startClass = $ratingDec >= 0.5 ? ceil($rating) : ($ratingDec > 0 ? $ratingInt.'5' : $ratingInt); $temp['ratingClass'] = 'mod-start-'.$startClass; } else $temp['ratingClass'] = ''; } elseif($key=='rating_count') $temp[$key] = (int)$val; else $temp[$key] = (string)strip_tags($val); } if($iso) { if(isset($temp['link_'.$iso]) && isset($temp['link_'.$iso])) $temp['link'] = $temp['link_'.$iso]; if(isset($temp['title_'.$iso]) && isset($temp['title_'.$iso])) $temp['title'] = $temp['title_'.$iso]; if(isset($temp['desc_'.$iso]) && isset($temp['desc_'.$iso])) $temp['desc'] = $temp['desc_'.$iso]; } $modules[] = $temp; } } } if(isset($xmlData->categories->item) && $xmlData->categories->item) { foreach($xmlData->categories->item as $arg) { if($arg) { $temp = array(); foreach($arg as $key=>$val) { $temp[$key] = (string)strip_tags($val); } if(isset($temp['title_'.$iso]) && $temp['title_'.$iso]) $temp['title'] = $temp['title_'.$iso]; $categories[] = $temp; } } } } if(isset($xmlData->{'intro_'.$iso})) $intro = $xmlData->{'intro_'.$iso}; else $intro = isset($xmlData->intro_en) ? $xmlData->intro_en : false; $this->smarty->assign(array( 'modules' => $modules, 'enabled' => $enabled, 'module_name' => $moduleName, 'categories' => $categories, 'img_dir' => $this->_path . 'views/img/', 'intro' => $intro, 'shortlink' => $this->shortlink, 'ets_profile_url' => isset($profileLinks[$iso]) ? $profileLinks[$iso] : $profileLinks['en'], 'trans' => array( 'txt_must_have' => $this->l('Must-Have'), 'txt_downloads' => $this->l('Downloads!'), 'txt_view_all' => $this->l('View all our modules'), 'txt_fav' => $this->l('Prestashop\'s favourite'), 'txt_elected' => $this->l('Elected by merchants'), 'txt_superhero' => $this->l('Superhero Seller'), 'txt_partner' => $this->l('Module Partner Creator'), 'txt_contact' => $this->l('Contact us'), 'txt_close' => $this->l('Close'), ), 'contactUrl' => $contactUrl, )); echo $this->display(__FILE__, 'module-list.tpl'); die; } public static function file_get_contents($url, $use_include_path = false, $stream_context = null, $curl_timeout = 60) { if ($stream_context == null && preg_match('/^https?:\/\//', $url)) { $stream_context = stream_context_create(array( "http" => array( "timeout" => $curl_timeout, "max_redirects" => 101, "header" => 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36' ), "ssl"=>array( "allow_self_signed"=>true, "verify_peer"=>false, "verify_peer_name"=>false, ), )); } if (function_exists('curl_init')) { $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => html_entity_decode($url), CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_TIMEOUT => $curl_timeout, CURLOPT_MAXREDIRS => 10, CURLOPT_FOLLOWLOCATION => true, )); $content = curl_exec($curl); curl_close($curl); return $content; } elseif (in_array(ini_get('allow_url_fopen'), array('On', 'on', '1')) || !preg_match('/^https?:\/\//', $url)) { return Tools::file_get_contents($url, $use_include_path, $stream_context); } else { return false; } } /** * @return string */ public function hookDisplayHeader() { if ((($pos = explode(',', Configuration::get('PA_CAPTCHA_POSITION'))) && (in_array('newsletter', $pos) || in_array('out_of_stock', $pos))) || in_array(Tools::getValue('controller', false), self::$pages)) { $this->context->controller->addJS($this->_path . 'views/js/front.js'); $this->context->controller->addCSS($this->_path . 'views/css/front.css', 'all'); if (($captcha_type = Configuration::get('PA_CAPTCHA_TYPE')) == 'google' || $captcha_type == 'google_v3') { $this->smarty->assign(array( 'PA_CAPTCHA_TYPE' => $captcha_type, 'PA_GOOGLE_CAPTCHA_SITE_KEY' => Configuration::get('PA_GOOGLE_CAPTCHA_SITE_KEY'), 'PA_GOOGLE_V3_CAPTCHA_SITE_KEY' => Configuration::get('PA_GOOGLE_V3_CAPTCHA_SITE_KEY'), 'hl' => $this->context->language->iso_code )); return $this->display(__FILE__, 'head.tpl'); } } } /** * @param bool $js * @return array|string */ public function getConfigs($js = false) { $configs = array(); foreach ($this->configs as $key => $val) { if (isset($val['js']) && $val['js']) { $configs[$key] = array( 'value' => Configuration::get($key, (isset($val['lang']) && $val['lang'] ? $this->context->language->id : null)), 'type' => $val['js'] ); } else $configs[$key] = Configuration::get($key); } if ($js) { $this->smarty->assign('configs', $configs); return $this->display(__FILE__, 'js.tpl'); } return $configs; } /** * @param $key * @return bool */ public function required($key) { if (!$key) return false; switch ($key) { case 'PA_GOOGLE_CAPTCHA_SITE_KEY': case 'PA_GOOGLE_CAPTCHA_SECRET_KEY': if (Tools::getValue('PA_CAPTCHA_TYPE', false) == 'google' && trim(Tools::getValue($key, '')) == '') return true; break; case 'PA_GOOGLE_V3_CAPTCHA_SITE_KEY': case 'PA_GOOGLE_V3_CAPTCHA_SECRET_KEY': if (Tools::getValue('PA_CAPTCHA_TYPE', false) == 'google_v3' && trim(Tools::getValue($key, '')) == '') return true; break; default: if (trim(Tools::getValue($key, '')) == '') return true; } return false; } /** * @param $errors * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function postConfig(&$errors) { $languages = Language::getLanguages(false); $id_lang_default = (int)Configuration::get('PS_LANG_DEFAULT'); $configs = $this->configs; if (Tools::isSubmit('pa_captcha_clear_log')) { $this->clearLogInstall(); if (Tools::getValue('pa_captcha_clear_log')) Tools::redirectAdmin($this->getAdminLink()); } elseif (Tools::isSubmit('pa_captcha_button_yes')) { Configuration::updateValue('PA_CAPTCHA_ERROR_IS_FIXED', 1); } elseif (Tools::isSubmit('saveConfig')) { if ($configs) { foreach ($configs as $key => $config) { if (isset($config['lang']) && $config['lang']) { if (isset($config['required']) && $config['required'] && $config['type'] != 'switch' && trim(Tools::getValue($key . '_' . $id_lang_default) == '')) { $errors[] = $config['label'] . ' ' . $this->l('is required'); } } else { if (isset($config['required']) && $config['required'] && $config['type'] != 'switch' && $this->required($key)) { $errors[] = $config['label'] . ' ' . $this->l('is required'); } elseif (isset($config['validate']) && method_exists('Validate', $config['validate'])) { $validate = $config['validate']; if (!Validate::$validate(trim(Tools::getValue($key)))) $errors[] = $config['label'] . ' ' . $this->l('is invalid'); unset($validate); } elseif (!is_array(Tools::getValue($key)) && !Validate::isCleanHtml(trim(Tools::getValue($key)))) { $errors[] = $config['label'] . ' ' . $this->l('is invalid'); } elseif ($key == 'PA_CAPTCHA_IP_BLACKLIST' && ($ip_blacklist = trim(Tools::getValue($key))) != '' && !preg_match('/^(([0-9A-Fa-f\.\*:])+(\n|(\r\n))*)+$/', $ip_blacklist)) { $errors[] = $config['label'] . ' ' . $this->l('is invalid'); } elseif ($key == 'PA_CAPTCHA_EMAIL_BLACKLIST' && ($email_blacklist = trim(Tools::getValue($key))) != '' && !preg_match('/^(([a-z0-9\*@\-\._])+(\n|(\r\n))*)+$/i', $email_blacklist)) { $errors[] = $config['label'] . ' ' . $this->l('is invalid'); } } } } if (!$errors) { if ($configs) { foreach ($configs as $key => $config) { if (isset($config['lang']) && $config['lang']) { $values = array(); foreach ($languages as $lang) { if ($config['type'] == 'switch') $values[$lang['id_lang']] = (int)trim(Tools::getValue($key . '_' . $lang['id_lang'])) ? 1 : 0; else $values[$lang['id_lang']] = trim(Tools::getValue($key . '_' . $lang['id_lang'])) ? trim(Tools::getValue($key . '_' . $lang['id_lang'])) : trim(Tools::getValue($key . '_' . $id_lang_default)); } Configuration::updateValue($key, $values, true); } else { if ($config['type'] == 'switch') { Configuration::updateValue($key, (int)trim(Tools::getValue($key)) ? 1 : 0, true); } elseif ($config['type'] == 'pa_checkbox' || ($config['type'] == 'select' && isset($config['multiple']) && $config['multiple'])) { $value = implode(',', Tools::getValue($key, array())); if (version_compare(_PS_VERSION_, '1.6.1', '<') && Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && Shop::getContext() !== Shop::CONTEXT_ALL) { $idConfig = (int)Configuration::getIdByName($key, (int)$this->context->shop->id_shop_group, (int)$this->context->shop->id); $configuration = new Configuration($idConfig); if (!$idConfig) { $configuration->name = $key; $configuration->id_shop = (int)$this->context->shop->id; $configuration->id_shop_group = (int)$this->context->shop->id_shop_group; } $configuration->value = $value; if ($configuration->save(true, true)) { Configuration::set($key, $value, (int)$this->context->shop->id_shop_group, (int)$this->context->shop->id); } } else Configuration::updateValue($key, $value, true); } else Configuration::updateValue($key, trim(Tools::getValue($key)), true); } } } } if (!$errors) Tools::redirectAdmin($this->getAdminLink(4)); } } /** * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function renderForm() { $configs = $this->configs; $fields_form = array( 'form' => array( 'legend' => array( 'title' => $this->l('Captcha settings'), 'icon' => 'icon-AdminAdmin' ), 'input' => array(), 'submit' => array( 'title' => $this->l('Save'), ) ), ); if ($configs) { foreach ($configs as $key => $config) { if (!(isset($config['unset'])) || !$config['unset']) { $confFields = array( 'name' => $key, 'type' => $config['type'], 'label' => $config['label'], 'desc' => isset($config['desc']) ? $config['desc'] : false, 'col' => isset($config['col']) && $config['col'] ? $config['col'] : 9, 'required' => isset($config['required']) && $config['required'] ? true : false, 'autoload_rte' => isset($config['autoload_rte']) && $config['autoload_rte'] ? true : false, 'options' => isset($config['options']) && $config['options'] ? $config['options'] : array(), 'suffix' => isset($config['suffix']) && $config['suffix'] ? $config['suffix'] : false, 'multiple' => isset($config['multiple']) ? $config['multiple'] : false, 'rows' => isset($config['rows']) ? $config['rows'] : false, 'cols' => isset($config['cols']) ? $config['cols'] : false, 'validate' => isset($config['validate']) ? $config['validate'] : false, 'values' => isset($config['values']) ? $config['values'] : ($config['type'] == 'switch' ? array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Yes') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('No') ) ) : false), 'lang' => isset($config['lang']) ? $config['lang'] : false, 'tab' => isset($config['tab']) ? $config['tab'] : false, ); if (isset($config['tab'])) $confFields['tab'] = $config['tab']; if (isset($config['tree'])) $confFields['tree'] = $config['tree']; if (!$confFields['suffix']) unset($confFields['suffix']); if (!$confFields['cols']) unset($confFields['cols']); if (!$confFields['rows']) unset($confFields['rows']); if (!$confFields['values']) unset($confFields['values']); if (!$confFields['validate']) unset($confFields['validate']); if (!$confFields['multiple']) unset($confFields['multiple']); elseif ($config['type'] == 'select' && stripos($confFields['name'], '[]') === false) $confFields['name'] .= '[]'; $fields_form['form']['input'][] = $confFields; } } } $helper = new HelperForm(); $helper->show_toolbar = false; $helper->table = $this->table; $lang = new Language((int)Configuration::get('PS_LANG_DEFAULT')); $helper->default_form_language = $lang->id; $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0; $this->fields_form = array(); $helper->module = $this; $helper->identifier = $this->identifier; $helper->submit_action = 'saveConfig'; $helper->currentIndex = $this->getAdminLink(); $helper->token = Tools::getAdminTokenLite('AdminModules'); $language = new Language((int)Configuration::get('PS_LANG_DEFAULT')); $fields = array(); $languages = Language::getLanguages(false); $helper->override_folder = '/'; if (Tools::isSubmit('saveConfig')) { if ($configs) { foreach ($configs as $key => $config) { if (isset($config['lang']) && $config['lang']) { foreach ($languages as $l) { $fields[$key][$l['id_lang']] = Tools::getValue($key . '_' . $l['id_lang'], isset($config['default']) ? $config['default'] : ''); } } elseif ($config['type'] == 'pa_checkbox' || ($config['type'] == 'select' && isset($config['multiple']) && $config['multiple'])) { $fields[$key . ($config['type'] == 'select' ? '[]' : '')] = Tools::getValue($key, array()); } else $fields[$key] = Tools::getValue($key, isset($config['default']) ? $config['default'] : ''); } } } else { if ($configs) { foreach ($configs as $key => $config) { if (isset($config['lang']) && $config['lang']) { foreach ($languages as $l) { $fields[$key][$l['id_lang']] = Configuration::get($key, $l['id_lang']); } } elseif ($config['type'] == 'pa_checkbox' || ($config['type'] == 'select' && isset($config['multiple']) && $config['multiple'])) { $fields[$key . ($config['type'] == 'select' ? '[]' : '')] = ($result = Configuration::get($key)) != '' ? explode(',', $result) : array(); } else $fields[$key] = Configuration::get($key); } } } $intro = true; $localIps = array( '127.0.0.1', '::1' ); $baseURL = Tools::strtolower(self::getBaseModLink()); if(!Tools::isSubmit('intro') && (in_array(Tools::getRemoteAddr(), $localIps) || preg_match('/^.*(localhost|demo|test|dev|:\d+).*$/i', $baseURL))) $intro = false; $helper->tpl_vars = array( 'base_url' => $this->context->shop->getBaseURL(), 'language' => array( 'id_lang' => $language->id, 'iso_code' => $language->iso_code ), 'fields_value' => $fields, 'languages' => $this->context->controller->getLanguages(), 'id_language' => $this->context->language->id, 'path' => $this->_path, 'is15' => !$this->is16, 'old_version' => version_compare(_PS_VERSION_, '1.6.0.7', '<'), 'log_install' => $this->displayLogInstall(), 'other_modules_link' => $this->context->link->getAdminLink('AdminModules', true) . '&configure=' . $this->name.'&othermodules=1', 'intro' => $intro, ); $this->_html .= $helper->generateForm(array($fields_form)); } public static function getBaseModLink() { $context = Context::getContext(); return (Configuration::get('PS_SSL_ENABLED_EVERYWHERE')?'https://':'http://').$context->shop->domain.$context->shop->getBaseURI(); } /** * @param $key * @return string */ public function generateHTML($key) { $this->smarty->assign(array( 'key' => $key, 'is17' => $this->is17, 'path' => $this->_path, )); return $this->display(__FILE__, 'gen-html.tpl'); } /** * @return bool|string */ public function getContent() { if (!$this->active) return false; $this->context->smarty->assign(array( 'root_dir' => $this->_path, )); $this->postConfig($this->_errors); $this->renderForm(); $this->smarty->assign(array( 'html' => $this->_html, 'base_dir' => $this->_path, 'is16' => $this->is16, )); if (count($this->_errors)) $this->context->controller->errors = $this->_errors; return $this->display(__FILE__, 'admin-form.tpl'); } /** * @param int $conf * @return string * @throws PrestaShopException */ public function getAdminLink($conf = 0) { if ($this->is16) return $this->context->link->getAdminLink('AdminModules', true) . ($conf ? '&conf=' . $conf : '') . '&configure=' . $this->name; else return AdminController::$currentIndex . '&token=' . Tools::getAdminTokenLite('AdminModules') . ($conf ? '&conf=' . $conf : '') . '&configure=' . $this->name; } /** * @param $params * @return bool|string */ public function hookDisplayPaCaptcha($params) { if (($page = Tools::getValue('controller', false)) && isset($params['posTo']) && $params['posTo'] && $this->hookVal($page, $params['posTo'])) { $params['page'] = $page; $params['rand'] = md5(rand()); return $this->captchaPro($params); } } /** * @param $params * @return bool|string */ public function captchaPro($params) { if (!(isset($params['rand'])) || !$params['rand'] || !(isset($params['posTo'])) || !$params['posTo']) return false; $this->smarty->assign(array_merge(array( 'captcha_page' => isset($params['page']) ? $params['page'] : 'index', 'captcha_image' => $this->context->link->getModuleLink($this->name, 'captcha', array('pos' => $params['posTo'], 'rand' => $params['rand']), Tools::usingSecureMode()), 'rand' => $params['rand'], 'modules_dir' => _MODULE_DIR_, 'is16' => $this->is16, 'is17' => $this->is17, 'hl' => $this->context->language->iso_code, 'posTo' => isset($params['posTo']) ? $params['posTo'] : false, ), $this->getConfigs())); return $this->display(__FILE__, 'captcha.tpl'); } /** * @return bool|string */ public function hookDisplayCustomerAccountForm() { return $this->hookDisplayPaCaptcha(array( 'posTo' => 'register' )); } /** * @return bool|string */ public function hookDisplayReassurance() { if ($this->is17 && Tools::getValue('controller', false) == 'order') { return $this->hookDisplayPaCaptcha(array( 'posTo' => 'login' )); } } /** * @param $params * @return string */ public function hookDisplayOverrideTemplate($params) { if (isset($params['template_file']) && $params['template_file']) { if (Tools::strpos($params['template_file'], 'contact') !== false) { return $this->getTemplatePath('contact.tpl'); } elseif (Tools::strpos($params['template_file'], 'authentication') !== false) { return $this->getTemplatePath('authentication.tpl'); } elseif (Tools::strpos($params['template_file'], 'password-email') !== false) { return $this->getTemplatePath('password-email.tpl'); } } } /** * @param null $hookName * @param array $configuration * @return string * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function renderWidget($hookName = null, array $configuration = array()) { if (($page = Tools::getValue('controller', false)) && Tools::strpos($page, 'contact') !== false) { $this->smarty->assign($this->getWidgetVariables($hookName, $configuration)); return $this->display(__FILE__, 'contact-form.tpl'); } } /** * @return $this */ protected function createNewToken() { $this->context->cookie->contactFormToken = md5(uniqid()); $this->context->cookie->contactFormTokenTTL = time() + 600; return $this; } /** * @param null $hookName * @param array $configuration * @return array * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function getWidgetVariables($hookName = null, array $configuration = array()) { $notifications = false; if (Tools::isSubmit('submitMessage')) { $this->sendMessage(); if (!empty($this->context->controller->errors)) { $notifications['messages'] = $this->context->controller->errors; $notifications['nw_error'] = true; } elseif (!empty($this->context->controller->success)) { $notifications['messages'] = $this->context->controller->success; $notifications['nw_error'] = false; } } elseif (empty($this->context->cookie->contactFormToken) || empty($this->context->cookie->contactFormTokenTTL) || $this->context->cookie->contactFormTokenTTL < time() ) { $this->createNewToken(); } if (($id_customer_thread = (int)Tools::getValue('id_customer_thread')) && $token = Tools::getValue('token')) { $cm = new CustomerThread($id_customer_thread); if ($cm->token == $token) { $this->customer_thread = $this->context->controller->objectPresenter->present($cm); $order = new Order((int)$this->customer_thread['id_order']); if (Validate::isLoadedObject($order)) { $this->customer_thread['reference'] = $order->getUniqReference(); } } } $this->contact['contacts'] = $this->getTemplateVarContact(); $this->contact['message'] = html_entity_decode(Tools::getValue('message')); $this->contact['allow_file_upload'] = (bool)Configuration::get('PS_CUSTOMER_SERVICE_FILE_UPLOAD'); if (!(bool)Configuration::isCatalogMode()) { $this->contact['orders'] = $this->getTemplateVarOrders(); } else { $this->contact['orders'] = array(); } if ($this->customer_thread['email']) { $this->contact['email'] = $this->customer_thread['email']; } else { $this->contact['email'] = Tools::safeOutput(Tools::getValue('from', ((isset($this->context->cookie) && isset($this->context->cookie->email) && Validate::isEmail($this->context->cookie->email)) ? $this->context->cookie->email : ''))); } unset($hookName); unset($configuration); return array( 'contact' => $this->contact, 'notifications' => $notifications, 'token' => $this->context->cookie->contactFormToken, 'id_module' => $this->id ); } public function sendMessage() { if ($this->hookVal(Tools::getValue('controller', false), 'contact')) { $this->captchaVal($this->context->controller->errors); } if ($this->context->controller->errors) return false; $extension = array('.txt', '.rtf', '.doc', '.docx', '.pdf', '.zip', '.png', '.jpeg', '.gif', '.jpg'); $file_attachment = Tools::fileAttachment('fileUpload'); $message = Tools::getValue('message'); if (!($from = trim(Tools::getValue('from'))) || !Validate::isEmail($from)) { $this->context->controller->errors[] = $this->l('Invalid email address.'); } elseif (!$message) { $this->context->controller->errors[] = $this->l('The message cannot be blank.'); } elseif (!Validate::isCleanHtml($message)) { $this->context->controller->errors[] = $this->l('Invalid message'); } elseif (!($id_contact = (int)Tools::getValue('id_contact')) || !(Validate::isLoadedObject($contact = new Contact($id_contact, $this->context->language->id)))) { $this->context->controller->errors[] = $this->l('Please select a subject from the list provided. '); } elseif (!empty($file_attachment['name']) && $file_attachment['error'] != 0) { $this->context->controller->errors[] = $this->l('An error occurred during the file-upload process.'); } elseif (!empty($file_attachment['name']) && !in_array(Tools::strtolower(Tools::substr($file_attachment['name'], -4)), $extension) && !in_array(Tools::strtolower(Tools::substr($file_attachment['name'], -5)), $extension)) { $this->context->controller->errors[] = $this->l('Bad file extension'); } else { $customer = $this->context->customer; if (!$customer->id) { $customer->getByEmail($from); } $id_order = (int)Tools::getValue('id_order'); $id_customer_thread = CustomerThread::getIdCustomerThreadByEmailAndIdOrder($from, $id_order); if ($contact->customer_service) { if ((int)$id_customer_thread) { $ct = new CustomerThread($id_customer_thread); $ct->status = 'open'; $ct->id_lang = (int)$this->context->language->id; $ct->id_contact = (int)$id_contact; $ct->id_order = (int)$id_order; if ($id_product = (int)Tools::getValue('id_product')) { $ct->id_product = $id_product; } $ct->update(); } else { $ct = new CustomerThread(); if (isset($customer->id)) { $ct->id_customer = (int)$customer->id; } $ct->id_shop = (int)$this->context->shop->id; $ct->id_order = (int)$id_order; if ($id_product = (int)Tools::getValue('id_product')) { $ct->id_product = $id_product; } $ct->id_contact = (int)$id_contact; $ct->id_lang = (int)$this->context->language->id; $ct->email = $from; $ct->status = 'open'; $ct->token = Tools::passwdGen(12); $ct->add(); } if ($ct->id) { $lastMessage = CustomerMessage::getLastMessageForCustomerThread($ct->id); $testFileUpload = (isset($file_attachment['rename']) && !empty($file_attachment['rename'])); // if last message is the same as new message (and no file upload), do not consider this contact if ($lastMessage != $message || $testFileUpload) { $cm = new CustomerMessage(); $cm->id_customer_thread = $ct->id; $cm->message = $message; if ($testFileUpload && rename($file_attachment['tmp_name'], _PS_UPLOAD_DIR_ . basename($file_attachment['rename']))) { $cm->file_name = $file_attachment['rename']; @chmod(_PS_UPLOAD_DIR_ . basename($file_attachment['rename']), 0664); } $cm->ip_address = (int)ip2long(Tools::getRemoteAddr()); $cm->user_agent = $_SERVER['HTTP_USER_AGENT']; if (!$cm->add()) { $this->context->controller->errors[] = $this->l('An error occurred while sending the message.'); } } else { $mailAlreadySend = true; } } else { $this->context->controller->errors[] = $this->l('An error occurred while sending the message.'); } } $sendConfirmationEmail = Module::isEnabled('contactform') && (Configuration::hasKey(self::SEND_CONFIRMATION_EMAIL) || Configuration::hasKey(self::SEND_CONFIRMATION_EMAIL, null, $this->context->shop->id_shop_group, $this->context->shop->id))? (int)Configuration::get(self::SEND_CONFIRMATION_EMAIL) : 1; $sendNotificationEmail = Module::isEnabled('contactform') && (Configuration::hasKey(self::SEND_NOTIFICATION_EMAIL) || Configuration::hasKey(self::SEND_NOTIFICATION_EMAIL, null, $this->context->shop->id_shop_group, $this->context->shop->id))? (int)Configuration::get(self::SEND_NOTIFICATION_EMAIL) : 1; if (!count($this->context->controller->errors) && empty($mailAlreadySend) && ($sendConfirmationEmail || $sendNotificationEmail) ) { $var_list = array( '{order_name}' => '-', '{attached_file}' => '-', '{message}' => Tools::nl2br(Tools::stripslashes($message)), '{email}' => $from, '{product_name}' => '', ); if (isset($file_attachment['name'])) { $var_list['{attached_file}'] = $file_attachment['name']; } $id_product = (int)Tools::getValue('id_product'); if (isset($ct) && Validate::isLoadedObject($ct) && $ct->id_order) { $order = new Order((int)$ct->id_order); $var_list['{order_name}'] = $order->getUniqReference(); $var_list['{id_order}'] = (int)$order->id; } if ($id_product) { $product = new Product((int)$id_product); if (Validate::isLoadedObject($product) && isset($product->name[Context::getContext()->language->id])) { $var_list['{product_name}'] = $product->name[Context::getContext()->language->id]; } } if (empty($contact->email) && $sendConfirmationEmail) { Mail::Send( $this->context->language->id, 'contact_form', ((isset($ct) && Validate::isLoadedObject($ct)) ? sprintf($this->l('Your message has been correctly sent #ct%s #tc%s'), $ct->id, $ct->token) : $this->l('Your message has been correctly sent')), $var_list, $from, null, null, null, $file_attachment ); } elseif ($contact->email) { if ($sendNotificationEmail && !Mail::Send( $this->context->language->id, 'contact', $this->l('Message from contact form') . ' [no_sync]', $var_list, $contact->email, $contact->name, null, null, $file_attachment, null, _PS_MAIL_DIR_, false, null, null, $from ) || $sendConfirmationEmail && !Mail::Send( $this->context->language->id, 'contact_form', ((isset($ct) && Validate::isLoadedObject($ct)) ? sprintf($this->l('Your message has been correctly sent #ct%s #tc%s'), $ct->id, $ct->token) : $this->l('Your message has been correctly sent')), $var_list, $from, null, null, null, $file_attachment, null, _PS_MAIL_DIR_, false, null, null, $contact->email )) { $this->context->controller->errors[] = $this->l('An error occurred while sending the message.'); } } } if (!count($this->context->controller->errors)) { $this->context->controller->success[] = $this->l('Your message has been successfully sent to our team.'); } } } /** * @return array */ public function getTemplateVarContact() { $contacts = array(); $all_contacts = Contact::getContacts($this->context->language->id); foreach ($all_contacts as $one_contact) { $contacts[$one_contact['id_contact']] = $one_contact; } if ($this->customer_thread['id_contact']) { $contacts_arr = array(); $contacts_arr[] = $contacts[$this->customer_thread['id_contact']]; return $contacts_arr; } return $contacts; } /** * @return array * @throws PrestaShopDatabaseException * @throws PrestaShopException */ public function getTemplateVarOrders() { $orders = array(); if (!isset($this->customer_thread['id_order']) && $this->context->customer->isLogged()) { $customer_orders = Order::getCustomerOrders($this->context->customer->id); foreach ($customer_orders as $customer_order) { $myOrder = new Order((int)$customer_order['id_order']); if (Validate::isLoadedObject($myOrder)) { $orders[$customer_order['id_order']] = $customer_order; $orders[$customer_order['id_order']]['products'] = $myOrder->getProducts(); } } } elseif ((int)$this->customer_thread['id_order'] > 0) { $myOrder = new Order($this->customer_thread['id_order']); if (Validate::isLoadedObject($myOrder)) { $orders[$myOrder->id] = $this->context->controller->objectPresenter->present($myOrder); $orders[$myOrder->id]['id_order'] = $myOrder->id; $orders[$myOrder->id]['products'] = $myOrder->getProducts(); } } if ($this->customer_thread['id_product']) { $id_order = 0; if (isset($this->customer_thread['id_order'])) { $id_order = (int)$this->customer_thread['id_order']; } $orders[$id_order]['products'][(int)$this->customer_thread['id_product']] = $this->context->controller->objectPresenter->present(new Product((int)$this->customer_thread['id_product'])); } return $orders; } /** * @param $page * @param $posTo * @return bool */ public function hookVal($page, $posTo) { if ($this->context->customer->isLogged() && Configuration::get('PA_CAPTCHA_OFF_CUSTOMER_LOGIN') || !$posTo) return false; $position = ($result = Configuration::get('PA_CAPTCHA_POSITION')) != '' ? explode(',', $result) : false; if (!$position) return false; if (in_array($posTo, $position)) { switch ($posTo) { case 'newsletter': if ((Module::isEnabled('ps_emailsubscription') || Module::isEnabled('blocknewsletter'))) return true; break; case 'out_of_stock': if ($page == 'product' && (Module::isEnabled('ps_emailalerts') || Module::isEnabled('mailalerts'))) return true; break; case 'register': case 'login': if (($this->is17 || !Configuration::get('PS_ORDER_PROCESS_TYPE') || Configuration::get('PA_CAPTCHA_TYPE') != 'google') && in_array($page, self::$pages)) return true; break; default: if (in_array($page, self::$pages)) return true; break; } } return false; } /** * @param $errors */ public function captchaVal(&$errors) { if (($captcha_type = Configuration::get('PA_CAPTCHA_TYPE')) == 'google' || $captcha_type == 'google_v3') { if (Tools::getIsset('g-recaptcha-response') && ($reCaptcha = Tools::getValue('g-recaptcha-response'))) { $secret = Configuration::get('PA_GOOGLE' . ($captcha_type == 'google_v3' ? '_V3' : '') . '_CAPTCHA_SECRET_KEY'); $site_verify = "https://www.google.com/recaptcha/api/siteverify"; $query_build = http_build_query(array( 'secret' => $secret, 'response' => $reCaptcha )); $curl_timeout = 5; $this->refreshCACertFile(); $stream_context = @stream_context_create(array( 'http' => array('timeout' => $curl_timeout), 'ssl' => array( 'verify_peer' => true, 'cafile' => $this->getBundledCaBundlePath(), ), )); $response = Tools::file_get_contents($site_verify . '?' . $query_build, false, $stream_context, $curl_timeout); $response = Tools::jsonDecode($response); if (!$response || (property_exists($response, 'success') && $response->success == false) || (property_exists($response, 'score') && $response->score < 0.5)) { $errors[] = $this->l('reCaptcha is invalid.'); } } else $errors[] = $this->l('reCaptcha error'); if (!Tools::getIsset('g-recaptcha-response')) { die(Tools::jsonEncode(array( 'error' => true, 'message' => $this->l('404 not found!'), ))); } } else { $antiHack = true; if (($posTo = Tools::getValue('posTo', false))) { $security = ($captcha = self::PREFIX_CODE . $posTo) && isset($this->context->cookie->{$captcha}) && ($cookieVal = $this->context->cookie->{$captcha}) ? $cookieVal : false; $pa_captcha = Tools::getIsset('pa_captcha') && ($val = Tools::getValue('pa_captcha', false)) ? Tools::strtolower(trim($val)) : false; if (!$security || ($security !== $pa_captcha)) { $errors[] = $this->l('Security code does not match'); } if (!(isset($this->context->cookie->{$captcha}))) $antiHack = false; } if (!Tools::getIsset('pa_captcha') || !Tools::getIsset('posTo') || !$antiHack) { die(Tools::jsonEncode(array( 'error' => true, 'message' => $this->l('404 not found!'), ))); } } if (!$errors) { if ($this->ipBlackList(Configuration::get('PA_CAPTCHA_IP_BLACKLIST'))) { $errors[] = $this->l('Your IP is blocked. Contact webmaster for more info.'); } elseif ($this->emailBlackList(Configuration::get('PA_CAPTCHA_EMAIL_BLACKLIST'))) { $errors[] = $this->l('Your email is blocked. Contact webmaster for more info.'); } } } public function ipBlackList($ip_blacklist) { if (!$ip_blacklist) return false; $remote_addr = Tools::getRemoteAddr(); $ips = explode("\n", $ip_blacklist); if ($ips) { foreach ($ips as $ip) { if (preg_match('/^' . $this->formatPattern($ip) . '$/', $remote_addr)) { return true; } } } return false; } public function emailBlackList($email_blacklist) { if (!$email_blacklist || !($email = Tools::getValue('email', Tools::getValue('from')))) return false; $emails = explode("\n", $email_blacklist); if ($emails) { foreach ($emails as $pattern) { if (preg_match('/^' . $this->formatPattern($pattern) . '$/', $email)) { return true; } } } return false; } public function formatPattern($pattern) { return str_replace('*', '(.*)', trim($pattern)); } public function refreshCACertFile() { if ((time() - @filemtime($this->local_path . 'cache/cacert.pem') > 0)) { $stream_context = @stream_context_create(array( 'http' => array('timeout' => 3), 'ssl' => array( 'cafile' => $this->getBundledCaBundlePath(), ), )); $ca_cert_content = Tools::file_get_contents(self::CACERT_LOCATION, false, $stream_context); if (empty($ca_cert_content)) { $ca_cert_content = Tools::file_get_contents($this->getBundledCaBundlePath()); } if (preg_match('/(.*-----BEGIN CERTIFICATE-----.*-----END CERTIFICATE-----){50}$/Uims', $ca_cert_content) && Tools::substr(rtrim($ca_cert_content), -1) == '-') { @file_put_contents(_PS_CACHE_CA_CERT_FILE_, $ca_cert_content); } } } public function getBundledCaBundlePath() { $caBundleFile = $this->local_path . 'cache/cacert.pem'; if (0 === strpos($caBundleFile, 'phar://')) { @file_put_contents( $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'), Tools::file_get_contents($caBundleFile) ); register_shutdown_function(function () use ($tempCaBundleFile) { @unlink($tempCaBundleFile); }); $caBundleFile = $tempCaBundleFile; } return $caBundleFile; } public function checkFile($dir, $name, $ver = false) { $checkFile = _PS_THEME_DIR_ . 'modules' . DIRECTORY_SEPARATOR . ($baseDir = @str_replace('/', DIRECTORY_SEPARATOR, 'ets_advancedcaptcha/views/templates/') . $dir . DIRECTORY_SEPARATOR . $name . (!$this->is16 && $ver ? '-15' : '') . '.tpl'); if (!@file_exists($checkFile)) $checkFile = _PS_MODULE_DIR_ . $baseDir; return @file_exists($checkFile) ? ($this->is17 ? 'module:' . $baseDir : $checkFile) : false; } /** * @return array|null */ public function getOverrides() { if (!$this->is17) { if (!is_dir($this->getLocalPath() . 'override')) { return null; } $result = array(); foreach (Tools::scandir($this->getLocalPath() . 'override', 'php', '', true) as $file) { $class = basename($file, '.php'); if (PrestaShopAutoload::getInstance()->getClassPath($class . 'Core') || Module::getModuleIdByName($class)) { $result[] = $class; } } return $result; } else return parent::getOverrides(); } /** * @param string $classname * @return bool * @throws ReflectionException */ public function addOverride($classname) { $_errors = array(); $orig_path = $path = PrestaShopAutoload::getInstance()->getClassPath($classname . 'Core'); if (!$path) { $path = 'modules' . DIRECTORY_SEPARATOR . $classname . DIRECTORY_SEPARATOR . $classname . '.php'; } $path_override = $this->getLocalPath() . 'override' . DIRECTORY_SEPARATOR . $path; if (!@file_exists($path_override)) { return true; } else { @file_put_contents($path_override, preg_replace('#(\r\n|\r)#ism', "\n", Tools::file_get_contents($path_override))); } $pattern_escape_com = '#(^\s*?\/\/.*?\n|\/\*(?!\n\s+\* module:.*?\* date:.*?\* version:.*?\*\/).*?\*\/)#ism'; if ($file = PrestaShopAutoload::getInstance()->getClassPath($classname)) { $override_path = _PS_ROOT_DIR_ . '/' . $file; if ((!@file_exists($override_path) && !is_writable(dirname($override_path))) || (@file_exists($override_path) && !is_writable($override_path))) { $_errors[] = sprintf($this->l('file (%s) is not writable'), $override_path); } do { $uniq = uniqid(); } while (@class_exists($classname . 'OverrideOriginal_remove', false)); $override_file = file($override_path); $override_file = array_diff($override_file, array("\n")); $this->execEval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+' . $classname . '\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'), array(' ', 'class ' . $classname . 'OverrideOriginal' . $uniq), implode('', $override_file))); $override_class = new ReflectionClass($classname . 'OverrideOriginal' . $uniq); $module_file = file($path_override); $module_file = array_diff($module_file, array("\n")); $this->execEval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+' . $classname . '(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array(' ', 'class ' . $classname . 'Override' . $uniq), implode('', $module_file))); $module_class = new ReflectionClass($classname . 'Override' . $uniq); foreach ($module_class->getMethods() as $method) { if ($override_class->hasMethod($method->getName())) { $method_override = $override_class->getMethod($method->getName()); if (preg_match('/module: (.*)/ism', $override_file[$method_override->getStartLine() - 5], $name) && preg_match('/date: (.*)/ism', $override_file[$method_override->getStartLine() - 4], $date) && preg_match('/version: ([0-9.]+)/ism', $override_file[$method_override->getStartLine() - 3], $version)) { $_errors[] = sprintf($this->l('The method %1$s in the class %2$s is already overridden by the module %3$s version %4$s at %5$s.'), $method->getName(), $classname, $name[1], $version[1], $date[1]); } else { $_errors[] = sprintf($this->l('The method %1$s in the class %2$s is already overridden.'), $method->getName(), $classname); } } $module_file = preg_replace('/((:?public|private|protected)\s+(static\s+)?function\s+(?:\b' . $method->getName() . '\b))/ism', "/*\n * module: " . $this->name . "\n * date: " . date('Y-m-d H:i:s') . "\n * version: " . $this->version . "\n */\n $1", $module_file); if ($module_file === null) { $_errors[] = sprintf($this->l('Failed to override method %1$s in class %2$s.'), $method->getName(), $classname); } } if (!$_errors) { $copy_from = array_slice($module_file, $module_class->getStartLine() + 1, $module_class->getEndLine() - $module_class->getStartLine() - 2); array_splice($override_file, $override_class->getEndLine() - 1, 0, $copy_from); $code = implode('', $override_file); @file_put_contents($override_path, preg_replace($pattern_escape_com, '', $code)); } } else { $override_src = $path_override; $override_dest = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'override' . DIRECTORY_SEPARATOR . $path; $dir_name = dirname($override_dest); if (!$orig_path && !is_dir($dir_name)) { $oldumask = umask(0000); @mkdir($dir_name, 0777); umask($oldumask); } if (!is_writable($dir_name)) { $_errors[] = sprintf($this->l('directory (%s) is not writable'), $dir_name); } $module_file = file($override_src); $module_file = array_diff($module_file, array("\n")); if ($orig_path) { do { $uniq = uniqid(); } while (@class_exists($classname . 'OverrideOriginal_remove', false)); $this->execEval(preg_replace(array('#^\s*<\?(?:php)?#', '#class\s+' . $classname . '(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array(' ', 'class ' . $classname . 'Override' . $uniq), implode('', $module_file))); $module_class = new ReflectionClass($classname . 'Override' . $uniq); foreach ($module_class->getMethods() as $method) { $module_file = preg_replace('/((:?public|private|protected)\s+(static\s+)?function\s+(?:\b' . $method->getName() . '\b))/ism', "/*\n * module: " . $this->name . "\n * date: " . date('Y-m-d H:i:s') . "\n * version: " . $this->version . "\n */\n $1", $module_file); if ($module_file === null) { $_errors[] = sprintf($this->l('Failed to override method %1$s in class %2$s.'), $method->getName(), $classname); } } } if (!$_errors) { @file_put_contents($override_dest, preg_replace($pattern_escape_com, '', $module_file)); $this->generateIndex(); } } if ($_errors) $this->logInstall($classname, $_errors); return true; } public function generateIndex() { if ($this->is16) { Tools::generateIndex(); } else { Autoload::getInstance()->generateIndex(); } } /** * @param $php_code */ public function execEval($php_code) { if (function_exists('ets_captcha_excelVal')) { return call_user_func('ets_captcha_excelVal', $php_code); } else { $temp = @tempnam($this->getLocalPath() . 'cache', 'execEval'); $handle = fopen($temp, "w+"); fwrite($handle, "isLogInstall($classname)) return true; $orig_path = $path = PrestaShopAutoload::getInstance()->getClassPath($classname . 'Core'); if ($orig_path && !$file = PrestaShopAutoload::getInstance()->getClassPath($classname)) return true; elseif (!$orig_path && Module::getModuleIdByName($classname)) $path = 'modules' . DIRECTORY_SEPARATOR . $classname . DIRECTORY_SEPARATOR . $classname . '.php'; $override_path = $orig_path ? _PS_ROOT_DIR_ . '/' . $file : _PS_OVERRIDE_DIR_ . $path; if (!@is_file($override_path) || !is_writable($override_path)) return true; return parent::removeOverride($classname); } public $log_file = 'install.log'; /** * @param $classname * @param $_errors */ public function logInstall($classname, $_errors) { $log_file = $this->getLocalPath() . $this->log_file; $data = array(); if (@file_exists($log_file)) $data = (array)Tools::jsonDecode(Tools::file_get_contents($log_file)); $data[$classname] = $_errors; @file_put_contents($log_file, Tools::jsonEncode($data)); } /** * @param $classname * @return bool */ public function isLogInstall($classname) { $log_file = $this->getLocalPath() . $this->log_file; if (!@file_exists($log_file)) return false; $cached = (array)Tools::jsonDecode(Tools::file_get_contents($log_file)); if ($cached && !empty($cached[$classname])) return true; return false; } /** * @return bool */ public function clearLogInstall() { $log_file = $this->getLocalPath() . $this->log_file; if (@file_exists($log_file)) @unlink($log_file); Configuration::deleteByName('PA_CAPTCHA_ERROR_IS_FIXED'); return true; } /** * @return bool|string */ public function displayLogInstall() { $log_file = $this->getLocalPath() . $this->log_file; if (!@file_exists($log_file)) return false; $errors = (array)Tools::jsonDecode(Tools::file_get_contents($log_file)); if ($errors) { $this->smarty->assign(array( 'PA_CAPTCHA_ERROR_IS_FIXED' => (int)Configuration::get('PA_CAPTCHA_ERROR_IS_FIXED'), 'link' => $this->_path . $this->log_file, 'errors' => $errors, )); return $this->display(__FILE__, 'log.tpl'); } return false; } }