2013-03-19 10:16:59 +00:00
< ? php
2014-06-26 08:57:10 +01:00
if ( ! class_exists ( 'WP_FFPC_Backend' )) :
include_once ( 'wp-common/plugin_utils.php' );
2013-03-19 10:16:59 +00:00
/**
*
2014-06-26 08:57:10 +01:00
* @ var string $plugin_constant Namespace of the plugin
* @ var mixed $connection Backend object storage variable
* @ var boolean $alive Alive flag of backend connection
* @ var boolean $network WordPress Network flag
* @ 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
2013-03-19 10:16:59 +00:00
*
*/
2014-06-26 08:57:10 +01:00
class WP_FFPC_Backend {
const network_key = 'network' ;
const host_separator = ',' ;
const port_separator = ':' ;
private $plugin_constant = 'wp-ffpc' ;
private $connection = NULL ;
private $alive = false ;
private $network = false ;
private $options = array ();
private $status = array ();
public $cookies = array ();
private $urimap = array ();
private $utilities ;
/**
* constructor
*
* @ param mixed $config Configuration options
* @ param boolean $network WordPress Network indicator flah
*
*/
public function __construct ( $config , $network = false ) {
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* no config, nothing is going to work */
if ( empty ( $config ) ) {
return false ;
//die ( __translate__ ( 'WP-FFPC Backend class received empty configuration array, the plugin will not work this way', $this->plugin_constant ) );
}
2013-06-07 17:56:56 +01:00
2014-06-26 08:57:10 +01:00
/* set config */
$this -> options = $config ;
2013-06-07 17:56:56 +01:00
2014-06-26 08:57:10 +01:00
/* set network flag */
$this -> network = $network ;
/* these are the list of the cookies to look for when looking for logged in user */
$this -> cookies = array ( 'comment_author_' , 'wordpressuser_' , 'wp-postpass_' , 'wordpress_logged_in_' );
/* make utilities singleton */
2014-06-26 11:02:13 +01:00
$this -> utilities = new PluginUtils ();
2014-06-26 08:57:10 +01:00
/* map the key with the predefined schemes */
$ruser = isset ( $_SERVER [ 'REMOTE_USER' ] ) ? $_SERVER [ 'REMOTE_USER' ] : '' ;
$ruri = isset ( $_SERVER [ 'REQUEST_URI' ] ) ? $_SERVER [ 'REQUEST_URI' ] : '' ;
$rhost = isset ( $_SERVER [ 'HTTP_HOST' ] ) ? $_SERVER [ 'HTTP_HOST' ] : '' ;
$scookie = isset ( $_COOKIE [ 'PHPSESSID' ] ) ? $_COOKIE [ 'PHPSESSID' ] : '' ;
$this -> urimap = array (
'$scheme' => str_replace ( '://' , '' , $this -> utilities -> replace_if_ssl ( 'http://' ) ),
'$host' => $rhost ,
'$request_uri' => $ruri ,
'$remote_user' => $ruser ,
'$cookie_PHPSESSID' => $scookie ,
);
/* split hosts entry to servers */
$this -> set_servers ();
/* call backend initiator based on cache type */
$init = $this -> proxy ( 'init' );
/* info level */
$this -> log ( __translate__ ( 'init starting' , $this -> plugin_constant ));
$this -> $init ();
2013-06-07 17:56:56 +01:00
2013-03-19 10:16:59 +00:00
}
2014-08-22 14:41:08 +01:00
public static function parse_urimap ( $uri , $default_urimap = null ) {
$uri_parts = parse_url ( $uri );
$uri_map = array (
'$scheme' => $uri_parts [ 'scheme' ],
'$host' => $uri_parts [ 'host' ],
'$request_uri' => $uri_parts [ 'path' ]
);
if ( is_array ( $default_urimap )) {
$uri_map = array_merge ( $default_urimap , $uri_map );
}
return $uri_map ;
}
public static function map_urimap ( $urimap , $subject ) {
return str_replace ( array_keys ( $urimap ), $urimap , $subject );
}
2014-06-26 08:57:10 +01:00
/*********************** PUBLIC / PROXY FUNCTIONS ***********************/
2013-03-19 10:16:59 +00:00
/**
2014-06-26 08:57:10 +01:00
* build key to make requests with
2013-03-19 10:16:59 +00:00
*
2014-06-26 08:57:10 +01:00
* @ param string $prefix prefix to add to prefix
2013-03-19 10:16:59 +00:00
*
*/
2014-06-26 08:57:10 +01:00
public function key ( & $prefix ) {
/* data is string only with content, meta is not used in nginx */
2014-08-22 14:41:08 +01:00
$key = $prefix . self :: map_urimap ( $this -> urimap , $this -> options [ 'key' ]);
2014-06-26 08:57:10 +01:00
$this -> log ( sprintf ( __translate__ ( 'original key configuration: %s' , $this -> plugin_constant ), $this -> options [ 'key' ] ) );
$this -> log ( sprintf ( __translate__ ( 'setting key to: %s' , $this -> plugin_constant ), $key ) );
return $key ;
}
2013-06-07 17:56:56 +01:00
2013-06-17 12:28:49 +01:00
2014-06-26 08:57:10 +01:00
/**
* public get function , transparent proxy to internal function based on backend
*
* @ param string $key Cache key to get value for
*
* @ return mixed False when entry not found or entry value on success
*/
public function get ( & $key ) {
2013-06-17 14:22:46 +01:00
2014-06-26 08:57:10 +01:00
/* look for backend aliveness, exit on inactive backend */
if ( ! $this -> is_alive () )
return false ;
2013-06-07 17:56:56 +01:00
2014-06-26 08:57:10 +01:00
/* log the current action */
$this -> log ( sprintf ( __translate__ ( 'get %s' , $this -> plugin_constant ), $key ) );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* proxy to internal function */
$internal = $this -> proxy ( 'get' );
$result = $this -> $internal ( $key );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
if ( $result === false )
$this -> log ( sprintf ( __translate__ ( 'failed to get entry: %s' , $this -> plugin_constant ), $key ) );
2013-06-17 14:22:46 +01:00
2014-06-26 08:57:10 +01:00
return $result ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* public set function , transparent proxy to internal function based on backend
*
* @ param string $key Cache key to set with ( reference only , for speed )
* @ param mixed $data Data to set ( reference only , for speed )
*
* @ return mixed $result status of set function
*/
public function set ( & $key , & $data ) {
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* look for backend aliveness, exit on inactive backend */
if ( ! $this -> is_alive () )
return false ;
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* log the current action */
$this -> log ( sprintf ( __translate__ ( 'set %s expiration time: %s' , $this -> plugin_constant ), $key , $this -> options [ 'expire' ] ) );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* proxy to internal function */
$internal = $this -> proxy ( 'set' );
$result = $this -> $internal ( $key , $data );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* check result validity */
if ( $result === false )
$this -> log ( sprintf ( __translate__ ( 'failed to set entry: %s' , $this -> plugin_constant ), $key ), LOG_WARNING );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
return $result ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* public get function , transparent proxy to internal function based on backend
*
* @ param string $post_id ID of post to invalidate
* @ 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 ) {
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* look for backend aliveness, exit on inactive backend */
if ( ! $this -> is_alive () )
return false ;
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* exit if no post_id is specified */
if ( empty ( $post_id ) && $force === false ) {
$this -> log ( __translate__ ( 'not clearing unidentified post ' , $this -> plugin_constant ), LOG_WARNING );
return false ;
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
/* if invalidation method is set to full, flush cache */
if ( ( $this -> options [ 'invalidation_method' ] === 0 || $force === true ) ) {
/* log action */
$this -> log ( __translate__ ( 'flushing cache' , $this -> plugin_constant ) );
2013-03-19 10:16:59 +00:00
/* proxy to internal function */
2014-06-26 08:57:10 +01:00
$internal = $this -> proxy ( 'flush' );
$result = $this -> $internal ();
2013-03-19 10:16:59 +00:00
if ( $result === false )
2014-06-26 08:57:10 +01:00
$this -> log ( __translate__ ( 'failed to flush cache' , $this -> plugin_constant ), LOG_WARNING );
2013-03-19 10:16:59 +00:00
return $result ;
}
2014-06-26 08:57:10 +01:00
/* storage for entries to clear */
$to_clear = array ();
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* clear taxonomies if settings requires it */
if ( $this -> options [ 'invalidation_method' ] == 2 ) {
/* this will only clear the current blog's entries */
$this -> taxonomy_links ( $to_clear );
}
2014-08-22 15:27:23 +01:00
/* clear pasts index page if settings requires it */
if ( $this -> options [ 'invalidation_method' ] == 3 ) {
$posts_page_id = get_option ( 'page_for_posts' );
$post_type = get_post_type ( $post_id );
if ( $post_type === 'post' && $posts_page_id != $post_id ) {
$this -> clear ( $posts_page_id , $force );
}
}
2014-06-26 08:57:10 +01:00
/* if there's a post id pushed, it needs to be invalidated in all cases */
if ( ! empty ( $post_id ) ) {
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* need permalink functions */
if ( ! function_exists ( 'get_permalink' ) )
include_once ( ABSPATH . 'wp-includes/link-template.php' );
2014-08-22 14:41:08 +01:00
/* get permalink */
$permalink = get_permalink ( $post_id );
2014-06-26 08:57:10 +01:00
/* no path, don't do anything */
2014-08-22 14:41:08 +01:00
if ( empty ( $permalink ) ) {
2014-06-26 08:57:10 +01:00
$this -> log ( sprintf ( __translate__ ( 'unable to determine path from Post Permalink, post ID: %s' , $this -> plugin_constant ), $post_id ), LOG_WARNING );
2013-03-19 10:16:59 +00:00
return false ;
}
2014-08-22 14:41:08 +01:00
/*
* It is possible that post / page is paginated with <!-- nextpage -->
* Wordpress doesn ' t seem to expose the number of pages via API .
* So let ' s just count it .
*/
$content_post = get_post ( $post_id );
$content = $content_post -> post_content ;
$number_of_pages = 1 + ( int ) preg_match_all ( '/<!--nextpage-->/' , $content , $matches );
$current_page_id = '' ;
do {
/* urimap */
$urimap = self :: parse_urimap ( $permalink , $this -> urimap );
$urimap [ '$request_uri' ] = $urimap [ '$request_uri' ] . ( $current_page_id ? $current_page_id . '/' : '' );
$clear_cache_key = self :: map_urimap ( $urimap , $this -> options [ 'key' ]);
$to_clear [ $clear_cache_key ] = true ;
2013-03-19 10:16:59 +00:00
2014-08-22 14:41:08 +01:00
$current_page_id = 1 + ( int ) $current_page_id ;
} while ( $number_of_pages > 1 && $current_page_id <= $number_of_pages );
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-08-22 15:48:49 +01:00
/* Hook to customise clearing array. */
apply_filters ( 'wp_ffpc_to_clear_array' , $to_clear , $post_id );
2014-06-26 08:57:10 +01:00
foreach ( $to_clear as $link => $dummy ) {
/* clear all feeds as well */
$to_clear [ $link . 'feed' ] = true ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* add data & meta prefixes */
foreach ( $to_clear as $link => $dummy ) {
unset ( $to_clear [ $link ]);
$to_clear [ $this -> options [ 'prefix_meta' ] . $link ] = true ;
$to_clear [ $this -> options [ 'prefix_data' ] . $link ] = true ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* run clear */
$internal = $this -> proxy ( 'clear' );
$this -> $internal ( $to_clear );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* clear cache triggered by new comment
*
* @ param $comment_id Comment ID
* @ param $comment_object The whole comment object ?
*/
public function clear_by_comment ( $comment_id , $comment_object ) {
if ( empty ( $comment_id ) )
return false ;
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
$comment = get_comment ( $comment_id );
$post_id = $comment -> comment_post_ID ;
if ( ! empty ( $post_id ) )
$this -> clear ( $post_id );
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
unset ( $comment );
unset ( $post_id );
}
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
/**
* to collect all permalinks of all taxonomy terms used in invalidation & precache
*
* @ param array & $links Passed by reference array that has to be filled up with the links
* @ param mixed $site Site ID or false ; used in WordPress Network
*
*/
public function taxonomy_links ( & $links , $site = false ) {
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
if ( $site !== false ) {
$current_blog = get_current_blog_id ();
switch_to_blog ( $site );
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
$url = get_blog_option ( $site , 'siteurl' );
if ( substr ( $url , - 1 ) !== '/' )
$url = $url . '/' ;
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
$links [ $url ] = true ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* we're only interested in public taxonomies */
$args = array (
'public' => true ,
);
/* get taxonomies as objects */
$taxonomies = get_taxonomies ( $args , 'objects' );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
if ( ! empty ( $taxonomies ) ) {
foreach ( $taxonomies as $taxonomy ) {
/* reset array, just in case */
$terms = array ();
/* get all the terms for this taxonomy, only if not empty */
$sargs = array (
'hide_empty' => true ,
'fields' => 'all' ,
'hierarchical' => false ,
);
$terms = get_terms ( $taxonomy -> name , $sargs );
if ( ! empty ( $terms ) ) {
foreach ( $terms as $term ) {
/* get the permalink for the term */
$link = get_term_link ( $term -> slug , $taxonomy -> name );
/* add to container */
$links [ $link ] = true ;
/* remove the taxonomy name from the link , lots of plugins remove this for SEO , it ' s better to include them than leave them out
in worst case , we cache some 404 as well
*/
$link = str_replace ( '/' . $taxonomy -> rewrite [ 'slug' ], '' , $link );
/* add to container */
$links [ $link ] = true ;
}
}
2013-03-28 22:27:54 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* switch back to original site if we navigated away */
if ( $site !== false ) {
switch_to_blog ( $current_blog );
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/**
* get backend aliveness
*
* @ return array Array of configured servers with aliveness value
*
*/
public function status () {
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/* look for backend aliveness, exit on inactive backend */
if ( ! $this -> is_alive () )
return false ;
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
$internal = $this -> proxy ( 'status' );
$this -> $internal ();
return $this -> status ;
}
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 ;
}
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
/**
* function to check backend aliveness
*
* @ return boolean true if backend is alive , false if not
*
*/
private function is_alive () {
if ( ! $this -> alive ) {
$this -> log ( __translate__ ( " backend is not active, exiting function " , $this -> plugin_constant ) . __FUNCTION__ , LOG_WARNING );
return false ;
}
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
return true ;
}
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
/**
* split hosts string to backend servers
*
*
*/
private function set_servers () {
/* replace servers array in config according to hosts field */
$servers = explode ( self :: host_separator , $this -> options [ 'hosts' ]);
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
$options [ 'servers' ] = array ();
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
foreach ( $servers as $snum => $sstring ) {
$separator = strpos ( $sstring , self :: port_separator );
$host = substr ( $sstring , 0 , $separator );
$port = substr ( $sstring , $separator + 1 );
// unix socket failsafe
if ( empty ( $port ) ) $port = 0 ;
2013-03-28 22:27:54 +00:00
2014-06-26 08:57:10 +01:00
$this -> options [ 'servers' ][ $sstring ] = array (
'host' => $host ,
'port' => $port
);
2013-03-28 22:27:54 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* get current array of servers
*
* @ return array Server list in current config
*
*/
public function get_servers () {
$r = isset ( $this -> options [ 'servers' ] ) ? $this -> options [ 'servers' ] : '' ;
return $r ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* log wrapper to include options
*
* @ var mixed $message Message to log
* @ var int $log_level Log level
*/
private function log ( $message , $log_level = LOG_WARNING ) {
if ( ! isset ( $this -> options [ 'log' ] ) || $this -> options [ 'log' ] != 1 )
return false ;
else
$this -> utilities -> log ( $this -> plugin_constant , $message , $log_level );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/*********************** 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 ;
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
/* verify apc is working */
if ( apc_cache_info ( " user " , true ) ) {
$this -> log ( __translate__ ( 'backend OK' , $this -> plugin_constant ) );
$this -> alive = true ;
}
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* health checker for APC
*
* @ return boolean Aliveness status
*
*/
private function apc_status () {
$this -> status = true ;
return $this -> alive ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 ) {
return apc_store ( $key , $data , $this -> options [ 'expire' ] );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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_ERR );
//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 ) );
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/*********************** 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 ;
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
/* verify apcu is working */
2014-08-22 11:55:25 +01:00
if ( apcu_cache_info ( " user " ) ) {
2014-06-26 08:57:10 +01:00
$this -> log ( __translate__ ( 'backend OK' , $this -> plugin_constant ) );
$this -> alive = true ;
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* health checker for APC
*
* @ return boolean Aliveness status
*
*/
private function apcu_status () {
$this -> status = true ;
return $this -> alive ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 ) {
return apcu_store ( $key , $data , $this -> options [ '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_ERR );
//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 ) );
2014-05-30 11:22:21 +01:00
}
}
2014-06-26 08:57:10 +01:00
}
2014-05-30 11:22:21 +01:00
2014-06-26 08:57:10 +01:00
/*********************** END APC FUNCTIONS ***********************/
2014-05-30 11:22:21 +01:00
2014-06-26 08:57:10 +01:00
/*********************** XCACHE FUNCTIONS ***********************/
/**
* init apc backend : test APC availability and set alive status
*/
private function xcache_init () {
/* verify apc functions exist, apc extension is loaded */
if ( ! function_exists ( 'xcache_info' ) ) {
$this -> log ( __translate__ ( 'XCACHE extension missing' , $this -> plugin_constant ) );
return false ;
2014-05-30 11:22:21 +01:00
}
2014-08-22 11:55:25 +01:00
$xcache_admin = ini_get ( 'xcache.admin.user' );
$xcache_pass = ini_get ( 'xcache.admin.pass' );
if ( empty ( $xcache_admin ) || empty ( $xcache_pass ) ) {
$this -> log ( __translate__ ( 'XCACHE xcache.admin.user or xcache.admin.pass is not set in php.ini. Please set them, otherwise the use cache part of xcache is not accessible.' , $this -> plugin_constant ) );
return false ;
}
2014-06-26 08:57:10 +01:00
/* verify apc is working */
$info = xcache_info ();
if ( ! empty ( $info )) {
$this -> log ( __translate__ ( 'backend OK' , $this -> plugin_constant ) );
$this -> alive = true ;
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* health checker for Xcache
*
* @ return boolean Aliveness status
*
*/
private function xcache_status () {
$this -> status = true ;
return $this -> alive ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* get function for APC backend
*
* @ param string $key Key to get values for
*
* @ return mixed Fetched data based on key
*
*/
private function xcache_get ( & $key ) {
if ( xcache_isset ( $key ) )
return xcache_get ( $key );
else
return false ;
}
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/**
* 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 xcache_set ( & $key , & $data ) {
return xcache_set ( $key , $data , $this -> options [ 'expire' ] );
}
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/**
* Flushes APC user entry storage
*
* @ return boolean APC flush outcome status
*
*/
private function xcache_flush ( ) {
return xcache_clear_cache ( XC_TYPE_VAR );
}
/**
* Removes entry from APC or flushes APC user entry storage
*
* @ param mixed $keys Keys to clear , string or array
*/
private function xcache_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 ( ! xcache_unset ( $key ) ) {
$this -> log ( sprintf ( __translate__ ( 'Failed to delete XCACHE entry: %s' , $this -> plugin_constant ), $key ), LOG_ERR );
//throw new Exception ( __translate__('Deleting APC entry failed with key ', $this->plugin_constant ) . $key );
}
else {
$this -> log ( sprintf ( __translate__ ( 'XCACHE entry delete: %s' , $this -> plugin_constant ), $key ) );
2014-05-12 15:48:22 +01:00
}
}
2014-06-26 08:57:10 +01:00
}
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/*********************** END XCACHE FUNCTIONS ***********************/
2014-05-12 15:48:22 +01:00
2014-06-26 08:57:10 +01:00
/*********************** 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' , $this -> plugin_constant ), LOG_ERR );
return false ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* check is there's no backend connection yet */
if ( $this -> connection === NULL ) {
/* persistent backend needs an identifier */
if ( $this -> options [ 'persistent' ] == '1' )
$this -> connection = new Memcached ( $this -> plugin_constant );
else
$this -> connection = new Memcached ();
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* use binary and not compressed format, good for nginx and still fast */
$this -> connection -> setOption ( Memcached :: OPT_COMPRESSION , false );
$this -> connection -> setOption ( Memcached :: OPT_BINARY_PROTOCOL , true );
2014-06-02 16:02:13 +01:00
2014-08-22 11:55:25 +01:00
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' ]) ) {
2014-06-26 08:57:10 +01:00
$this -> connection -> setSaslAuthData ( $this -> options [ 'authuser' ], $this -> options [ 'authpass' ]);
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ;
2013-03-19 10:16:59 +00:00
}
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* adding servers */
foreach ( $this -> options [ 'servers' ] as $server_id => $server ) {
/* reset server status to unknown */
$this -> status [ $server_id ] = - 1 ;
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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, persistent mode: %s' , $this -> plugin_constant ), $server_id , $this -> options [ 'persistent' ] ) );
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* backend is now alive */
$this -> alive = true ;
$this -> memcached_status ();
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 servers statistic from connection */
$report = $this -> connection -> getStats ();
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
foreach ( $report as $server_id => $details ) {
/* reset server status to offline */
$this -> status [ $server_id ] = 0 ;
/* if server uptime is not empty, it's most probably up & running */
if ( ! empty ( $details [ 'uptime' ]) ) {
$this -> log ( sprintf ( __translate__ ( '%s server is up & running' , $this -> plugin_constant ), $server_id ) );
$this -> status [ $server_id ] = 1 ;
}
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* get function for Memcached backend
*
* @ param string $key Key to get values for
*
*/
private function memcached_get ( & $key ) {
return $this -> connection -> get ( $key );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* Set function for Memcached backend
*
* @ param string $key Key to set with
* @ param mixed $data Data to set
*
*/
private function memcached_set ( & $key , & $data ) {
$result = $this -> connection -> set ( $key , $data , $this -> options [ 'expire' ] );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 );
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
return $result ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
*
* Flush memcached entries
*/
private function memcached_flush ( ) {
return $this -> connection -> flush ();
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 ) {
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ) );
2013-03-19 10:16:59 +00:00
}
}
2014-06-26 08:57:10 +01:00
}
/*********************** END MEMCACHED FUNCTIONS ***********************/
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/*********************** 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_ERR );
return false ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* check is there's no backend connection yet */
if ( $this -> connection === NULL )
$this -> connection = new Memcache ();
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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 ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* adding servers */
foreach ( $this -> options [ 'servers' ] as $server_id => $server ) {
if ( $this -> options [ 'persistent' ] == '1' )
$conn = 'pconnect' ;
else
$conn = 'connect' ;
2013-11-07 21:11:12 +00:00
2014-06-26 08:57:10 +01:00
/* in case of unix socket */
if ( $server [ 'port' ] === 0 )
$this -> status [ $server_id ] = $this -> connection -> $conn ( 'unix:/' . $server [ 'host' ] );
else
$this -> status [ $server_id ] = $this -> connection -> $conn ( $server [ 'host' ] , $server [ 'port' ] );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
$this -> log ( sprintf ( __translate__ ( '%s added, persistent mode: %s' , $this -> plugin_constant ), $server_id , $this -> options [ 'persistent' ] ) );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/* 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' ] );
else
2013-03-19 10:16:59 +00:00
$this -> status [ $server_id ] = $this -> connection -> getServerStatus ( $server [ 'host' ], $server [ 'port' ] );
2014-06-26 08:57:10 +01:00
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 ) );
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* get function for Memcached backend
*
* @ param string $key Key to get values for
*
*/
private function memcache_get ( & $key ) {
return $this -> connection -> get ( $key );
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* Set function for Memcached backend
*
* @ param string $key Key to set with
* @ param mixed $data Data to set
*
*/
private function memcache_set ( & $key , & $data ) {
$result = $this -> connection -> set ( $key , $data , 0 , $this -> options [ 'expire' ] );
return $result ;
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
*
* Flush memcached entries
*/
private function memcache_flush ( ) {
return $this -> connection -> flush ();
}
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
/**
* 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 );
2013-03-19 10:16:59 +00:00
2014-06-26 08:57:10 +01:00
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 ) );
2013-03-19 10:16:59 +00:00
}
}
}
2014-06-26 08:57:10 +01:00
/*********************** END MEMCACHE FUNCTIONS ***********************/
2013-03-19 10:16:59 +00:00
}
2014-06-26 08:57:10 +01:00
endif ; ?>