spip_nursit/plugins-dist/dist/nursit/memoization/memoization_options.php

335 lines
9.3 KiB
PHP
Raw Permalink Normal View History

2023-06-01 15:30:12 +00:00
<?php
/**
* Calculer la taille du cache
*
* @package SPIP\memoization\Options
**/
// Sécurité
if (!defined('_ECRIRE_INC_VERSION')){
return;
}
/**
* Interface MCacheBackend
* Implémentée par les différentes méthodes disponibles
*/
interface MCacheBackend {
public function init($params = null);
public function get($key);
public function set($key, $value, $ttl = null);
public function exists($key);
public function del($key);
public function inc($key, $value = null, $ttl = null);
public function dec($key, $value = null, $ttl = null);
public function lock($key, /* private */ $unlock = false);
public function unlock($key);
public function size();
public function purge();
}
/* objet MCache */
class MCache {
private $methode;
private $backend;
private $is_memory;
public function __construct($methode = null, array $params = []){
// Initialiser les namespace si pas encore fait
if (isset($GLOBALS['meta']['cache_namespace'])){
if (!defined('_CACHE_NAMESPACE')){
define('_CACHE_NAMESPACE',
(isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : "cli")
. ':'
. (isset($_SERVER["SERVER_PORT"]) ? $_SERVER["SERVER_PORT"] : "cli")
. ':'
. $GLOBALS['meta']['cache_namespace']
. ':'
);
}
if (isset($GLOBALS['meta']['cache_key']) and !defined('_CACHE_KEY')){
define('_CACHE_KEY', $GLOBALS['meta']['cache_key']);
}
}
// autodetect si pas fournie
$this->methode = $methode ? $methode : self::autodetect();
if (!$f = find_in_path($this->methode . '.inc', "memo/", true)){
spip_log("Methode " . $this->methode . " non implementee - fallback filecache", "memoization" . _LOG_ERREUR);
$this->methode = 'filecache';
require_once(find_in_path($this->methode . '.inc', "memo/"));
}
$this->is_memory = (!in_array($this->methode, ['filecache', 'nocache']));
$obj = 'MCacheBackend_' . $this->methode;
$this->backend = new $obj;
$this->backend->init($params);
}
/**
* Indiquer si la methode de cache est une méthode rapide
* @return bool
*/
public function is_memory(): bool{
return $this->is_memory;
}
/**
* Lire la méthode utilisée
* @return string
*/
public function methode(): string{
return $this->methode;
}
/**
* Autodetection de la methode disponible
* @return string
*/
static public function autodetect(): string{
$methodes = ['apcu', 'apc', 'xcache', 'filecache', 'nocache'];
foreach ($methodes as $methode){
if (self::methode_disponible($methode)){
return $methode;
}
}
// ne doit jamais arriver, car nocache est toujours disponible
return $methode;
}
/**
* @param string $methode
* @return bool|string
*/
static public function methode_disponible(string $methode){
switch ($methode) {
case 'apc':
return function_exists('apc_exists');
case 'apcu':
return function_exists('apcu_exists');
case 'xcache':
if (!function_exists('xcache_set')){
return false;
}
@xcache_set('xcache_autodetect', 1234);
return @xcache_get('xcache_autodetect')==1234;
case 'memcache':
return function_exists('memcache_set');
case 'memcached':
return class_exists('Memcached');
case 'redis':
return extension_loaded('redis');
case 'filecache':
case 'nocache':
return true;
// Methode inconnue ?
// TODO : charger le fichier memo/xxx et chercher une methode static detect ?
default:
return false;
}
}
/**
* Méthode de memoization (si explicitement configurée)
*
* @return string|null
*/
public static function config_methode(){
if (empty($GLOBALS['meta']['memoization'])){
return null;
}
$cfg = @unserialize($GLOBALS['meta']['memoization']);
if (isset($cfg['methode'])){
return preg_replace(",\W,", "", $cfg['methode']);
}
return null;
}
static public function config_redis_server(){
$cfg = @unserialize($GLOBALS['meta']['memoization']);
if (!$cfg || !isset($cfg['redis_type']) || empty($cfg['redis_type'])){
$cfg = array(
'redis_type' => 'serveur',
'redis_server' => '127.0.0.1:6379',
'redis_sock' => '/tmp/redis.sock',
'redis_auth' => '',
'redis_dbindex' => 0,
'redis_serializer' => 'php',
);
}
return $cfg;
}
// outil pour memcache (hosts et ports a configurer dans le CFG)
static public function config_memcache_servers(){
$cfg = @unserialize($GLOBALS['meta']['memoization']);
if (!$cfg = $cfg['memcache_servers']){
$cfg = 'localhost:11211';
}
preg_match_all('/[a-z0-9._-]*(?::\d+)/', $cfg, $s, PREG_PATTERN_ORDER);
return $s[0];
}
/* Proxies vers le backend */
public function get($key){return $this->backend->get($key);}
public function set($key, $value, $ttl = null){return $this->backend->set($key, $value, $ttl);}
public function exists($key){return $this->backend->exists($key);}
public function del($key){return $this->backend->del($key);}
public function inc($key, $value = null, $ttl = null){return $this->backend->inc($key, $value, $ttl);}
public function dec($key, $value = null, $ttl = null){return $this->backend->dec($key, $value, $ttl);}
public function lock($key){return $this->backend->lock($key);}
public function unlock($key){return $this->backend->unlock($key);}
public function size(){return $this->backend->size();}
public function purge(){return $this->backend->purge();}
/* Cache Editorial */
/**
* Recuperer de l'editorial cache, mais invalide avec la meta derniere_modif ou avec un var_mode
* @param string $key
* @return string
*/
public function edito_get($key){
if (!_VAR_MODE
and $cache = $this->get("::edito::{$key}")
and isset($cache['time'])
and isset($cache['value'])
and (!isset($GLOBALS['meta']['derniere_modif']) or $cache['time']>$GLOBALS['meta']['derniere_modif'])){
return $cache['value'];
}
return null;
}
/**
* Stocker de l'editorial cache, avec un timestamp pour gerer l'invalidation
* @param string $key
* @param mixed $value
* @return mixed
*/
public function edito_set($key, $value){
$cache = array('value' => $value, 'time' => $_SERVER['REQUEST_TIME']);
$this->set("::edito::$key", $cache);
return $value;
}
}
/**
* Interface principale d'utilisation de Memoization
* @return MCache
*/
function memoization(): MCache{
static $Memoization = null;
if (is_null($Memoization)){
$Memoization = new MCache(MCache::config_methode());
}
return $Memoization;
}
/* Interface procedurale */
function cache_get($key){return memoization()->get($key);}
function cache_set($key, $value, $ttl = null): bool{return memoization()->set($key, $value, $ttl);}
function cache_exists($key): bool{return memoization()->exists($key);}
function cache_del($key): bool{return memoization()->del($key);}
function cache_inc($key, $value = null, $ttl = null): int{return memoization()->inc($key, $value, $ttl);}
function cache_dec($key, $value = null, $ttl = null): int{return memoization()->dec($key, $value, $ttl);}
function cache_lock($key){return memoization()->lock($key);}
function cache_unlock($key){return memoization()->unlock($key);}
function cache_purge(){return memoization()->purge();}
/**
* Cache Editorial : le contenu memoizé est invalidé quand le cache SPIP est invalidé
*/
function cache_edito_get($key){return memoization()->edito_get($key);}
function cache_edito_set($key, $value){return memoization()->edito_set($key, $value);}
/**
* Cache a function's result cache_me()
* (c) Fil 2009 - Double-licensed under the GNU/LGPL and MIT licenses
* http://zzz.rezo.net/-SPIP-
* Usage:
* In any cacheable function add at top:
* if(!is_null($c=cache_me())) return$c;
*/
if (!function_exists('debug_backtrace')){
function cache_me($vars = null, $ttl = 3600){
return;
}
} else {
/**
* @param null|mixed $vars other variables that could change the result
* in addition to the function's args that are automatically taken into account
* @param int $ttl time to live
* @return false|mixed
*/
function cache_me($vars = null, $ttl = 3600){
// uniquement si on a une methode de cache rapide (en memoire)
if (!memoization()->is_memory()){
return null;
}
$trace = debug_backtrace();
$trace = $trace[1];
if (isset($trace['object'])){
$fun = [$trace['object'], $trace['function']];
} else {
$fun = $trace['function'];
}
$key = md5(json_encode(['function' => $fun, 'args' => $trace['args'], 'vars' => $vars]));
if (!memoization()->exists($key)){
memoization()->set($key, null, $ttl);
// eviter une boucle infinie par re-entrance si memoization est actif mais n'a pas de memoire dispo
if (!memoization()->exists($key)) {
return null;
}
$r = call_user_func_array($fun, $trace['args']);
memoization()->set($key, $r, $ttl);
return $r;
}
return memoization()->get($key);
}
}
/**
* Filtres pour le formulaire de configuration
*/
/**
* @param null|string $methode
* @return bool|string
*/
function memoization_methode($methode = null){
return MCache::methode_disponible($methode);
}
/**
* @return array
*/
function memoization_redis_liste_serializer(){
$serializers = array();
if (defined('Redis::SERIALIZER_IGBINARY') && extension_loaded('igbinary')){
$serializers['igbinary'] = array('libelle' => 'SERIALIZER_IGBINARY', 'statut' => 'actif');
} else {
$serializers['igbinary'] = array('libelle' => 'SERIALIZER_IGBINARY', 'statut' => 'inactif');
}
$serializers['php'] = array('libelle' => 'SERIALIZER_PHP', 'statut' => 'actif');
return $serializers;
}