Files
2025-06-24 14:14:35 +02:00

796 lines
36 KiB
PHP

<?php
/**
* Page Cache Ultimate, Page Cache standard and Speed pack are powered by Jpresta (jpresta . com)
*
* @author Jpresta
* @copyright Jpresta
* @license See the license of this module in file LICENSE.txt, thank you.
*/
if (!defined('_PS_VERSION_')) {exit;}
include_once(dirname(__FILE__) . '/../../pagecache.php');
class pagecacheCacheWarmerModuleFrontController extends ModuleFrontController
{
const SEPARATOR = "\t";
const CONTROLLER_INDEX = 1;
const CONTROLLER_PRODUCT = 2;
const CONTROLLER_CATEGORY = 3;
const CONTROLLER_CMS = 4;
const CONTROLLER_CMS_CATEGORY = 5;
const CONTROLLER_SUPPLIER = 6;
const CONTROLLER_MANUFACTURER = 7;
const CONTROLLER_CONTACT = 8;
const CONTROLLER_SITEMAP = 9;
const CONTROLLER_NEW_PRODUCTS = 10;
const CONTROLLER_PRICE_DROPS = 11;
const CONTROLLER_BEST_SALES = 12;
private $start_time;
private $url_count = 0;
public function __construct()
{
parent::__construct();
$this->start_time = microtime(true);
}
public function init()
{
try {
// Disable redirect from autolanguagecurrency module
$this->context->cookie->autolocation = 1;
parent::init();
}
catch (Throwable $e) {
header('HTTP/1.0 500 ' . $e->getMessage());
JprestaUtils::addLog('An error occured when the cache-warmer tried to get the list of URLs (init): '. $e->getMessage() . ". ". JprestaUtils::jTraceEx($e), 2);
die("\n** error **\n" . JprestaUtils::jTraceEx($e));
}
}
public function initContent()
{
try {
parent::initContent();
if (Module::isEnabled("pagecache")) {
$token = Tools::getValue('token', '');
$goodToken = JprestaUtils::getSecurityToken();
if (!$goodToken || strcmp($goodToken, $token) === 0) {
if (!Configuration::get('pagecache_debug')) {
// Make sure that the column used_by_cw has been created, the upgrade script was not executed
// on multiple customers but I don't know why
if (!JprestaUtils::dbColumnExists(_DB_PREFIX_ . PageCacheDAO::TABLE_CONTEXTS, 'used_by_cw')) {
JprestaUtils::dbExecuteSQL('ALTER TABLE `' . _DB_PREFIX_ . PageCacheDAO::TABLE_CONTEXTS . '` ADD `used_by_cw` TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER v_js');
}
self::checkSecurityParameters();
$action = Tools::getValue('action');
if ($action === 'GetShopInfos') {
self::processGetShopInfos(Tools::getValue('shopId'));
}
elseif ($action === 'GetReportStats') {
$start = new DateTime('@' . (double)Tools::getValue('start'));
$end = new DateTime('@' . (double)Tools::getValue('end'));
self::processGetReportStats(Tools::getValue('shopId'), $start, $end);
}
}
else {
header("HTTP/1.0 503 Module is in test mode");
die('Module is in test mode');
}
} else {
header("HTTP/1.0 403 Bad token");
die('Bad token ' . $token);
}
} else {
// Cannot be called when module is disabled but...
header("HTTP/1.0 503 Module not enabled");
die('Module not enabled');
}
}
catch (Throwable $e) {
header('HTTP/1.0 500 ' . $e->getMessage());
JprestaUtils::addLog('An error occured when the cache-warmer tried to get the list of URLs (initContent): '. $e->getMessage() . ". ". JprestaUtils::jTraceEx($e), 2);
die("\n** error **\n" . JprestaUtils::jTraceEx($e));
}
header("HTTP/1.0 404 Not found");
die('Not found');
}
private static function processGetReportStats($shopId, $start, $end)
{
$shopArray = Shop::getShop((int)$shopId);
if (!$shopArray) {
header("HTTP/1.0 404 Shop not found");
die('Shop not found #' . $shopId);
}
try {
// Set the context shop for external modules to generate links for this shop
Shop::setContext(/*Shop::CONTEXT_SHOP*/ 1, $shopId);
ob_end_clean();
header('Content-Type: application/json');
$infos = [
'hit_missed' => PageCacheDAO::getPerformances($shopId),
'ttfb_all' => self::getTTFBDatas($shopId, $start, $end),
'ttfb_home' => self::getTTFBDatas($shopId, $start, $end, 'index'),
'ttfb_products' => self::getTTFBDatas($shopId, $start, $end, 'product'),
'ttfb_categories' => self::getTTFBDatas($shopId, $start, $end, 'category')
];
die(json_encode($infos));
}
catch (Throwable $e) {
header('HTTP/1.0 500 ' . $e->getMessage());
JprestaUtils::addLog('An error occured when the cache-warmer tried to get statistics: '. $e->getMessage() . ". ". JprestaUtils::jTraceEx($e), 2);
die("\n** error **\n" . JprestaUtils::jTraceEx($e));
}
}
private function getTTFBDatas($shopId, $start, $end, $controller = null)
{
$id_controller = PageCache::getManagedControllerId($controller);
$whereClause = 'WHERE id_shop=' . (int) $shopId;
if ($id_controller) {
$whereClause .= ' AND id_controller=' . (int) $id_controller;
}
$whereClause .= ' AND date_add >= FROM_UNIXTIME(' . $start->format('U') . ') AND date_add <= FROM_UNIXTIME(' . $end->format('U') . ')';
$query = 'SELECT UNIX_TIMESTAMP(day_add) AS day,
ROUND(AVG(ttfb_ms_hit_server)) AS ttfb_ms_hit_server,
ROUND(AVG(ttfb_ms_hit_static)) AS ttfb_ms_hit_static,
ROUND(AVG(ttfb_ms_hit_browser)) AS ttfb_ms_hit_browser,
ROUND(AVG(ttfb_ms_hit_bfcache)) AS ttfb_ms_hit_bfcache,
ROUND(AVG(ttfb_ms_missed)) AS ttfb_ms_missed
FROM `' . _DB_PREFIX_ . PageCacheDAO::TABLE_PERFS . '` '.$whereClause.' GROUP BY day_add ORDER BY day_add ASC;';
$rows = JprestaUtils::dbSelectRows($query);
$missed = $server = $static = $browser = $bf = [];
foreach ($rows as $row) {
$missed[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_missed']];
$server[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_server']];
$static[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_static']];
$browser[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_browser']];
$bf[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_bfcache']];
}
$datas = [
[
'values' => $missed,
'key' => 'none',
],
[
'values' => $server,
'key' => 'server',
],
[
'values' => $static,
'key' => 'static',
],
[
'values' => $browser,
'key' => 'browser',
],
[
'values' => $bf,
'key' => 'bf',
],
];
$query = 'SELECT date_format(MIN(day_add), \'%Y-%m-%d\') AS start_date,
SUM(1) AS total_count
FROM `' . _DB_PREFIX_ . PageCacheDAO::TABLE_PERFS . '` '.$whereClause;
$rows = JprestaUtils::dbSelectRows($query);
$start_date = 0;
$total_count = 0;
if (count($rows) > 0) {
$start_date = $rows[0]['start_date'];
$total_count = (int)$rows[0]['total_count'];
}
return ['datas' => $datas, 'start_date' => $start_date, 'total_count' => $total_count];
}
private function processGetShopInfos($shopId)
{
$shopArray = Shop::getShop((int)$shopId);
if (!$shopArray) {
header("HTTP/1.0 404 Shop not found");
die('Shop not found #' . $shopId);
}
try {
// Set the context shop for external modules to generate links for this shop
Shop::setContext(/*Shop::CONTEXT_SHOP*/ 1, $shopId);
$shop = new Shop($shopId);
$settings = JprestaCacheWarmerSettings::get($shopId);
ob_end_clean();
header('Content-Type: text/plain');
echo $this->module->version . self::SEPARATOR;
echo _PS_VERSION_ . self::SEPARATOR;
echo $shop->getBaseURL(true) . self::SEPARATOR;
echo $settings->getPagesCount() . self::SEPARATOR;
echo $settings->getContextCount();
echo "\n";
if (!$this->getShopUrls($settings)) {
echo "...\n";
}
else {
// This will inform the cache-warmer that there is no more data to wait.
echo ".\n";
}
}
catch (Throwable $e) {
header('HTTP/1.0 500 ' . $e->getMessage());
JprestaUtils::addLog('An error occured when the cache-warmer tried to get the list of URLs: '. $e->getMessage() . ". ". JprestaUtils::jTraceEx($e), 2);
die("\n** error **\n" . JprestaUtils::jTraceEx($e));
}
die();
}
/**
* @return boolean true if max execution time has been reached
*/
private function isMaxExecutionTime() {
static $max_in_seconds = null;
if ($max_in_seconds === null) {
$userDefinedMax = (int) Configuration::get('pagecache_max_exec_time');
$serverDefinedMax = (int) Tools::getValue('timeout_s', 300);
$max_in_seconds = 0.8 * min(8*60, max(1, min($userDefinedMax, $serverDefinedMax)));
}
$spent = microtime(true) - $this->start_time;
return $spent >= $max_in_seconds;
}
private function isMaxUrlCount() {
static $max_url_count = null;
if ($max_url_count === null) {
$max_url_count = (int) Tools::getValue('max', 100000);
}
return $this->url_count >= $max_url_count;
}
private static function displaySuppliers() {
return Configuration::get('PS_DISPLAY_SUPPLIERS');
}
private static function displayManufacturers() {
if (version_compare(_PS_VERSION_, '1.7', '>=')) {
return Configuration::get('PS_DISPLAY_MANUFACTURERS');
}
return true;
}
private static function displayBestSales() {
return Configuration::get('PS_DISPLAY_BEST_SELLERS');
}
/**
* @param $settings JprestaCacheWarmerSettings
* @return boolean true if all URLs have been returned, false if the script was too long and all URLs have not been returned
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
private function getShopUrls($settings)
{
$link = new Link();
$shop = new Shop($settings->id_shop);
foreach ($settings->getContextsToWarmup() as $context) {
$customerArray = Customer::getCustomersByEmail($context['group']);
if ($customerArray && count($customerArray) === 1) {
if (JprestaCustomer::isVisitor($customerArray[0]['id_customer'])) {
// The Visitor group must not be specified
$context['group'] = null;
}
}
//
// GENERIC PAGES
//
if (Configuration::get('pagecache_index') && array_key_exists('index', $settings->controllers) && $settings->controllers['index']['checked']) {
$this->addPage($settings, $link, 'index', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
if (Configuration::get('pagecache_newproducts') && array_key_exists('newproducts', $settings->controllers) && $settings->controllers['newproducts']['checked']) {
$this->addPage($settings, $link, 'new-products', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
if (Configuration::get('pagecache_pricesdrop') && array_key_exists('pricesdrop', $settings->controllers) && $settings->controllers['pricesdrop']['checked']) {
$this->addPage($settings, $link, 'prices-drop', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
if (Configuration::get('pagecache_contact') && array_key_exists('contact', $settings->controllers) && $settings->controllers['contact']['checked']) {
$this->addPage($settings, $link, 'contact', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
if (Configuration::get('pagecache_sitemap') && array_key_exists('sitemap', $settings->controllers) && $settings->controllers['sitemap']['checked']) {
$this->addPage($settings, $link, 'sitemap', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
if (self::displayBestSales() && (int)Configuration::get('pagecache_bestsales') && array_key_exists('bestsales', $settings->controllers) && $settings->controllers['bestsales']['checked']) {
$this->addPage($settings, $link, 'best-sales', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
//
// MANUFACTURERS
//
if (self::displayManufacturers() && Configuration::get('pagecache_manufacturer') && array_key_exists('manufacturer', $settings->controllers) && $settings->controllers['manufacturer']['checked']) {
// List of manufacturers
$this->addPage($settings, $link, 'manufacturer', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
// Each manufacturers
$sql = 'SELECT c.id_manufacturer
FROM `' . _DB_PREFIX_ . 'manufacturer` c' . $shop->addSqlAssociation('manufacturer', 'c') . '
WHERE c.`active` = 1';
$id_manufacturer_rows = DB::getInstance()->executeS($sql);
foreach ($id_manufacturer_rows as $id_manufacturer_row) {
$this->addManufacturer($settings, $link, $id_manufacturer_row['id_manufacturer'], $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
//
// SUPPLIERS
//
if (self::displaySuppliers() && Configuration::get('pagecache_supplier') && array_key_exists('supplier', $settings->controllers) && $settings->controllers['supplier']['checked']) {
// List of suppliers
$this->addPage($settings, $link, 'supplier', $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
// Each suppliers
$sql = 'SELECT c.id_supplier
FROM `' . _DB_PREFIX_ . 'supplier` c' . $shop->addSqlAssociation('supplier', 'c') . '
WHERE c.`active` = 1';
$id_supplier_rows = DB::getInstance()->executeS($sql);
foreach ($id_supplier_rows as $id_supplier_row) {
$this->addSupplier($settings, $link, $id_supplier_row['id_supplier'], $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
//
// PRODUCTS
//
if (Configuration::get('pagecache_product') && array_key_exists('product', $settings->controllers) && $settings->controllers['product']['checked']) {
$sql = 'SELECT p.id_product FROM `' . _DB_PREFIX_ . 'product` p' . $shop->addSqlAssociation('product', 'p');
$whereClauses = [];
$whereClauses[] = 'product_shop.`active` = 1';
if (Module::isEnabled('ndk_advanced_custom_fields')) {
$whereClauses[] = 'p.reference NOT LIKE \'custom-%\'';
$whereClauses[] = 'p.supplier_reference NOT LIKE \'custom-%\'';
}
$sql .= ' WHERE ' . implode(' AND ', $whereClauses);
$id_product_rows = DB::getInstance()->executeS($sql);
foreach ($id_product_rows as $id_product_row) {
if (!Configuration::get('pagecache_cache_customizable')) {
// Check that product is not customizable
$customizationFieldCount = (int)JprestaUtils::dbGetValue('SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'customization_field` WHERE `id_product` = ' . (int)$id_product_row['id_product']);
if ($customizationFieldCount) {
// Skip this product
continue;
}
}
if (!$this->addProduct($settings, $link, $shop, $id_product_row['id_product'], $context)) {
return false;
}
}
}
//
// CATEGORIES
//
if (Configuration::get('pagecache_category') && array_key_exists('category', $settings->controllers) && $settings->controllers['category']['checked']) {
$sql = 'SELECT c.id_category
FROM `' . _DB_PREFIX_ . 'category` c' . $shop->addSqlAssociation('category', 'c') . '
WHERE c.`active` = 1 AND c.is_root_category = 0 AND c.id_parent > 0';
$id_category_rows = DB::getInstance()->executeS($sql);
foreach ($id_category_rows as $id_category_row) {
$this->addCategory($settings, $link, $id_category_row['id_category'], $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
//
// CMS
//
if (Configuration::get('pagecache_cms') && array_key_exists('cms', $settings->controllers) && $settings->controllers['cms']['checked']) {
$sql = 'SELECT c.id_cms
FROM `' . _DB_PREFIX_ . 'cms` c' . $shop->addSqlAssociation('cms', 'c') . '
WHERE c.`active` = 1';
$id_cms_rows = DB::getInstance()->executeS($sql);
foreach ($id_cms_rows as $id_cms_row) {
$this->addCMS($settings, $link, $id_cms_row['id_cms'], $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
//
// CMS CATEGORIES
//
$sql = 'SELECT c.id_cms_category
FROM `' . _DB_PREFIX_ . 'cms_category` c' . $shop->addSqlAssociation('cms_category', 'c') . '
WHERE c.`active` = 1';
$id_cms_category_rows = DB::getInstance()->executeS($sql);
foreach ($id_cms_category_rows as $id_cms_category_row) {
$this->addCMSCategory($settings, $link, $id_cms_category_row['id_cms_category'], $context);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
//
// Pages generated by other modules
//
$id_lang = (int) Language::getIdByIso($context['language']);
foreach ($settings->controllers as $controllerName => $controllerSettings) {
if ($controllerSettings['checked']
&& JprestaUtilsModule::isModuleController($controllerName)
&& JprestaUtilsModule::canBeWarmed($controllerName)
) {
$timeout_minutes = (int)Configuration::get('pagecache_'.str_replace('-', '', $controllerName).'_timeout');
$urls = JprestaUtilsModule::getAllURLs($controllerName, $id_lang);
foreach ($urls as $url) {
$this->addURL($settings, $url, 0, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
}
}
return true;
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $controller string
* @param $context
*/
private function addPage($settings, $link, $controller, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_'.str_replace('-', '', $controller).'_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getPageLink($controller, null, $id_lang, null, false, $settings->id_shop);
switch ($controller) {
case 'index':
$id_controller = self::CONTROLLER_INDEX;
break;
case 'new-products':
$id_controller = self::CONTROLLER_NEW_PRODUCTS;
break;
case 'prices-drop':
$id_controller = self::CONTROLLER_PRICE_DROPS;
break;
case 'contact':
$id_controller = self::CONTROLLER_CONTACT;
break;
case 'sitemap':
$id_controller = self::CONTROLLER_SITEMAP;
break;
case 'best-sales':
$id_controller = self::CONTROLLER_BEST_SALES;
break;
default:
$id_controller = 0;
}
$this->addURL($settings, $url, $id_controller, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $id
*/
private function addManufacturer($settings, $link, $id, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_manufacturer_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getManufacturerLink((int) $id, null, $id_lang, $settings->id_shop);
$this->addURL($settings, $url, self::CONTROLLER_MANUFACTURER, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $id
*/
private function addSupplier($settings, $link, $id, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_supplier_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getSupplierLink((int) $id, null, $id_lang, $settings->id_shop);
$this->addURL($settings, $url, self::CONTROLLER_SUPPLIER, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $id
*/
private function addCMS($settings, $link, $id, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_cms_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getCMSLink((int) $id, null, null, $id_lang, $settings->id_shop);
$this->addURL($settings, $url, self::CONTROLLER_CMS, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $id
*/
private function addCMSCategory($settings, $link, $id, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_cms_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getCMSCategoryLink((int) $id, null, $id_lang, $settings->id_shop);
$this->addURL($settings, $url, self::CONTROLLER_CMS_CATEGORY, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $id
*/
private function addCategory($settings, $link, $id, $context) {
$timeout_minutes = (int)Configuration::get('pagecache_category_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
$url = $link->getCategoryLink((int) $id, null, $id_lang, null, $settings->id_shop);
$this->addURL($settings, $url, self::CONTROLLER_CATEGORY, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param $link LinkCore
* @param $shop ShopCore
* @param $id_product integer
* @throws PrestaShopException
*/
private function addProduct($settings, $link, $shop, $id_product, $context) {
if ($settings->filter_products_cats_ids) {
$sqlFilterCats = 'SELECT id_category
FROM `' . _DB_PREFIX_ . 'product` p
' . Shop::addSqlAssociation('product', 'p') . '
LEFT JOIN `' . _DB_PREFIX_ . 'category_product` cp ON p.`id_product` = cp.`id_product`
WHERE p.id_product='.(int)$id_product.'
AND cp.`id_category` IN ('.$settings->filter_products_cats_ids.')
AND product_shop.`visibility` IN ("both", "catalog")
AND product_shop.`active` = 1
LIMIT 1;';
if (!JprestaUtils::dbGetValue($sqlFilterCats)) {
return true;
}
}
// Sometimes product combinaisons have the same URL so we need to check it to avoid warming the same URL multiple times
// I don't do it at the global level to avoid consumming to much memory
$urls = [];
$timeout_minutes = (int)Configuration::get('pagecache_product_timeout');
$id_lang = (int) Language::getIdByIso($context['language']);
// START Bottle neck : it's fast but would be good to make it even faster because it is executed a lot of time
// Gettting the product object here will reduce SQL query count
$product = new Product((int) $id_product, false, $id_lang, $settings->id_shop);
// Simple product (even products with combinations have a simple URL)
$url = $link->getProductLink($product, null, null, null, $id_lang, $settings->id_shop);
$urls[$url] = true;
$this->addURL($settings, $url, self::CONTROLLER_PRODUCT, $timeout_minutes, $id_lang, $context['currency'], $context['device'], $context['country'], $context['group'], isset($context['specifics']) ? $context['specifics'] : null);
// END bottle neck
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
$dispatcher = Dispatcher::getInstance();
if ($dispatcher->hasKeyword('product_rule', $id_lang, 'id_product_attribute')) {
// Check if it is a product with combinations
$sql = 'SELECT pa.id_product_attribute
FROM `' . _DB_PREFIX_ . 'product_attribute` pa' . $shop->addSqlAssociation('product_attribute', 'pa') . '
WHERE pa.id_product = ' . (int) $id_product;
$ipa_rows = DB::getInstance()->executeS($sql);
if ($ipa_rows && count($ipa_rows) > 0) {
// Product with combinations
foreach ($ipa_rows as $ipa_row) {
// Add URL for all combinations
$url = $link->getProductLink($product, null, null, null, $id_lang, $settings->id_shop,
$ipa_row['id_product_attribute']);
$url_no_anchor = strtok($url, "#");
if (!array_key_exists($url_no_anchor, $urls)) {
$urls[$url_no_anchor] = true;
$this->addURL($settings, $url_no_anchor, self::CONTROLLER_PRODUCT, $timeout_minutes, $id_lang,
$context['currency'], $context['device'], $context['country'], $context['group'],
isset($context['specifics']) ? $context['specifics'] : null);
}
if ($this->isMaxExecutionTime() || $this->isMaxUrlCount()) {
return false;
}
}
}
}
return true;
}
/**
* @param $settings JprestaCacheWarmerSettings
* @param string $url string
* @param integer $id_controller One of self::CONTROLLER_*
* @param integer $timeout_minutes Configured timeout
* @param string $iso_currency A valid currency ISO value or null
* @param string $device 'desktop' or 'mobile'
* @param string $iso_country A valid country ISO value or null
* @param string $group Email of the group or null
* @param integer $id_specifics
*/
private function addURL($settings, $url, $id_controller, $timeout_minutes, $id_lang, $iso_currency, $device, $iso_country, $group, $id_specifics) {
static $baseUrl = null;
static $baseUrlFromRoot = null;
if ($baseUrl === null) {
$shop = new Shop($settings->id_shop);
$baseUrl = $shop->getBaseURL(true);
$baseUrlFromRoot = $shop->getBaseURL(true, false);
}
if (PageCache::isExcludedByRegex($url)) {
// This URL will not be cached
return;
}
static $lgseoredirect = null;
if ($lgseoredirect === null) {
$lgseoredirect = Module::isEnabled('lgseoredirect') && JprestaUtils::dbTableExists(_DB_PREFIX_ . 'lgseoredirect');
if ($lgseoredirect && !JprestaUtils::dbIndexExists(_DB_PREFIX_ . 'lgseoredirect', ['url_old', 'id_shop'])) {
JprestaUtils::dbExecuteSQL('ALTER TABLE `'._DB_PREFIX_.'lgseoredirect` ADD INDEX `url_old_id_shop` (`url_old`(250), `id_shop`);');
}
}
if ($lgseoredirect) {
if (self::isRedirectedByLGSeoRedirect('/' . self::reduceUrl($baseUrl, $url), $settings->id_shop)) {
return;
}
}
static $arseopro = null;
if ($arseopro === null) {
$arseopro = Module::isEnabled('arseopro') && JprestaUtils::dbTableExists(_DB_PREFIX_ . 'arseopro_redirect');
}
if ($arseopro) {
if (self::isRedirectedByArSeoPro(self::reduceUrl($baseUrlFromRoot, $url), $settings->id_shop)) {
return;
}
}
static $ids_currency = array();
if ($iso_currency && !array_key_exists($iso_currency, $ids_currency)) {
$ids_currency[$iso_currency] = Currency::getIdByIsoCode($iso_currency);
}
$id_currency = $iso_currency ? $ids_currency[$iso_currency] : null;
$id_device = PageCache::DEVICE_COMPUTER;
if ($device && $device === 'mobile') {
$id_device = PageCache::DEVICE_MOBILE;
}
static $ids_country = array();
if ($iso_country && !array_key_exists($iso_country, $ids_country)) {
if ($settings->isCountryOthers($iso_country)) {
$ids_country[$iso_country] = null;
}
else {
$ids_country[$iso_country] = Country::getByIso($iso_country);
}
}
$id_country = $iso_country ? $ids_country[$iso_country] : null;
static $ids_fake_customer = array();
if ($group && !array_key_exists($group, $ids_fake_customer)) {
$customerArray = Customer::getCustomersByEmail($group);
if ($customerArray && count($customerArray) === 1) {
$ids_fake_customer[$group] = $customerArray[0]['id_customer'];
}
else {
$ids_fake_customer[$group] = null;
}
}
$id_fake_customer = $group ? $ids_fake_customer[$group] : null;
$id_context = PageCacheDAO::getContextIdByInfos($settings->id_shop, $id_lang, $id_currency, $id_device, $id_country, $id_fake_customer, null, $id_specifics);
$stats = PageCacheDAO::getStatsByURLAndContext($url, $id_context);
if (!$stats) {
$ttl = 0;
$priority = 1000;
}
else {
$timeout_minutes_to_use = $timeout_minutes;
if ($timeout_minutes < 0) {
// Timeout is defined to infinity
$timeout_minutes_to_use = PHP_INT_MAX;
}
$ttl = $stats['deleted'] ? 0 : max(0, $timeout_minutes_to_use - $stats['max_age_minutes']);
$priority = $stats['sum_hit'] + $stats['sum_missed'];
}
if ($ttl < (24 * 60)) {
echo self::reduceUrl($baseUrl, $url) . self::SEPARATOR;
echo $priority . self::SEPARATOR;
echo $device . self::SEPARATOR;
echo $iso_currency . self::SEPARATOR;
echo ($iso_country ? $iso_country : '') . self::SEPARATOR;
echo ($group ? $group : '') . self::SEPARATOR;
echo self::SEPARATOR; // tax manager
echo ($id_specifics ? $id_specifics : '') . self::SEPARATOR;
echo $id_controller;
echo "\n";
$this->url_count++;
}
}
private static function isRedirectedByLGSeoRedirect($url, $id_shop)
{
$sql = 'SELECT COUNT(*) FROM ' . _DB_PREFIX_ . 'lgseoredirect ' .
'WHERE (url_old="' . pSQL($url) . '" OR url_old LIKE "' . pSQL($url) . '#%") ' .
'AND id_shop = "' . (int)$id_shop . '"';
return JprestaUtils::dbGetValue($sql, false, false);
}
private static function isRedirectedByArSeoPro($url, $id_shop)
{
$sql = 'SELECT COUNT(*) FROM ' . _DB_PREFIX_ . 'arseopro_redirect ' .
'WHERE `from` = "' . pSQL($url) . '" ' .
'AND id_shop IN(0, ' . (int)$id_shop . ') ' .
'AND status = 1';
return JprestaUtils::dbGetValue($sql, false, false);
}
private static function checkSecurityParameters() {
if (Module::isEnabled('securitypro')) {
$whiteList = Configuration::get('PRO_FIREWALL_WHITELIST');
if (!$whiteList) {
Configuration::updateValue('PRO_FIREWALL_WHITELIST', '18.119.72.109,18.189.172.189');
}
else if (strpos($whiteList, '18.119.72.109,') === false) {
Configuration::updateValue('PRO_FIREWALL_WHITELIST', $whiteList . ',18.119.72.109,18.189.172.189');
}
}
}
private static function reduceUrl($baseUrl, $url) {
// Yes, some shops have tab in URLs... Of course it does not work but it exists
return str_replace([$baseUrl, '\t'], ['', '%09'], $url);
}
}