From bf0a8ca7ea0e372b5b4975d0224823f067b1fafa Mon Sep 17 00:00:00 2001 From: mustafauysal Date: Sat, 2 May 2020 01:07:45 +0300 Subject: [PATCH 1/6] Ensure proper escaping around the stats method --- object-cache.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/object-cache.php b/object-cache.php index 3700bcf..332f4ca 100644 --- a/object-cache.php +++ b/object-cache.php @@ -2,8 +2,8 @@ /* Plugin Name: Memcached Redux Description: The real Memcached (not Memcache) backend for the WP Object Cache. -Version: 0.1.6 -Plugin URI: http://wordpress.org/extend/plugins/memcached-redux/ +Version: 0.1.7 +Plugin URI: https://github.com/Ipstenu/memcached-redux Author: Scott Taylor - uses code from Ryan Boren, Denis de Bernardy, Matt Martz, Mike Schroder, Mika Epstein Install this file to wp-content/object-cache.php @@ -387,15 +387,15 @@ function colorize_debug_line( $line ) { $cmd = substr( $line, 0, strpos( $line, ' ' ) ); - $cmd2 = "$cmd"; + $cmd2 = "" . esc_html( $cmd ) . ""; - return $cmd2 . substr( $line, strlen( $cmd ) ) . "\n"; + return $cmd2 . esc_html( substr( $line, strlen( $cmd ) ) ) . "\n"; } function stats() { echo "

\n"; foreach ( $this->stats as $stat => $n ) { - echo "$stat $n"; + echo "" . esc_html( $stat ) . " " . esc_html( $n ); echo "
\n"; } echo "

\n"; @@ -403,9 +403,8 @@ function stats() { foreach ( $this->group_ops as $group => $ops ) { if ( !isset( $_GET['debug_queries'] ) && 500 < count( $ops ) ) { $ops = array_slice( $ops, 0, 500 ); - echo "Too many to show! Show them anyway.\n"; - } - echo "

$group commands

"; + echo "Too many to show! Show them anyway.\n"; } + echo "

" . esc_html( $group ) . " commands

"; echo "
\n";
 			$lines = array();
 			foreach ( $ops as $op ) {

From 89edbd956d95af99020ce9e2ac8a507cb8965e78 Mon Sep 17 00:00:00 2001
From: Mustafa Uysal 
Date: Thu, 6 Apr 2023 15:35:25 +0300
Subject: [PATCH 2/6] Update object-cache.php

Add *_multiple support
---
 object-cache.php | 862 ++++++++++++++++++++++++++++-------------------
 1 file changed, 509 insertions(+), 353 deletions(-)

diff --git a/object-cache.php b/object-cache.php
index 332f4ca..7eb7d72 100644
--- a/object-cache.php
+++ b/object-cache.php
@@ -2,7 +2,7 @@
 /*
 Plugin Name: Memcached Redux
 Description: The real Memcached (not Memcache) backend for the WP Object Cache.
-Version: 0.1.7
+Version: 0.1.8
 Plugin URI: https://github.com/Ipstenu/memcached-redux
 Author: Scott Taylor - uses code from Ryan Boren, Denis de Bernardy, Matt Martz, Mike Schroder, Mika Epstein
 
@@ -15,475 +15,631 @@
 
 if ( class_exists( 'Memcached' ) ):
 
-function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
-	global $wp_object_cache;
+	function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->add( $key, $data, $group, $expire );
-}
-
-function wp_cache_incr( $key, $n = 1, $group = '' ) {
-	global $wp_object_cache;
-
-	return $wp_object_cache->incr( $key, $n, $group );
-}
+		return $wp_object_cache->add( $key, $data, $group, $expire );
+	}
 
-function wp_cache_decr( $key, $n = 1, $group = '' ) {
-	global $wp_object_cache;
+	function wp_cache_add_multiple( array $data, $group = '', $expire = 0 ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->decr( $key, $n, $group );
-}
+		return $wp_object_cache->add_multiple( $data, $group, $expire );
+	}
 
-function wp_cache_close() {
-	global $wp_object_cache;
+	function wp_cache_incr( $key, $n = 1, $group = '' ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->close();
-}
+		return $wp_object_cache->incr( $key, $n, $group );
+	}
 
-function wp_cache_delete( $key, $group = '' ) {
-	global $wp_object_cache;
+	function wp_cache_decr( $key, $n = 1, $group = '' ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->delete( $key, $group );
-}
+		return $wp_object_cache->decr( $key, $n, $group );
+	}
 
-function wp_cache_flush() {
-	global $wp_object_cache;
+	function wp_cache_close() {
+		global $wp_object_cache;
 
-	return $wp_object_cache->flush();
-}
+		return $wp_object_cache->close();
+	}
 
-function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
-	global $wp_object_cache;
+	function wp_cache_delete( $key, $group = '' ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->get( $key, $group, $force, $found );
-}
+		return $wp_object_cache->delete( $key, $group );
+	}
 
-/**
- * $keys_and_groups = array(
- *      array( 'key', 'group' ),
- *      array( 'key', '' ),
- *      array( 'key', 'group' ),
- *      array( 'key' )
- * );
- *
- */
-function wp_cache_get_multi( $key_and_groups, $bucket = 'default' ) {
-	global $wp_object_cache;
-
-	return $wp_object_cache->get_multi( $key_and_groups, $bucket );
-}
+	function wp_cache_delete_multiple( array $keys, $group = '' ) {
+		global $wp_object_cache;
 
-/**
- * $items = array(
- *      array( 'key', 'data', 'group' ),
- *      array( 'key', 'data' )
- * );
- *
- */
-function wp_cache_set_multi( $items, $expire = 0, $group = 'default' ) {
-	global $wp_object_cache;
-
-	return $wp_object_cache->set_multi( $items, $expire = 0, $group = 'default' );
-}
+		return $wp_object_cache->delete_multiple( $keys, $group );
+	}
 
-function wp_cache_init() {
-	global $wp_object_cache;
+	function wp_cache_flush() {
+		global $wp_object_cache;
 
-	$wp_object_cache = new WP_Object_Cache();
-}
+		return $wp_object_cache->flush();
+	}
 
-function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
-	global $wp_object_cache;
+	function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
+		global $wp_object_cache;
 
-	return $wp_object_cache->replace( $key, $data, $group, $expire );
-}
+		return $wp_object_cache->get( $key, $group, $force, $found );
+	}
 
-function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
-	global $wp_object_cache;
+	function wp_cache_get_multiple( $keys, $group = '' ) {
+		global $wp_object_cache;
 
-	if ( defined( 'WP_INSTALLING' ) == false )
-		return $wp_object_cache->set( $key, $data, $group, $expire );
-	else
-		return $wp_object_cache->delete( $key, $group );
-}
+		return $wp_object_cache->get_multiple( $keys, $group );
+	}
 
-function wp_cache_add_global_groups( $groups ) {
-	global $wp_object_cache;
+	/**
+	 * $keys_and_groups = array(
+	 *      array( 'key', 'group' ),
+	 *      array( 'key', '' ),
+	 *      array( 'key', 'group' ),
+	 *      array( 'key' )
+	 * );
+	 */
+	function wp_cache_get_multi( $key_and_groups, $bucket = 'default' ) {
+		global $wp_object_cache;
+
+		return $wp_object_cache->get_multi( $key_and_groups, $bucket );
+	}
 
-	$wp_object_cache->add_global_groups( $groups );
-}
+	function wp_cache_set_multiple( array $data, $group = '', $expire = 0 ) {
+		global $wp_object_cache;
 
-function wp_cache_add_non_persistent_groups( $groups ) {
-	global $wp_object_cache;
+		return $wp_object_cache->set_multiple( $data, $group, $expire );
+	}
 
-	$wp_object_cache->add_non_persistent_groups( $groups );
-}
+	/**
+	 * $items = array(
+	 *      array( 'key', 'data', 'group' ),
+	 *      array( 'key', 'data' )
+	 * );
+	 */
+	function wp_cache_set_multi( $items, $expire = 0, $group = 'default' ) {
+		global $wp_object_cache;
 
-class WP_Object_Cache {
-	var $global_groups = array();
+		return $wp_object_cache->set_multi( $items, $expire = 0, $group = 'default' );
+	}
 
-	var $no_mc_groups = array();
+	function wp_cache_init() {
+		global $wp_object_cache;
 
-	var $cache = array();
-	var $mc = array();
-	var $stats = array();
-	var $group_ops = array();
+		$wp_object_cache = new WP_Object_Cache();
+	}
 
-	var $cache_enabled = true;
-	var $default_expiration = 0;
+	function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
+		global $wp_object_cache;
 
-	function add( $id, $data, $group = 'default', $expire = 0 ) {
-		$key = $this->key( $id, $group );
+		return $wp_object_cache->replace( $key, $data, $group, $expire );
+	}
 
-		if ( is_object( $data ) )
-			$data = clone $data;
+	function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
+		global $wp_object_cache;
 
-		if ( in_array( $group, $this->no_mc_groups ) ) {
-			$this->cache[$key] = $data;
-			return true;
-		} elseif ( isset( $this->cache[$key] ) && $this->cache[$key] !== false ) {
-			return false;
+		if ( defined( 'WP_INSTALLING' ) == false ) {
+			return $wp_object_cache->set( $key, $data, $group, $expire );
+		} else {
+			return $wp_object_cache->delete( $key, $group );
 		}
+	}
 
-		$mc =& $this->get_mc( $group );
-		$expire = ( $expire == 0) ? $this->default_expiration : $expire;
-		$result = $mc->add( $key, $data, $expire );
-
-		if ( false !== $result ) {
-			++$this->stats['add'];
-			$this->group_ops[$group][] = "add $id";
-			$this->cache[$key] = $data;
-		}
+	function wp_cache_add_global_groups( $groups ) {
+		global $wp_object_cache;
 
-		return $result;
+		$wp_object_cache->add_global_groups( $groups );
 	}
 
-	function add_global_groups( $groups ) {
-		if ( ! is_array( $groups ) )
-			$groups = (array) $groups;
+	function wp_cache_add_non_persistent_groups( $groups ) {
+		global $wp_object_cache;
 
-		$this->global_groups = array_merge( $this->global_groups, $groups );
-		$this->global_groups = array_unique( $this->global_groups );
+		$wp_object_cache->add_non_persistent_groups( $groups );
 	}
 
-	function add_non_persistent_groups( $groups ) {
-		if ( ! is_array( $groups ) )
-			$groups = (array) $groups;
+	class WP_Object_Cache {
+		var $global_groups = array();
 
-		$this->no_mc_groups = array_merge( $this->no_mc_groups, $groups );
-		$this->no_mc_groups = array_unique( $this->no_mc_groups );
-	}
+		var $no_mc_groups = array();
 
-	function incr( $id, $n = 1, $group = 'default' ) {
-		$key = $this->key( $id, $group );
-		$mc =& $this->get_mc( $group );
-		$this->cache[ $key ] = $mc->increment( $key, $n );
-		return $this->cache[ $key ];
-	}
+		var $cache = array();
+		var $mc = array();
+		var $stats = array();
+		var $group_ops = array();
 
-	function decr( $id, $n = 1, $group = 'default' ) {
-		$key = $this->key( $id, $group );
-		$mc =& $this->get_mc( $group );
-		$this->cache[ $key ] = $mc->decrement( $key, $n );
-		return $this->cache[ $key ];
-	}
+		var $cache_enabled = true;
+		var $default_expiration = 0;
 
-	function close() {
-		// Silence is Golden.
-	}
+		function add( $id, $data, $group = 'default', $expire = 0 ) {
+			$key = $this->key( $id, $group );
 
-	function delete( $id, $group = 'default' ) {
-		$key = $this->key( $id, $group );
+			if ( is_object( $data ) ) {
+				$data = clone $data;
+			}
 
-		if ( in_array( $group, $this->no_mc_groups ) ) {
-			unset( $this->cache[$key] );
-			return true;
-		}
+			if ( in_array( $group, $this->no_mc_groups ) ) {
+				$this->cache[ $key ] = $data;
 
-		$mc =& $this->get_mc( $group );
+				return true;
+			} elseif ( isset( $this->cache[ $key ] ) && $this->cache[ $key ] !== false ) {
+				return false;
+			}
+
+			$mc     =& $this->get_mc( $group );
+			$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
+			$result = $mc->add( $key, $data, $expire );
 
-		$result = $mc->delete( $key );
+			if ( false !== $result ) {
+				++ $this->stats['add'];
+				$this->group_ops[ $group ][] = "add $id";
+				$this->cache[ $key ]         = $data;
+			}
 
-		if ( false !== $result ) {
-			++$this->stats['delete'];
-			$this->group_ops[$group][] = "delete $id";
-			unset( $this->cache[$key] );
+			return $result;
 		}
 
-		return $result;
-	}
+		function add_global_groups( $groups ) {
+			if ( ! is_array( $groups ) ) {
+				$groups = (array) $groups;
+			}
 
-	function flush() {
-		// Don't flush if multi-blog.
-		if ( function_exists( 'is_site_admin' ) || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) )
-			return true;
+			$this->global_groups = array_merge( $this->global_groups, $groups );
+			$this->global_groups = array_unique( $this->global_groups );
+		}
 
-		$ret = true;
-		foreach ( array_keys( $this->mc ) as $group )
-			$ret &= $this->mc[$group]->flush();
-		return $ret;
-	}
+		public function add_multiple( array $data, $group = '', $expire = 0 ) {
+			$values = array();
 
-	function get( $id, $group = 'default', $force = false, &$found = null ) {
-		$key = $this->key( $id, $group );
-		$mc =& $this->get_mc( $group );
-		$found = false;
-
-		if ( isset( $this->cache[$key] ) && ( !$force || in_array( $group, $this->no_mc_groups ) ) ) {
-			$found = true;
-			if ( is_object( $this->cache[$key] ) )
-				$value = clone $this->cache[$key];
-			else
-				$value = $this->cache[$key];
-		} else if ( in_array( $group, $this->no_mc_groups ) ) {
-			$this->cache[$key] = $value = false;
-		} else {
-			$value = $mc->get( $key );
-			if ( empty( $value ) || ( is_integer( $value ) && -1 == $value ) ){
-				$value = false;
-				$found = $mc->getResultCode() !== Memcached::RES_NOTFOUND;
-			} else {
-				$found = true;
+			foreach ( $data as $key => $value ) {
+				$values[ $key ] = $this->add( $key, $value, $group, $expire );
 			}
-			$this->cache[$key] = $value;
+
+			return $values;
 		}
 
-		if ( $found ) {
-			++$this->stats['get'];
-			$this->group_ops[$group][] = "get $id";
-		} else {
-			++$this->stats['miss'];
+
+		function add_non_persistent_groups( $groups ) {
+			if ( ! is_array( $groups ) ) {
+				$groups = (array) $groups;
+			}
+
+			$this->no_mc_groups = array_merge( $this->no_mc_groups, $groups );
+			$this->no_mc_groups = array_unique( $this->no_mc_groups );
 		}
 
-		if ( 'checkthedatabaseplease' === $value ) {
-			unset( $this->cache[$key] );
-			$value = false;
+		function incr( $id, $n = 1, $group = 'default' ) {
+			$key                 = $this->key( $id, $group );
+			$mc                  =& $this->get_mc( $group );
+			$this->cache[ $key ] = $mc->increment( $key, $n );
+
+			return $this->cache[ $key ];
 		}
 
-		return $value;
-	}
+		function decr( $id, $n = 1, $group = 'default' ) {
+			$key                 = $this->key( $id, $group );
+			$mc                  =& $this->get_mc( $group );
+			$this->cache[ $key ] = $mc->decrement( $key, $n );
 
-	function get_multi( $keys, $group = 'default' ) {
-		$return = array();
-		$gets = array();
-		foreach ( $keys as $i => $values ) {
-			$mc =& $this->get_mc( $group );
-			$values = (array) $values;
-			if ( empty( $values[1] ) )
-				$values[1] = 'default';
+			return $this->cache[ $key ];
+		}
 
-			list( $id, $group ) = (array) $values;
+		function close() {
+			// Silence is Golden.
+		}
+
+		function delete( $id, $group = 'default' ) {
 			$key = $this->key( $id, $group );
 
-			if ( isset( $this->cache[$key] ) ) {
+			if ( in_array( $group, $this->no_mc_groups ) ) {
+				unset( $this->cache[ $key ] );
 
-				if ( is_object( $this->cache[$key] ) )
-					$return[$key] = clone $this->cache[$key];
-				else
-					$return[$key] = $this->cache[$key];
+				return true;
+			}
 
-			} else if ( in_array( $group, $this->no_mc_groups ) ) {
-				$return[$key] = false;
+			$mc =& $this->get_mc( $group );
 
-			} else {
-				$gets[$key] = $key;
+			$result = $mc->delete( $key );
+
+			if ( false !== $result ) {
+				++ $this->stats['delete'];
+				$this->group_ops[ $group ][] = "delete $id";
+				unset( $this->cache[ $key ] );
 			}
+
+			return $result;
 		}
 
-		if ( !empty( $gets ) ) {
-			$results = $mc->getMulti( $gets, $null, Memcached::GET_PRESERVE_ORDER );
-			$joined = array_combine( array_keys( $gets ), array_values( $results ) );
-			$return = array_merge( $return, $joined );
+		public function delete_multiple( array $keys, $group = '' ) {
+			$values = array();
+
+			foreach ( $keys as $key ) {
+				$values[ $key ] = $this->delete( $key, $group );
+			}
+
+			return $values;
 		}
 
-		++$this->stats['get_multi'];
-		$this->group_ops[$group][] = "get_multi $id";
-		$this->cache = array_merge( $this->cache, $return );
-		return array_values( $return );
-	}
+		function flush() {
+			// Don't flush if multi-blog.
+			if ( function_exists( 'is_site_admin' ) || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) {
+				return true;
+			}
+
+			$ret = true;
+			foreach ( array_keys( $this->mc ) as $group ) {
+				$ret &= $this->mc[ $group ]->flush();
+			}
 
-	function key( $key, $group ) {
-		if ( empty( $group ) )
-			$group = 'default';
+			return $ret;
+		}
 
-		if ( false !== array_search( $group, $this->global_groups ) )
-			$prefix = $this->global_prefix;
-		else
-			$prefix = $this->blog_prefix;
+		function get( $id, $group = 'default', $force = false, &$found = null ) {
+			$key   = $this->key( $id, $group );
+			$mc    =& $this->get_mc( $group );
+			$found = false;
 
-		return preg_replace( '/\s+/', '', WP_CACHE_KEY_SALT . "$prefix$group:$key" );
-	}
+			if ( isset( $this->cache[ $key ] ) && ( ! $force || in_array( $group, $this->no_mc_groups ) ) ) {
+				$found = true;
+				if ( is_object( $this->cache[ $key ] ) ) {
+					$value = clone $this->cache[ $key ];
+				} else {
+					$value = $this->cache[ $key ];
+				}
+			} else if ( in_array( $group, $this->no_mc_groups ) ) {
+				$this->cache[ $key ] = $value = false;
+			} else {
+				$value = $mc->get( $key );
+				if ( empty( $value ) || ( is_integer( $value ) && - 1 == $value ) ) {
+					$value = false;
+					$found = $mc->getResultCode() !== Memcached::RES_NOTFOUND;
+				} else {
+					$found = true;
+				}
+				$this->cache[ $key ] = $value;
+			}
+
+			if ( $found ) {
+				++ $this->stats['get'];
+				$this->group_ops[ $group ][] = "get $id";
+			} else {
+				++ $this->stats['miss'];
+			}
+
+			if ( 'checkthedatabaseplease' === $value ) {
+				unset( $this->cache[ $key ] );
+				$value = false;
+			}
 
-	function replace( $id, $data, $group = 'default', $expire = 0 ) {
-		$key = $this->key( $id, $group );
-		$expire = ( $expire == 0) ? $this->default_expiration : $expire;
-		$mc =& $this->get_mc( $group );
+			return $value;
+		}
 
-		if ( is_object( $data ) )
-			$data = clone $data;
+		public function get_multiple( $keys, $group = 'default' ) {
+			$return = array();
+			$gets   = array();
+			foreach ( $keys as $i => $values ) {
+				$mc     =& $this->get_mc( $group );
+				$values = (array) $values;
+				if ( empty( $values[1] ) ) {
+					$values[1] = 'default';
+				}
+
+				list( $id, $group ) = (array) $values;
+				$key = $this->key( $id, $group );
+
+				if ( isset( $this->cache[ $key ] ) ) {
+
+					if ( is_object( $this->cache[ $key ] ) ) {
+						$return[ $key ] = clone $this->cache[ $key ];
+					} else {
+						$return[ $key ] = $this->cache[ $key ];
+					}
+
+				} else if ( in_array( $group, $this->no_mc_groups ) ) {
+					$return[ $key ] = false;
+
+				} else {
+					$gets[ $key ] = $key;
+				}
+			}
 
-		$result = $mc->replace( $key, $data, $expire );
-		if ( false !== $result )
-			$this->cache[$key] = $data;
-		return $result;
-	}
+			if ( ! empty( $gets ) ) {
+				$results = $mc->getMulti( $gets, $null, Memcached::GET_PRESERVE_ORDER );
+				$joined  = array_combine( array_keys( $gets ), array_values( $results ) );
+				$return  = array_merge( $return, $joined );
+			}
 
-	function set( $id, $data, $group = 'default', $expire = 0 ) {
-		$key = $this->key( $id, $group );
-		if ( isset( $this->cache[$key] ) && ( 'checkthedatabaseplease' === $this->cache[$key] ) )
-			return false;
+			++ $this->stats['get_multi'];
+			$this->group_ops[ $group ][] = "get_multi $id";
+			$this->cache                 = array_merge( $this->cache, $return );
 
-		if ( is_object( $data) )
-			$data = clone $data;
+			return array_values( $return );
+		}
 
-		$this->cache[$key] = $data;
+		function get_multi( $keys, $group = 'default' ) {
+			$return = array();
+			$gets   = array();
+			foreach ( $keys as $i => $values ) {
+				$mc     =& $this->get_mc( $group );
+				$values = (array) $values;
+				if ( empty( $values[1] ) ) {
+					$values[1] = 'default';
+				}
+
+				list( $id, $group ) = (array) $values;
+				$key = $this->key( $id, $group );
+
+				if ( isset( $this->cache[ $key ] ) ) {
+
+					if ( is_object( $this->cache[ $key ] ) ) {
+						$return[ $key ] = clone $this->cache[ $key ];
+					} else {
+						$return[ $key ] = $this->cache[ $key ];
+					}
+
+				} else if ( in_array( $group, $this->no_mc_groups ) ) {
+					$return[ $key ] = false;
+
+				} else {
+					$gets[ $key ] = $key;
+				}
+			}
 
-		if ( in_array( $group, $this->no_mc_groups ) )
-			return true;
+			if ( ! empty( $gets ) ) {
+				$results = $mc->getMulti( $gets, $null, Memcached::GET_PRESERVE_ORDER );
+				$joined  = array_combine( array_keys( $gets ), array_values( $results ) );
+				$return  = array_merge( $return, $joined );
+			}
 
-		$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
-		$mc =& $this->get_mc( $group );
-		$result = $mc->set( $key, $data, $expire );
+			++ $this->stats['get_multi'];
+			$this->group_ops[ $group ][] = "get_multi $id";
+			$this->cache                 = array_merge( $this->cache, $return );
 
-		return $result;
-	}
+			return array_values( $return );
+		}
+
+		function key( $key, $group ) {
+			if ( empty( $group ) ) {
+				$group = 'default';
+			}
+
+			if ( false !== array_search( $group, $this->global_groups ) ) {
+				$prefix = $this->global_prefix;
+			} else {
+				$prefix = $this->blog_prefix;
+			}
+
+			return preg_replace( '/\s+/', '', WP_CACHE_KEY_SALT . "$prefix$group:$key" );
+		}
 
-	function set_multi( $items, $expire = 0, $group = 'default' ) {
-		$sets = array();
-		$mc =& $this->get_mc( $group );
-		$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
+		function replace( $id, $data, $group = 'default', $expire = 0 ) {
+			$key    = $this->key( $id, $group );
+			$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
+			$mc     =& $this->get_mc( $group );
+
+			if ( is_object( $data ) ) {
+				$data = clone $data;
+			}
 
-		foreach ( $items as $i => $item ) {
-			if ( empty( $item[2] ) )
-				$item[2] = 'default';
+			$result = $mc->replace( $key, $data, $expire );
+			if ( false !== $result ) {
+				$this->cache[ $key ] = $data;
+			}
 
-			list( $id, $data, $group ) = $item;
+			return $result;
+		}
 
+		function set( $id, $data, $group = 'default', $expire = 0 ) {
 			$key = $this->key( $id, $group );
-			if ( isset( $this->cache[$key] ) && ( 'checkthedatabaseplease' === $this->cache[$key] ) )
-				continue;
+			if ( isset( $this->cache[ $key ] ) && ( 'checkthedatabaseplease' === $this->cache[ $key ] ) ) {
+				return false;
+			}
 
-			if ( is_object( $data) )
+			if ( is_object( $data ) ) {
 				$data = clone $data;
+			}
 
-			$this->cache[$key] = $data;
+			$this->cache[ $key ] = $data;
 
-			if ( in_array( $group, $this->no_mc_groups ) )
-				continue;
+			if ( in_array( $group, $this->no_mc_groups ) ) {
+				return true;
+			}
+
+			$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
+			$mc     =& $this->get_mc( $group );
+			$result = $mc->set( $key, $data, $expire );
 
-			$sets[$key] = $data;
+			return $result;
 		}
 
-		if ( !empty( $sets ) )
-			$mc->setMulti( $sets, $expire );
-	}
+		function set_multiple( $items, $group = 'default', $expire = 0 ) {
+			$sets   = array();
+			$mc     =& $this->get_mc( $group );
+			$expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
 
-	function colorize_debug_line( $line ) {
-		$colors = array(
-			'get'   => 'green',
-			'set'   => 'purple',
-			'add'   => 'blue',
-			'delete'=> 'red'
-		);
+			foreach ( $items as $i => $item ) {
+				if ( empty( $item[2] ) ) {
+					$item[2] = 'default';
+				}
 
-		$cmd = substr( $line, 0, strpos( $line, ' ' ) );
+				list( $id, $data, $group ) = $item;
 
-		$cmd2 = "" . esc_html( $cmd ) . "";
+				$key = $this->key( $id, $group );
+				if ( isset( $this->cache[ $key ] ) && ( 'checkthedatabaseplease' === $this->cache[ $key ] ) ) {
+					continue;
+				}
 
-		return $cmd2 . esc_html( substr( $line, strlen( $cmd ) ) ) . "\n";
-	}
+				if ( is_object( $data ) ) {
+					$data = clone $data;
+				}
+
+				$this->cache[ $key ] = $data;
 
-	function stats() {
-		echo "

\n"; - foreach ( $this->stats as $stat => $n ) { - echo "" . esc_html( $stat ) . " " . esc_html( $n ); - echo "
\n"; + if ( in_array( $group, $this->no_mc_groups ) ) { + continue; + } + + $sets[ $key ] = $data; + } + + if ( ! empty( $sets ) ) { + $mc->setMulti( $sets, $expire ); + } } - echo "

\n"; - echo "

Memcached:

"; - foreach ( $this->group_ops as $group => $ops ) { - if ( !isset( $_GET['debug_queries'] ) && 500 < count( $ops ) ) { - $ops = array_slice( $ops, 0, 500 ); - echo "Too many to show! Show them anyway.\n"; } - echo "

" . esc_html( $group ) . " commands

"; - echo "
\n";
-			$lines = array();
-			foreach ( $ops as $op ) {
-				$lines[] = $this->colorize_debug_line( $op );
-			}
-			print_r( $lines );
-			echo "
\n"; + + function set_multi( $items, $expire = 0, $group = 'default' ) { + $sets = array(); + $mc =& $this->get_mc( $group ); + $expire = ( $expire == 0 ) ? $this->default_expiration : $expire; + + foreach ( $items as $i => $item ) { + if ( empty( $item[2] ) ) { + $item[2] = 'default'; + } + + list( $id, $data, $group ) = $item; + + $key = $this->key( $id, $group ); + if ( isset( $this->cache[ $key ] ) && ( 'checkthedatabaseplease' === $this->cache[ $key ] ) ) { + continue; + } + + if ( is_object( $data ) ) { + $data = clone $data; + } + + $this->cache[ $key ] = $data; + + if ( in_array( $group, $this->no_mc_groups ) ) { + continue; + } + + $sets[ $key ] = $data; + } + + if ( ! empty( $sets ) ) { + $mc->setMulti( $sets, $expire ); + } } - if ( !empty( $this->debug ) && $this->debug ) - var_dump( $this->memcache_debug ); - } + function colorize_debug_line( $line ) { + $colors = array( + 'get' => 'green', + 'set' => 'purple', + 'add' => 'blue', + 'delete' => 'red' + ); - function &get_mc( $group ) { - if ( isset( $this->mc[$group] ) ) - return $this->mc[$group]; - return $this->mc['default']; - } + $cmd = substr( $line, 0, strpos( $line, ' ' ) ); + + $cmd2 = "" . esc_html( $cmd ) . ""; + + return $cmd2 . esc_html( substr( $line, strlen( $cmd ) ) ) . "\n"; + } - function __construct() { - - $this->stats = array( - 'get' => 0, - 'get_multi' => 0, - 'add' => 0, - 'set' => 0, - 'delete' => 0, - 'miss' => 0, - ); - - global $memcached_servers; - - if ( isset( $memcached_servers ) ) - $buckets = $memcached_servers; - else - $buckets = array( '127.0.0.1' ); - - reset( $buckets ); - if ( is_int( key( $buckets ) ) ) - $buckets = array( 'default' => $buckets ); - - foreach ( $buckets as $bucket => $servers ) { - $this->mc[$bucket] = new Memcached(); - - $instances = array(); - foreach ( $servers as $server ) { - @list( $node, $port ) = explode( ':', $server ); - if ( empty( $port ) ) - $port = ini_get( 'memcache.default_port' ); - $port = intval( $port ); - if ( !$port ) - $port = 11211; - - $instances[] = array( $node, $port, 1 ); - } - $this->mc[$bucket]->addServers( $instances ); + function stats() { + echo "

\n"; + foreach ( $this->stats as $stat => $n ) { + echo "" . esc_html( $stat ) . " " . esc_html( $n ); + echo "
\n"; + } + echo "

\n"; + echo "

Memcached:

"; + foreach ( $this->group_ops as $group => $ops ) { + if ( ! isset( $_GET['debug_queries'] ) && 500 < count( $ops ) ) { + $ops = array_slice( $ops, 0, 500 ); + echo "Too many to show! Show them anyway.\n"; + } + echo "

" . esc_html( $group ) . " commands

"; + echo "
\n";
+				$lines = array();
+				foreach ( $ops as $op ) {
+					$lines[] = $this->colorize_debug_line( $op );
+				}
+				print_r( $lines );
+				echo "
\n"; + } + + if ( ! empty( $this->debug ) && $this->debug ) { + var_dump( $this->memcache_debug ); + } } - global $blog_id, $table_prefix; - $this->global_prefix = ''; - $this->blog_prefix = ''; - if ( function_exists( 'is_multisite' ) ) { - $this->global_prefix = ( is_multisite() || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix; - $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ) . ':'; + function &get_mc( $group ) { + if ( isset( $this->mc[ $group ] ) ) { + return $this->mc[ $group ]; + } + + return $this->mc['default']; } - $this->cache_hits =& $this->stats['get']; - $this->cache_misses =& $this->stats['miss']; + function __construct() { + + $this->stats = array( + 'get' => 0, + 'get_multi' => 0, + 'add' => 0, + 'set' => 0, + 'delete' => 0, + 'miss' => 0, + ); + + global $memcached_servers; + + if ( isset( $memcached_servers ) ) { + $buckets = $memcached_servers; + } else { + $buckets = array( '127.0.0.1:11211' ); + } + + reset( $buckets ); + if ( is_int( key( $buckets ) ) ) { + $buckets = array( 'default' => $buckets ); + } + + foreach ( $buckets as $bucket => $servers ) { + $this->mc[ $bucket ] = new Memcached(); + + $instances = array(); + foreach ( $servers as $server ) { + @list( $node, $port ) = explode( ':', $server ); + if ( empty( $port ) ) { + $port = ini_get( 'memcache.default_port' ); + } + $port = intval( $port ); + if ( ! $port ) { + $port = 11211; + } + + $instances[] = array( $node, $port, 1 ); + } + $this->mc[ $bucket ]->addServers( $instances ); + } + + global $blog_id, $table_prefix; + $this->global_prefix = ''; + $this->blog_prefix = ''; + if ( function_exists( 'is_multisite' ) ) { + $this->global_prefix = ( is_multisite() || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix; + $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ) . ':'; + } + + $this->cache_hits =& $this->stats['get']; + $this->cache_misses =& $this->stats['miss']; + } } -} else: // No Memcached // In 3.7+, we can handle this smoothly if ( function_exists( 'wp_using_ext_object_cache' ) ) { wp_using_ext_object_cache( false ); - // In earlier versions, there isn't a clean bail-out method. + // In earlier versions, there isn't a clean bail-out method. } else { wp_die( 'Memcached class not available.' ); } -endif; \ No newline at end of file +endif; From 8f74747f04f8cfbbdb9e4606e5de8aa00c890f55 Mon Sep 17 00:00:00 2001 From: mustafauysal Date: Mon, 8 May 2023 17:06:35 +0300 Subject: [PATCH 3/6] Add wp_cache_supports --- object-cache.php | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/object-cache.php b/object-cache.php index 7eb7d72..20e7a6d 100644 --- a/object-cache.php +++ b/object-cache.php @@ -2,7 +2,7 @@ /* Plugin Name: Memcached Redux Description: The real Memcached (not Memcache) backend for the WP Object Cache. -Version: 0.1.8 +Version: 0.1.9 Plugin URI: https://github.com/Ipstenu/memcached-redux Author: Scott Taylor - uses code from Ryan Boren, Denis de Bernardy, Matt Martz, Mike Schroder, Mika Epstein @@ -15,6 +15,30 @@ if ( class_exists( 'Memcached' ) ): + /** + * Determines whether the object cache implementation supports a particular feature. + * + * @param string $feature Name of the feature to check for. Possible values include: + * 'add_multiple', 'set_multiple', 'get_multiple', 'delete_multiple', + * 'flush_runtime', 'flush_group'. + * + * @return bool True if the feature is supported, false otherwise. + * @since 0.1.9 + * + */ + function wp_cache_supports( $feature ) { + switch ( $feature ) { + case 'add_multiple': + case 'set_multiple': + case 'get_multiple': + case 'delete_multiple': + return true; + + default: + return false; + } + } + function wp_cache_add( $key, $data, $group = '', $expire = 0 ) { global $wp_object_cache; From 855a76ee764d6bed90c17592b67848ad5e3b7a4c Mon Sep 17 00:00:00 2001 From: mustafauysal Date: Wed, 10 May 2023 14:01:25 +0300 Subject: [PATCH 4/6] Update memcached redux --- object-cache.php | 64 ++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/object-cache.php b/object-cache.php index 20e7a6d..84997cc 100644 --- a/object-cache.php +++ b/object-cache.php @@ -2,7 +2,7 @@ /* Plugin Name: Memcached Redux Description: The real Memcached (not Memcache) backend for the WP Object Cache. -Version: 0.1.9 +Version: 0.2 Plugin URI: https://github.com/Ipstenu/memcached-redux Author: Scott Taylor - uses code from Ryan Boren, Denis de Bernardy, Matt Martz, Mike Schroder, Mika Epstein @@ -30,6 +30,7 @@ function wp_cache_supports( $feature ) { switch ( $feature ) { case 'add_multiple': case 'set_multiple': + case 'flush_runtime': case 'get_multiple': case 'delete_multiple': return true; @@ -93,10 +94,10 @@ function wp_cache_get( $key, $group = '', $force = false, &$found = null ) { return $wp_object_cache->get( $key, $group, $force, $found ); } - function wp_cache_get_multiple( $keys, $group = '' ) { + function wp_cache_get_multiple( $keys, $group = '', $force = false ) { global $wp_object_cache; - return $wp_object_cache->get_multiple( $keys, $group ); + return $wp_object_cache->get_multiple( $keys, $group, $force ); } /** @@ -165,6 +166,13 @@ function wp_cache_add_non_persistent_groups( $groups ) { $wp_object_cache->add_non_persistent_groups( $groups ); } + function wp_cache_flush_runtime() { + global $wp_object_cache; + + return $wp_object_cache->flush_runtime(); + } + + class WP_Object_Cache { var $global_groups = array(); @@ -255,6 +263,13 @@ function close() { // Silence is Golden. } + function flush_runtime() { + $this->cache = array(); + $this->group_ops = array(); + + return true; + } + function delete( $id, $group = 'default' ) { $key = $this->key( $id, $group ); @@ -341,46 +356,14 @@ function get( $id, $group = 'default', $force = false, &$found = null ) { return $value; } - public function get_multiple( $keys, $group = 'default' ) { - $return = array(); - $gets = array(); - foreach ( $keys as $i => $values ) { - $mc =& $this->get_mc( $group ); - $values = (array) $values; - if ( empty( $values[1] ) ) { - $values[1] = 'default'; - } - - list( $id, $group ) = (array) $values; - $key = $this->key( $id, $group ); - - if ( isset( $this->cache[ $key ] ) ) { - - if ( is_object( $this->cache[ $key ] ) ) { - $return[ $key ] = clone $this->cache[ $key ]; - } else { - $return[ $key ] = $this->cache[ $key ]; - } - - } else if ( in_array( $group, $this->no_mc_groups ) ) { - $return[ $key ] = false; - - } else { - $gets[ $key ] = $key; - } - } + public function get_multiple( $keys, $group = 'default', $force = false) { + $values = array(); - if ( ! empty( $gets ) ) { - $results = $mc->getMulti( $gets, $null, Memcached::GET_PRESERVE_ORDER ); - $joined = array_combine( array_keys( $gets ), array_values( $results ) ); - $return = array_merge( $return, $joined ); + foreach ( $keys as $key ) { + $values[ $key ] = $this->get( $key, $group, $force ); } - ++ $this->stats['get_multi']; - $this->group_ops[ $group ][] = "get_multi $id"; - $this->cache = array_merge( $this->cache, $return ); - - return array_values( $return ); + return $values; } function get_multi( $keys, $group = 'default' ) { @@ -667,3 +650,4 @@ function __construct() { } endif; + From 78b0d00cbf0430e35b0df24903c83bb911ea4e44 Mon Sep 17 00:00:00 2001 From: mustafauysal Date: Tue, 30 May 2023 19:06:34 +0300 Subject: [PATCH 5/6] fix set_multiple --- object-cache.php | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/object-cache.php b/object-cache.php index 84997cc..1e0eb12 100644 --- a/object-cache.php +++ b/object-cache.php @@ -2,7 +2,7 @@ /* Plugin Name: Memcached Redux Description: The real Memcached (not Memcache) backend for the WP Object Cache. -Version: 0.2 +Version: 0.2.1 Plugin URI: https://github.com/Ipstenu/memcached-redux Author: Scott Taylor - uses code from Ryan Boren, Denis de Bernardy, Matt Martz, Mike Schroder, Mika Epstein @@ -462,39 +462,14 @@ function set( $id, $data, $group = 'default', $expire = 0 ) { return $result; } - function set_multiple( $items, $group = 'default', $expire = 0 ) { - $sets = array(); - $mc =& $this->get_mc( $group ); - $expire = ( $expire == 0 ) ? $this->default_expiration : $expire; - - foreach ( $items as $i => $item ) { - if ( empty( $item[2] ) ) { - $item[2] = 'default'; - } - - list( $id, $data, $group ) = $item; - - $key = $this->key( $id, $group ); - if ( isset( $this->cache[ $key ] ) && ( 'checkthedatabaseplease' === $this->cache[ $key ] ) ) { - continue; - } - - if ( is_object( $data ) ) { - $data = clone $data; - } - - $this->cache[ $key ] = $data; - - if ( in_array( $group, $this->no_mc_groups ) ) { - continue; - } + public function set_multiple( array $data, $group = '', $expire = 0 ) { + $values = array(); - $sets[ $key ] = $data; + foreach ( $data as $key => $value ) { + $values[ $key ] = $this->set( $key, $value, $group, $expire ); } - if ( ! empty( $sets ) ) { - $mc->setMulti( $sets, $expire ); - } + return $values; } function set_multi( $items, $expire = 0, $group = 'default' ) { From 4ebc8a4821407be89164909a2efa381ee53cded3 Mon Sep 17 00:00:00 2001 From: mustafauysal Date: Mon, 4 Sep 2023 16:40:43 +0300 Subject: [PATCH 6/6] Add class properties to avoid Dynamic property warnings See: https://github.com/Automattic/wp-memcached/pull/149 --- object-cache.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/object-cache.php b/object-cache.php index 1e0eb12..696f33c 100644 --- a/object-cache.php +++ b/object-cache.php @@ -180,12 +180,37 @@ class WP_Object_Cache { var $cache = array(); var $mc = array(); - var $stats = array(); - var $group_ops = array(); + var $default_mcs = array(); + var $stats = array( + 'get' => 0, + 'get_local' => 0, + 'get_multi' => 0, + 'set' => 0, + 'set_local' => 0, + 'add' => 0, + 'delete' => 0, + 'delete_local' => 0, + 'slow-ops' => 0, + ); + var $group_ops = array(); + var $cache_hits = 0; + var $cache_misses = 0; + var $global_prefix = ''; + var $blog_prefix = ''; + var $key_salt = ''; + + var $flush_group = 'WP_Object_Cache'; + var $global_flush_group = 'WP_Object_Cache_global'; + var $flush_key = "flush_number_v4"; + var $old_flush_key = "flush_number"; + var $flush_number = array(); + var $global_flush_number = null; var $cache_enabled = true; var $default_expiration = 0; + var $time_start = 0; + function add( $id, $data, $group = 'default', $expire = 0 ) { $key = $this->key( $id, $group );