first commit

This commit is contained in:
2024-10-25 14:16:28 +02:00
commit 925276dbb2
33795 changed files with 4780077 additions and 0 deletions

View File

@@ -0,0 +1,651 @@
<?php
/**
* LiteSpeed Cache for Prestashop.
*
* NOTICE OF LICENSE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://opensource.org/licenses/GPL-3.0 .
*
* @author LiteSpeed Technologies
* @copyright Copyright (c) 2017-2018 LiteSpeed Technologies, Inc. (https://www.litespeedtech.com)
* @license https://opensource.org/licenses/GPL-3.0
*/
use LiteSpeedCacheConfig as Conf;
class AdminLiteSpeedCacheConfigController extends ModuleAdminController
{
private $config;
private $is_shop_level; // -1: not multishop, 0: multishop global, 1: multishop shop
private $labels;
private $current_values;
private $license_disabled;
// BITMASK for changed
const BMC_SHOP = 1; // change for shop
const BMC_ALL = 2; // change for all
const BMC_NONEED_PURGE = 4; // no need to purge, effective immediately
const BMC_MAY_PURGE = 8; // purge to be effective, but don't have to
const BMC_MUST_PURGE = 16;
const BMC_DONE_PURGE = 32; // already purged
const BMC_HTACCESS_UPDATE = 64;
private $original_values;
private $changed = 0;
public function __construct()
{
$this->bootstrap = true;
$this->display = 'view';
parent::__construct();
$this->config = Conf::getInstance();
if (!$this->module->active) {
Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome'));
}
$title = $this->l('LiteSpeed Cache Configuration');
$this->page_header_toolbar_title = $title;
$this->meta_title = $title;
//// -1: not multishop, 0: multishop global, 1: multishop shop or group
if (Shop::isFeatureActive()) {
$this->is_shop_level = (Shop::getContext() == Shop::CONTEXT_ALL) ? 0 : 1;
} else {
$this->is_shop_level = -1;
}
}
public function init()
{
parent::init();
if (!LiteSpeedCacheHelper::licenseEnabled()) {
$this->license_disabled = true;
$this->errors[] = $this->l('LiteSpeed Server with LSCache module is required.') . ' '
. $this->l('Please contact your sysadmin or your host to get a valid LiteSpeed license.');
}
$this->original_values = $this->config->getAllConfigValues();
$this->current_values = $this->original_values;
$this->labels = array(
Conf::CFG_ENABLED => $this->l('Enable LiteSpeed Cache'),
Conf::CFG_PUBLIC_TTL => $this->l('Default Public Cache TTL'),
Conf::CFG_PRIVATE_TTL => $this->l('Default Private Cache TTL'),
Conf::CFG_HOME_TTL => $this->l('Home Page TTL'),
Conf::CFG_404_TTL => $this->l('404 Pages TTL'),
Conf::CFG_DIFFMOBILE => $this->l('Separate Mobile View'),
Conf::CFG_DIFFCUSTGRP => $this->l('Separate Cache Copy per Customer Group'),
Conf::CFG_FLUSH_PRODCAT => $this->l('Flush Product and Categories When Order Placed'),
Conf::CFG_GUESTMODE => $this->l('Enable Guest Mode'),
Conf::CFG_NOCACHE_VAR => $this->l('Do-Not-Cache GET Parameters'),
Conf::CFG_NOCACHE_URL => $this->l('URL Blacklist'),
Conf::CFG_ALLOW_IPS => $this->l('Enable Cache Only for Listed IPs'),
Conf::CFG_DEBUG => $this->l('Enable Debug Log'),
Conf::CFG_DEBUG_IPS => $this->l('Log Only for Listed IPs'),
Conf::CFG_DEBUG_LEVEL => $this->l('Debug Level'),
);
}
public function initPageHeaderToolbar()
{
$this->page_header_toolbar_btn['purge_shops'] = array(
'href' => self::$currentIndex . '&purge_shops&token=' . $this->token,
'desc' => $this->l('Flush All PrestaShop Pages'),
'icon' => 'process-icon-delete',
);
parent::initPageHeaderToolbar();
}
public function postProcess()
{
if (Tools::isSubmit('submitConfig')) {
$this->processConfigSave();
} elseif (Tools::isSubmit('purge_shops')) {
if ($this->license_disabled) {
$this->warnings[] = $this->l('No action taken. No LiteSpeed Server with LSCache available.');
} else {
$this->processPurgeShops();
}
}
return parent::postProcess();
}
private function processConfigSave()
{
$inputs = array(
Conf::CFG_PUBLIC_TTL,
Conf::CFG_PRIVATE_TTL,
Conf::CFG_HOME_TTL,
Conf::CFG_404_TTL,
Conf::CFG_DIFFCUSTGRP,
);
if ($this->is_shop_level != 1) {
$all = array(
Conf::CFG_ENABLED,
Conf::CFG_DIFFMOBILE,
Conf::CFG_GUESTMODE,
Conf::CFG_NOCACHE_VAR,
Conf::CFG_NOCACHE_URL,
Conf::CFG_FLUSH_PRODCAT,
Conf::CFG_DEBUG,
Conf::CFG_DEBUG_LEVEL,
Conf::CFG_ALLOW_IPS,
Conf::CFG_DEBUG_IPS,
);
$inputs = array_merge($inputs, $all);
}
foreach ($inputs as $field) {
$this->validateInput($field);
}
if (count($this->errors)) {
return;
}
if ($this->changed == 0) {
$this->confirmations[] = $this->l('No changes detected. Nothing to save.');
return;
}
$guest = ($this->current_values[Conf::CFG_GUESTMODE] == 1);
$mobile = $this->current_values[Conf::CFG_DIFFMOBILE];
if ($guest && ($this->original_values[Conf::CFG_DIFFMOBILE] != $mobile)) {
$this->changed |= self::BMC_HTACCESS_UPDATE;
}
if ($this->changed & self::BMC_SHOP) {
$this->config->updateConfiguration(Conf::ENTRY_SHOP, $this->current_values);
}
if ($this->changed & self::BMC_ALL) {
$this->config->updateConfiguration(Conf::ENTRY_ALL, $this->current_values);
}
$this->confirmations[] = $this->l('Settings updated successfully.');
//please manually fix .htaccess, may due to permission
if ($this->changed & self::BMC_DONE_PURGE) {
$this->processPurgeShops();
$this->confirmations[] = $this->l('Disabled LiteSpeed Cache.');
} elseif ($this->changed & self::BMC_MUST_PURGE) {
$this->confirmations[] = $this->l('You must flush all pages to make this change effective.');
} elseif ($this->changed & self::BMC_MAY_PURGE) {
$this->confirmations[] = $this->l('You may want to purge related contents to make this change effective.');
} elseif ($this->changed & self::BMC_NONEED_PURGE) {
$this->confirmations[] = $this->l('Changes will be effective immediately. No need to purge.');
}
if ($this->changed & self::BMC_HTACCESS_UPDATE) {
$res = LiteSpeedCacheHelper::htAccessUpdate($this->current_values[Conf::CFG_ENABLED], $guest, $mobile);
if ($res) {
$this->confirmations[] = $this->l('.htaccess file updated accordingly.');
} else {
$url = 'https://www.litespeedtech.com/support/wiki/doku.php/'
. 'litespeed_wiki:cache:lscps:installation#htaccess_update';
$this->warnings[] = $this->l('Failed to update .htaccess due to permission.') . ' ' . '<a href="' . $url
. '" target="_blank" rel="noopener noreferrer">' . $this->l('Please manually update.') . '</a>';
}
}
}
private function processPurgeShops()
{
$params = array('from' => 'AdminLiteSpeedCacheConfig', 'public' => '*');
Hook::exec('litespeedCachePurge', $params);
$this->confirmations[] = $this->l('Notified LiteSpeed Server to flush all pages of this PrestaShop.');
}
private function validateInput($name)
{
$postVal = Tools::getValue($name);
$origVal = $this->original_values[$name];
$invalid = $this->l('Invalid value') . ': ' . $this->labels[$name];
$s = ' - '; // spacer
$pattern = "/[\s,]+/";
// 1: no need to purge, 2: purge to be effective, but don't have to, 4: have to purge, 8: already purged
switch ($name) {
case Conf::CFG_ENABLED:
$postVal = (int) $postVal;
if ($postVal != $origVal) {
// if disable, purge all
$this->changed |= self::BMC_ALL | self::BMC_HTACCESS_UPDATE
| (($postVal == 0) ? self::BMC_DONE_PURGE : self::BMC_NONEED_PURGE);
}
break;
case Conf::CFG_PUBLIC_TTL:
if (!Validate::isUnsignedInt($postVal)) {
$this->errors[] = $invalid;
} else {
$postVal = (int) $postVal;
if ($postVal < 300) {
$this->errors[] = $invalid . $s . $this->l('Must be greater than 300 seconds');
} elseif ($postVal != $origVal) {
$this->changed |= self::BMC_SHOP;
$this->changed |= ($postVal < $origVal) ? self::BMC_MUST_PURGE : self::BMC_MAY_PURGE;
}
}
break;
case Conf::CFG_PRIVATE_TTL:
if (!Validate::isUnsignedInt($postVal)) {
$this->errors[] = $invalid;
} else {
$postVal = (int) $postVal;
if ($postVal < 180 || $postVal > 7200) {
$this->errors[] = $invalid . $s . $this->l('Must be within the 180 to 7200 range.');
} elseif ($postVal != $origVal) {
$this->changed |= self::BMC_SHOP | self::BMC_NONEED_PURGE;
}
}
break;
case Conf::CFG_HOME_TTL:
if (!Validate::isUnsignedInt($postVal)) {
$this->errors[] = $invalid;
} else {
$postVal = (int) $postVal;
if ($postVal < 60 && $postVal != 0) {
$this->errors[] = $invalid . $s .
$this->l('Must be greater than 60 seconds. Enter 0 to disable cache.');
} elseif ($postVal != $origVal) {
$this->changed |= self::BMC_SHOP;
$this->changed |= ($postVal < $origVal) ? self::BMC_MUST_PURGE : self::BMC_MAY_PURGE;
}
}
break;
case Conf::CFG_404_TTL:
if (!Validate::isUnsignedInt($postVal)) {
$this->errors[] = $invalid;
} else {
$postVal = (int) $postVal;
if ($postVal > 0 && $postVal < 300) {
$this->errors[] = $invalid . $s . $this->l('Must be greater than 300 seconds.');
} elseif ($postVal != $origVal) {
if ($postVal == 0) {
$this->changed |= self::BMC_SHOP | self::BMC_MUST_PURGE;
} else {
$this->changed |= self::BMC_SHOP;
$this->changed |= ($postVal < $origVal) ? self::BMC_MUST_PURGE : self::BMC_MAY_PURGE;
}
}
}
break;
case Conf::CFG_DIFFMOBILE:
$postVal = (int) $postVal;
if ($postVal != 0 && $postVal != 1 && $postVal != 2) {
// should not happen in drop down
$postVal = 0;
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_MUST_PURGE;
}
break;
case Conf::CFG_DIFFCUSTGRP:
$postVal = (int) $postVal;
if ($postVal != 0 && $postVal != 1 && $postVal != 2) {
// should not happen in drop down
$postVal = 0;
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_SHOP | self::BMC_MUST_PURGE;
}
break;
case Conf::CFG_FLUSH_PRODCAT:
$postVal = (int) $postVal;
if ($postVal < 0 || $postVal > 3) {
// should not happen in drop down
$postVal = 0;
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_NONEED_PURGE;
}
break;
case Conf::CFG_GUESTMODE:
$postVal = (int) $postVal;
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_NONEED_PURGE | self::BMC_HTACCESS_UPDATE;
}
break;
case Conf::CFG_NOCACHE_VAR:
$clean = array_unique(preg_split($pattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
$postVal = implode(', ', $clean);
if (!preg_match('/^[a-zA-Z1-9_\- ,]+$/', $postVal)) {
$this->errors[] = $invalid;
}
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_MUST_PURGE;
}
break;
case Conf::CFG_NOCACHE_URL:
$clean = array_unique(preg_split($pattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $url) {
if ($url{0} != '/') {
$this->errors[] = $invalid . $s . $this->l('Relative URL must start with "/".');
}
}
$postVal = implode("\n", $clean);
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_MUST_PURGE;
}
break;
case Conf::CFG_DEBUG:
$postVal = (int) $postVal;
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_NONEED_PURGE;
}
break;
case Conf::CFG_DEBUG_LEVEL:
if (!Validate::isUnsignedInt($postVal) || $postVal < 1 || $postVal > 10) {
$this->errors[] = $invalid . $s . $this->l('Valid range is 1 to 10.');
} else {
$postVal = (int) $postVal;
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_NONEED_PURGE;
}
}
break;
case Conf::CFG_ALLOW_IPS:
$clean = array_unique(preg_split($pattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $ip) {
if (!preg_match('/^[[:alnum:]._-]+$/', $ip)) {
$this->errors[] = $invalid;
}
}
$postVal = implode(', ', $clean);
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_MUST_PURGE;
}
break;
case Conf::CFG_DEBUG_IPS:
$clean = array_unique(preg_split($pattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $ip) {
if (!preg_match('/^[[:alnum:]._-]+$/', $ip)) {
$this->errors[] = $invalid;
}
}
$postVal = implode(', ', $clean);
}
if ($postVal != $origVal) {
$this->changed |= self::BMC_ALL | self::BMC_NONEED_PURGE;
}
break;
}
$this->current_values[$name] = $postVal;
}
public function renderView()
{
$disabled = ($this->is_shop_level == 1);
if ($disabled) {
$this->informations[] = $this->l('Some settings can only be set at the global level.');
}
$secs = $this->l('seconds');
$s = ' - '; // spacer
$fg = $this->newFieldForm($this->l('General'), 'cogs');
$fg['input'][] = $this->addInputSwitch(Conf::CFG_ENABLED, $this->labels[Conf::CFG_ENABLED], '', $disabled);
$fg['input'][] = $this->addInputText(
Conf::CFG_PUBLIC_TTL,
$this->labels[Conf::CFG_PUBLIC_TTL],
$this->l('Default timeout for publicly cached pages.') . ' ' . $this->l('Recommended value is 86400.'),
$secs
);
$fg['input'][] = $this->addInputText(
Conf::CFG_PRIVATE_TTL,
$this->labels[Conf::CFG_PRIVATE_TTL],
$this->l('Default timeout for private cache ESI blocks. Suggested value is 1800. Must be less than 7200.'),
$secs
);
$fg['input'][] = $this->addInputText(
Conf::CFG_HOME_TTL,
$this->labels[Conf::CFG_HOME_TTL],
$this->l('Default timeout for the home page.') . ' '
. $this->l('If you have random displayed items, you can have shorter TTL to make it refresh more often.'),
$secs
);
$fg['input'][] = $this->addInputText(
Conf::CFG_404_TTL,
$this->labels[Conf::CFG_404_TTL],
$this->l('Default timeout for all 404 (Not found) pages. 0 will disable caching for 404 pages.'),
$secs
);
$fg['input'][] = $this->addInputSwitch(
Conf::CFG_DIFFMOBILE,
$this->labels[Conf::CFG_DIFFMOBILE],
$this->l('Enable this if you have a separate mobile theme.'),
$disabled
);
$custgrpOptions = array(
array('id' => 0, 'name' => $this->l('No') . $s . $this->l('Everyone shares the same view')),
array('id' => 1, 'name' => $this->l('Yes') . $s . $this->l('Each group has its own view')),
array('id' => 2, 'name' => $this->l('Two views') . $s .
$this->l('One for all logged-in users and another for logged-out users'), ),
);
$fg['input'][] = $this->addInputSelect(
Conf::CFG_DIFFCUSTGRP,
$this->labels[Conf::CFG_DIFFCUSTGRP],
$custgrpOptions,
$this->l('Enable this option if there is different pricing based on customer groups.')
);
$flushprodOptions = array(
array('id' => 0, 'name' => $this->l('Flush product when quantity or stock status change, flush categories only when stock status changes')),
array('id' => 1, 'name' => $this->l('Flush product and categories only when stock status changes')),
array('id' => 2, 'name' => $this->l('Flush product when stock status changes, do not flush categories when stock status or quantity change')),
array('id' => 3, 'name' => $this->l('Always flush product and categories when quantity or stock status change')),
);
$fg['input'][] = $this->addInputSelect(
Conf::CFG_FLUSH_PRODCAT,
$this->labels[Conf::CFG_FLUSH_PRODCAT],
$flushprodOptions,
$this->l('Determines how changes in product quantity and stock status affect product pages and their associated category pages.'),
$disabled
);
$guestOptions = array(
array('id' => 0, 'name' => $this->l('No') . $s . $this->l('No default guest view')),
array('id' => 1, 'name' => $this->l('Yes') . $s . $this->l('Has default guest view')),
array('id' => 2, 'name' => $this->l('First Page Only') . $s .
$this->l('Only first page will show the default guest view'), ),
);
$fg['input'][] = $this->addInputSelect(
Conf::CFG_GUESTMODE,
$this->labels[Conf::CFG_GUESTMODE],
$guestOptions,
$this->l('This will speed up the first page view for new visitors by serving the default view.') . ' '
. $this->l('Robots will get an instant response without hitting the backend.') . ' '
. $this->l('If you have different views based on GeoIP,') . ' '
. $this->l('select "First Page Only" to make sure the second page will have the correct view.'),
$disabled
);
$formUser = $this->newFieldForm(
$this->l('User-Defined Cache Rules'),
'cogs',
$disabled ? $this->l('These settings can only be set at the global level.') :
$this->l('Only need to set it NOT-CACHEABLE if a page is being cached by default.')
);
$formUser['input'][] = $this->addInputTextArea(
Conf::CFG_NOCACHE_VAR,
$this->labels[Conf::CFG_NOCACHE_VAR],
$this->l('Comma-separated list of GET variables that prevents caching URLs within Cacheable Routes.'),
$disabled
);
$formUser['input'][] = $this->addInputTextArea(
Conf::CFG_NOCACHE_URL,
$this->labels[Conf::CFG_NOCACHE_URL],
$this->l('List of relative URLs contained in Cacheable Routes to be excluded from caching.') . ' '
. $this->l('They start with "/" and don\t include the domain name.') . ' '
. $this->l('Partial matches can be performed by adding an "*" to the end of a URL.') . ' '
. $this->l('Enter one relative URL per line.'),
$disabled
);
$formDev = $this->newFieldForm($this->l('Developer Testing'), 'stethoscope');
$formDev['input'][] = $this->addInputTextArea(
Conf::CFG_ALLOW_IPS,
$this->labels[Conf::CFG_ALLOW_IPS],
$this->l('Limit LiteSpeed Cache to specified IPs. (Space or comma separated.)') . ' '
. $this->l('Allows cache testing on a live site. If empty, cache will be served to everyone.'),
$disabled
);
$formDev['input'][] = $this->addInputSwitch(
Conf::CFG_DEBUG,
$this->labels[Conf::CFG_DEBUG],
$this->l('Prints additional information to "lscache.log." Turn off for production use.'),
$disabled
);
$formDev['input'][] = $this->addInputTextArea(
Conf::CFG_DEBUG_IPS,
$this->labels[Conf::CFG_DEBUG_IPS],
$this->l('Only log activities from specified IPs. (Space or comma separated.)') . ' '
. $this->l('If empty, all activities will be logged. Only effective when debug log is enabled.'),
$disabled
);
$formDev['input'][] = $this->addInputText(
Conf::CFG_DEBUG_LEVEL,
$this->labels[Conf::CFG_DEBUG_LEVEL],
$this->l('Specifies log level ranging from 1 to 10. The higher the value, the more detailed the output.'),
'',
false,
$disabled
);
$forms = array(array('form' => $fg), array('form' => $formUser), array('form' => $formDev));
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->languages = $this->getLanguages();
$helper->name_controller = $this->controller_name;
$helper->token = $this->token;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitConfig';
$helper->currentIndex = self::$currentIndex;
$helper->tpl_vars = array('fields_value' => $this->current_values);
return $helper->generateForm($forms);
}
private function addInputText($name, $label, $desc, $suffix = '', $required = true, $disabled = false)
{
$input = array(
'type' => 'text', 'name' => $name, 'label' => $label,
'desc' => $desc, 'class' => 'input fixed-width-sm', 'required' => $required,
);
if ($disabled) {
$input['disabled'] = 1;
}
if ($suffix) {
$input['suffix'] = $suffix;
}
return $input;
}
private function addInputSwitch($name, $label, $desc = '', $disabled = false)
{
$input = array(
'type' => 'switch', 'name' => $name, 'label' => $label,
'values' => array(array('value' => 1), array('value' => 0)),
);
if ($desc) {
$input['desc'] = $desc;
}
if ($disabled) {
$input['disabled'] = 1;
}
return $input;
}
private function addInputSelect($name, $label, $query, $desc = '', $required = true, $disabled = false)
{
$input = array(
'type' => 'select', 'name' => $name, 'label' => $label,
'options' => array('query' => $query, 'id' => 'id', 'name' => 'name'),
'required' => $required, 'class' => 'input fixed-width-xxl',
);
if ($desc) {
$input['desc'] = $desc;
}
if ($disabled) {
$input['disabled'] = 1;
}
return $input;
}
private function addInputTextArea($name, $label, $desc, $disabled = false)
{
$input = array(
'type' => 'textarea', 'name' => $name, 'label' => $label,
'desc' => $desc,
);
if ($disabled) {
$input['readonly'] = 1;
}
return $input;
}
private function newFieldForm($title, $icon, $desc = '')
{
$form = array('legend' => array('title' => $title, 'icon' => "icon-$icon"));
if ($desc) {
$form['description'] = $desc;
}
$form['input'] = array();
$form['submit'] = array('title' => $this->l('Save'));
return $form;
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* LiteSpeed Cache for Prestashop.
*
* NOTICE OF LICENSE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://opensource.org/licenses/GPL-3.0 .
*
* @author LiteSpeed Technologies
* @copyright Copyright (c) 2017 LiteSpeed Technologies, Inc. (https://www.litespeedtech.com)
* @license https://opensource.org/licenses/GPL-3.0
*/
class AdminLiteSpeedCacheController extends ModuleAdminController
{
/* this file serve as place holder for tab space. No content needed.
* But class needs to be existed and extend ModuleAdminController
*/
public function __construct()
{
parent::__construct();
$linkClass = $this->module->active ? 'AdminLiteSpeedCacheManage' : 'AdminHome';
Tools::redirectAdmin($this->context->link->getAdminLink($linkClass));
}
}

View File

@@ -0,0 +1,655 @@
<?php
/**
* LiteSpeed Cache for Prestashop.
*
* NOTICE OF LICENSE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://opensource.org/licenses/GPL-3.0 .
*
* @author LiteSpeed Technologies
* @copyright Copyright (c) 2017-2018 LiteSpeed Technologies, Inc. (https://www.litespeedtech.com)
* @license https://opensource.org/licenses/GPL-3.0
*/
use LiteSpeedCacheConfig as Conf;
use LiteSpeedCacheEsiModConf as EsiConf;
class AdminLiteSpeedCacheCustomizeController extends ModuleAdminController
{
private $config;
private $is_shop_level; // -1: not multishop, 0: multishop global, 1: multishop shop
private $labels;
private $current_values;
private $default_ids;
private $license_disabled;
private $module_options;
private $changed;
private $config_values;
private $original_values;
private $current_id;
public function __construct()
{
$this->bootstrap = true;
//$this->display = 'list';
parent::__construct();
if (!$this->module->active) {
Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome'));
}
$this->config = Conf::getInstance();
$title = $this->l('LiteSpeed Cache Customization');
$this->page_header_toolbar_title = $title;
$this->meta_title = $title;
$this->list_id = 'esimods';
$this->identifier = 'id';
$this->table = 'esimod'; // no real table, faked
//// -1: not multishop, 0: multishop global, 1: multishop shop or group
if (Shop::isFeatureActive()) {
$this->is_shop_level = (Shop::getContext() == Shop::CONTEXT_ALL) ? 0 : 1;
} else {
$this->is_shop_level = -1;
}
}
public function init()
{
parent::init(); // parent init must be at beginning
if (!LiteSpeedCacheHelper::licenseEnabled()) {
$this->license_disabled = true;
$this->errors[] = $this->l('LiteSpeed Server with LSCache module is required.') . ' '
. $this->l('Please contact your sysadmin or your host to get a valid LiteSpeed license.');
}
include_once _PS_MODULE_DIR_ . 'litespeedcache/thirdparty/lsc_include.php';
$this->initDisplayValues();
$this->labels = array(
'id' => $this->l('Module'),
'name' => $this->l('Name'),
'pubpriv' => $this->l('Cache'),
'priv' => $this->l('Is Private'),
'ttl' => $this->l('TTL'),
'tag' => $this->l('Cache Tag'),
'type' => $this->l('Type'),
'events' => $this->l('Purge Events'),
'ctrl' => $this->l('Purge Controllers'),
'methods' => $this->l('Hooked Methods'),
'render' => $this->l('Widget Render Hooks'),
'asvar' => $this->l('As Variable'),
'ie' => $this->l('Ignore If Empty'),
'ce' => $this->l('Only Cache When Empty'),
);
}
public function initPageHeaderToolbar()
{
if ($this->is_shop_level !== 1) {
if ($this->display == 'list') {
$this->page_header_toolbar_btn['new_esi'] = array(
'href' => self::$currentIndex . '&addesimod&token=' . $this->token,
'desc' => $this->l('Add New ESI Block'),
'icon' => 'process-icon-new',
);
} else {
$this->page_header_toolbar_btn['goback'] = array(
'href' => self::$currentIndex . '&token=' . $this->token,
'desc' => $this->l('Back to List'),
'icon' => 'process-icon-back',
);
}
}
parent::initPageHeaderToolbar();
}
private function initDisplayValues()
{
$data = $this->config->get(Conf::ENTRY_MODULE);
$this->config_values = array();
$this->default_ids = array();
foreach ($data as $id => $ci) {
$idata = $ci->getCustConfArray();
if ($idata['priv']) {
$idata['pubpriv'] = $this->l('Private');
$idata['badge_success'] = true;
} else {
$idata['pubpriv'] = $this->l('Public');
$idata['badge_danger'] = true;
}
if ($idata['type'] == EsiConf::TYPE_CUSTOMIZED) {
$idata['typeD'] = $this->l('Customized');
} else {
$this->default_ids[] = $id;
$idata['badge_warning'] = 1; // no edits allowed
$idata['typeD'] = ($idata['type'] == EsiConf::TYPE_BUILTIN) ?
$this->l('Built-in') : $this->l('Integrated');
}
if ($idata['tipurl']) {
$this->warnings[] = $idata['name'] . ': <a href="' . $idata['tipurl']
. '" target="_blank" rel="noopener noreferrer">' . $this->l('See online tips') . '</a>';
$idata['name'] .= ' (*)';
}
$this->config_values[$id] = $idata;
}
if ($this->display == 'edit' || $this->display == 'view') {
$name = $this->current_id;
$this->original_values = $this->config_values[$name];
} elseif ($this->display == 'add') {
$this->original_values = array(
'id' => '',
'name' => '',
'priv' => 1,
'ttl' => 1800,
'tag' => '',
'events' => '',
'ctrl' => '',
'methods' => '',
'render' => '',
'asvar' => '',
'ie' => '',
'ce' => '',
);
} else { // list
$this->original_values = $this->config_values;
}
if ($this->display != 'list') {
$this->getModuleOptions();
}
$this->current_values = $this->original_values;
}
/**
* Retrieve GET and POST value and translate them to actions.
*/
public function initProcess()
{
$t = $this->table;
$this->current_id = Tools::getIsset($this->identifier) ? Tools::getValue($this->identifier) : null;
$this->display = 'list'; // default
if (Tools::getIsset('add' . $t)) {
if ($this->canDo('add')) {
$this->action = 'new';
$this->display = 'add';
} else {
$this->errors[] = $this->l('You do not have permission to add this.');
}
} elseif (Tools::getIsset('update' . $t) && $this->current_id) {
if ($this->canDo('edit')) {
$this->action = 'edit';
$this->display = 'edit';
} else {
$this->errors[] = $this->l('You do not have permission to edit this.');
}
} elseif (Tools::getIsset('delete' . $t) && $this->current_id) {
// Delete object
if ($this->canDo('delete')) {
$this->action = 'delete';
} else {
$this->errors[] = $this->l('You do not have permission to delete this.');
}
} elseif (Tools::getIsset('view' . $t) && $this->current_id) {
$this->display = 'view';
$this->action = 'view';
}
}
protected function canDo($action)
{
if (method_exists($this, 'access')) { // 1.7 +
return $this->access($action);
} else {
return ($this->tabAccess[$action] === '1');
}
}
public function initContent()
{
// if (!$this->viewAccess()) {
// $this->errors[] = $this->l('You do not have permission to view this.');
// return;
// }
//
parent::initContent();
if ($this->is_shop_level == 1) {
$this->informations[] = $this->l('This section is only available at the global level.');
return;
}
if ($this->display == 'edit' || $this->display == 'add' || $this->display == 'view') {
$this->content = $this->renderForm();
} elseif ($this->display == 'list') {
$s = ' ';
$this->informations[] = $this->l('You can make an ESI block for a widget, also known as Hole-Punching.') . $s
. $this->l('Built-in and integrated modules cannot be changed.') . $s
. $this->l('These are advanced settings for third-party modules.') . $s
. '<a href="https://www.litespeedtech.com/support/wiki/doku.php/litespeed_wiki:cache:lscps" '
. 'target="_blank" rel="noopener noreferrer">'
. $this->l('Wiki Help') . '</a>';
$this->content = $this->renderList();
}
$this->context->smarty->assign(array(
'content' => $this->content,
));
}
public function postProcess()
{
if (Tools::isSubmit('submitConfig')) {
$this->processFormSave();
} elseif ($this->action == 'delete') {
$this->saveModConfig(array('id' => $this->current_id));
} else {
parent::postProcess();
}
}
private function validateInput($name)
{
//'id', 'priv', 'ttl', 'tag', 'events'
$postVal = trim(Tools::getValue($name));
$origVal = $this->original_values[$name];
$invalid = $this->l('Invalid value') . ': ' . $this->labels[$name];
$s = ' - '; // spacer
$invalidChars = $this->l('Invalid characters found.');
$splitPattern = '/[\s,]+/';
switch ($name) {
case 'id':
break;
case 'priv':
case 'asvar':
case 'ie':
case 'ce':
$postVal = (int) $postVal;
break;
case 'ttl':
if ($postVal === '') {
// ok, will use default value
} elseif (!Validate::isUnsignedInt($postVal)) {
$this->errors[] = $invalid;
} elseif ($postVal < 60) {
$this->errors[] = $invalid . $s . $this->l('Must be greater than 60 seconds.');
} elseif ($this->current_values['priv'] == 1 && $postVal > 7200) {
$this->errors[] = $invalid . $s . $this->l('Private TTL must be less than 7200 seconds.');
} else {
$postVal = (int) $postVal;
}
break;
case 'tag':
if ($postVal === '') {
// ok, will use default value
} elseif (preg_match('/^[a-zA-Z-_0-9]+$/', $postVal) !== 1) {
$this->errors[] = $invalid . $s . $invalidChars;
}
break;
case 'events':
$clean = array_unique(preg_split($splitPattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $ci) {
if (!preg_match('/^[a-zA-Z]+$/', $ci)) {
$this->errors[] = $invalid . $s . $invalidChars;
} elseif (Tools::strlen($ci) < 8) {
$this->errors[] = $invalid . $s . $this->l('Event string usually starts with "action".');
}
}
$postVal = implode(', ', $clean);
}
break;
case 'ctrl':
$clean = array_unique(preg_split($splitPattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $ci) {
// allow ClassName?param1&param2
if (!preg_match('/^([a-zA-Z_]+)(\?[a-zA-Z_0-9\-&]+)?$/', $ci, $m)) {
$this->errors[] = $invalid . $s . $invalidChars;
} /*elseif (!class_exists($m[1])) {
$this->errors[] = $invalid . $s . ' ' . $m[1] . ' ' . $this->l('Invalid class name.');
}*/
}
$postVal = implode(', ', $clean);
}
break;
case 'methods':
$clean = array_unique(preg_split($splitPattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} else {
foreach ($clean as $ci) {
if (!preg_match('/^(\!)?([a-zA-Z_]+)$/', $ci, $m)) {
$this->errors[] = $invalid . $s . $invalidChars;
} else {
// no further validation for now
}
}
$postVal = implode(', ', $clean);
}
break;
case 'render':
$clean = array_unique(preg_split($splitPattern, $postVal, null, PREG_SPLIT_NO_EMPTY));
if (count($clean) == 0) {
$postVal = '';
} elseif (count($clean) == 1 && $clean[0] == '*') {
$postVal = '*'; // allow * for all
} else {
foreach ($clean as $ci) {
if (!preg_match('/^(\!)?([a-zA-Z_]+)$/', $ci, $m)) {
$this->errors[] = $invalid . $s . $invalidChars;
} else {
// no further validation for now
}
}
$postVal = implode(', ', $clean);
}
break;
}
if ($postVal != $origVal) {
$this->changed |= 1;
}
$this->current_values[$name] = $postVal;
}
private function processFormSave()
{
$inputs = array('id', 'priv', 'ttl', 'tag', 'events', 'ctrl', 'methods', 'render', 'asvar', 'ie', 'ce');
$this->changed = 0;
foreach ($inputs as $field) {
$this->validateInput($field);
}
if (count($this->errors)) {
return;
}
if ($this->changed == 0) {
$this->confirmations[] = $this->l('No changes detected. Nothing to save.');
return;
}
$this->saveModConfig($this->current_values);
}
private function saveModConfig($values)
{
$res = $this->config->saveModConfigValues($values, $this->action);
if ($res && ($this->display == 'add')) { // successfully added
$this->display = 'list';
}
$this->initDisplayValues();
if ($res == 1) {
$this->confirmations[] = $this->l('Settings saved.') . ' '
. $this->l('Please flush all cached pages.');
} elseif ($res == 2) {
$this->confirmations[] = $this->l('Settings saved and hooks updated') . ' '
. $this->l('Please flush all cached pages.');
} else {
$this->errors[] = $this->l('Fail to update the settings.');
}
}
private function getModuleOptions()
{
$moduleOptions = array();
$is17 = version_compare(_PS_VERSION_, '1.7.0.0', '>=');
if ($this->display == 'edit' || $this->display == 'view') {
$name = $this->current_id;
$moduleOptions[] = array(
'id' => $name,
'name' => "[$name] " . $this->config_values[$name]['name'],
);
} elseif ($this->display == 'add') {
$list = array();
$modules = Module::getModulesInstalled();
$existing = array_keys($this->config_values);
foreach ($modules as $module) {
if (($module['active'] == 1)
&& (!in_array($module['name'], $existing))
&& ($tmp_instance = Module::getInstanceByName($module['name']))
/*&& (!$is17
|| ($tmp_instance instanceof PrestaShop\PrestaShop\Core\Module\WidgetInterface))*/) {
$list[$module['name']] = $tmp_instance->displayName;
}
}
natsort($list);
foreach ($list as $id => $name) {
$name = "[$id] $name";
$moduleOptions[] = array('id' => $id, 'name' => $name);
}
}
$this->module_options = $moduleOptions;
}
public function renderForm()
{
$s = ' ';
// for new & edit & view
$disabled = ($this->display == 'view');
$input = array(
array(
'type' => 'select',
'label' => $this->labels['id'],
'name' => 'id',
'hint' => $this->l('This will only be effective if this widget is showing on a cacheable page.'),
'options' => array('query' => $this->module_options, 'id' => 'id', 'name' => 'name'),
'desc' => $this->l('Please select a front-end widget module only.'),
),
array(
'type' => 'switch',
'label' => $this->labels['priv'],
'desc' => $this->l('A public block will only have one cached copy which is shared by everyone.')
. $s . $this->l('A private block will be cached individually for each user.'),
'name' => 'priv',
'disabled' => $disabled,
'is_bool' => true,
'values' => array(array('value' => 1), array('value' => 0)),
),
array(
'type' => 'text',
'label' => $this->labels['ttl'],
'name' => 'ttl',
'readonly' => $disabled,
'desc' => $this->l('Leave this blank if you want to use the default setting.'),
'suffix' => $this->l('seconds'),
),
array(
'type' => 'text',
'label' => $this->labels['tag'],
'name' => 'tag',
'readonly' => $disabled,
'desc' => $this->l('Only allow one tag per module.') . $s
. $this->l('Same tag can be used for multiple modules.') . $s
. $this->l('Leave blank to use the module name as the default value.'),
),
array(
'type' => 'textarea',
'label' => $this->labels['events'],
'name' => 'events',
'hint' => $this->l('No need to add login/logout events.') . $s
. $this->l('Those are included by default for all private blocks.'),
'readonly' => $disabled,
'desc' => $this->l('You can automatically purge the cached ESI blocks by events.') . $s .
$this->l('Specify a comma-delimited list of events.'),
),
array(
'type' => 'textarea',
'label' => $this->labels['ctrl'],
'name' => 'ctrl',
'hint' => $this->l('For example, cart block is set to be purged by this setting:')
. $s . '"CartController:id_product"',
'readonly' => $disabled, // allow ClassName?param1&param2
'desc' => $this->l('You can automatically purge the cached ESI blocks by dispatched controllers.')
. $s . $this->l('Specify a comma-delimited list of controller class names.') . $s
. $this->l('If you add "?param" after the name, purge will be triggered only if that param is set.')
. $s . $this->l('You can add multiple parameters, like "className?param1&param2".'),
),
array(
'type' => 'textarea',
'label' => $this->labels['methods'],
'name' => 'methods',
'hint' => $this->l('Instead of listing all possible ones, you can simply define an exlusion list.'),
'readonly' => $disabled,
'desc' => $this->l('Hooked methods that will trigger ESI injection.') . $s
. $this->l('Specify a comma-delimited list of methods (prefix with "!" to exclude one).') . $s
. $this->l('Leave blank to disable injection on CallHook method.'),
),
array(
'type' => 'textarea',
'label' => $this->labels['render'],
'name' => 'render',
'hint' => $this->l('This is only available for PS1.7.'),
'readonly' => $disabled,
'desc' => $this->l('You can further tune ESI injection for widget rendering by invoking hooks.')
. '<br> ' . $this->l('Specify a comma-delimited list of allowed hooks;')
. $s . $this->l('Or a list of not-allowed hooks by prefixing with "!".')
. $s . $this->l('Use "*" for all hooks allowed; leave blank to disable renderWidget injection.'),
),
array(
'type' => 'switch',
'label' => $this->labels['asvar'],
'desc' => $this->l('Enable if the rendered content is used as a variable, such as a token,')
. $s . $this->l('or if it is small enough (e.g. less than 256 bytes).'),
'name' => 'asvar',
'disabled' => $disabled,
'is_bool' => true,
'values' => array(array('value' => 1), array('value' => 0)),
),
array(
'type' => 'switch',
'label' => $this->labels['ie'],
'desc' => $this->l('Enable to avoid punching a hole for an ESI block whose rendered content is empty.'),
'name' => 'ie',
'hint' => $this->l('No need to hole-punch if the overridden template intentionally blank it out.'),
'disabled' => $disabled,
'is_bool' => true,
'values' => array(array('value' => 1), array('value' => 0)),
),
array(
'type' => 'switch',
'label' => $this->labels['ce'],
'desc' => $this->l('Enable to selectively cache this ESI block only when it contains no content.') . ' '
. $this->l('Non-empty blocks will not be cached. Can be used for popup notices or message blocks.'),
'name' => 'ce',
'disabled' => $disabled,
'is_bool' => true,
'values' => array(array('value' => 1), array('value' => 0)),
),
);
$form = array(
'legend' => array(
'title' => $this->l('Convert Widget to ESI Block'),
'icon' => 'icon-cogs',
),
'description' => $this->l('You can hole punch a widget as an ESI block.') . $s
. $this->l('Each ESI block can have its own TTL and purge events.') . $s
. $this->l('For more complicated cases, a third-party integration class is required.') . $s
. $this->l('This requires a deep understanding of the internals of Prestashop.') . $s
. $this->l('If you need help, you can order Support service from LiteSpeed Tech.'),
'input' => $input,
);
if (!$disabled) {
$form['submit'] = array('title' => $this->l('Save'));
}
$forms = array(array('form' => $form));
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->languages = $this->getLanguages();
$helper->name_controller = $this->controller_name;
$helper->token = $this->token;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitConfig';
if ($this->display == 'add') {
$helper->currentIndex = self::$currentIndex . '&addesimod';
} else {
$helper->currentIndex = self::$currentIndex . '&updateesimod&id=' . $this->original_values['id'];
}
$helper->tpl_vars = array('fields_value' => $this->current_values);
return $helper->generateForm($forms);
}
public function renderList()
{
$this->fields_list = array(
'id' => array('title' => $this->labels['id'], 'width' => 'auto'),
'name' => array('title' => $this->labels['name'], 'width' => 'auto'),
'pubpriv' => array('title' => $this->labels['pubpriv'], 'width' => '25', 'align' => 'center',
'badge_success' => true, 'badge_danger' => true, ),
'ttl' => array('title' => $this->labels['ttl'], 'align' => 'center', 'class' => 'fixed-width-sm'),
'tag' => array('title' => $this->labels['tag'], 'align' => 'center', 'class' => 'fixed-width-sm'),
'typeD' => array('title' => $this->labels['type'], 'align' => 'center', 'badge_warning' => true),
);
$this->_list = $this->config_values;
$this->actions[] = 'view';
$this->actions[] = 'edit';
$this->actions[] = 'delete';
$this->list_skip_actions['edit'] = $this->default_ids;
$this->list_skip_actions['delete'] = $this->default_ids;
// populate _list
$helper = new HelperList();
$this->setHelperDisplay($helper);
$helper->simple_header = true;
$helper->tpl_vars = $this->getTemplateListVars();
$helper->tpl_delete_link_vars = $this->tpl_delete_link_vars;
$helper->languages = $this->getLanguages();
$helper->name_controller = $this->controller_name;
$helper->token = $this->token;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->identifier = $this->identifier;
$list = $helper->generateList($this->_list, $this->fields_list);
return $list;
}
}

View File

@@ -0,0 +1,404 @@
<?php
/**
* LiteSpeed Cache for Prestashop.
*
* NOTICE OF LICENSE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://opensource.org/licenses/GPL-3.0 .
*
* @author LiteSpeed Technologies
* @copyright Copyright (c) 2017 LiteSpeed Technologies, Inc. (https://www.litespeedtech.com)
* @license https://opensource.org/licenses/GPL-3.0
*/
use LiteSpeedCacheConfig as Conf;
class AdminLiteSpeedCacheManageController extends ModuleAdminController
{
private $config;
private $is_shop_level; // -1: not multishop, 0: multishop global, 1: multishop shop
private $labels;
private $current_values;
private $license_disabled;
public function __construct()
{
$this->bootstrap = true;
$this->display = 'view';
parent::__construct();
$this->config = Conf::getInstance();
if (!$this->module->active) {
Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome'));
}
$title = $this->l('LiteSpeed Cache Management');
$this->page_header_toolbar_title = $title;
$this->meta_title = $title;
//// -1: not multishop, 0: multishop global, 1: multishop shop or group
if (Shop::isFeatureActive()) {
$this->is_shop_level = (Shop::getContext() == Shop::CONTEXT_ALL) ? 0 : 1;
} else {
$this->is_shop_level = -1;
}
}
public function init()
{
parent::init();
if (!LiteSpeedCacheHelper::licenseEnabled()) {
$this->license_disabled = true;
$this->errors[] = $this->l('LiteSpeed Server with LSCache module is required.') . ' '
. $this->l('Please contact your sysadmin or your host to get a valid LiteSpeed license.');
}
$this->labels = array(
'home' => $this->l('Home Page'),
'404' => $this->l('All 404 Pages'),
'search' => $this->l('All Categories and Products Pages'),
'brand' => $this->l('All Brands Pages'),
'supplier' => $this->l('All Suppliers Pages'),
'sitemap' => $this->l('Site Map'),
'cms' => $this->l('All CMS Pages'),
'priv' => $this->l('All Private ESI Blocks'),
'prod0' => $this->l('Product'),
'cat0' => $this->l('Category'),
'brand0' => $this->l('Brand'),
'supplier0' => $this->l('Supplier'),
'cms0' => $this->l('CMS'),
'shop0' => $this->l('Shop'),
'affectall' => $this->l('This will affect all shops'),
);
// is_shop_level -1: not multishop, 0: multishop global, 1: multishop shop or group
}
public function initPageHeaderToolbar()
{
if ($this->is_shop_level !== 1) {
$this->page_header_toolbar_btn['purge_shops'] = array(
'href' => self::$currentIndex . '&purge_shops&token=' . $this->token,
'desc' => $this->l('Flush All PrestaShop Pages'),
'icon' => 'process-icon-delete',
);
$this->page_header_toolbar_btn['purge_all'] = array(
'href' => self::$currentIndex . '&purge_all&token=' . $this->token,
'desc' => $this->l('Flush Entire Cache Storage'),
'icon' => 'process-icon-delete',
'class' => 'btn-warning',
);
}
parent::initPageHeaderToolbar();
}
public function postProcess()
{
if (Tools::isSubmit('purge_shops')) {
$this->processPurgeShops();
} elseif (Tools::isSubmit('purge_all')) {
$this->processPurgeAll();
} elseif (Tools::isSubmit('submitPurgeSelection')) {
$this->processPurgeSelection();
} elseif (Tools::isSubmit('submitPurgeId')) {
$this->processPurgeIds();
}
return parent::postProcess();
}
private function processPurgeAll()
{
if ($this->doPurge(1, 'ALL')) {
$this->confirmations[] = $this->l('Notified LiteSpeed Server to flush the entire cache storage.');
}
}
private function processPurgeShops()
{
if ($this->doPurge('*')) {
$this->confirmations[] = $this->l('Notified LiteSpeed Server to flush all pages of this PrestaShop.');
}
}
private function processPurgeSelection()
{
$tags = array();
$info = array();
if (Tools::getValue('cbPurge_home')) {
$tags[] = Conf::TAG_HOME;
$info[] = $this->labels['home'];
}
if (Tools::getValue('cbPurge_404')) {
$tags[] = Conf::TAG_404;
$info[] = $this->labels['404'];
}
if (Tools::getValue('cbPurge_search')) {
$tags[] = Conf::TAG_SEARCH;
$info[] = $this->labels['search'];
}
if (Tools::getValue('cbPurge_brand')) {
$tags[] = Conf::TAG_PREFIX_MANUFACTURER;
$info[] = $this->labels['brand'];
}
if (Tools::getValue('cbPurge_supplier')) {
$tags[] = Conf::TAG_PREFIX_SUPPLIER;
$info[] = $this->labels['supplier'];
}
if (Tools::getValue('cbPurge_sitemap')) {
$tags[] = Conf::TAG_SITEMAP;
$info[] = $this->labels['sitemap'];
}
if (Tools::getValue('cbPurge_cms')) {
$tags[] = Conf::TAG_PREFIX_CMS;
$info[] = $this->labels['cms'];
}
if (Tools::getValue('cbPurge_priv')) {
$tags[] = Conf::TAG_PREFIX_PRIVATE;
$info[] = $this->labels['priv'];
LiteSpeedCacheHelper::clearInternalCache();
}
if ($cid = Tools::getValue('rcats')) {
$tags[] = Conf::TAG_PREFIX_CATEGORY . $cid;
$info[] = $this->l('Category with ID') . ' ' . $cid;
}
if (count($tags)) {
if ($this->doPurge($tags)) {
$t = implode(', ', $info);
$this->confirmations[] = $this->l('Notified LiteSpeed Server to flush cached pages:') . ' ' . $t;
}
} else {
$this->warnings[] = $this->l('Nothing selected. No action taken.');
}
}
private function processPurgeIds()
{
$by = Tools::getValue('purgeby');
switch ($by) {
case 'prod':
$pre = Conf::TAG_PREFIX_PRODUCT;
$desc = $this->labels['prod0'];
break;
case 'cat':
$pre = Conf::TAG_PREFIX_CATEGORY;
$desc = $this->labels['cat0'];
break;
case 'brand':
$pre = Conf::TAG_PREFIX_MANUFACTURER;
$desc = $this->labels['brand0'];
break;
case 'supplier':
$pre = Conf::TAG_PREFIX_SUPPLIER;
$desc = $this->labels['supplier0'];
break;
case 'cms':
$pre = Conf::TAG_PREFIX_CMS;
$desc = $this->labels['cms0'];
break;
case 'shop':
$pre = Conf::TAG_PREFIX_SHOP;
$desc = $this->labels['shop0'];
break;
default:
$this->errors[] = $this->l('Illegal entrance');
return;
}
$pattern = "/[\s,]+/";
$id = Tools::getValue('purgeids');
$ids = preg_split($pattern, $id, null, PREG_SPLIT_NO_EMPTY);
$tags = array();
$hasError = false;
if (empty($ids)) {
$hasError = true;
} else {
foreach ($ids as $i) {
if (((string) ((int) $i) === (string) $i) && ((int) $i > 0)) { // make sure is int
$tags[] = $pre . $i;
} else {
$hasError = true;
break;
}
}
}
if ($hasError) {
$this->current_values['purgeby'] = $by;
$this->current_values['purgeids'] = $id;
$this->errors[] = $this->l('Please enter valid IDs');
} else {
if ($this->doPurge($tags)) {
$t = $desc . ' ' . implode(', ', $ids);
$this->confirmations[] = $this->l('Notified LiteSpeed Server to flush cached pages:') . ' ' . $t;
}
}
}
private function doPurge($tags, $key = 'public')
{
if (LiteSpeedCache::isActive() || $tags == '*') {
$params = array('from' => 'AdminLiteSpeedCacheManage', $key => $tags);
Hook::exec('litespeedCachePurge', $params);
return true;
}
$this->warnings[] = $this->l('No action taken.') . ' '
. $this->l('This Module is not enabled. Only action allowed is Flush All Prestashop Pages.');
return false;
}
public function renderView()
{
if ($this->license_disabled) {
$this->warnings[] = $this->l('No action taken.') . ' '
. $this->l('No LiteSpeed Server with LSCache available.');
return false;
}
$html = $this->renderPurgeSelection();
$html .= $this->renderPurgeId();
return $html;
}
private function renderPurgeSelection()
{
$title = $this->l('Purge by Selection');
$form = $this->newFieldForm($title, 'list-ul', $title);
$cbPurge = array(
'type' => 'checkbox',
'label' => $this->l('Select All Pages You Want to Purge'),
'name' => 'cbPurge',
'values' => array(
'query' => array(
array('id' => 'home', 'name' => $this->labels['home']),
array('id' => '404', 'name' => $this->labels['404']),
array('id' => 'search', 'name' => $this->labels['search']),
array('id' => 'brand', 'name' => $this->labels['brand']),
array('id' => 'supplier', 'name' => $this->labels['supplier']),
array('id' => 'sitemap', 'name' => $this->labels['sitemap']),
array('id' => 'cms', 'name' => $this->labels['cms']),
array('id' => 'priv', 'name' => $this->labels['priv']),
),
'id' => 'id', 'name' => 'name', ),
);
$selCat = array(
'type' => 'categories',
'label' => $this->l('Select Categories'),
'name' => 'rcats',
'tree' => array(
'root_category' => 1,
'id' => 'id_category',
'name' => 'name_category',
),
);
if ($this->is_shop_level !== -1) {
$cbPurge['hint'] = $this->labels['affectall'];
$selCat['hint'] = $this->labels['affectall'];
}
$form['input'][] = $cbPurge;
$form['input'][] = $selCat;
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->languages = $this->getLanguages();
$helper->name_controller = $this->controller_name;
$helper->token = $this->token;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitPurgeSelection';
$helper->currentIndex = self::$currentIndex;
return $helper->generateForm(array(array('form' => $form)));
}
private function renderPurgeId()
{
$title = $this->l('Purge by ID');
$desc = $this->l('Cached pages should be automatically purged through related hooks.') . ' '
. $this->l('This tool is mainly for testing purposes.') . ' '
. $this->l('You need to know the exact IDs if you want to use this function.') . ' '
. $this->l('No extra validation on the ID value.');
$form = $this->newFieldForm($title, 'list-ol', $title, $desc);
$query = array(
array('purgeby' => 'prod', 'name' => $this->labels['prod0']),
array('purgeby' => 'cat', 'name' => $this->labels['cat0']),
array('purgeby' => 'brand', 'name' => $this->labels['brand0']),
array('purgeby' => 'supplier', 'name' => $this->labels['supplier0']),
array('purgeby' => 'cms', 'name' => $this->labels['cms0']),
);
$textareaIds = array(
'type' => 'textarea',
'class' => 'input',
'desc' => $this->l('You can enter multiple IDs by using a comma-delimited string.'),
'label' => $this->l('Enter the IDs of the Pages You Want to Purge'),
'name' => 'purgeids',
);
if ($this->is_shop_level !== -1) {
$query[] = array('purgeby' => 'shop', 'name' => $this->labels['shop0']);
$textareaIds['hint'] = $this->labels['affectall'];
}
$form['input'][] = array(
'type' => 'select',
'label' => $this->l('Select ID Type'),
'name' => 'purgeby',
'required' => false,
'options' => array('query' => $query, 'id' => 'purgeby', 'name' => 'name'),
);
$form['input'][] = $textareaIds;
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->languages = $this->getLanguages();
$helper->name_controller = $this->controller_name;
$helper->token = $this->token;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitPurgeId';
$helper->currentIndex = self::$currentIndex;
$cur_purgeby = isset($this->current_values['purgeby']) ? $this->current_values['purgeby'] : '';
$cur_ids = isset($this->current_values['purgeids']) ? $this->current_values['purgeids'] : '';
$helper->tpl_vars = array(
'fields_value' => array('purgeby' => $cur_purgeby, 'purgeids' => $cur_ids),
);
return $helper->generateForm(array(array('form' => $form)));
}
private function newFieldForm($title, $icon, $submit_title, $desc = '')
{
$form = array(
'legend' => array('title' => $title, 'icon' => "icon-$icon"),
'submit' => array('icon' => 'process-icon-delete', 'title' => $submit_title),
);
if ($desc) {
$form['description'] = $desc;
}
$form['input'] = array();
return $form;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* LiteSpeed Cache for Prestashop.
*
* NOTICE OF LICENSE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://opensource.org/licenses/GPL-3.0 .
*
* @author LiteSpeed Technologies
* @copyright Copyright (c) 2017 LiteSpeed Technologies, Inc. (https://www.litespeedtech.com)
* @license https://opensource.org/licenses/GPL-3.0
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;