| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/clients/client2/web32/web/wp-content/ |
Upload File : |
<?php
/**
* Memcached-Object-Cache-Dropin für WordPress.
*
* Schlanke, eigenständige Implementierung auf Basis der PECL-`memcached`-Extension.
* Nur das WordPress-WP_Object_Cache-API; kein Multi-Server, kein Compression-Toggle.
*
* Sicherheitsgurte:
* - Bei Initialisierungs-Fehlern → Fallback auf In-Process-Cache (Single-Request).
* - Salt aus WP_CACHE_KEY_SALT (oder ABSPATH) → kein Cross-Site-Clashing.
* - Globale Groups werden NICHT an blog_prefix angehängt.
* - Non-persistent groups landen nur in der In-Process-Map.
*
* @package taschenmuschi-kaufen
*/
if ( ! defined( 'ABSPATH' ) ) exit;
if ( ! defined( 'WP_CACHE_KEY_SALT' ) ) {
define( 'WP_CACHE_KEY_SALT', md5( ABSPATH ) );
}
/* ---------------------------------------------------------------------------
* Globale API-Funktionen — Signaturen wie wp-includes/cache.php / cache-compat.php
* ------------------------------------------------------------------------- */
function wp_cache_init() {
$GLOBALS['wp_object_cache'] = new WP_Object_Cache();
}
function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
return $GLOBALS['wp_object_cache']->add( $key, $data, $group, (int) $expire );
}
function wp_cache_add_multiple( array $data, $group = '', $expire = 0 ) {
$out = array();
foreach ( $data as $k => $v ) $out[ $k ] = wp_cache_add( $k, $v, $group, $expire );
return $out;
}
function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
return $GLOBALS['wp_object_cache']->replace( $key, $data, $group, (int) $expire );
}
function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
return $GLOBALS['wp_object_cache']->set( $key, $data, $group, (int) $expire );
}
function wp_cache_set_multiple( array $data, $group = '', $expire = 0 ) {
$out = array();
foreach ( $data as $k => $v ) $out[ $k ] = wp_cache_set( $k, $v, $group, $expire );
return $out;
}
function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
return $GLOBALS['wp_object_cache']->get( $key, $group, (bool) $force, $found );
}
function wp_cache_get_multiple( $keys, $group = '', $force = false ) {
$out = array();
foreach ( (array) $keys as $k ) $out[ $k ] = wp_cache_get( $k, $group, $force );
return $out;
}
function wp_cache_delete( $key, $group = '' ) {
return $GLOBALS['wp_object_cache']->delete( $key, $group );
}
function wp_cache_delete_multiple( array $keys, $group = '' ) {
$out = array();
foreach ( $keys as $k ) $out[ $k ] = wp_cache_delete( $k, $group );
return $out;
}
function wp_cache_incr( $key, $offset = 1, $group = '' ) {
return $GLOBALS['wp_object_cache']->incr( $key, (int) $offset, $group );
}
function wp_cache_decr( $key, $offset = 1, $group = '' ) {
return $GLOBALS['wp_object_cache']->decr( $key, (int) $offset, $group );
}
function wp_cache_flush() {
return $GLOBALS['wp_object_cache']->flush();
}
function wp_cache_flush_runtime() {
return $GLOBALS['wp_object_cache']->flush_runtime();
}
function wp_cache_flush_group( $group ) {
return $GLOBALS['wp_object_cache']->flush_group( $group );
}
function wp_cache_supports( $feature ) {
return in_array( $feature, array( 'add_multiple', 'set_multiple', 'get_multiple', 'delete_multiple', 'flush_runtime', 'flush_group' ), true );
}
function wp_cache_close() {
return true;
}
function wp_cache_switch_to_blog( $blog_id ) {
$GLOBALS['wp_object_cache']->switch_to_blog( (int) $blog_id );
}
function wp_cache_add_global_groups( $groups ) {
$GLOBALS['wp_object_cache']->add_global_groups( (array) $groups );
}
function wp_cache_add_non_persistent_groups( $groups ) {
$GLOBALS['wp_object_cache']->add_non_persistent_groups( (array) $groups );
}
function wp_cache_reset() {
// Legacy, no-op.
}
/* ---------------------------------------------------------------------------
* WP_Object_Cache — Memcached + In-Process-Hybrid
* ------------------------------------------------------------------------- */
class WP_Object_Cache {
/** @var Memcached|null */
private $mc = null;
/** @var bool */
private $persistent = false;
/** @var array<string,array<string,mixed>> Runtime-Cache je Group */
private $runtime = array();
/** @var array<string,bool> */
private $global_groups = array();
/** @var array<string,bool> */
private $non_persistent_groups = array();
/** @var int */
public $blog_prefix = 1;
/** @var string */
private $salt;
/** @var int */
public $cache_hits = 0;
/** @var int */
public $cache_misses = 0;
public function __construct() {
$this->salt = WP_CACHE_KEY_SALT;
$this->blog_prefix = is_multisite() ? (int) get_current_blog_id() : 1;
if ( class_exists( 'Memcached' ) ) {
try {
$this->mc = new Memcached();
$this->mc->setOption( Memcached::OPT_LIBKETAMA_COMPATIBLE, true );
$this->mc->setOption( Memcached::OPT_BINARY_PROTOCOL, true );
$this->mc->setOption( Memcached::OPT_CONNECT_TIMEOUT, 200 ); // ms
// Falls noch keine Server konfiguriert: lokalen Daemon nehmen.
if ( count( $this->mc->getServerList() ) === 0 ) {
$this->mc->addServer( '127.0.0.1', 11211 );
}
$this->persistent = true;
} catch ( Throwable $e ) {
$this->mc = null;
$this->persistent = false;
}
}
// Standard-Global-Groups (entsprechen WP-Core, falls plugins_loaded sie ggf. später ergänzen).
$this->add_global_groups( array(
'blog-details', 'blog-id-cache', 'blog-lookup', 'blog_meta', 'global-posts',
'networks', 'network-queries', 'sites', 'site-details', 'site-lookup',
'site-options', 'site-queries', 'site-transient', 'rss', 'users',
'useremail', 'userlogins', 'usermeta', 'user_meta', 'userslugs',
) );
}
/* ---- Group-Konfiguration ---- */
public function add_global_groups( array $groups ) {
foreach ( $groups as $g ) $this->global_groups[ $g ] = true;
}
public function add_non_persistent_groups( array $groups ) {
foreach ( $groups as $g ) $this->non_persistent_groups[ $g ] = true;
}
public function switch_to_blog( $blog_id ) {
$this->blog_prefix = is_multisite() ? (int) $blog_id : 1;
}
/* ---- Key-Berechnung ---- */
private function key( $key, $group ) {
if ( '' === $group ) $group = 'default';
$prefix = isset( $this->global_groups[ $group ] ) ? 'g' : (string) $this->blog_prefix;
return $this->salt . ':' . $prefix . ':' . $group . ':' . $key;
}
private function is_persistent( $group ) {
if ( '' === $group ) $group = 'default';
return $this->persistent && empty( $this->non_persistent_groups[ $group ] );
}
/* ---- Standard-Operationen ---- */
public function get( $key, $group = 'default', $force = false, &$found = null ) {
$group = $group ?: 'default';
$k = $this->key( $key, $group );
// Runtime-Cache.
if ( ! $force && isset( $this->runtime[ $group ][ $key ] ) ) {
$found = true;
$this->cache_hits++;
return $this->runtime[ $group ][ $key ];
}
if ( ! $this->is_persistent( $group ) ) {
$found = false;
$this->cache_misses++;
return false;
}
$val = $this->mc->get( $k );
if ( $this->mc->getResultCode() === Memcached::RES_NOTFOUND ) {
$found = false;
$this->cache_misses++;
return false;
}
$found = true;
$this->cache_hits++;
$this->runtime[ $group ][ $key ] = $val;
return $val;
}
public function set( $key, $data, $group = 'default', $expire = 0 ) {
$group = $group ?: 'default';
if ( is_object( $data ) ) $data = clone $data;
$this->runtime[ $group ][ $key ] = $data;
if ( ! $this->is_persistent( $group ) ) return true;
return $this->mc->set( $this->key( $key, $group ), $data, (int) $expire );
}
public function add( $key, $data, $group = 'default', $expire = 0 ) {
$group = $group ?: 'default';
if ( isset( $this->runtime[ $group ][ $key ] ) ) return false;
if ( ! $this->is_persistent( $group ) ) {
$this->runtime[ $group ][ $key ] = is_object( $data ) ? clone $data : $data;
return true;
}
$ok = $this->mc->add( $this->key( $key, $group ), $data, (int) $expire );
if ( $ok ) $this->runtime[ $group ][ $key ] = is_object( $data ) ? clone $data : $data;
return $ok;
}
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
$group = $group ?: 'default';
if ( ! $this->is_persistent( $group ) ) {
if ( ! isset( $this->runtime[ $group ][ $key ] ) ) return false;
$this->runtime[ $group ][ $key ] = is_object( $data ) ? clone $data : $data;
return true;
}
$ok = $this->mc->replace( $this->key( $key, $group ), $data, (int) $expire );
if ( $ok ) $this->runtime[ $group ][ $key ] = is_object( $data ) ? clone $data : $data;
return $ok;
}
public function delete( $key, $group = 'default' ) {
$group = $group ?: 'default';
unset( $this->runtime[ $group ][ $key ] );
if ( ! $this->is_persistent( $group ) ) return true;
return $this->mc->delete( $this->key( $key, $group ) );
}
public function incr( $key, $offset = 1, $group = 'default' ) {
$group = $group ?: 'default';
if ( ! $this->is_persistent( $group ) ) {
$cur = isset( $this->runtime[ $group ][ $key ] ) ? (int) $this->runtime[ $group ][ $key ] : 0;
$cur = max( 0, $cur + (int) $offset );
$this->runtime[ $group ][ $key ] = $cur;
return $cur;
}
$res = $this->mc->increment( $this->key( $key, $group ), (int) $offset );
if ( $res === false ) {
// Falls Schlüssel fehlt: initial setzen.
$this->mc->add( $this->key( $key, $group ), max( 0, (int) $offset ), 0 );
$res = $this->mc->get( $this->key( $key, $group ) );
}
$this->runtime[ $group ][ $key ] = $res;
return $res;
}
public function decr( $key, $offset = 1, $group = 'default' ) {
$group = $group ?: 'default';
if ( ! $this->is_persistent( $group ) ) {
$cur = isset( $this->runtime[ $group ][ $key ] ) ? (int) $this->runtime[ $group ][ $key ] : 0;
$cur = max( 0, $cur - (int) $offset );
$this->runtime[ $group ][ $key ] = $cur;
return $cur;
}
$res = $this->mc->decrement( $this->key( $key, $group ), (int) $offset );
if ( $res === false ) {
$this->mc->add( $this->key( $key, $group ), 0, 0 );
$res = 0;
}
$this->runtime[ $group ][ $key ] = $res;
return $res;
}
public function flush() {
$this->runtime = array();
if ( ! $this->persistent ) return true;
// flush() betrifft die GESAMTE memcached-Instanz – nutze ein Salt-Increment
// als günstigere Alternative, falls Server geteilt werden.
return $this->mc->flush();
}
public function flush_runtime() {
$this->runtime = array();
return true;
}
public function flush_group( $group ) {
unset( $this->runtime[ $group ] );
// Memcached unterstützt keinen Group-Flush; ohne Salt-Trick ein No-Op.
return false;
}
/* ---- Debug ---- */
public function stats() {
echo '<p>';
echo '<strong>Cache Hits:</strong> ' . (int) $this->cache_hits . '<br/>';
echo '<strong>Cache Misses:</strong> ' . (int) $this->cache_misses . '<br/>';
echo '<strong>Persistent:</strong> ' . ( $this->persistent ? 'memcached' : 'process-only' ) . '<br/>';
echo '</p>';
}
}