diff --git a/wp-common b/wp-common
index 2749265..d12b345 160000
--- a/wp-common
+++ b/wp-common
@@ -1 +1 @@
-Subproject commit 2749265f11b2c2e9d34cc35aa74aca55b2b1b93b
+Subproject commit d12b345560c77634b25fc8ee7571c19730794c69
diff --git a/wp-ffpc-backend.php b/wp-ffpc-backend.php
index c26a783..9923c33 100644
--- a/wp-ffpc-backend.php
+++ b/wp-ffpc-backend.php
@@ -1,992 +1,973 @@
plugin_constant ) );
+ }
+
+ /* set config */
+ $this->options = $config;
+
+ /* 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 */
+ $this->utilities = PluginUtils::S();
+
+ /* 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();
- /* __ only availabe if we're running from the inside of wordpress, not in advanced-cache.php phase */
- if ( function_exists ( '__' ) ) {
- function __translate__ ( $text, $domain ) { return __($text, $domain); }
}
- else {
- function __translate__ ( $text, $domain ) { return $text; }
+
+ /*********************** PUBLIC / PROXY FUNCTIONS ***********************/
+
+ /**
+ * build key to make requests with
+ *
+ * @param string $prefix prefix to add to prefix
+ *
+ */
+ public function key ( &$prefix ) {
+ /* data is string only with content, meta is not used in nginx */
+ $key = $prefix . str_replace ( array_keys( $this->urimap ), $this->urimap, $this->options['key'] );
+ $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;
+ }
+
+
+ /**
+ * 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 ) {
+
+ /* look for backend aliveness, exit on inactive backend */
+ if ( ! $this->is_alive() )
+ return false;
+
+ /* log the current action */
+ $this->log ( sprintf( __translate__( 'get %s', $this->plugin_constant ), $key ) );
+
+ /* proxy to internal function */
+ $internal = $this->proxy( 'get' );
+ $result = $this->$internal( $key );
+
+ if ( $result === false )
+ $this->log ( sprintf( __translate__( 'failed to get entry: %s', $this->plugin_constant ), $key ) );
+
+ return $result;
+ }
+
+ /**
+ * 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 ) {
+
+ /* look for backend aliveness, exit on inactive backend */
+ if ( ! $this->is_alive() )
+ return false;
+
+ /* log the current action */
+ $this->log ( sprintf( __translate__( 'set %s expiration time: %s', $this->plugin_constant ), $key, $this->options['expire'] ) );
+
+ /* proxy to internal function */
+ $internal = $this->proxy( 'set' );
+ $result = $this->$internal( $key, $data );
+
+ /* check result validity */
+ if ( $result === false )
+ $this->log ( sprintf( __translate__( 'failed to set entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
+
+ return $result;
+ }
+
+ /**
+ * 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 ) {
+
+ /* look for backend aliveness, exit on inactive backend */
+ if ( ! $this->is_alive() )
+ return false;
+
+ /* 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;
+ }
+
+ /* 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 ) );
+
+ /* proxy to internal function */
+ $internal = $this->proxy ( 'flush' );
+ $result = $this->$internal();
+
+ if ( $result === false )
+ $this->log ( __translate__('failed to flush cache', $this->plugin_constant ), LOG_WARNING );
+
+ return $result;
+ }
+
+ /* storage for entries to clear */
+ $to_clear = array();
+
+ /* 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 );
+ }
+
+ /* if there's a post id pushed, it needs to be invalidated in all cases */
+ if ( !empty ( $post_id ) ) {
+
+ /* need permalink functions */
+ if ( !function_exists('get_permalink') )
+ include_once ( ABSPATH . 'wp-includes/link-template.php' );
+
+ /* get path from permalink */
+ $path = substr ( get_permalink( $post_id ) , 7 );
+
+ /* no path, don't do anything */
+ if ( empty( $path ) ) {
+ $this->log ( sprintf( __translate__( 'unable to determine path from Post Permalink, post ID: %s', $this->plugin_constant ), $post_id ), LOG_WARNING );
+ return false;
+ }
+
+ if ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) )
+ $protocol = 'https://';
+ else
+ $protocol = 'http://';
+
+ /* elements to clear
+ values are keys, faster to process and eliminates duplicates
+ */
+ $to_clear[ $protocol . $path ] = true;
+ }
+
+ foreach ( $to_clear as $link => $dummy ) {
+ /* clear all feeds as well */
+ $to_clear[ $link. 'feed' ] = true;
+ }
+
+ /* 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;
+ }
+
+ /* run clear */
+ $internal = $this->proxy ( 'clear' );
+ $this->$internal ( $to_clear );
+ }
+
+ /**
+ * 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;
+
+ $comment = get_comment( $comment_id );
+ $post_id = $comment->comment_post_ID;
+ if ( !empty( $post_id ) )
+ $this->clear ( $post_id );
+
+ unset ( $comment );
+ unset ( $post_id );
+ }
+
+ /**
+ * 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 ) {
+
+ if ( $site !== false ) {
+ $current_blog = get_current_blog_id();
+ switch_to_blog( $site );
+
+ $url = get_blog_option ( $site, 'siteurl' );
+ if ( substr( $url, -1) !== '/' )
+ $url = $url . '/';
+
+ $links[ $url ] = true;
+ }
+
+ /* we're only interested in public taxonomies */
+ $args = array(
+ 'public' => true,
+ );
+
+ /* get taxonomies as objects */
+ $taxonomies = get_taxonomies( $args, 'objects' );
+
+ 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;
+ }
+ }
+ }
+ }
+
+ /* switch back to original site if we navigated away */
+ if ( $site !== false ) {
+ switch_to_blog( $current_blog );
+ }
+
+ }
+
+ /**
+ * get backend aliveness
+ *
+ * @return array Array of configured servers with aliveness value
+ *
+ */
+ public function status () {
+
+ /* look for backend aliveness, exit on inactive backend */
+ if ( ! $this->is_alive() )
+ return false;
+
+ $internal = $this->proxy ( 'status' );
+ $this->$internal();
+ 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
+ *
+ * @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;
+ }
+
+ return true;
+ }
+
+ /**
+ * 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']);
+
+ $options['servers'] = array();
+
+ 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;
+
+ $this->options['servers'][$sstring] = array (
+ 'host' => $host,
+ 'port' => $port
+ );
+ }
+
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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 );
+ }
+
+ /*********************** 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 ) {
+ return apc_store( $key , $data , $this->options['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_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 ) );
+ }
+ }
+ }
+
+ /*********************** 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",true) ) {
+ $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 ) {
+ 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 ) );
+ }
+ }
+ }
+
+ /*********************** END APC FUNCTIONS ***********************/
+
+ /*********************** 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;
+ }
+
+ /* verify apc is working */
+ $info = xcache_info();
+ if ( !empty( $info )) {
+ $this->log ( __translate__('backend OK', $this->plugin_constant ) );
+ $this->alive = true;
+ }
+ }
+
+ /**
+ * health checker for Xcache
+ *
+ * @return boolean Aliveness status
+ *
+ */
+ private function xcache_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 xcache_get ( &$key ) {
+ if ( xcache_isset ( $key ) )
+ return xcache_get( $key );
+ else
+ return false;
+ }
+
+ /**
+ * 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'] );
+ }
+
+
+ /**
+ * 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 ) );
+ }
+ }
+ }
+
+ /*********************** END XCACHE 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', $this->plugin_constant ), LOG_ERR );
+ 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 ) {
+ /* persistent backend needs an identifier */
+ if ( $this->options['persistent'] == '1' )
+ $this->connection = new Memcached( $this->plugin_constant );
+ else
+ $this->connection = new Memcached();
+
+ /* 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 );
+
+ if ( version_compare( phpversion( 'memcached' ) , '2.0.0', '>=' ) && ini_get( 'memcached.use_sasl' ) == 1 ) {
+ $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, persistent mode: %s', $this->plugin_constant ), $server_id, $this->options['persistent'] ) );
+ }
+ }
+
+ /* 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 servers statistic from connection */
+ $report = $this->connection->getStats();
+
+ 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;
+ }
+ }
+
+ }
+
+ /**
+ * 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 ) {
+ $result = $this->connection->set ( $key, $data , $this->options['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;
}
/**
*
- * @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
+ * 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_ERR );
+ 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 ) {
+ if ( $this->options['persistent'] == '1' )
+ $conn = 'pconnect';
+ else
+ $conn = 'connect';
+
+ /* 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'] );
+
+ $this->log ( sprintf( __translate__( '%s added, persistent mode: %s', $this->plugin_constant ), $server_id, $this->options['persistent'] ) );
+ }
+
+ /* backend is now alive */
+ $this->alive = true;
+ $this->memcache_status();
+ }
+
+ /**
+ * check current backend alive status for Memcached
*
*/
- 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 ) {
-
- /* 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 ) );
- }
-
- /* set config */
- $this->options = $config;
-
- /* 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 */
- $this->utilities = WP_Plugins_Utilities_v1::Utility();
-
- /* 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();
-
- }
-
- /*********************** PUBLIC / PROXY FUNCTIONS ***********************/
-
- /**
- * build key to make requests with
- *
- * @param string $prefix prefix to add to prefix
- *
- */
- public function key ( &$prefix ) {
- /* data is string only with content, meta is not used in nginx */
- $key = $prefix . str_replace ( array_keys( $this->urimap ), $this->urimap, $this->options['key'] );
- $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;
- }
-
-
- /**
- * 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 ) {
-
- /* look for backend aliveness, exit on inactive backend */
- if ( ! $this->is_alive() )
- return false;
-
- /* log the current action */
- $this->log ( sprintf( __translate__( 'get %s', $this->plugin_constant ), $key ) );
-
- /* proxy to internal function */
- $internal = $this->proxy( 'get' );
- $result = $this->$internal( $key );
-
- if ( $result === false )
- $this->log ( sprintf( __translate__( 'failed to get entry: %s', $this->plugin_constant ), $key ) );
-
- return $result;
- }
-
- /**
- * 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 ) {
-
- /* look for backend aliveness, exit on inactive backend */
- if ( ! $this->is_alive() )
- return false;
-
- /* log the current action */
- $this->log ( sprintf( __translate__( 'set %s expiration time: %s', $this->plugin_constant ), $key, $this->options['expire'] ) );
-
- /* proxy to internal function */
- $internal = $this->proxy( 'set' );
- $result = $this->$internal( $key, $data );
-
- /* check result validity */
- if ( $result === false )
- $this->log ( sprintf( __translate__( 'failed to set entry: %s', $this->plugin_constant ), $key ), LOG_WARNING );
-
- return $result;
- }
-
- /**
- * 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 ) {
-
- /* look for backend aliveness, exit on inactive backend */
- if ( ! $this->is_alive() )
- return false;
-
- /* 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;
- }
-
- /* 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 ) );
-
- /* proxy to internal function */
- $internal = $this->proxy ( 'flush' );
- $result = $this->$internal();
-
- if ( $result === false )
- $this->log ( __translate__('failed to flush cache', $this->plugin_constant ), LOG_WARNING );
-
- return $result;
- }
-
- /* storage for entries to clear */
- $to_clear = array();
-
- /* 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 );
- }
-
- /* if there's a post id pushed, it needs to be invalidated in all cases */
- if ( !empty ( $post_id ) ) {
-
- /* need permalink functions */
- if ( !function_exists('get_permalink') )
- include_once ( ABSPATH . 'wp-includes/link-template.php' );
-
- /* get path from permalink */
- $path = substr ( get_permalink( $post_id ) , 7 );
-
- /* no path, don't do anything */
- if ( empty( $path ) ) {
- $this->log ( sprintf( __translate__( 'unable to determine path from Post Permalink, post ID: %s', $this->plugin_constant ), $post_id ), LOG_WARNING );
- return false;
- }
-
- if ( isset($_SERVER['HTTPS']) && ( ( strtolower($_SERVER['HTTPS']) == 'on' ) || ( $_SERVER['HTTPS'] == '1' ) ) )
- $protocol = 'https://';
- else
- $protocol = 'http://';
-
- /* elements to clear
- values are keys, faster to process and eliminates duplicates
- */
- $to_clear[ $protocol . $path ] = true;
- }
-
- foreach ( $to_clear as $link => $dummy ) {
- /* clear all feeds as well */
- $to_clear[ $link. 'feed' ] = true;
- }
-
- /* 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;
- }
-
- /* run clear */
- $internal = $this->proxy ( 'clear' );
- $this->$internal ( $to_clear );
- }
-
- /**
- * 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;
-
- $comment = get_comment( $comment_id );
- $post_id = $comment->comment_post_ID;
- if ( !empty( $post_id ) )
- $this->clear ( $post_id );
-
- unset ( $comment );
- unset ( $post_id );
- }
-
- /**
- * 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 ) {
-
- if ( $site !== false ) {
- $current_blog = get_current_blog_id();
- switch_to_blog( $site );
-
- $url = get_blog_option ( $site, 'siteurl' );
- if ( substr( $url, -1) !== '/' )
- $url = $url . '/';
-
- $links[ $url ] = true;
- }
-
- /* we're only interested in public taxonomies */
- $args = array(
- 'public' => true,
- );
-
- /* get taxonomies as objects */
- $taxonomies = get_taxonomies( $args, 'objects' );
-
- 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;
- }
- }
- }
- }
-
- /* switch back to original site if we navigated away */
- if ( $site !== false ) {
- switch_to_blog( $current_blog );
- }
-
- }
-
- /**
- * get backend aliveness
- *
- * @return array Array of configured servers with aliveness value
- *
- */
- public function status () {
-
- /* look for backend aliveness, exit on inactive backend */
- if ( ! $this->is_alive() )
- return false;
-
- $internal = $this->proxy ( 'status' );
- $this->$internal();
- 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
- *
- * @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;
- }
-
- return true;
- }
-
- /**
- * 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']);
-
- $options['servers'] = array();
-
- 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;
-
- $this->options['servers'][$sstring] = array (
- 'host' => $host,
- 'port' => $port
- );
- }
-
- }
-
- /**
- * 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;
- }
-
- /**
- * 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;
+ 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
- $this->utilities->log ( $this->plugin_constant , $message, $log_level );
- }
-
- /*********************** 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 ) {
- return apc_store( $key , $data , $this->options['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_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 ) );
- }
- }
- }
-
- /*********************** 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",true) ) {
- $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 ) {
- 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 ) );
- }
- }
- }
-
- /*********************** END APC FUNCTIONS ***********************/
-
- /*********************** 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;
- }
-
- /* verify apc is working */
- $info = xcache_info();
- if ( !empty( $info )) {
- $this->log ( __translate__('backend OK', $this->plugin_constant ) );
- $this->alive = true;
- }
- }
-
- /**
- * health checker for Xcache
- *
- * @return boolean Aliveness status
- *
- */
- private function xcache_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 xcache_get ( &$key ) {
- if ( xcache_isset ( $key ) )
- return xcache_get( $key );
- else
- return false;
- }
-
- /**
- * 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'] );
- }
-
-
- /**
- * 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 ) );
- }
- }
- }
-
- /*********************** END XCACHE 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', $this->plugin_constant ), LOG_ERR );
- 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 ) {
- /* persistent backend needs an identifier */
- if ( $this->options['persistent'] == '1' )
- $this->connection = new Memcached( $this->plugin_constant );
- else
- $this->connection = new Memcached();
-
- /* 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 );
-
- if ( version_compare( phpversion( 'memcached' ) , '2.0.0', '>=' ) && ini_get( 'memcached.use_sasl' ) == 1 ) {
- $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, persistent mode: %s', $this->plugin_constant ), $server_id, $this->options['persistent'] ) );
- }
- }
-
- /* 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 servers statistic from connection */
- $report = $this->connection->getStats();
-
- 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;
- }
- }
-
- }
-
- /**
- * 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 ) {
- $result = $this->connection->set ( $key, $data , $this->options['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_ERR );
- 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 ) {
- if ( $this->options['persistent'] == '1' )
- $conn = 'pconnect';
- else
- $conn = 'connect';
-
- /* 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'] );
-
- $this->log ( sprintf( __translate__( '%s added, persistent mode: %s', $this->plugin_constant ), $server_id, $this->options['persistent'] ) );
- }
-
- /* 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 ) {
$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 ) );
- }
+ 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 ) {
- $result = $this->connection->set ( $key, $data , 0 , $this->options['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 ***********************/
-
}
+ /**
+ * 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 ) {
+ $result = $this->connection->set ( $key, $data , 0 , $this->options['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 ***********************/
+
}
-?>
+endif; ?>
diff --git a/wp-ffpc-class.php b/wp-ffpc-class.php
index 7d71713..3961d77 100644
--- a/wp-ffpc-class.php
+++ b/wp-ffpc-class.php
@@ -1,1202 +1,1183 @@
acache_worker = $this->plugin_dir . $this->plugin_constant . '-acache.php';
+ /* WordPress advanced-cache.php file location */
+ $this->acache = WP_CONTENT_DIR . '/advanced-cache.php';
+ /* nginx sample config file */
+ $this->nginx_sample = $this->plugin_dir . $this->plugin_constant . '-nginx-sample.conf';
+ /* backend driver file */
+ $this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-backend.php';
+ /* flush button identifier */
+ $this->button_flush = $this->plugin_constant . '-flush';
+ /* precache button identifier */
+ $this->button_precache = $this->plugin_constant . '-precache';
+ /* global options identifier */
+ $this->global_option = $this->plugin_constant . '-global';
+ /* precache log */
+ $this->precache_logfile = sys_get_temp_dir() . '/' . self::precache_log;
+ /* this is the precacher php worker file */
+ $this->precache_phpfile = sys_get_temp_dir() . '/' . self::precache_php;
+ /* search for a system function */
+ $this->shell_possibilities = array ( 'shell_exec', 'exec', 'system', 'passthru' );
+ /* get disabled functions list */
+ $disabled_functions = array_map('trim', explode(',', ini_get('disable_functions') ) );
- /**
- * init hook function runs before admin panel hook, themeing and options read
- */
- public function plugin_init() {
- /* advanced cache "worker" file */
- $this->acache_worker = $this->plugin_dir . $this->plugin_constant . '-acache.php';
- /* WordPress advanced-cache.php file location */
- $this->acache = WP_CONTENT_DIR . '/advanced-cache.php';
- /* nginx sample config file */
- $this->nginx_sample = $this->plugin_dir . $this->plugin_constant . '-nginx-sample.conf';
- /* backend driver file */
- $this->acache_backend = $this->plugin_dir . $this->plugin_constant . '-backend.php';
- /* flush button identifier */
- $this->button_flush = $this->plugin_constant . '-flush';
- /* precache button identifier */
- $this->button_precache = $this->plugin_constant . '-precache';
- /* global options identifier */
- $this->global_option = $this->plugin_constant . '-global';
- /* precache log */
- $this->precache_logfile = sys_get_temp_dir() . '/' . self::precache_log;
- /* this is the precacher php worker file */
- $this->precache_phpfile = sys_get_temp_dir() . '/' . self::precache_php;
- /* search for a system function */
- $this->shell_possibilities = array ( 'shell_exec', 'exec', 'system', 'passthru' );
- /* get disabled functions list */
- $disabled_functions = array_map('trim', explode(',', ini_get('disable_functions') ) );
-
- foreach ( $this->shell_possibilities as $possible ) {
- if ( function_exists ($possible) && ! ( ini_get('safe_mode') || in_array( $possible, $disabled_functions ) ) ) {
- /* set shell function */
- $this->shell_function = $possible;
- break;
- }
- }
-
- /* set global config key; here, because it's needed for migration */
- if ( $this->network )
- $this->global_config_key = 'network';
- else
- $this->global_config_key = $_SERVER['HTTP_HOST'];
-
- /* cache type possible values array */
- $this->select_cache_type = array (
- 'apc' => __( 'APC' , $this->plugin_constant ),
- 'apcu' => __( 'APCu' , $this->plugin_constant ),
- 'xcache' => __( 'XCache' , $this->plugin_constant ),
- 'memcache' => __( 'PHP Memcache' , $this->plugin_constant ),
- 'memcached' => __( 'PHP Memcached' , $this->plugin_constant ),
- );
- /* check for required functions / classes for the cache types */
- $this->valid_cache_type = array (
- 'apc' => function_exists( 'apc_cache_info' ) ? true : false,
- 'apcu' => function_exists( 'apcu_cache_info' ) ? true : false,
- 'xcache' => function_exists( 'xcache_info' ) ? true : false,
- 'memcache' => class_exists ( 'Memcache') ? true : false,
- 'memcached' => class_exists ( 'Memcached') ? true : false,
- );
-
- /* invalidation method possible values array */
- $this->select_invalidation_method = array (
- 0 => __( 'flush cache' , $this->plugin_constant ),
- 1 => __( 'only modified post' , $this->plugin_constant ),
- 2 => __( 'modified post and all taxonomies' , $this->plugin_constant ),
- );
-
- /* map of possible key masks */
- $this->list_uri_vars = array (
- '$scheme' => __('The HTTP scheme (i.e. http, https).', $this->plugin_constant ),
- '$host' => __('Host in the header of request or name of the server processing the request if the Host header is not available.', $this->plugin_constant ),
- '$request_uri' => __('The *original* request URI as received from the client including the args', $this->plugin_constant ),
- '$remote_user' => __('Name of user, authenticated by the Auth Basic Module', $this->plugin_constant ),
- '$cookie_PHPSESSID' => __('PHP Session Cookie ID, if set ( empty if not )', $this->plugin_constant ),
- //'$cookie_COOKnginy IE' => __('Value of COOKIE', $this->plugin_constant ),
- //'$http_HEADER' => __('Value of HTTP request header HEADER ( lowercase, dashes converted to underscore )', $this->plugin_constant ),
- //'$query_string' => __('Full request URI after rewrites', $this->plugin_constant ),
- //'' => __('', $this->plugin_constant ),
- );
-
- /* get current wp_cron schedules */
- $wp_schedules = wp_get_schedules();
- /* add 'null' to switch off timed precache */
- $schedules['null'] = __( 'do not use timed precache' );
- foreach ( $wp_schedules as $interval=>$details ) {
- $schedules[ $interval ] = $details['display'];
- }
- $this->select_schedules = $schedules;
-
- }
-
- /**
- * additional init, steps that needs the plugin options
- *
- */
- public function plugin_setup () {
-
- /* initiate backend */
- $this->backend = new WP_FFPC_Backend ( $this->options, $this->network );
-
- /* get all available post types */
- $post_types = get_post_types( );
-
- /* cache invalidation hooks */
- foreach ( $post_types as $post_type ) {
- add_action( 'new_to_publish_' .$post_type , array( &$this->backend , 'clear' ), 0 );
- add_action( 'draft_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
- add_action( 'pending_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
- add_action( 'private_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
- add_action( 'publish_' . $post_type , array( &$this->backend , 'clear' ), 0 );
- }
-
- /* comments invalidation hooks */
- if ( $this->options['comments_invalidate'] ) {
- add_action( 'comment_post', array( &$this->backend , 'clear' ), 0 );
- add_action( 'edit_comment', array( &$this->backend , 'clear' ), 0 );
- add_action( 'trashed_comment', array( &$this->backend , 'clear' ), 0 );
- add_action( 'pingback_post', array( &$this->backend , 'clear' ), 0 );
- add_action( 'trackback_post', array( &$this->backend , 'clear' ), 0 );
- add_action( 'wp_insert_comment', array( &$this->backend , 'clear' ), 0 );
- add_action( '', array( &$this->backend , 'clear' ), 0 );
- }
-
- /* invalidation on some other ocasions as well */
- add_action( 'switch_theme', array( &$this->backend , 'clear' ), 0 );
- add_action( 'deleted_post', array( &$this->backend , 'clear' ), 0 );
- add_action( 'edit_post', array( &$this->backend , 'clear' ), 0 );
-
- /* add filter for catching canonical redirects */
- if ( WP_CACHE )
- add_filter('redirect_canonical', 'wp_ffpc_redirect_callback', 10, 2);
-
- /* clean up schedule if needed */
- if ( !isset( $this->options['precache_schedule'] ) || $this->options['precache_schedule'] == 'null' ) {
- $this->log ( sprintf ( __( 'clearing scheduled hook %s', $this->plugin_constant ), self::precache_id ) );
- }
-
- /* add precache coldrun action */
- add_action( self::precache_id , array( &$this, 'precache_coldrun' ) );
-
- $settings_link = ' » ' . __( 'WP-FFPC Settings', $this->plugin_constant ) . '';
- /* check for errors */
- if ( ! WP_CACHE )
- $this->errors['no_wp_cache'] = __("WP_CACHE is disabled, plugin will not work that way. Please add define `( 'WP_CACHE', true );` in wp-config.php", $this->plugin_constant ) . $settings_link;
-
- if ( ! $this->global_saved )
- $this->errors['no_global_saved'] = __("Plugin settings are not yet saved for the site, please save settings!", $this->plugin_constant) . $settings_link;
-
- if ( ! file_exists ( $this->acache ) )
- $this->errors['no_acache_saved'] = __("Advanced cache file is yet to be generated, please save settings!", $this->plugin_constant). $settings_link;
-
- if ( file_exists ( $this->acache ) && ! is_writable ( $this->acache ) )
- $this->errors['no_acache_write'] = __("Advanced cache file is not writeable!
Please change the permissions on the file: ", $this->plugin_constant) . $this->acache;
-
- foreach ( $this->valid_cache_type as $backend => $status ) {
- if ( $this->options['cache_type'] == $backend && ! $status ) {
- $this->errors['no_backend'] = sprintf ( __('%s cache backend activated but no PHP %s extension was found.
Please either use different backend or activate the module!', $this->plugin_constant), $backend, $backend );
- }
- }
-
- /* get the current runtime configuration for memcache in PHP because Memcache in binary mode is really problematic */
- if ( extension_loaded ( 'memcache' ) ) {
- $memcache_settings = ini_get_all( 'memcache' );
- if ( !empty ( $memcache_settings ) && $this->options['cache_type'] == 'memcache' )
- {
- $memcache_protocol = strtolower($memcache_settings['memcache.protocol']['local_value']);
- if ( $memcache_protocol == 'binary' ) {
- $this->errors['binary_memcache'] = __('WARNING: Memcache extension is configured to use binary mode. This is very buggy and the plugin will most probably not work correctly.
Please consider to change either to ASCII mode or to Memcached extension.', $this->plugin_constant );
- }
- }
- }
-
- /* display errors globally */
- if ( $this->network )
- add_action( 'network_admin_notices', array( &$this, 'display_errors') );
- else
- add_action( 'admin_notices', array( &$this, 'display_errors') );
- }
-
- /**
- * activation hook function, to be extended
- */
- public function plugin_activate() {
- /* we leave this empty to avoid not detecting WP network correctly */
- }
-
- /**
- * deactivation hook function, to be extended
- */
- public function plugin_deactivate () {
- /* remove current site config from global config */
- $this->update_global_config( true );
- }
-
- /**
- * uninstall hook function, to be extended
- */
- public function plugin_uninstall( $delete_options = true ) {
- /* delete advanced-cache.php file */
- unlink ( $this->acache );
-
- /* delete site settings */
- if ( $delete_options ) {
- $this->plugin_options_delete ();
+ foreach ( $this->shell_possibilities as $possible ) {
+ if ( function_exists ($possible) && ! ( ini_get('safe_mode') || in_array( $possible, $disabled_functions ) ) ) {
+ /* set shell function */
+ $this->shell_function = $possible;
+ break;
}
}
- /**
- * extending admin init
- *
- */
- public function plugin_hook_admin_init () {
- /* save parameter updates, if there are any */
- if ( isset( $_POST[ $this->button_flush ] ) ) {
+ /* set global config key; here, because it's needed for migration */
+ if ( $this->network )
+ $this->global_config_key = 'network';
+ else
+ $this->global_config_key = $_SERVER['HTTP_HOST'];
- /* remove precache log entry */
- $this->_delete_option( self::precache_log );
- /* remove precache timestamp entry */
- $this->_delete_option( self::precache_timestamp );
+ /* cache type possible values array */
+ $this->select_cache_type = array (
+ 'apc' => __( 'APC' , $this->plugin_constant ),
+ 'apcu' => __( 'APCu' , $this->plugin_constant ),
+ 'xcache' => __( 'XCache' , $this->plugin_constant ),
+ 'memcache' => __( 'PHP Memcache' , $this->plugin_constant ),
+ 'memcached' => __( 'PHP Memcached' , $this->plugin_constant ),
+ );
+ /* check for required functions / classes for the cache types */
+ $this->valid_cache_type = array (
+ 'apc' => function_exists( 'apc_cache_info' ) ? true : false,
+ 'apcu' => function_exists( 'apcu_cache_info' ) ? true : false,
+ 'xcache' => function_exists( 'xcache_info' ) ? true : false,
+ 'memcache' => class_exists ( 'Memcache') ? true : false,
+ 'memcached' => class_exists ( 'Memcached') ? true : false,
+ );
- /* remove precache logfile */
- if ( @file_exists ( $this->precache_logfile ) ) {
- unlink ( $this->precache_logfile );
- }
+ /* invalidation method possible values array */
+ $this->select_invalidation_method = array (
+ 0 => __( 'flush cache' , $this->plugin_constant ),
+ 1 => __( 'only modified post' , $this->plugin_constant ),
+ 2 => __( 'modified post and all taxonomies' , $this->plugin_constant ),
+ );
- /* remove precache PHP worker */
- if ( @file_exists ( $this->precache_phpfile ) ) {
- unlink ( $this->precache_phpfile );
- }
+ /* map of possible key masks */
+ $this->list_uri_vars = array (
+ '$scheme' => __('The HTTP scheme (i.e. http, https).', $this->plugin_constant ),
+ '$host' => __('Host in the header of request or name of the server processing the request if the Host header is not available.', $this->plugin_constant ),
+ '$request_uri' => __('The *original* request URI as received from the client including the args', $this->plugin_constant ),
+ '$remote_user' => __('Name of user, authenticated by the Auth Basic Module', $this->plugin_constant ),
+ '$cookie_PHPSESSID' => __('PHP Session Cookie ID, if set ( empty if not )', $this->plugin_constant ),
+ //'$cookie_COOKnginy IE' => __('Value of COOKIE', $this->plugin_constant ),
+ //'$http_HEADER' => __('Value of HTTP request header HEADER ( lowercase, dashes converted to underscore )', $this->plugin_constant ),
+ //'$query_string' => __('Full request URI after rewrites', $this->plugin_constant ),
+ //'' => __('', $this->plugin_constant ),
+ );
- /* flush backend */
- $this->backend->clear( false, true );
- $this->status = 3;
- header( "Location: ". $this->settings_link . self::slug_flush );
+ /* get current wp_cron schedules */
+ $wp_schedules = wp_get_schedules();
+ /* add 'null' to switch off timed precache */
+ $schedules['null'] = __( 'do not use timed precache' );
+ foreach ( $wp_schedules as $interval=>$details ) {
+ $schedules[ $interval ] = $details['display'];
+ }
+ $this->select_schedules = $schedules;
+
+ }
+
+ /**
+ * additional init, steps that needs the plugin options
+ *
+ */
+ public function plugin_post_init () {
+
+ /* initiate backend */
+ $this->backend = new WP_FFPC_Backend ( $this->options, $this->network );
+
+ /* get all available post types */
+ $post_types = get_post_types( );
+
+ /* cache invalidation hooks */
+ foreach ( $post_types as $post_type ) {
+ add_action( 'new_to_publish_' .$post_type , array( &$this->backend , 'clear' ), 0 );
+ add_action( 'draft_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
+ add_action( 'pending_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
+ add_action( 'private_to_publish' .$post_type , array( &$this->backend , 'clear' ), 0 );
+ add_action( 'publish_' . $post_type , array( &$this->backend , 'clear' ), 0 );
+ }
+
+ /* comments invalidation hooks */
+ if ( $this->options['comments_invalidate'] ) {
+ add_action( 'comment_post', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'edit_comment', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'trashed_comment', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'pingback_post', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'trackback_post', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'wp_insert_comment', array( &$this->backend , 'clear' ), 0 );
+ add_action( '', array( &$this->backend , 'clear' ), 0 );
+ }
+
+ /* invalidation on some other ocasions as well */
+ add_action( 'switch_theme', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'deleted_post', array( &$this->backend , 'clear' ), 0 );
+ add_action( 'edit_post', array( &$this->backend , 'clear' ), 0 );
+
+ /* add filter for catching canonical redirects */
+ if ( WP_CACHE )
+ add_filter('redirect_canonical', 'wp_ffpc_redirect_callback', 10, 2);
+
+ /* clean up schedule if needed */
+ if ( !isset( $this->options['precache_schedule'] ) || $this->options['precache_schedule'] == 'null' ) {
+ $this->log ( sprintf ( __( 'clearing scheduled hook %s', $this->plugin_constant ), self::precache_id ) );
+ }
+
+ /* add precache coldrun action */
+ add_action( self::precache_id , array( &$this, 'precache_coldrun' ) );
+
+ $settings_link = ' » ' . __( 'WP-FFPC Settings', $this->plugin_constant ) . '';
+ /* check for errors */
+ if ( ! WP_CACHE )
+ $this->errors['no_wp_cache'] = __("WP_CACHE is disabled, plugin will not work that way. Please add define `( 'WP_CACHE', true );` in wp-config.php", $this->plugin_constant ) . $settings_link;
+
+ if ( ! $this->global_saved )
+ $this->errors['no_global_saved'] = __("Plugin settings are not yet saved for the site, please save settings!", $this->plugin_constant) . $settings_link;
+
+ if ( ! file_exists ( $this->acache ) )
+ $this->errors['no_acache_saved'] = __("Advanced cache file is yet to be generated, please save settings!", $this->plugin_constant). $settings_link;
+
+ if ( file_exists ( $this->acache ) && ! is_writable ( $this->acache ) )
+ $this->errors['no_acache_write'] = __("Advanced cache file is not writeable!
Please change the permissions on the file: ", $this->plugin_constant) . $this->acache;
+
+ foreach ( $this->valid_cache_type as $backend => $status ) {
+ if ( $this->options['cache_type'] == $backend && ! $status ) {
+ $this->errors['no_backend'] = sprintf ( __('%s cache backend activated but no PHP %s extension was found.
Please either use different backend or activate the module!', $this->plugin_constant), $backend, $backend );
}
+ }
- /* save parameter updates, if there are any */
- if ( isset( $_POST[ $this->button_precache ] ) ) {
-
- /* is no shell function is possible, fail */
- if ( $this->shell_function == false ) {
- $this->status = 5;
- header( "Location: ". $this->settings_link . self::slug_precache_disabled );
- }
- /* otherwise start full precache */
- else {
- $this->precache_message = $this->precache_coldrun();
- $this->status = 4;
- header( "Location: ". $this->settings_link . self::slug_precache );
+ /* get the current runtime configuration for memcache in PHP because Memcache in binary mode is really problematic */
+ if ( extension_loaded ( 'memcache' ) ) {
+ $memcache_settings = ini_get_all( 'memcache' );
+ if ( !empty ( $memcache_settings ) && $this->options['cache_type'] == 'memcache' )
+ {
+ $memcache_protocol = strtolower($memcache_settings['memcache.protocol']['local_value']);
+ if ( $memcache_protocol == 'binary' ) {
+ $this->errors['binary_memcache'] = __('WARNING: Memcache extension is configured to use binary mode. This is very buggy and the plugin will most probably not work correctly.
Please consider to change either to ASCII mode or to Memcached extension.', $this->plugin_constant );
}
}
}
- /**
- * admin help panel
- */
- public function plugin_admin_help($contextual_help, $screen_id ) {
+ foreach ( $this->errors as $e => $msg ) {
+ $this->utils->alert ( $msg, 'error', $this->network );
+ }
+ }
- /* add our page only if the screenid is correct */
- if ( strpos( $screen_id, $this->plugin_settings_page ) ) {
- $contextual_help = __('
Please visit the official support forum of the plugin for help.
', $this->plugin_constant ); + /** + * activation hook function, to be extended + */ + public function plugin_activate() { + /* we leave this empty to avoid not detecting WP network correctly */ + } - /* [TODO] give detailed information on errors & troubleshooting - get_current_screen()->add_help_tab( array( - 'id' => $this->plugin_constant . '-issues', - 'title' => __( 'Troubleshooting' ), - 'content' => __( 'List of errors, possible reasons and solutions
plugin_constant ) ?>
plugin_constant ) ?>
plugin_constant ); ?>
plugin_constant ) ?>
plugin_constant); echo $this->options['cache_type']; ?>
- options['cache_type'], 'memcache') ) { - ?>Backend status:
', $this->plugin_constant );
-
- /* we need to go through all servers */
- $servers = $this->backend->status();
- foreach ( $servers as $server_string => $status ) {
- echo $server_string ." => ";
-
- if ( $status == 0 )
- _e ( 'down
', $this->plugin_constant );
- elseif ( ( $this->options['cache_type'] == 'memcache' && $status > 0 ) || $status == 1 )
- _e ( 'up & running
', $this->plugin_constant );
- else
- _e ( 'unknown, please try re-saving settings!
', $this->plugin_constant );
- }
-
- ?>
Please visit the official support forum of the plugin for help.
', $this->plugin_constant ); - /* deploy advanced-cache.php */ - $this->deploy_advanced_cache (); - - /* save options to database */ - update_site_option( $this->global_option , $this->global_config ); - } - - - /** - * generate cache entry for every available permalink, might be very-very slow, - * therefore it starts a background process - * - */ - private function precache ( &$links ) { - - /* double check if we do have any links to pre-cache */ - if ( !empty ( $links ) && !$this->precache_running() ) { - - $out = ' $dummy ) { - $starttime = explode ( " ", microtime() ); - $starttime = $starttime[1] + $starttime[0]; - - $page = file_get_contents( $permalink ); - $size = round ( ( strlen ( $page ) / 1024 ), 2 ); - - $endtime = explode ( " ", microtime() ); - $endtime = round( ( $endtime[1] + $endtime[0] ) - $starttime, 2 ); - - echo $permalink . "\t" . $endtime . "\t" . $size . "\n"; - unset ( $page, $size, $starttime, $endtime ); - sleep( 1 ); - } - unlink ( "'. $this->precache_phpfile .'" ); - ?>'; - - file_put_contents ( $this->precache_phpfile, $out ); - /* call the precache worker file in the background */ - $shellfunction = $this->shell_function; - $shellfunction( 'php '. $this->precache_phpfile .' >'. $this->precache_logfile .' 2>&1 &' ); - } - - } - - /** - * check is precache is still ongoing - * - */ - private function precache_running () { - $return = false; - - /* if the precache file exists, it did not finish running as it should delete itself on finish */ - if ( file_exists ( $this->precache_phpfile )) { - $return = true; - } - /* - [TODO] cross-platform process check; this is *nix only - else { - $shellfunction = $this->shell_function; - $running = $shellfunction( "ps aux | grep \"". $this->precache_phpfile ."\" | grep -v grep | awk '{print $2}'" ); - if ( is_int( $running ) && $running != 0 ) { - $return = true; - } - } + /* [TODO] give detailed information on errors & troubleshooting + get_current_screen()->add_help_tab( array( + 'id' => $this->plugin_constant . '-issues', + 'title' => __( 'Troubleshooting' ), + 'content' => __( 'List of errors, possible reasons and solutions
plugin_constant ) ?>
plugin_constant ) ?>
plugin_constant ); ?>
plugin_constant ) ?>
plugin_constant); echo $this->options['cache_type']; ?>
+ options['cache_type'], 'memcache') ) { + ?>Backend status:
', $this->plugin_constant );
+
+ /* we need to go through all servers */
+ $servers = $this->backend->status();
+ foreach ( $servers as $server_string => $status ) {
+ echo $server_string ." => ";
+
+ if ( $status == 0 )
+ _e ( 'down
', $this->plugin_constant );
+ elseif ( ( $this->options['cache_type'] == 'memcache' && $status > 0 ) || $status == 1 )
+ _e ( 'up & running
', $this->plugin_constant );
+ else
+ _e ( 'unknown, please try re-saving settings!
', $this->plugin_constant );
+ }
+
+ ?>