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

360 lines
12 KiB
PHP

<?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 LiteSpeedCacheEsiItem as EsiItem;
use LiteSpeedCacheLog as LSLog;
class LiteSpeedCacheEsiModConf implements JsonSerializable
{
// avail types
const TYPE_BUILTIN = 0;
const TYPE_INTEGRATED = 1;
const TYPE_CUSTOMIZED = 2;
// avail fields
const FLD_PRIV = 'priv';
const FLD_TAG = 'tag';
const FLD_TTL = 'ttl';
// comma separated purge events
const FLD_PURGE_EVENTS = 'events';
// comma separate controller classes, with :P for POST only
const FLD_PURGE_CONTROLLERS = 'ctrl';
// comma separated list of method, if proceed with "!", meaning not included
const FLD_HOOK_METHODS = 'methods';
// *: all, list of allowed hooks, or not-allowed hooks
const FLD_RENDER_WIDGETS = 'render';
const FLD_ASVAR = 'asvar';
const FLD_IGNORE_EMPTY = 'ie';
const FLD_ONLY_CACHE_EMPTY = 'ce';
const FLD_TIPURL = 'tipurl';
private $moduleName;
private $type;
private $data;
private $parsed = [];
private $customHandler = null;
public function __construct($moduleName, $type, $data)
{
$this->moduleName = $moduleName;
$this->type = $type;
$this->data = [];
//sanatize data
$this->data[self::FLD_PRIV] = $data[self::FLD_PRIV] ? 1 : 0;
if (isset($data[self::FLD_TAG])) {
$this->data[self::FLD_TAG] = is_array($data[self::FLD_TAG])
? $data[self::FLD_TAG] : [$data[self::FLD_TAG]];
}
if (isset($data[self::FLD_TTL])) {
$this->data[self::FLD_TTL] = $data[self::FLD_TTL];
}
if (isset($data[self::FLD_PURGE_EVENTS])) {
$this->data[self::FLD_PURGE_EVENTS] = $data[self::FLD_PURGE_EVENTS];
}
if (isset($data[self::FLD_PURGE_CONTROLLERS])) {
$this->data[self::FLD_PURGE_CONTROLLERS] = $data[self::FLD_PURGE_CONTROLLERS];
}
if (isset($data[self::FLD_HOOK_METHODS])) {
$this->data[self::FLD_HOOK_METHODS] = $data[self::FLD_HOOK_METHODS];
}
if (isset($data[self::FLD_RENDER_WIDGETS])) {
$this->data[self::FLD_RENDER_WIDGETS] = $data[self::FLD_RENDER_WIDGETS];
}
if (isset($data[self::FLD_ASVAR])) {
$this->data[self::FLD_ASVAR] = $data[self::FLD_ASVAR];
}
if (isset($data[self::FLD_IGNORE_EMPTY])) {
$this->data[self::FLD_IGNORE_EMPTY] = $data[self::FLD_IGNORE_EMPTY];
}
if (isset($data[self::FLD_ONLY_CACHE_EMPTY])) {
$this->data[self::FLD_ONLY_CACHE_EMPTY] = $data[self::FLD_ONLY_CACHE_EMPTY];
}
if (isset($data[self::FLD_TIPURL])) {
$this->data[self::FLD_TIPURL] = $data[self::FLD_TIPURL];
}
$this->parseList(self::FLD_RENDER_WIDGETS);
$this->parseList(self::FLD_HOOK_METHODS);
}
public function getModuleName()
{
return $this->moduleName;
}
public function getCustConfArray()
{
$cdata = [
'id' => $this->moduleName,
'name' => $this->moduleName,
'priv' => $this->isPrivate(),
'ttl' => $this->getTTL(),
'tag' => implode(', ', $this->getTags()),
'type' => $this->type,
'events' => $this->getFieldValue(self::FLD_PURGE_EVENTS, false, true),
'ctrl' => $this->getFieldValue(self::FLD_PURGE_CONTROLLERS, false, true),
'methods' => $this->getFieldValue(self::FLD_HOOK_METHODS, false, true),
'render' => $this->getFieldValue(self::FLD_RENDER_WIDGETS, false, true),
'asvar' => $this->getFieldValue(self::FLD_ASVAR, true),
'ie' => $this->getFieldValue(self::FLD_IGNORE_EMPTY, true),
'ce' => $this->getFieldValue(self::FLD_ONLY_CACHE_EMPTY, true),
'tipurl' => $this->getFieldValue(self::FLD_TIPURL),
];
if ($tmp_instance = Module::getInstanceByName($this->moduleName)) {
$cdata['name'] = htmlspecialchars_decode($tmp_instance->displayName);
}
return $cdata;
}
public function jsonSerialize()
{
$sdata = $this->data;
$sdata['id'] = $this->moduleName;
return $sdata;
}
public function setCustomHandler($customHandler)
{
if ($this->customHandler === null) { // only allow set once
$this->customHandler = $customHandler;
}
}
public function isPrivate($params=[])
{
if ($this->customHandler && method_exists($this->customHandler, 'isPrivate')) {
return $this->customHandler->isPrivate($params);
}
return $this->data[self::FLD_PRIV] != null;
}
public function getTTL($params=[])
{
if ($this->customHandler && method_exists($this->customHandler, 'getTTL')) {
return $this->customHandler->getTTL($params);
}
return isset($this->data[self::FLD_TTL]) ?
$this->data[self::FLD_TTL] : '';
}
public function getTags($params=[])
{
if ($this->customHandler && method_exists($this->customHandler, 'getTags')) {
return $this->customHandler->getTags($params);
}
if (!empty($this->data[self::FLD_TAG])) {
return $this->data[self::FLD_TAG];
} else {
return [$this->moduleName];
}
}
public function getNoItemCache($params)
{
if ($this->customHandler && method_exists($this->customHandler, 'getNoItemCache')) {
return $this->customHandler->getNoItemCache($params);
}
return false;
}
public function asVar($params)
{
if ($this->customHandler && method_exists($this->customHandler, 'asVar')) {
return $this->customHandler->asVar($params);
}
return isset($this->data[self::FLD_ASVAR]) && $this->data[self::FLD_ASVAR];
}
public function onlyCacheEmtpy($params)
{
if ($this->customHandler && method_exists($this->customHandler, 'onlyCacheEmtpy')) {
return $this->customHandler->onlyCacheEmtpy($params);
}
return isset($this->data[self::FLD_ONLY_CACHE_EMPTY]) && $this->data[self::FLD_ONLY_CACHE_EMPTY];
}
public function ignoreEmptyContent($params)
{
if ($this->customHandler && method_exists($this->customHandler, 'ignoreEmptyContent')) {
return $this->customHandler->ignoreEmptyContent($params);
}
return isset($this->data[self::FLD_IGNORE_EMPTY]) && $this->data[self::FLD_IGNORE_EMPTY];
}
// return array( lowercased classname => 0, 1 )
public function getPurgeControllers()
{
if (empty($this->data[self::FLD_PURGE_CONTROLLERS])) {
return null;
}
$controllers = [];
$list = preg_split("/[\s,]+/", $this->data[self::FLD_PURGE_CONTROLLERS], null, PREG_SPLIT_NO_EMPTY);
foreach ($list as $item) {
// allow ClassName?param1&param2
$ct = explode('?', $item);
if (count($ct) == 1) {
$controllers[$item] = 0; // no param
} else {
$controllers[$ct[0]] = $ct[1]; // with param
// if param is custom_handler, will let module handle it
}
}
return $controllers;
}
public function getPurgeEvents()
{
if (isset($this->data[self::FLD_PURGE_EVENTS])) {
return preg_split("/[\s,]+/", $this->data[self::FLD_PURGE_EVENTS], null, PREG_SPLIT_NO_EMPTY);
}
return null;
}
public function canInject(&$params)
{
if (empty($params['pt'])) {
if (_LITESPEED_DEBUG_ >= LSLog::LEVEL_UNEXPECTED) {
LSLog::log(__FUNCTION__ . ' missing pt', LSLog::LEVEL_UNEXPECTED);
}
return false;
}
if ($this->customHandler && method_exists($this->customHandler, 'canInject')) {
return $this->customHandler->canInject($params);
}
switch ($params['pt']) { // param type
case EsiItem::ESI_RENDERWIDGET:
return $this->checkInjection(self::FLD_RENDER_WIDGETS, $params['h']);
case EsiItem::ESI_CALLHOOK:
return $this->checkInjection(self::FLD_HOOK_METHODS, $params['mt']);
case EsiItem::ESI_SMARTYFIELD:
default:
return true;
}
}
public function isCustomized()
{
return $this->type == self::TYPE_CUSTOMIZED;
}
private function getFieldValue($field, $isbool = false, $splitClean = false)
{
$value = (isset($this->data[$field])) ? $this->data[$field] : '';
if ($isbool) {
$value = ($value) ? true : false;
}
if ($splitClean && $value) {
$dv = preg_split("/[\s,]+/", $value, null, PREG_SPLIT_NO_EMPTY);
$value = implode(', ', $dv);
}
return $value;
}
private function checkInjection($field, $value)
{
$res = $this->parsed[$field];
$type = $res[0];
if ($type == 9) { // allow all
return true;
}
$value = Tools::strtolower($value);
if ($type == 1) {
return in_array($value, $res[1]); // include
} elseif ($type == 2) {
return !in_array($value, $res[2]); // exclude
} else {
return false;
}
}
// stringData is comma separated list, * for all, ! is not include
private function parseList($field)
{
// $res[0] = -1: none; 9: all; 1: included, 2: excluded
$res = [];
if (!isset($this->data[$field])) {
$res[0] = -1; // none
} elseif ($this->data[$field] instanceof LscIntegration) {
$res = $this->data[$field]; // custom handler
} elseif ($this->data[$field] == '*') {
$res[0] = 9; // all
} else {
$list = preg_split("/[\s,]+/", $this->data[$field], null, PREG_SPLIT_NO_EMPTY);
$isInclude = 0; // included is 1, excluded is 2
foreach ($list as $d) {
$d = Tools::strtolower($d);
if ($d[0] == '!') {
$isInclude |= 2;
if (!isset($res[2])) {
$res[2] = [];
}
$res[2][] = ltrim($d, '!');
} else {
$isInclude |= 1;
if (!isset($res[1])) {
$res[1] = [];
}
$res[1][] = $d;
}
}
if (($isInclude & 1) == 1) {
$res[0] = 1; // if contains included, will only check included
} elseif (($isInclude & 2) == 2) {
$res[0] = 2;
} else {
$res[0] = -1;
}
}
$this->parsed[$field] = $res;
}
}