= 1.8.4 =

*2015-10-13*

* changes in HTML debug comment: instead of the former, single comment, now 2 comments are added. The first is added when the cache entry is generated; the second only appears if the page was served from the cached entry. Please note that this last bit will - should - change with every single refresh.
* backend code is now split into separate files
* more debug code
This commit is contained in:
Peter Molnar 2015-10-13 11:13:13 +01:00
parent 7b16741af8
commit 457ad184c4
9 changed files with 756 additions and 684 deletions

92
backends/apc.php Normal file
View file

@ -0,0 +1,92 @@
<?php
if (!class_exists('WP_FFPC_Backend_apc')):
class WP_FFPC_Backend_apc extends WP_FFPC_Backend {
/**
* init apc backend: test APC availability and set alive status
*/
protected function _init () {
/* verify apc functions exist, apc extension is loaded */
if ( ! function_exists( 'apc_cache_info' ) ) {
$this->log ( __translate__('APC extension missing', $this->plugin_constant ) );
return false;
}
/* verify apc is working */
if ( apc_cache_info("user",true) ) {
$this->log ( __translate__('backend OK', $this->plugin_constant ) );
$this->alive = true;
}
}
/**
* health checker for APC
*
* @return boolean Aliveness status
*
*/
protected function _status () {
$this->status = true;
return $this->alive;
}
/**
* get function for APC backend
*
* @param string $key Key to get values for
*
* @return mixed Fetched data based on key
*
*/
protected function _get ( &$key ) {
return apc_fetch( $key );
}
/**
* Set function for APC backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
* @return boolean APC store outcome
*/
protected function _set ( &$key, &$data, &$expire ) {
return apc_store( $key , $data , $expire );
}
/**
* Flushes APC user entry storage
*
* @return boolean APC flush outcome status
*
*/
protected function _flush ( ) {
return apc_clear_cache('user');
}
/**
* Removes entry from APC or flushes APC user entry storage
*
* @param mixed $keys Keys to clear, string or array
*/
protected function _clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
if ( ! apc_delete ( $key ) ) {
$this->log ( sprintf( __translate__( 'Failed to delete APC entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
//throw new Exception ( __translate__('Deleting APC entry failed with key ', $this->plugin_constant ) . $key );
}
else {
$this->log ( sprintf( __translate__( 'APC entry delete: %s', $this->plugin_constant ), $key ) );
}
}
}
}
endif;

92
backends/apcu.php Normal file
View file

@ -0,0 +1,92 @@
<?php
if (!class_exists('WP_FFPC_Backend_apcu')):
class WP_FFPC_Backend_apcu extends WP_FFPC_Backend {
/**
* init apcu backend: test APCu availability and set alive status
*/
protected function _init () {
/* verify apcu functions exist, apcu extension is loaded */
if ( ! function_exists( 'apcu_cache_info' ) ) {
$this->log ( __translate__('APCu extension missing', $this->plugin_constant ) );
return false;
}
/* verify apcu is working */
if ( @apcu_cache_info("user") != false ) {
$this->log ( __translate__('backend OK', $this->plugin_constant ) );
$this->alive = true;
}
}
/**
* health checker for APC
*
* @return boolean Aliveness status
*
*/
protected function _status () {
$this->status = true;
return $this->alive;
}
/**
* get function for APC backend
*
* @param string $key Key to get values for
*
* @return mixed Fetched data based on key
*
*/
protected function _get ( &$key ) {
return apcu_fetch( $key );
}
/**
* Set function for APC backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
* @return boolean APC store outcome
*/
protected function _set ( &$key, &$data, &$expire ) {
return apcu_store( $key , $data , $expire );
}
/**
* Flushes APC user entry storage
*
* @return boolean APC flush outcome status
*
*/
protected function _flush ( ) {
return apcu_clear_cache();
}
/**
* Removes entry from APC or flushes APC user entry storage
*
* @param mixed $keys Keys to clear, string or array
*/
protected function _clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
if ( ! apcu_delete ( $key ) ) {
$this->log ( sprintf( __translate__( 'Failed to delete APC entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
//throw new Exception ( __translate__('Deleting APC entry failed with key ', $this->plugin_constant ) . $key );
}
else {
$this->log ( sprintf( __translate__( 'APC entry delete: %s', $this->plugin_constant ), $key ) );
}
}
}
}
endif;

122
backends/memcache.php Normal file
View file

@ -0,0 +1,122 @@
<?php
if (!class_exists('WP_FFPC_Backend_memcache')):
class WP_FFPC_Backend_memcache extends WP_FFPC_Backend {
/**
* init memcache backend
*/
protected function _init () {
/* Memcached class does not exist, Memcache extension is not available */
if (!class_exists('Memcache')) {
$this->log ( __translate__('PHP Memcache extension missing', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL )
$this->connection = new Memcache();
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Memcache PHP extension, exiting', $this->plugin_constant ) );
return false;
}
/* adding servers */
foreach ( $this->options['servers'] as $server_id => $server ) {
/* in case of unix socket */
if ( $server['port'] === 0 )
$this->status[$server_id] = $this->connection->connect ( 'unix:/' . $server['host'] );
else
$this->status[$server_id] = $this->connection->connect ( $server['host'] , $server['port'] );
$this->log ( sprintf( __translate__( '%s added', $this->plugin_constant ), $server_id ) );
}
/* backend is now alive */
$this->alive = true;
$this->_status();
}
/**
* check current backend alive status for Memcached
*
*/
protected function _status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server statuses", $this->plugin_constant ));
/* get servers statistic from connection */
foreach ( $this->options['servers'] as $server_id => $server ) {
if ( $server['port'] === 0 )
$this->status[$server_id] = $this->connection->getServerStatus( $server['host'], 11211 );
else
$this->status[$server_id] = $this->connection->getServerStatus( $server['host'], $server['port'] );
if ( $this->status[$server_id] == 0 )
$this->log ( sprintf( __translate__( '%s server is down', $this->plugin_constant ), $server_id ) );
else
$this->log ( sprintf( __translate__( '%s server is up & running', $this->plugin_constant ), $server_id ) );
}
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
protected function _get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
protected function _set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data , 0 , $expire );
return $result;
}
/**
*
* Flush memcached entries
*/
protected function _flush ( ) {
return $this->connection->flush();
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
protected function _clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
$kresult = $this->connection->delete( $key );
if ( $kresult === false ) {
$this->log ( sprintf( __translate__( 'unable to delete entry: %s', $this->plugin_constant ), $key ) );
}
else {
$this->log ( sprintf( __translate__( 'entry deleted: %s', $this->plugin_constant ), $key ) );
}
}
}
}
endif;

159
backends/memcached.php Normal file
View file

@ -0,0 +1,159 @@
<?php
if (!class_exists('WP_FFPC_Backend_memcached')):
class WP_FFPC_Backend_memcached extends WP_FFPC_Backend {
protected function _init () {
/* Memcached class does not exist, Memcached extension is not available */
if (!class_exists('Memcached')) {
$this->log ( __translate__(' Memcached extension missing, wp-ffpc will not be able to function correctly!', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("Memcached servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL ) {
$this->connection = new Memcached();
/* use binary and not compressed format, good for nginx and still fast */
$this->connection->setOption( Memcached::OPT_COMPRESSION , false );
if ($this->options['memcached_binary']){
$this->connection->setOption( Memcached::OPT_BINARY_PROTOCOL , true );
}
if ( version_compare( phpversion( 'memcached' ) , '2.0.0', '>=' ) && ini_get( 'memcached.use_sasl' ) == 1 && isset($this->options['authpass']) && !empty($this->options['authpass']) && isset($this->options['authuser']) && !empty($this->options['authuser']) ) {
$this->connection->setSaslAuthData ( $this->options['authuser'], $this->options['authpass']);
}
}
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Memcached PHP extension, exiting', $this->plugin_constant ) );
return false;
}
/* check if we already have list of servers, only add server(s) if it's not already connected */
$servers_alive = array();
if ( !empty ( $this->status ) ) {
$servers_alive = $this->connection->getServerList();
/* create check array if backend servers are already connected */
if ( !empty ( $servers ) ) {
foreach ( $servers_alive as $skey => $server ) {
$skey = $server['host'] . ":" . $server['port'];
$servers_alive[ $skey ] = true;
}
}
}
/* adding servers */
foreach ( $this->options['servers'] as $server_id => $server ) {
/* reset server status to unknown */
//$this->status[$server_id] = -1;
/* only add servers that does not exists already in connection pool */
if ( !@array_key_exists($server_id , $servers_alive ) ) {
$this->connection->addServer( $server['host'], $server['port'] );
$this->log ( sprintf( __translate__( '%s added', $this->plugin_constant ), $server_id ) );
}
}
/* backend is now alive */
$this->alive = true;
$this->_status();
}
/**
* sets current backend alive status for Memcached servers
*
*/
protected function _status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server statuses", $this->plugin_constant ));
/* get server list from connection */
$servers = $this->connection->getServerList();
foreach ( $servers as $server ) {
$server_id = $server['host'] . self::port_separator . $server['port'];
/* reset server status to offline */
$this->status[$server_id] = 0;
if ($this->connection->set($this->plugin_constant, time())) {
$this->log ( sprintf( __translate__( '%s server is up & running', $this->plugin_constant ), $server_id ) );
$this->status[$server_id] = 1;
}
}
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
protected function _get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
protected function _set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data , $expire );
/* if storing failed, log the error code */
if ( $result === false ) {
$code = $this->connection->getResultCode();
$this->log ( sprintf( __translate__( 'unable to set entry: %s', $this->plugin_constant ), $key ) );
$this->log ( sprintf( __translate__( 'Memcached error code: %s', $this->plugin_constant ), $code ) );
//throw new Exception ( __translate__('Unable to store Memcached entry ', $this->plugin_constant ) . $key . __translate__( ', error code: ', $this->plugin_constant ) . $code );
}
return $result;
}
/**
*
* Flush memcached entries
*/
protected function _flush ( ) {
return $this->connection->flush();
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
protected function _clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
$kresult = $this->connection->delete( $key );
if ( $kresult === false ) {
$code = $this->connection->getResultCode();
$this->log ( sprintf( __translate__( 'unable to delete entry: %s', $this->plugin_constant ), $key ) );
$this->log ( sprintf( __translate__( 'Memcached error code: %s', $this->plugin_constant ), $code ) );
}
else {
$this->log ( sprintf( __translate__( 'entry deleted: %s', $this->plugin_constant ), $key ) );
}
}
}
}
endif;

156
backends/redis.php Normal file
View file

@ -0,0 +1,156 @@
<?php
if (!class_exists('WP_FFPC_Backend_redis')):
class WP_FFPC_Backend_redis extends WP_FFPC_Backend {
protected function _init () {
/* Memcached class does not exist, Memcached extension is not available */
if (!class_exists('Redis')) {
$this->log ( __translate__('Redis extension missing, wp-ffpc will not be able to function correctly!', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("Redis servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL ) {
$this->connection = new Redis();
}
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Redis PHP extension, exiting', $this->plugin_constant ) );
return false;
}
/* check if we already have list of servers, only add server(s) if it's not already connected *
$servers_alive = array();
if ( !empty ( $this->status ) ) {
$servers_alive = $this->connection->getServerList();
/* create check array if backend servers are already connected *
if ( !empty ( $servers ) ) {
foreach ( $servers_alive as $skey => $server ) {
$skey = $server['host'] . ":" . $server['port'];
$servers_alive[ $skey ] = true;
}
}
}
/* adding servers */
foreach ( $this->options['servers'] as $server_id => $server ) {
/* only add servers that does not exists already in connection pool */
if ( !@array_key_exists($server_id , $servers_alive ) ) {
if ( $server['port'] != 0)
$this->connection->connect($server['host'], $server['port'] );
else
$this->connection->connect($server['host'] );
if ( isset($this->options['authpass']) && !empty($this->options['authpass']) )
$this->connection->auth ( $this->options['authpass'] );
$this->log ( sprintf( __translate__( '%s added', $this->plugin_constant ), $server_id ) );
}
}
/* backend is now alive */
$this->alive = true;
$this->_status();
}
/**
* sets current backend alive status for Memcached servers
*
*/
protected function _status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server status", $this->plugin_constant ));
try {
$info = $this->connection->ping();
} catch ( Exception $e ) {
$this->log ( __translate__("Exception occured: " . json_encode($e), $this->plugin_constant ));
}
$status = empty( $info ) ? 0 : 1;
foreach ( $this->options['servers'] as $server_id => $server ) {
/* reset server status to offline */
$this->status[$server_id] = $status;
}
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
protected function _get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
protected function _set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data, $expire );
/* if storing failed, log the error code */
//if ( $result === false ) {
$this->log ( sprintf( __translate__( 'set entry returned: %s', $this->plugin_constant ), $result ) );
//}
return $result;
}
/**
*
* Flush memcached entries
*/
protected function _flush ( ) {
try {
$r = $this->connection->flushDB();
} catch ( Exception $e ) {
$this->log ( sprintf( __translate__( 'unable to flush, error: %s', $this->plugin_constant ), json_encode($r) ) );
}
return $r;
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
protected function _clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
try {
$kresult = $this->connection->delete( $keys );
} catch ( Exception $e ) {
$this->log ( sprintf( __translate__( 'unable to delete entry(s): %s', $this->plugin_constant ), json_encode($key) ) );
$this->log ( sprintf( __translate__( 'Redis error: %s', $this->plugin_constant ), json_encode($e) ) );
}
finally {
$this->log ( sprintf( __translate__( 'entry(s) deleted: %s', $this->plugin_constant ), json_encode($keys) ) );
}
}
}
endif;

View file

@ -3,7 +3,7 @@ Contributors: cadeyrn, ameir, haroldkyle, plescheff, dkcwd, IgorCode
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XU3DG7LLA76WC Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XU3DG7LLA76WC
Tags: cache, page cache, full page cache, nginx, memcached, apc, speed Tags: cache, page cache, full page cache, nginx, memcached, apc, speed
Requires at least: 3.0 Requires at least: 3.0
Tested up to: 4.2.1 Tested up to: 4.3.1
Stable tag: 1.8.4 Stable tag: 1.8.4
License: GPLv3 License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.html License URI: http://www.gnu.org/licenses/gpl-3.0.html
@ -78,6 +78,7 @@ Many thanks for donations, contributors, supporters, testers & bug reporters:
* Meint Post * Meint Post
* Knut Sparhell * Knut Sparhell
* Christian Kernbeis * Christian Kernbeis
* Gausden Barry
== Installation == == Installation ==
@ -128,9 +129,11 @@ Version numbering logic:
* every ..C indicates bugfixes for A.B version. * every ..C indicates bugfixes for A.B version.
= 1.8.4 = = 1.8.4 =
*2015-* *2015-10-13*
* changes in HTML debug comment: instead of the former, single comment, now 2 comments are added. The first is added when the cache entry is generated; the second only appears if the page was served from the cached entry. Please note that this last bit will - should - change with every single refresh. * changes in HTML debug comment: instead of the former, single comment, now 2 comments are added. The first is added when the cache entry is generated; the second only appears if the page was served from the cached entry. Please note that this last bit will - should - change with every single refresh.
* backend code is now split into separate files
* more debug code
= 1.8.3 = = 1.8.3 =
*2015-05-07* *2015-05-07*

View file

@ -3,6 +3,15 @@
* advanced cache worker of WordPress plugin WP-FFPC * advanced cache worker of WordPress plugin WP-FFPC
*/ */
if ( !function_exists ('__debug__') ) {
/* __ only availabe if we're running from the inside of wordpress, not in advanced-cache.php phase */
function __debug__ ( $text ) {
if ( defined('WP_FFPC__DEBUG_MODE') && WP_FFPC__DEBUG_MODE == true)
error_log ( __FILE__ . ': ' . $text );
}
}
/* check for WP cache enabled*/ /* check for WP cache enabled*/
if ( !WP_CACHE ) if ( !WP_CACHE )
return false; return false;
@ -26,12 +35,16 @@ if (!isset($wp_ffpc_config))
$wp_ffpc_uri = $_SERVER['REQUEST_URI']; $wp_ffpc_uri = $_SERVER['REQUEST_URI'];
/* no cache for robots.txt */ /* no cache for robots.txt */
if ( stripos($wp_ffpc_uri, 'robots.txt') ) if ( stripos($wp_ffpc_uri, 'robots.txt') ) {
__debug__ ( 'Skippings robots.txt hit');
return false; return false;
}
/* multisite files can be too large for memcached */ /* multisite files can be too large for memcached */
if ( function_exists('is_multisite') && stripos($wp_ffpc_uri, '/files/') && is_multisite() ) if ( function_exists('is_multisite') && stripos($wp_ffpc_uri, '/files/') && is_multisite() ) {
__debug__ ( 'Skippings multisite /files/ hit');
return false; return false;
}
/* check if config is network active: use network config */ /* check if config is network active: use network config */
if (!empty ( $wp_ffpc_config['network'] ) ) if (!empty ( $wp_ffpc_config['network'] ) )
@ -44,8 +57,10 @@ else
return false; return false;
/* no cache for uri with query strings, things usually go bad that way */ /* no cache for uri with query strings, things usually go bad that way */
if ( isset($wp_ffpc_config['nocache_dyn']) && !empty($wp_ffpc_config['nocache_dyn']) && stripos($wp_ffpc_uri, '?') !== false ) if ( isset($wp_ffpc_config['nocache_dyn']) && !empty($wp_ffpc_config['nocache_dyn']) && stripos($wp_ffpc_uri, '?') !== false ) {
__debug__ ( 'Dynamic url cache is disabled ( url with "?" ), skipping');
return false; return false;
}
/* check for cookies that will make us not cache the content, like logged in WordPress cookie */ /* check for cookies that will make us not cache the content, like logged in WordPress cookie */
if ( isset($wp_ffpc_config['nocache_cookies']) && !empty($wp_ffpc_config['nocache_cookies']) ) { if ( isset($wp_ffpc_config['nocache_cookies']) && !empty($wp_ffpc_config['nocache_cookies']) ) {
@ -56,6 +71,7 @@ if ( isset($wp_ffpc_config['nocache_cookies']) && !empty($wp_ffpc_config['nocach
/* check for any matches to user-added cookies to no-cache */ /* check for any matches to user-added cookies to no-cache */
foreach ( $nocache_cookies as $nocache_cookie ) { foreach ( $nocache_cookies as $nocache_cookie ) {
if( strpos( $n, $nocache_cookie ) === 0 ) { if( strpos( $n, $nocache_cookie ) === 0 ) {
__debug__ ( "Cookie exception matched: $n, skipping");
return false; return false;
} }
} }
@ -67,6 +83,7 @@ if ( isset($wp_ffpc_config['nocache_cookies']) && !empty($wp_ffpc_config['nocach
if ( isset($wp_ffpc_config['nocache_url']) && trim($wp_ffpc_config['nocache_url']) ) { if ( isset($wp_ffpc_config['nocache_url']) && trim($wp_ffpc_config['nocache_url']) ) {
$pattern = sprintf('#%s#', trim($wp_ffpc_config['nocache_url'])); $pattern = sprintf('#%s#', trim($wp_ffpc_config['nocache_url']));
if ( preg_match($pattern, $wp_ffpc_uri) ) { if ( preg_match($pattern, $wp_ffpc_uri) ) {
__debug__ ( "Cache exceptions matched, skipping");
return false; return false;
} }
} }
@ -75,7 +92,10 @@ if ( isset($wp_ffpc_config['nocache_url']) && trim($wp_ffpc_config['nocache_url'
$wp_ffpc_redirect = null; $wp_ffpc_redirect = null;
/* fires up the backend storage array with current config */ /* fires up the backend storage array with current config */
include_once ('wp-ffpc-backend.php'); include_once ('wp-ffpc-backend.php');
$wp_ffpc_backend = new WP_FFPC_Backend( $wp_ffpc_config ); $backend_class = 'WP_FFPC_Backend_' . $wp_ffpc_config['cache_type'];
$wp_ffpc_backend = new $backend_class ( $wp_ffpc_config );
//$wp_ffpc_backend = new WP_FFPC_Backend( $wp_ffpc_config );
/* no cache for for logged in users unless it's set /* no cache for for logged in users unless it's set
identifier cookies are listed in backend as var for easier usage identifier cookies are listed in backend as var for easier usage
@ -85,6 +105,7 @@ if ( !isset($wp_ffpc_config['cache_loggedin']) || $wp_ffpc_config['cache_loggedi
foreach ($_COOKIE as $n=>$v) { foreach ($_COOKIE as $n=>$v) {
foreach ( $wp_ffpc_backend->cookies as $nocache_cookie ) { foreach ( $wp_ffpc_backend->cookies as $nocache_cookie ) {
if( strpos( $n, $nocache_cookie ) === 0 ) { if( strpos( $n, $nocache_cookie ) === 0 ) {
__debug__ ( "No cache for cookie: $n, skipping");
return false; return false;
} }
} }
@ -95,13 +116,17 @@ if ( !isset($wp_ffpc_config['cache_loggedin']) || $wp_ffpc_config['cache_loggedi
$wp_ffpc_gentime = 0; $wp_ffpc_gentime = 0;
/* backend connection failed, no caching :( */ /* backend connection failed, no caching :( */
if ( $wp_ffpc_backend->status() === false ) if ( $wp_ffpc_backend->status() === false ) {
__debug__ ( "Backend offline, skipping");
return false; return false;
}
/* try to get data & meta keys for current page */ /* try to get data & meta keys for current page */
$wp_ffpc_keys = array ( 'meta' => $wp_ffpc_config['prefix_meta'], 'data' => $wp_ffpc_config['prefix_data'] ); $wp_ffpc_keys = array ( 'meta' => $wp_ffpc_config['prefix_meta'], 'data' => $wp_ffpc_config['prefix_data'] );
$wp_ffpc_values = array(); $wp_ffpc_values = array();
__debug__ ( "Trying to fetch entries");
foreach ( $wp_ffpc_keys as $internal => $key ) { foreach ( $wp_ffpc_keys as $internal => $key ) {
$key = $wp_ffpc_backend->key ( $key ); $key = $wp_ffpc_backend->key ( $key );
$value = $wp_ffpc_backend->get ( $key ); $value = $wp_ffpc_backend->get ( $key );
@ -309,6 +334,8 @@ function wp_ffpc_callback( $buffer ) {
if ( get_option ( 'default_ping_status' ) == 'open' ) if ( get_option ( 'default_ping_status' ) == 'open' )
$meta['pingback'] = get_bloginfo('pingback_url'); $meta['pingback'] = get_bloginfo('pingback_url');
$to_store = $buffer;
/* add generation info is option is set, but only to HTML */ /* add generation info is option is set, but only to HTML */
if ( $wp_ffpc_config['generate_time'] == '1' && stripos($buffer, '</body>') ) { if ( $wp_ffpc_config['generate_time'] == '1' && stripos($buffer, '</body>') ) {
global $wp_ffpc_gentime; global $wp_ffpc_gentime;

View file

@ -11,39 +11,29 @@ if ( !function_exists ('__translate__') ) {
} }
} }
/* this is the base class for all backends; the actual workers
* are included at the end of the file from backends/ directory */
if (!class_exists('WP_FFPC_Backend')) : if (!class_exists('WP_FFPC_Backend')) :
//include_once ( 'wp-common/plugin_utils.php');
/** abstract class WP_FFPC_Backend {
*
* @var string $plugin_constant Namespace of the plugin
* @var mixed $connection Backend object storage variable
* @var boolean $alive Alive flag of backend connection
* @var array $options Configuration settings array
* @var array $status Backends status storage
* @var array $cookies Logged in cookies to search for
* @var array $urimap Map to render key with
* @var object $utilities Utilities singleton
*
*/
class WP_FFPC_Backend {
const host_separator = ','; const host_separator = ',';
const port_separator = ':'; const port_separator = ':';
private $plugin_constant = 'wp-ffpc'; protected $plugin_constant = 'wp-ffpc';
private $connection = NULL; protected $connection = NULL;
private $alive = false; protected $alive = false;
private $options = array(); protected $options = array();
private $status = array(); protected $status = array();
public $cookies = array(); public $cookies = array();
private $urimap = array(); protected $urimap = array();
/** /**
* constructor * constructor
* *
* @param mixed $config Configuration options * @param mixed $config Configuration options
* @param boolean $network WordPress Network indicator flah
* *
*/ */
public function __construct( $config ) { public function __construct( $config ) {
@ -54,7 +44,6 @@ class WP_FFPC_Backend {
//die ( __translate__ ( 'WP-FFPC Backend class received empty configuration array, the plugin will not work this way', $this->plugin_constant ) ); //die ( __translate__ ( 'WP-FFPC Backend class received empty configuration array, the plugin will not work this way', $this->plugin_constant ) );
} }
/* set config */
$this->options = $config; $this->options = $config;
/* these are the list of the cookies to look for when looking for logged in user */ /* these are the list of the cookies to look for when looking for logged in user */
@ -79,16 +68,14 @@ class WP_FFPC_Backend {
'$cookie_PHPSESSID' => $scookie, '$cookie_PHPSESSID' => $scookie,
); );
/* split hosts entry to servers */ /* split single line hosts entry */
$this->set_servers(); $this->set_servers();
/* call backend initiator based on cache type */
$init = $this->proxy( 'init' );
/* info level */ /* info level */
$this->log ( __translate__('init starting', $this->plugin_constant )); $this->log ( __translate__('init starting', $this->plugin_constant ));
$this->$init();
/* call backend initiator based on cache type */
$init = $this->_init();
if (is_admin() && function_exists('add_filter')) { if (is_admin() && function_exists('add_filter')) {
add_filter('wp_ffpc_clear_keys_array', function($to_clear, $options) { add_filter('wp_ffpc_clear_keys_array', function($to_clear, $options) {
@ -105,7 +92,10 @@ class WP_FFPC_Backend {
} }
} }
/*
* @param string $uri
* @param mixed $default_urimap
*/
public static function parse_urimap($uri, $default_urimap=null) { public static function parse_urimap($uri, $default_urimap=null) {
$uri_parts = parse_url( $uri ); $uri_parts = parse_url( $uri );
@ -122,11 +112,14 @@ class WP_FFPC_Backend {
return $uri_map; return $uri_map;
} }
/**
* @param array $urimap
* @param string $subject
*/
public static function map_urimap($urimap, $subject) { public static function map_urimap($urimap, $subject) {
return str_replace(array_keys($urimap), $urimap, $subject); return str_replace(array_keys($urimap), $urimap, $subject);
} }
/*********************** PUBLIC / PROXY FUNCTIONS ***********************/
/** /**
* build key to make requests with * build key to make requests with
@ -140,7 +133,7 @@ class WP_FFPC_Backend {
$key_base = self::map_urimap($urimap, $this->options['key']); $key_base = self::map_urimap($urimap, $this->options['key']);
if ( isset($this->options['hashkey']) && $this->options['hashkey'] == true) if (( isset($this->options['hashkey']) && $this->options['hashkey'] == true) || $this->options['cache_type'] == 'redis' )
$key_base = sha1($key_base); $key_base = sha1($key_base);
$key = $prefix . $key_base; $key = $prefix . $key_base;
@ -161,17 +154,17 @@ class WP_FFPC_Backend {
*/ */
public function get ( &$key ) { public function get ( &$key ) {
/* look for backend aliveness, exit on inactive backend */ /* look for backend aliveness, exit on inactive backend */
if ( ! $this->is_alive() ) if ( ! $this->is_alive() ) {
$this->log ('WARNING: Backend offline');
return false; return false;
}
/* log the current action */ /* log the current action */
$this->log ( sprintf( __translate__( 'get %s', $this->plugin_constant ), $key ) ); $this->log ( sprintf( __translate__( 'GET %s', $this->plugin_constant ), $key ) );
/* proxy to internal function */ $result = $this->_get( $key );
$internal = $this->proxy( 'get' );
$result = $this->$internal( $key );
if ( $result === false ) if ( $result === false || $result === null )
$this->log ( sprintf( __translate__( 'failed to get entry: %s', $this->plugin_constant ), $key ) ); $this->log ( sprintf( __translate__( 'failed to get entry: %s', $this->plugin_constant ), $key ) );
return $result; return $result;
@ -203,18 +196,23 @@ class WP_FFPC_Backend {
elseif (( is_tax() || is_category() || is_tag() || is_archive() ) && isset($this->options['expire_taxonomy'])) elseif (( is_tax() || is_category() || is_tag() || is_archive() ) && isset($this->options['expire_taxonomy']))
$expire = (int) $this->options['expire_taxonomy']; $expire = (int) $this->options['expire_taxonomy'];
/* log the current action */
$this->log ( sprintf( __translate__( 'SET %s', $this->plugin_constant ), $key ) );
/* proxy to internal function */ /* proxy to internal function */
$internal = $this->proxy( 'set' ); $result = $this->_set( $key, $data, $expire );
$result = $this->$internal( $key, $data, $expire );
/* check result validity */ /* check result validity */
if ( $result === false ) if ( $result === false || $result === null )
$this->log ( sprintf( __translate__( 'failed to set entry: %s', $this->plugin_constant ), $key ), LOG_WARNING ); $this->log ( sprintf( __translate__( 'failed to set entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
return $result; return $result;
} }
/*
* next generation clean
*
*
*/
public function clear_ng ( $new_status, $old_status, $post ) { public function clear_ng ( $new_status, $old_status, $post ) {
$this->clear ( $post->ID ); $this->clear ( $post->ID );
} }
@ -224,7 +222,6 @@ class WP_FFPC_Backend {
* *
* @param string $post_id ID of post to invalidate * @param string $post_id ID of post to invalidate
* @param boolean $force Force flush cache * @param boolean $force Force flush cache
* @param boolean $comment Clear a single page based on comment trigger
* *
*/ */
public function clear ( $post_id = false, $force = false ) { public function clear ( $post_id = false, $force = false ) {
@ -245,8 +242,7 @@ class WP_FFPC_Backend {
$this->log ( __translate__('flushing cache', $this->plugin_constant ) ); $this->log ( __translate__('flushing cache', $this->plugin_constant ) );
/* proxy to internal function */ /* proxy to internal function */
$internal = $this->proxy ( 'flush' ); $internal = $this->_flush();
$result = $this->$internal();
if ( $result === false ) if ( $result === false )
$this->log ( __translate__('failed to flush cache', $this->plugin_constant ), LOG_WARNING ); $this->log ( __translate__('failed to flush cache', $this->plugin_constant ), LOG_WARNING );
@ -320,10 +316,13 @@ class WP_FFPC_Backend {
$this->clear_keys( $to_clear ); $this->clear_keys( $to_clear );
} }
/*
* unset entries by key
* @param array $keys
*/
public function clear_keys( $keys ) { public function clear_keys( $keys ) {
$to_clear = apply_filters('wp_ffpc_clear_keys_array', $keys, $this->options); $to_clear = apply_filters('wp_ffpc_clear_keys_array', $keys, $this->options);
$internal = $this->proxy ( 'clear' ); $this->_clear ( $to_clear );
$this->$internal ( $to_clear );
} }
/** /**
@ -422,28 +421,17 @@ class WP_FFPC_Backend {
if ( ! $this->is_alive() ) if ( ! $this->is_alive() )
return false; return false;
$internal = $this->proxy ( 'status' ); $internal = $this->_status();
$this->$internal();
return $this->status; return $this->status;
} }
/**
* backend proxy function name generator
*
* @return string Name of internal function based on cache_type
*
*/
private function proxy ( $method ) {
return $this->options['cache_type'] . '_' . $method;
}
/** /**
* function to check backend aliveness * function to check backend aliveness
* *
* @return boolean true if backend is alive, false if not * @return boolean true if backend is alive, false if not
* *
*/ */
private function is_alive() { protected function is_alive() {
if ( ! $this->alive ) { if ( ! $this->alive ) {
$this->log ( __translate__("backend is not active, exiting function ", $this->plugin_constant ) . __FUNCTION__, LOG_WARNING ); $this->log ( __translate__("backend is not active, exiting function ", $this->plugin_constant ) . __FUNCTION__, LOG_WARNING );
return false; return false;
@ -457,7 +445,10 @@ class WP_FFPC_Backend {
* *
* *
*/ */
private function set_servers () { protected function set_servers () {
if ( empty ($this->options['hosts']) )
return false;
/* replace servers array in config according to hosts field */ /* replace servers array in config according to hosts field */
$servers = explode( self::host_separator , $this->options['hosts']); $servers = explode( self::host_separator , $this->options['hosts']);
@ -465,11 +456,15 @@ class WP_FFPC_Backend {
foreach ( $servers as $snum => $sstring ) { foreach ( $servers as $snum => $sstring ) {
$separator = strpos( $sstring , self::port_separator ); if ( stristr($sstring, 'unix://' ) ) {
$host = substr( $sstring, 0, $separator ); $host = str_replace('unix:/','',$sstring);
$port = substr( $sstring, $separator + 1 ); $port = 0;
// unix socket failsafe }
if ( empty ($port) ) $port = 0; else {
$separator = strpos( $sstring , self::port_separator );
$host = substr( $sstring, 0, $separator );
$port = substr( $sstring, $separator + 1 );
}
$this->options['servers'][$sstring] = array ( $this->options['servers'][$sstring] = array (
'host' => $host, 'host' => $host,
@ -496,7 +491,7 @@ class WP_FFPC_Backend {
* @var mixed $message Message to log * @var mixed $message Message to log
* @var int $log_level Log level * @var int $log_level Log level
*/ */
private function log ( $message, $level = LOG_NOTICE ) { protected function log ( $message, $level = LOG_NOTICE ) {
if ( @is_array( $message ) || @is_object ( $message ) ) if ( @is_array( $message ) || @is_object ( $message ) )
$message = json_encode($message); $message = json_encode($message);
@ -514,601 +509,19 @@ class WP_FFPC_Backend {
error_log( __CLASS__ . ": " . $message ); error_log( __CLASS__ . ": " . $message );
} }
/*********************** END PUBLIC FUNCTIONS ***********************/
/*********************** APC FUNCTIONS ***********************/
/**
* init apc backend: test APC availability and set alive status
*/
private function apc_init () {
/* verify apc functions exist, apc extension is loaded */
if ( ! function_exists( 'apc_cache_info' ) ) {
$this->log ( __translate__('APC extension missing', $this->plugin_constant ) );
return false;
}
/* verify apc is working */
if ( apc_cache_info("user",true) ) {
$this->log ( __translate__('backend OK', $this->plugin_constant ) );
$this->alive = true;
}
}
/**
* health checker for APC
*
* @return boolean Aliveness status
*
*/
private function apc_status () {
$this->status = true;
return $this->alive;
}
/**
* get function for APC backend
*
* @param string $key Key to get values for
*
* @return mixed Fetched data based on key
*
*/
private function apc_get ( &$key ) {
return apc_fetch( $key );
}
/**
* Set function for APC backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
* @return boolean APC store outcome
*/
private function apc_set ( &$key, &$data, &$expire ) {
return apc_store( $key , $data , $expire );
}
/**
* Flushes APC user entry storage
*
* @return boolean APC flush outcome status
*
*/
private function apc_flush ( ) {
return apc_clear_cache('user');
}
/**
* Removes entry from APC or flushes APC user entry storage
*
* @param mixed $keys Keys to clear, string or array
*/
private function apc_clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
if ( ! apc_delete ( $key ) ) {
$this->log ( sprintf( __translate__( 'Failed to delete APC entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
//throw new Exception ( __translate__('Deleting APC entry failed with key ', $this->plugin_constant ) . $key );
}
else {
$this->log ( sprintf( __translate__( 'APC entry delete: %s', $this->plugin_constant ), $key ) );
}
}
}
/*********************** END APC FUNCTIONS ***********************/
/*********************** APCu FUNCTIONS ***********************/
/**
* init apcu backend: test APCu availability and set alive status
*/
private function apcu_init () {
/* verify apcu functions exist, apcu extension is loaded */
if ( ! function_exists( 'apcu_cache_info' ) ) {
$this->log ( __translate__('APCu extension missing', $this->plugin_constant ) );
return false;
}
/* verify apcu is working */
if ( apcu_cache_info("user") ) {
$this->log ( __translate__('backend OK', $this->plugin_constant ) );
$this->alive = true;
}
}
/**
* health checker for APC
*
* @return boolean Aliveness status
*
*/
private function apcu_status () {
$this->status = true;
return $this->alive;
}
/**
* get function for APC backend
*
* @param string $key Key to get values for
*
* @return mixed Fetched data based on key
*
*/
private function apcu_get ( &$key ) {
return apcu_fetch( $key );
}
/**
* Set function for APC backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
* @return boolean APC store outcome
*/
private function apcu_set ( &$key, &$data, &$expire ) {
return apcu_store( $key , $data , $expire );
}
/**
* Flushes APC user entry storage
*
* @return boolean APC flush outcome status
*
*/
private function apcu_flush ( ) {
return apcu_clear_cache();
}
/**
* Removes entry from APC or flushes APC user entry storage
*
* @param mixed $keys Keys to clear, string or array
*/
private function apcu_clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
if ( ! apcu_delete ( $key ) ) {
$this->log ( sprintf( __translate__( 'Failed to delete APC entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
//throw new Exception ( __translate__('Deleting APC entry failed with key ', $this->plugin_constant ) . $key );
}
else {
$this->log ( sprintf( __translate__( 'APC entry delete: %s', $this->plugin_constant ), $key ) );
}
}
}
/*********************** END APC FUNCTIONS ***********************/
/*********************** MEMCACHED FUNCTIONS ***********************/
/**
* init memcached backend
*/
private function memcached_init () {
/* Memcached class does not exist, Memcached extension is not available */
if (!class_exists('Memcached')) {
$this->log ( __translate__(' Memcached extension missing, wp-ffpc will not be able to function correctly!', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("Memcached servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL ) {
$this->connection = new Memcached();
/* use binary and not compressed format, good for nginx and still fast */
$this->connection->setOption( Memcached::OPT_COMPRESSION , false );
if ($this->options['memcached_binary']){
$this->connection->setOption( Memcached::OPT_BINARY_PROTOCOL , true );
}
if ( version_compare( phpversion( 'memcached' ) , '2.0.0', '>=' ) && ini_get( 'memcached.use_sasl' ) == 1 && isset($this->options['authpass']) && !empty($this->options['authpass']) && isset($this->options['authuser']) && !empty($this->options['authuser']) ) {
$this->connection->setSaslAuthData ( $this->options['authuser'], $this->options['authpass']);
}
}
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Memcached PHP extension, exiting', $this->plugin_constant ) );
return false;
}
/* check if we already have list of servers, only add server(s) if it's not already connected */
$servers_alive = array();
if ( !empty ( $this->status ) ) {
$servers_alive = $this->connection->getServerList();
/* create check array if backend servers are already connected */
if ( !empty ( $servers ) ) {
foreach ( $servers_alive as $skey => $server ) {
$skey = $server['host'] . ":" . $server['port'];
$servers_alive[ $skey ] = true;
}
}
}
/* adding servers */
foreach ( $this->options['servers'] as $server_id => $server ) {
/* reset server status to unknown */
$this->status[$server_id] = -1;
/* only add servers that does not exists already in connection pool */
if ( !@array_key_exists($server_id , $servers_alive ) ) {
$this->connection->addServer( $server['host'], $server['port'] );
$this->log ( sprintf( __translate__( '%s added', $this->plugin_constant ), $server_id ) );
}
}
/* backend is now alive */
$this->alive = true;
$this->memcached_status();
}
/**
* sets current backend alive status for Memcached servers
*
*/
private function memcached_status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server statuses", $this->plugin_constant ));
/* get server list from connection */
$servers = $this->connection->getServerList();
foreach ( $servers as $server ) {
$server_id = $server['host'] . self::port_separator . $server['port'];
/* reset server status to offline */
$this->status[$server_id] = 0;
if ($this->connection->set($this->plugin_constant, time())) {
$this->log ( sprintf( __translate__( '%s server is up & running', $this->plugin_constant ), $server_id ) );
$this->status[$server_id] = 1;
}
}
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
private function memcached_get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
private function memcached_set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data , $expire );
/* if storing failed, log the error code */
if ( $result === false ) {
$code = $this->connection->getResultCode();
$this->log ( sprintf( __translate__( 'unable to set entry: %s', $this->plugin_constant ), $key ) );
$this->log ( sprintf( __translate__( 'Memcached error code: %s', $this->plugin_constant ), $code ) );
//throw new Exception ( __translate__('Unable to store Memcached entry ', $this->plugin_constant ) . $key . __translate__( ', error code: ', $this->plugin_constant ) . $code );
}
return $result;
}
/**
*
* Flush memcached entries
*/
private function memcached_flush ( ) {
return $this->connection->flush();
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
private function memcached_clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
$kresult = $this->connection->delete( $key );
if ( $kresult === false ) {
$code = $this->connection->getResultCode();
$this->log ( sprintf( __translate__( 'unable to delete entry: %s', $this->plugin_constant ), $key ) );
$this->log ( sprintf( __translate__( 'Memcached error code: %s', $this->plugin_constant ), $code ) );
}
else {
$this->log ( sprintf( __translate__( 'entry deleted: %s', $this->plugin_constant ), $key ) );
}
}
}
/*********************** END MEMCACHED FUNCTIONS ***********************/
/*********************** MEMCACHE FUNCTIONS ***********************/
/**
* init memcache backend
*/
private function memcache_init () {
/* Memcached class does not exist, Memcache extension is not available */
if (!class_exists('Memcache')) {
$this->log ( __translate__('PHP Memcache extension missing', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL )
$this->connection = new Memcache();
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Memcache PHP extension, exiting', $this->plugin_constant ) );
return false;
}
/* adding servers */
foreach ( $this->options['servers'] as $server_id => $server ) {
/* in case of unix socket */
if ( $server['port'] === 0 )
$this->status[$server_id] = $this->connection->connect ( 'unix:/' . $server['host'] );
else
$this->status[$server_id] = $this->connection->connect ( $server['host'] , $server['port'] );
$this->log ( sprintf( __translate__( '%s added', $this->plugin_constant ), $server_id ) );
}
/* backend is now alive */
$this->alive = true;
$this->memcache_status();
}
/**
* check current backend alive status for Memcached
*
*/
private function memcache_status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server statuses", $this->plugin_constant ));
/* get servers statistic from connection */
foreach ( $this->options['servers'] as $server_id => $server ) {
if ( $server['port'] === 0 )
$this->status[$server_id] = $this->connection->getServerStatus( $server['host'], 11211 );
else
$this->status[$server_id] = $this->connection->getServerStatus( $server['host'], $server['port'] );
if ( $this->status[$server_id] == 0 )
$this->log ( sprintf( __translate__( '%s server is down', $this->plugin_constant ), $server_id ) );
else
$this->log ( sprintf( __translate__( '%s server is up & running', $this->plugin_constant ), $server_id ) );
}
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
private function memcache_get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
private function memcache_set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data , 0 , $expire );
return $result;
}
/**
*
* Flush memcached entries
*/
private function memcache_flush ( ) {
return $this->connection->flush();
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
private function memcache_clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
foreach ( $keys as $key => $dummy ) {
$kresult = $this->connection->delete( $key );
if ( $kresult === false ) {
$this->log ( sprintf( __translate__( 'unable to delete entry: %s', $this->plugin_constant ), $key ) );
}
else {
$this->log ( sprintf( __translate__( 'entry deleted: %s', $this->plugin_constant ), $key ) );
}
}
}
/*********************** END MEMCACHE FUNCTIONS ***********************/
/*********************** REDIS FUNCTIONS ***********************/
/**
* init memcache backend
*/
private function redis_init () {
if (!class_exists('Redis')) {
$this->log ( __translate__('PHP Redis extension missing', $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check for existing server list, otherwise we cannot add backends */
if ( empty ( $this->options['servers'] ) && ! $this->alive ) {
$this->log ( __translate__("servers list is empty, init failed", $this->plugin_constant ), LOG_WARNING );
return false;
}
/* check is there's no backend connection yet */
if ( $this->connection === NULL )
$this->connection = new Redis();
/* check if initialization was success or not */
if ( $this->connection === NULL ) {
$this->log ( __translate__( 'error initializing Redis extension, exiting', $this->plugin_constant ) );
return false;
}
//$this->connection->setOption(Redis::OPT_PREFIX, $this->plugin_constant );
/* adding server *
foreach ( $this->options['servers'] as $server_id => $server ) {
/* in case of unix socket *
if ( $server['port'] === 0 ) {
try {
$this->status[$server_id] = $this->connection->connect ( $server['host'] );
} catch ( RedisException $e ) {
$this->log ( sprintf( __translate__( 'adding %s to the Redis pool failed, error: %s', $this->plugin_constant ), $server['host'], $e ) );
}
}
else {
try {
$this->status[$server_id] = $this->connection->connect ( $server['host'] , $server['port'] );
} catch ( RedisException $e ) {
$this->log ( sprintf( __translate__( 'adding %s:%s to the Redis pool failed, error: %s', $this->plugin_constant ), $server['host'] , $server['port'], $e ) );
}
}
$this->log ( sprintf( __translate__( 'server #%s added', $this->plugin_constant ), $server_id ) );
}*/
/* adding server */
$key = array_unshift ( array_keys ( $this->options['servers'] ));
$server = array_unshift( $this->options['servers'] );
try {
if ( $server['port'] === 0 )
$this->status[$key] = $this->connection->connect ( $server['host'] );
else
$this->status[$key] = $this->connection->connect ( $server['host'], $server['port'] );
} catch ( RedisException $e ) {
$this->log ( sprintf( __translate__( 'adding %s to the Redis pool failed, error: %s', $this->plugin_constant ), $server['host'], $e ) );
}
$this->log ( sprintf( __translate__( 'server #%s added', $this->plugin_constant ), $server_id ) );
if ( !empty( $this->options['authpass'])) {
$auth = $this->connection->auth( $this->options['authpass'] );
if ( $auth == false ) {
$this->log ( __translate__( 'Redis authentication failed, exiting', $this->plugin_constant ), LOG_WARNING );
return false;
}
}
/* backend is now alive */
$this->alive = true;
$this->redis_status();
}
/**
* check current backend alive status for Memcached
*
*/
private function redis_status () {
/* server status will be calculated by getting server stats */
$this->log ( __translate__("checking server statuses", $this->plugin_constant ));
/* get servers statistic from connection */
try {
$this->connection->ping();
} catch ( RedisException $e ) {
$this->log ( sprintf( __translate__( 'Redis status check failed, error: %s', $this->plugin_constant ), $e ) );
}
$this->log ( sprintf( __translate__( 'Redis is up', $this->plugin_constant ), $server_id ) );
}
/**
* get function for Memcached backend
*
* @param string $key Key to get values for
*
*/
private function redis_get ( &$key ) {
return $this->connection->get($key);
}
/**
* Set function for Memcached backend
*
* @param string $key Key to set with
* @param mixed $data Data to set
*
*/
private function redis_set ( &$key, &$data, &$expire ) {
$result = $this->connection->set ( $key, $data , Array('nx', 'ex' => $expire) );
return $result;
}
/**
*
* Flush memcached entries
*/
private function redis_flush ( ) {
return $this->connection->flushDB();
}
/**
* Removes entry from Memcached or flushes Memcached storage
*
* @param mixed $keys String / array of string of keys to delete entries with
*/
private function redis_clear ( &$keys ) {
/* make an array if only one string is present, easier processing */
if ( !is_array ( $keys ) )
$keys = array ( $keys => true );
$kresults = $this->connection->delete( $keys );
foreach ( $kresults as $key => $value ) {
$this->log ( sprintf( __translate__( 'entry deleted: %s', $this->plugin_constant ), $value ) );
}
}
/*********************** END REDIS FUNCTIONS ***********************/
abstract protected function _init ();
abstract protected function _status ();
abstract protected function _get ( &$key );
abstract protected function _set ( &$key, &$data, &$expire );
abstract protected function _flush ();
abstract protected function _clear ( &$keys );
} }
endif; endif;
$wp_ffpc_backends = glob( dirname( __FILE__ ) . "/backends/*.php" );
foreach ( $wp_ffpc_backends as $backend )
include_once $backend;
unset( $wp_ffpc_backends, $backend );

View file

@ -85,7 +85,7 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
/* nginx sample config file */ /* nginx sample config file */
$this->nginx_sample = $this->plugin_dir . $this->plugin_constant . '-nginx-sample.conf'; $this->nginx_sample = $this->plugin_dir . $this->plugin_constant . '-nginx-sample.conf';
/* backend driver file */ /* backend driver file */
$this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-backend.php'; $this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-engine.php';
/* flush button identifier */ /* flush button identifier */
$this->button_flush = $this->plugin_constant . '-flush'; $this->button_flush = $this->plugin_constant . '-flush';
/* precache button identifier */ /* precache button identifier */
@ -181,7 +181,8 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
public function plugin_post_init () { public function plugin_post_init () {
/* initiate backend */ /* initiate backend */
$this->backend = new WP_FFPC_Backend ( $this->options ); $backend_class = 'WP_FFPC_Backend_' . $this->options['cache_type'];
$this->backend = new $backend_class ( $this->options );
/* re-save settings after update */ /* re-save settings after update */
add_action( 'upgrader_process_complete', array ( &$this->plugin_upgrade ), 10, 2 ); add_action( 'upgrader_process_complete', array ( &$this->plugin_upgrade ), 10, 2 );
@ -439,6 +440,7 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
/* we need to go through all servers */ /* we need to go through all servers */
$servers = $this->backend->status(); $servers = $this->backend->status();
error_log(__CLASS__ . ':' .json_encode($servers));
if ( is_array( $servers ) && !empty ( $servers ) ) { if ( is_array( $servers ) && !empty ( $servers ) ) {
foreach ( $servers as $server_string => $status ) { foreach ( $servers as $server_string => $status ) {
echo $server_string ." => "; echo $server_string ." => ";
@ -705,19 +707,10 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
<dd> <dd>
<input type="text" name="hosts" id="hosts" value="<?php echo $this->options['hosts']; ?>" /> <input type="text" name="hosts" id="hosts" value="<?php echo $this->options['hosts']; ?>" />
<span class="description"> <span class="description">
<?php _e('List of backends, with the following syntax: <br />- in case of TCP based connections, list the servers as host1:port1,host2:port2,... . Do not add trailing , and always separate host and port with : .<br />- in2.0.0b1 case using unix sockets with the Memcache driver: unix:// ', $this->plugin_constant); ?></span> <?php _e('List of backends, with the following syntax: <br />- in case of TCP based connections, list the servers as host1:port1,host2:port2,... . Do not add trailing , and always separate host and port with : .<br />- for a unix socket enter: unix://[socket_path]', $this->plugin_constant); ?></span>
</dd> </dd>
<dt> <h3><?php _e('Authentication ( only for SASL enabled Memcached or Redis')?></h3>
<label for="memcached_binary"><?php _e('Enable memcached binary mode', $this->plugin_constant); ?></label>
</dt>
<dd>
<input type="checkbox" name="memcached_binary" id="memcached_binary" value="1" <?php checked($this->options['memcached_binary'],true); ?> />
<span class="description"><?php _e('Some memcached proxies and implementations only support the ASCII protocol.', $this->plugin_constant); ?></span>
</dd>
<?php
if ( strstr ( $this->options['cache_type'], 'memcached') && extension_loaded ( 'memcached' ) && version_compare( phpversion( 'memcached' ) , '2.0.0', '>=' ) || ( $this->options['cache_type'] == 'redis' ) ) { ?>
<?php <?php
if ( ! ini_get('memcached.use_sasl') && ( !empty( $this->options['authuser'] ) || !empty( $this->options['authpass'] ) ) ) { ?> if ( ! ini_get('memcached.use_sasl') && ( !empty( $this->options['authuser'] ) || !empty( $this->options['authpass'] ) ) ) { ?>
<div class="error"><p><strong><?php _e( 'WARNING: you\'ve entered username and/or password for memcached authentication ( or your browser\'s autocomplete did ) which will not work unless you enable memcached sasl in the PHP settings: add `memcached.use_sasl=1` to php.ini' , $this->plugin_constant ) ?></strong></p></div> <div class="error"><p><strong><?php _e( 'WARNING: you\'ve entered username and/or password for memcached authentication ( or your browser\'s autocomplete did ) which will not work unless you enable memcached sasl in the PHP settings: add `memcached.use_sasl=1` to php.ini' , $this->plugin_constant ) ?></strong></p></div>
@ -728,7 +721,7 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
<dd> <dd>
<input type="text" autocomplete="off" name="authuser" id="authuser" value="<?php echo $this->options['authuser']; ?>" /> <input type="text" autocomplete="off" name="authuser" id="authuser" value="<?php echo $this->options['authuser']; ?>" />
<span class="description"> <span class="description">
<?php _e('Username for authentication with memcached backends', $this->plugin_constant); ?></span> <?php _e('Username for authentication with backends', $this->plugin_constant); ?></span>
</dd> </dd>
<dt> <dt>
@ -737,9 +730,19 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
<dd> <dd>
<input type="password" autocomplete="off" name="authpass" id="authpass" value="<?php echo $this->options['authpass']; ?>" /> <input type="password" autocomplete="off" name="authpass" id="authpass" value="<?php echo $this->options['authpass']; ?>" />
<span class="description"> <span class="description">
<?php _e('Password for authentication with memcached backends - WARNING, the password will be stored plain-text since it needs to be used!', $this->plugin_constant); ?></span> <?php _e('Password for authentication with for backends - WARNING, the password will be stored in an unsecure format!', $this->plugin_constant); ?></span>
</dd> </dd>
<?php } ?>
<h3><?php _e('Memcached specific settings')?></h3>
<dt>
<label for="memcached_binary"><?php _e('Enable memcached binary mode', $this->plugin_constant); ?></label>
</dt>
<dd>
<input type="checkbox" name="memcached_binary" id="memcached_binary" value="1" <?php checked($this->options['memcached_binary'],true); ?> />
<span class="description"><?php _e('Some memcached proxies and implementations only support the ASCII protocol.', $this->plugin_constant); ?></span>
</dd>
</dl> </dl>
</fieldset> </fieldset>
@ -988,12 +991,16 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
*/ */
private function deploy_advanced_cache( ) { private function deploy_advanced_cache( ) {
if ( @is_writable( $this->acache )) if ( !is_writable( $this->acache )) {
error_log('Generating advanced-cache.php failed: '.$this->acache.' is not writable');
return false; return false;
}
/* if no active site left no need for advanced cache :( */ /* if no active site left no need for advanced cache :( */
if ( empty ( $this->global_config ) ) if ( empty ( $this->global_config ) ) {
error_log('Generating advanced-cache.php failed: Global config is empty');
return false; return false;
}
/* add the required includes and generate the needed code */ /* add the required includes and generate the needed code */
$string[] = "<?php"; $string[] = "<?php";
@ -1003,6 +1010,7 @@ class WP_FFPC extends WP_FFPC_ABSTRACT {
/* write the file and start caching from this point */ /* write the file and start caching from this point */
return file_put_contents( $this->acache, join( "\n" , $string ) ); return file_put_contents( $this->acache, join( "\n" , $string ) );
} }
/** /**