Edit file File name : class.A2OptPrestaShop.php Content :<?php class A2OptPrestaShop extends A2OptBase { public $app; public $db_connection; public $db_server; public $db_prefix; public $db_name; public $db_user; public $db_passwd; public $memcached_socket; public $title; public $domain; public $path; public $ps_ver; public $type; public $cookie_key; public $pdo; public $htaccess; public $version; public function __construct($app) { $this->exit_on_error = false; try { $this->pdo = new PDO(''); } catch (Exception $e) { } $this->db_connection = new MySqli(); $this->app = $app; $this->path = $app->path; $this->domain = $app->domain; $this->ps_ver = $app->ps_ver; $this->type = 'PrestaShop'; $this->get_settings(); if (is_null($this->type) || is_null($this->db_connection)) { $this->log_action('Unable to get_settings ' . $this->path); $this->type = null; return; } $this->db_connect(true); if (is_null($this->type)) { $this->log_action('Unable to connect to DB ' . $this->path); return; } $this->version = $this->get_setting('_PS_VERSION_'); $this->get_shop_name(); $this->exit_on_error = true; $thisclass = $this; } //extended function with exit boolean public function error($msg, $exit = true) { error_log($msg); if ($this->exit_on_error) { parent::error($msg); } } public function get_settings() { if ($this->ps_ver == '1.7') { if (!($this->db_server = $this->get_setting('database_host'))) { $this->db_server = 'localhost'; } if (!($this->db_name = $this->get_setting('database_name'))) { $this->type = null; $this->error("There is no database name defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_user = $this->get_setting('database_user'))) { $this->type = null; $this->error("There is no database user defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_passwd = $this->get_setting('database_password'))) { $this->type = null; $this->error("There is no database password defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_prefix = $this->get_setting('database_prefix'))) { $this->db_prefix = 'ps_'; } } else { if (!($this->db_server = $this->get_setting('_DB_SERVER_'))) { $this->db_server = 'localhost'; } if (!($this->db_name = $this->get_setting('_DB_NAME_'))) { $this->type = null; $this->error("There is no database name defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_user = $this->get_setting('_DB_USER_'))) { $this->type = null; $this->error("There is no database user defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_passwd = $this->get_setting('_DB_PASSWD_'))) { $this->type = null; $this->error("There is no database password defined for PrestaShop in {$this->path}/config/settings.inc.php"); } if (!($this->db_prefix = $this->get_setting('_DB_PREFIX_'))) { $this->db_prefix = 'ps_'; } } } public function get_shop_name() { $table = $this->get_table('configuration'); $result = $this->db_connection->query("select value from {$table} where name='PS_SHOP_NAME'"); if (isset($result->num_rows) && $result->num_rows >= 1) { $title = ($row = $result->fetch_object()) ? $row->value : $this->domain; $this->title = $this->check_app_title($title, $this->app); } else { $this->title = $this->domain; } } public function db_connect($testing) { if ( isset($this->db_server) && isset($this->db_user) && isset($this->db_passwd) && isset($this->db_name) && $this->db_server != '' && $this->db_user != '' && $this->db_passwd != '' && $this->db_name ) { $this->db_connection = new MySQLi($this->db_server, $this->db_user, $this->db_passwd, $this->db_name); if ($this->db_connection->connect_errno) { if ($testing === true) { $this->type = null; } $this->error('Could not connect to the PrestaShop database.'); return; } $this->db_connection->autocommit(true); try { $this->pdo = new A2OptPDO($this->db_server, $this->db_user, $this->db_passwd, $this->db_name); } catch (PDOException $e) { if ($testing === true) { $this->type = null; } $this->error('Could not connect to the PrestaShop database.'); return; } } else { if ($testing === true) { $this->type = null; } $this->error('Could not connect to the PrestaShop database.'); } } public function get_percent_optimized() { $optimizations = $this->get_optimizations(); $count = 0; foreach ($optimizations as $name => $optimization) { if ($optimization['optimized']) { $count ++; } } return ceil(($count / count($optimizations)) * 100); } public function get_optimizations() { $thisclass = $this; $turbo_cache_enabled = false; if (isset($this->app->swiftcache->turbocache->enabled)) { $turbo_cache_enabled = $this->app->swiftcache->turbocache->enabled; } return [ 'Smarty Cache' => [ 'optimized' => ($this->get_configuration('PS_SMARTY_CACHE') == '1'), 'description' => 'Smarty Cache is a template caching engine built into PrestaShop', 'variable' => 'PS_SMARTY_CACHE', 'optimized_value' => '1', 'requires' => 'PS_SMARTY_CLEAR_CACHE', 'requires_default' => '', 'deoptimized_value' => '0', 'type' => 'core_config' ], 'Cache Theme CSS' => [ 'optimized' => ($this->get_configuration('PS_CSS_THEME_CACHE') == '1'), 'description' => 'Caches CSS generated by the theme', 'variable' => 'PS_CSS_THEME_CACHE', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config' ], 'Cache Theme JavaScript' => [ 'optimized' => ($this->get_configuration('PS_JS_THEME_CACHE') == '1'), 'description' => 'Caches JavaScript generated by the theme', 'variable' => 'PS_JS_THEME_CACHE', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config' ], 'Compress HTML' => [ 'optimized' => ($this->get_configuration('PS_HTML_THEME_COMPRESSION') == '1'), 'description' => 'Minify and Compress HTML pages', 'variable' => 'PS_HTML_THEME_COMPRESSION', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config' ], 'Compress JS in HTML' => [ 'optimized' => ($this->get_configuration('PS_JS_HTML_THEME_COMPRESSION') == '1'), 'description' => 'Compresses inline JavaScript in HTML pages', 'variable' => 'PS_JS_HTML_THEME_COMPRESSION', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config' ], 'Defer Javascript' => [ 'optimized' => ($this->get_configuration('PS_JS_DEFER') == '1'), 'description' => 'Moves loading of external JavaScript to the end of HTML documents', 'variable' => 'PS_JS_DEFER', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config' ], /*"Caching System"=>array( "optimized"=>($this->is_cachefs_enabled() || $this->is_memcached_enabled()), "description"=>"Page Cache System", "variable"=>"_PS_CACHE_ENABLED_", "optimized_value"=>"1", "deoptimized_value"=>"0", "type"=>"settings.inc.php", "requires"=>"_PS_CACHING_SYSTEM_", "requires_default"=>"CacheFs", "on_optimize"=> function() use(&$thisclass) { $thisclass->check_cache_system(); return true; } ),*/ 'Apache Optimization' => [ 'optimized' => ($this->get_configuration('PS_HTACCESS_CACHE_CONTROL') == '1'), 'description' => 'Enables Rules in .htaccess to improve performance', 'variable' => 'PS_HTACCESS_CACHE_CONTROL', 'optimized_value' => '1', 'deoptimized_value' => '0', 'type' => 'core_config', 'htaccess' => true ], 'TurboCache' => [ 'optimized' => $turbo_cache_enabled, 'description' => 'Static file caching by the web Server', 'controller' => 'TurboCache', 'advanced' => true ], 'Memcached' => [ 'optimized' => $this->is_memcached_enabled(), 'description' => 'Caching of database query results in memory', 'controller' => 'Memcached', 'advanced' => true ] ]; } public function check_cache_system() { if ($this->ps_ver == '1.7') { $setting = 'ps_caching_system'; } else { $setting = '_PS_CACHING_SYSTEM_'; } $system = $this->get_setting($setting); if ($system == 'CacheMemcached' || $system == 'CacheMemcache') { if (!$this->get_memcached_server()) { $this->update_settings($setting, 'CacheFs'); } } else { $this->update_settings($setting, 'CacheFs'); } return true; } public function get_memcached_server() { $tablename = $this->get_table('memcached_servers'); $stmt = $this->db_connection->prepare("select ip,port from {$tablename};"); $stmt->execute(); $stmt->store_result(); $stmt->bind_result($ip); while ($stmt->fetch()) { if ($this->can_connect_to_socket($ip)) { $stmt->close(); return true; } } $stmt->close(); return false; } public function set_optimization($name, $optimize) { $optimizations = $this->get_optimizations(); if (array_key_exists($name, $optimizations)) { if (isset($optimizations[$name]['type'])) { $value = $optimize ? $optimizations[$name]['optimized_value']: $optimizations[$name]['deptimized_value']; switch ($optimizations[$name]['type']) { case 'core_config': $this->update_configuration($optimizations[$name]['variable'], $value); break; case 'settings.inc.php': if (isset($optimizations[$name]['requires'])) { if (!$this->get_setting($optimizations[$name]['requires'])) { $this->update_settings($optimizations[$name]['requires'], $optimizations[$name]['requires_default']); } } $this->update_settings($optimizations[$name]['variable'], $value); break; } if (isset($optimizations[$name]['on_optimize'])) { $optimizations[$name]['on_optimize'](); } } if (isset($optimizations[$name]['htaccess']) && $optimizations[$name]['htaccess']) { $this->generate_htaccess(); } } return $this->get_optimizations(); } public function destroy_db_connection() { unset($this->db_server); unset($this->db_prefix); unset($this->db_name); unset($this->db_user); unset($this->db_passwd); if (isset($this->db_connection)) { $this->db_connection->close(); unset($this->db_connection); } } public function install_module() { chdir($this->app->path); $res = $this->su_exec(__DIR__ . '/../../prestashop/install-a2hosting'); } public function module_installed($name = 'a2hosting') { $tablename = $this->get_table('module'); $active = 0; $stmt = $this->db_connection->prepare("select active from {$tablename} where name=?"); $stmt->bind_param('s', $name); $stmt->execute(); $stmt->store_result(); $stmt->bind_result($active); if ($stmt->num_rows) { $stmt->fetch(); } $stmt->close(); return ($active == 0); } public function get_setting($name) { if ($this->ps_ver == '1.7') { if ($name == '_PS_VERSION_') { return '1.7'; } // PrestaShop 1.7 config is in /app/config/parameters.php if (file_exists("{$this->path}/app/config/parameters.php")) { $settings = file_get_contents("{$this->path}/app/config/parameters.php"); $reg_ex = $this->get_config_regex(); preg_match_all($reg_ex[0], $settings, $matches1, PREG_SET_ORDER, 0); preg_match_all($reg_ex[1], $settings, $matches2, PREG_SET_ORDER, 0); foreach ($matches1 as $match) { if ($match[1] == $name) { return $match[2]; } } foreach ($matches2 as $match) { if ($match[1] == $name) { if (!$match[2]) { // Some items are stored as false or null, return as a string so we can keep the value return 'NULL'; } else { return $match[2]; } } } } } else { if (file_exists("{$this->path}/config/settings.inc.php")) { $settings = file_get_contents("{$this->path}/config/settings.inc.php"); if ( !(preg_match('/define\(\s*[\'"]' . $name . '[\'"]\s*,\s*[\'"](.*)[\'"]\s*\)\s*;/iU', $settings, $matches) === false) ) { return $matches[1]; } } } $this->type = null; return false; } public function is_memcached_enabled() { if ($this->ps_ver == '1.7') { if (($this->get_setting('ps_cache_enable') === '1' || $this->get_setting('ps_cache_enable') == 'true' || !$this->get_setting('ps_cache_enable') == 'false') && ($this->get_setting('ps_caching_system') == 'CacheMemcached' || $this->get_setting('ps_caching_system') == 'CacheMemcache') ) { return true; } } else { if ($this->get_setting('_PS_CACHE_ENABLED_') === '1' && ($this->get_setting('_PS_CACHING_SYSTEM_') == 'CacheMemcached' || $this->get_setting('_PS_CACHING_SYSTEM_') == 'CacheMemcache') ) { return true; } } return false; } public function is_cachefs_enabled() { if ($this->ps_ver == '1.7') { if ($this->get_setting('ps_cache_enable') === '1' && $this->get_setting('ps_caching_system') == 'CacheFs') { return true; } } else { if ($this->get_setting('_PS_CACHE_ENABLED_') === '1' && $this->get_setting('_PS_CACHING_SYSTEM_') == 'CacheFs') { return true; } } return false; } public function get_configuration($name = '') { chdir($this->path); $name = escapeshellarg($name); $res = shell_exec("/opt/a2-optimized/prestashop/configuration-get {$name}"); return $res; } public function get_table($name = 'configuration') { if ($name == '') { return ''; } $var = "{$this->db_prefix}{$name}"; $table = ''; $stmt = $this->pdo->prepare('SHOW Tables LIKE ?'); $stmt->execute([$var]); if ($res = $stmt->fetchAll()) { $table = $res[0][0]; } else { $var = "%{$name}"; $stmt = $this->pdo->prepare('SHOW Tables LIKE ?'); $stmt->execute([$var]); if ($res = $stmt->fetchAll()) { $table = $res[0][0]; } } return $table; } private function update_configuration($name, $value) { chdir($this->path); $cmd = escapeshellcmd("/opt/a2-optimized/prestashop/configuration-update {$name} {$value}"); $res = shell_exec($cmd); if ($res == '') { return true; } else { return false; } } public function optimize() { if ($this->litespeed) {//install the prestashop module for litespeed cache $this->install_module(); } $optimizations = $this->get_optimizations(); foreach ($optimizations as $name => $optimization) { if (!$optimization['optimized']) { $this->set_optimization($name, true); } } } public function generate_htaccess() { chdir($this->path); $shell_res = $this->su_exec('/opt/a2-optimized/prestashop/generate-htaccess');//have PrestaShop generate new .htaccess rules unset($shell_res); } public function enable_cache($cachetype = 'CacheMemcache') { if ($this->ps_ver == '1.7') { $this->update_settings('ps_caching_system', $cachetype); $this->update_settings('ps_cache_enable', 'true', false); } else { $this->update_settings('_PS_CACHING_SYSTEM_', $cachetype); $this->update_settings('_PS_CACHE_ENABLED_', '1', false); } } public function update_settings($name, $value, $backup = true) { if ($this->ps_ver == '1.7') { $found_name = false; $output = "<?php\nreturn array(\n\t'parameters' =>\n\tarray (\n"; if ($value == 'NULL') { if (in_array($name, ['mailer_password', 'mailer_user', 'mailer_host', 'mailer_transport'])) { $value = null; } else { $value = false; } } $settings = file_get_contents("{$this->path}/app/config/parameters.php"); $reg_ex = $this->get_config_regex(); preg_match_all($reg_ex[0], $settings, $matches1, PREG_SET_ORDER, 0); preg_match_all($reg_ex[1], $settings, $matches2, PREG_SET_ORDER, 0); foreach ($matches1 as $match) { if ($match[1] == $name) { $found_name = true; $output .= "\t\t'" . $name . "' => '" . $value . "',\n"; } else { $output .= "\t\t'" . $match[1] . "' => '" . $match[2] . "',\n"; } } foreach ($matches2 as $match) { // This regex are items that do not have their values quoted if (in_array($name, ['mailer_password', 'mailer_user', 'mailer_host', 'mailer_transport'])) { // Some items are stored as NULL or false and we want to preserve this $tmp_output = "\t\t'" . $name . "' => NULL,\n"; } else { $tmp_output = "\t\t'" . $name . "' => false,\n"; } if ($match[1] == $name && $value != 'NULL') { $found_name = true; // We have a match for this name and we have a new value if ($value == 'true') { // If we're getting 'true' as a passed value, it should be written out as a bool $tmp_output .= "\t\t'" . $match[1] . "' => true,\n"; } else { $tmp_output .= "\t\t'" . $match[1] . "' => '" . $value . "',\n"; } } $output .= $tmp_output; } if (!$found_name) { // Add new name / value pair $output .= "\t\t'" . $name . "' => '" . $value . "',\n"; } $output .= "\t),\n);"; if ($backup) { copy("{$this->path}/app/config/parameters.php", "{$this->path}/app/config/parameters.bak.php"); } if (!file_put_contents("{$this->path}/app/config/parameters.php", $output)) { $this->error("{$this->path}/app/config/parameters.php is not writable by the web server.", true); } } else { $prev_settings = file_get_contents("{$this->path}/config/settings.inc.php"); $new_settings = preg_replace("/define\(['\"]{$name}['\"][^;]+;/Ui", "define('{$name}', '{$value}');", $prev_settings); if ($new_settings === $prev_settings && preg_match("/define\('{$name}'[^;]+;/Ui", $new_settings) === 0) { $new_settings = <<<CODE {$new_settings} define('{$name}', '{$value}'); CODE; } if (!($new_settings === $prev_settings)) { if ($backup) { copy("{$this->path}/config/settings.inc.php", "{$this->path}/config/settings.inc.bak.php"); } if ($fp = fopen("{$this->path}/config/settings.inc.php", 'w')) { fwrite($fp, $new_settings); fclose($fp); } else { $this->error("{$this->path}/config/settings.inc.php is not writable by the web server.", true); } } } } public function enable_memcached() {//PrestaShop $this->set_instance(); $this->memcached_socket = $this->instance->socket; $this->check_app_path(); //edit the settings file if (!is_bool($this->version) && version_compare($this->version, '1.6.1') >= 0) { $this->memcached_socket = $this->instance->socket_path; $memcached_lib = 'CacheMemcached'; $this->enable_cache($memcached_lib); $servers_table = $this->get_table('memcached_servers'); if ($servers_table == '') { $this->error('The memcached database table could not be found'); } //select from database to check for collision $this->db_connection->query("delete from {$servers_table};");//clear the servers table $stmt = $this->db_connection->prepare("INSERT INTO {$servers_table} SET ip=?,port=0,weight=1;"); //insert new Memcached server if not already set $stmt->bind_param('s', $this->memcached_socket); $stmt->execute(); $stmt->store_result(); if ($stmt->affected_rows == 0 || $stmt->error != '') { $this->error('The database could not be updated'); } $stmt->free_result(); $stmt->close(); //clear the smarty cache if (is_dir("{$this->path}/cache/smarty/compile")) { $this->su_exec("rm -rf {$this->path}/cache/smarty/compile/*"); } if (is_dir("{$this->path}/cache/smarty/cache")) { $this->su_exec("rm -rf {$this->path}/cache/smarty/cache/*"); } $this->app->swiftcache->memcached->enabled = true; } else { $this->error('We do not currently support Memcached on this version of PrestaShop'); $this->app->swiftcache->memcached->enabled = false; } } public function disable_memcached() { $this->check_app_path(); $this->enable_cache('CacheFs'); $this->app->swiftcache->memcached->enabled = false; } private function get_config_regex() { $re1 = '/\'([^\']*)\' => \'([^\']*?)\',/'; // Pick out key/value with quotes around value //$re2 = '/\'([^\']*)\' => ([^\']*?),/'; // Pick out key/value without quotes around value (bools, ints, etc) $re2 = '/\'([^\']*)\' => ([^\']*?),/'; return [$re1, $re2]; } public function get_turbocache_defaults() { //'PrestaShop': ['admin', 'cart', 'order', 'authentication', 'account', 'address', 'friend', 'login', 'logout', 'cuenta', 'autenticacion'], $reject_urls = [ 'admin', '404', 'address', 'authentication', 'best-sales', 'cart', 'contact', 'discount', 'guest-tracking', 'history', 'identity', 'order', 'password', 'products-comparison', 'search', 'account', 'friend', 'login', 'logout' ]; $meta_lang = $this->get_table('meta_lang'); $meta = $this->get_table('meta'); $stmt = $this->pdo->prepare("select distinct url_rewrite from $meta join $meta_lang on $meta.id_meta=$meta_lang.id_meta where url_rewrite != '' and page in ('404','address','addresses','authentication','best-sales','cart','contact','discount','guest-tracking','history','identity','my-account','order','order-confirmation','order-follow','order-opc','order-slip','password','products-comparison','search');"); $stmt->execute(); if ($res = $stmt->fetchAll()) { foreach ($res as $i => $row) { array_push($reject_urls, $row[0]); } } $reject_urls = array_unique($reject_urls); return [ 'reject_urls' => array_merge([], $reject_urls), 'reject_cookies' => ['logged', 'cart'], 'time' => '15 Minutes', 'ttl' => 900, 'enabled' => true ]; } } Save