Viewing file: FragmentCache.php (18.91 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/** * W3 Fragment Cache object */ class W3_Pro_FragmentCache { /** * Internal cache array * * @var array */ var $cache = array();
/** * Array of global groups * * @var array */ var $global_groups = array('site-transient');
/** * List of non-persistent groups * * @var array */ var $nonpersistent_groups = array();
/** * Total count of calls * * @var integer */ var $cache_total = 0;
/** * Cache hits count * * @var integer */ var $cache_hits = 0;
/** * Cache misses count * * @var integer */ var $cache_misses = 0;
/** * Total time * * @var integer */ var $time_total = 0;
/** * Store debug information of w3tc using * * @var array */ var $debug_info = array();
/** * Blog id of cache * * @var integer */ private $_blog_id;
/** * Key cache * * @var array */ var $_key_cache = array();
/** * Config * * @var W3_Config */ var $_config = null;
/** * Caching flag * * @var boolean */ var $_caching = false;
/** * Cache reject reason * * @var string */ var $cache_reject_reason = '';
/** * Lifetime * * @var integer */ var $_lifetime = 0;
/** * Debug flag * * @var boolean */ var $_debug = false;
private $_fragmentcache = null;
/** * Returns instance. for backward compatibility with 0.9.2.3 version of /wp-content files * * @return W3_ObjectCache */ function instance() { return w3_instance('W3_Pro_FragmentCache'); }
/** * PHP5 style constructor */ function __construct() { global $_wp_using_ext_object_cache;
$this->_config = w3_instance('W3_Config'); $this->_lifetime = $this->_config->get_integer('fragmentcache.lifetime'); $this->_debug = $this->_config->get_boolean('fragmentcache.debug'); $this->_caching = $_wp_using_ext_object_cache = $this->_can_cache();
$this->_blog_id = w3_get_blog_id(); $this->_fragmentcache = w3_instance('W3_Pro_Plugin_FragmentCache'); }
/** * Get from the cache * * @param string $id * @param string $group * @return mixed */ function get($id, $group = 'transient') { if ($this->_debug) { $time_start = w3_microtime(); }
$key = $this->_get_cache_key($id, $group); list($fragment_group, $fragment_group_expiration) = $this->_fragment_group($id); $internal = isset($this->cache[$fragment_group . $group][$key]);
if ($internal) { $value = $this->cache[$fragment_group . $group][$key]; } elseif ($this->_caching && !in_array($group, $this->nonpersistent_groups)) { $cache = $this->_get_cache(null, $group); $v = $cache->get($key, $fragment_group); if (is_array($v) && $v['content'] != null) $value = $v['content']; else $value = false; } else { $value = false; }
if ($value === null) { $value = false; }
if (is_object($value)) { $value = clone( $value ); }
$this->cache[$fragment_group . $group][$key] = $value; $this->cache_total++;
if ($value !== false) { $cached = true; $this->cache_hits++; } else { $cached = false; $this->cache_misses++; }
/** * Add debug info */ if ($this->_debug) { $time = w3_microtime() - $time_start; $this->time_total += $time;
if (!$group) { $group = 'transient'; }
$this->debug_info[] = array( 'id' => $id, 'group' => $group, 'cached' => $cached, 'internal' => $internal, 'data_size' => ($value ? strlen(serialize($value)) : ''), 'time' => $time ); }
return $value; }
/** * Set to the cache * * @param string $id * @param mixed $data * @param string $group * @param integer $expire * @return boolean */ function set($id, $data, $group = 'transient', $expire = 0) { $key = $this->_get_cache_key($id, $group);
if (is_object($data)) { $data = clone( $data ); }
list($fragment_group, $fragment_group_expiration) = $this->_fragment_group($id); if (is_int($fragment_group_expiration)) $expire = $fragment_group_expiration;
$this->cache[$fragment_group . $group][$key] = $data;
if ($this->_caching && !in_array($group, $this->nonpersistent_groups)) { $cache = $this->_get_cache(null, $group);
$v = array('content' => $data); return $cache->set($key, $v, ($expire ? $expire : $this->_lifetime), $fragment_group); }
return true; }
/** * Delete from the cache * * @param string $id * @param string $group * @param bool $force * @return boolean */ function delete($id, $group = 'transient', $force = false) { if (!$force && $this->get($id, $group) === false) { return false; } list($fragment_group, $fragment_group_expiration) = $this->_fragment_group($id);
$key = $this->_get_cache_key($id, $group);
unset($this->cache[$fragment_group . $group][$key]);
if ($this->_caching && !in_array($group, $this->nonpersistent_groups)) { $cache = $this->_get_cache(null, $group);
return $cache->delete($key, $fragment_group); }
return true; }
/** * Add to the cache * * @param string $id * @param mixed $data * @param string $group * @param integer $expire * @return boolean */ function add($id, $data, $group = 'default', $expire = 0) { if ($this->get($id, $group) !== false) { return false; }
return $this->set($id, $data, $group, $expire); }
/** * Replace in the cache * * @param string $id * @param mixed $data * @param string $group * @param integer $expire * @return boolean */ function replace($id, $data, $group = 'default', $expire = 0) { if ($this->get($id, $group) === false) { return false; }
return $this->set($id, $data, $group, $expire); }
/** * Reset keys * * @return boolean */ function reset() { global $_wp_using_ext_object_cache;
$_wp_using_ext_object_cache = $this->_caching;
return true; }
/** * Flush cache * @return boolean */ function flush() { $this->cache = array();
if ($this->_caching) { $cache1 = $this->_get_cache(null,'transient'); $groups = $this->_fragmentcache->get_registered_fragment_groups(); $cache1->flush('nogroup'); foreach ($groups as $group => $descriptor) $cache1->flush($group);
if (is_network_admin()) { $cache2 = $this->_get_cache(null,'site-transient'); $cache2->flush('nogroup'); $global_groups = $this->_fragmentcache->get_registered_global_fragment_groups(); foreach ($global_groups as $group => $descriptor) $cache2->flush($group); } return true; }
return true; }
/** * Purges all transients that belong to a transient group * * @param string $fragment_group fragment grouping * @param bool $global whether flush site group or network wide, default is site specific. Use true for network wide. * @return bool */ function flush_group($fragment_group, $global = false) { $group = $global ? 'site-transient' : 'transient'; unset($this->cache[$fragment_group . $group]); if ($this->_caching) { $cache = $this->_get_cache(null, $group); return $cache->flush($fragment_group); } return true; }
/** * Add global groups * * @param array $groups * @return void */ function add_global_groups($groups) { if (!is_array($groups)) { $groups = (array) $groups; }
$this->global_groups = array_merge($this->global_groups, $groups); $this->global_groups = array_unique($this->global_groups); }
/** * Add non-persistent groups * * @param array $groups * @return void */ function add_nonpersistent_groups($groups) { if (!is_array($groups)) { $groups = (array) $groups; }
$this->nonpersistent_groups = array_merge($this->nonpersistent_groups, $groups); $this->nonpersistent_groups = array_unique($this->nonpersistent_groups); }
/** * Increment numeric cache item's value * * @param int|string $key The cache key to increment * @param int $offset The amount by which to increment the item's value. Default is 1. * @param string $group The group the key is in. * @return bool|int False on failure, the item's new value on success. */ function incr( $key, $offset = 1, $group = 'default' ) { $value = $this->get($key, $group); if ($value === false) return false;
if (!is_numeric($value)) $value = 0;
$offset = (int) $offset; $value += $offset;
if ( $value < 0 ) $value = 0; $this->replace($key, $value, $group); return $value; }
/** * Decrement numeric cache item's value * * @param int|string $key The cache key to increment * @param int $offset The amount by which to decrement the item's value. Default is 1. * @param string $group The group the key is in. * @return bool|int False on failure, the item's new value on success. */ function decr( $key, $offset = 1, $group = 'default' ) { $value = $this->get($key, $group); if ($value === false) return false;
if (!is_numeric($value)) $value = 0;
$offset = (int) $offset; $value -= $offset;
if ( $value < 0 ) $value = 0; $this->replace($key, $value, $group); return $value; }
/** * Print Fragment Cache stats * * @return void */ function stats() { echo '<h2>Summary</h2>'; echo '<p>'; echo '<strong>Engine</strong>: ' . w3_get_engine_name($this->_config->get_string('fragmentcache.engine')) . '<br />'; echo '<strong>Caching</strong>: ' . ($this->_caching ? 'enabled' : 'disabled') . '<br />';
if (!$this->_caching) { echo '<strong>Reject reason</strong>: ' . $this->cache_reject_reason . '<br />'; }
echo '<strong>Total calls</strong>: ' . $this->cache_total . '<br />'; echo '<strong>Cache hits</strong>: ' . $this->cache_hits . '<br />'; echo '<strong>Cache misses</strong>: ' . $this->cache_misses . '<br />'; echo '<strong>Total time</strong>: '. round($this->time_total, 4) . 's'; echo '</p>';
echo '<h2>Cache info</h2>';
if ($this->_debug) { echo '<table cellpadding="0" cellspacing="3" border="1">'; echo '<tr><td>#</td><td>Status</td><td>Source</td><td>Data size (b)</td><td>Query time (s)</td><td>ID:Group</td></tr>';
foreach ($this->debug_info as $index => $debug) { echo '<tr>'; echo '<td>' . ($index + 1) . '</td>'; echo '<td>' . ($debug['cached'] ? 'cached' : 'not cached') . '</td>'; echo '<td>' . ($debug['internal'] ? 'internal' : 'persistent') . '</td>'; echo '<td>' . $debug['data_size'] . '</td>'; echo '<td>' . round($debug['time'], 4) . '</td>'; echo '<td>' . sprintf('%s:%s', $debug['id'], $debug['group']) . '</td>'; echo '</tr>'; }
echo '</table>'; } else { echo '<p>Enable debug mode.</p>'; } }
/** * Switches context to another blog * * @param integer $blog_id */ function switch_blog($blog_id) { $this->reset(); $this->_blog_id = $blog_id; }
/** * Returns cache key * * @param string $id * @param string $group * @return string */ function _get_cache_key($id, $group = 'transient') { if (!$group) { $group = 'default'; }
$blog_id = $this->_blog_id; if ($group == 'site-transient') $blog_id = 0;
$key_cache_id = $blog_id . $group . $id;
if (isset($this->_key_cache[$key_cache_id])) { $key = $this->_key_cache[$key_cache_id]; } else { $key = md5($key_cache_id); $this->_key_cache[$key_cache_id] = $key; }
return $key; }
/** * Returns cache object * * @param null $blog_id * @param string $group * @return W3_Cache_Base */ function _get_cache($blog_id = null, $group = 'transient') { static $cache = array();
if (is_null($blog_id) && $group != 'site-transient') $blog_id = $this->_blog_id; else $blog_id = 0;
if (!isset($cache[$blog_id])) { $engine = $this->_config->get_string('fragmentcache.engine');
switch ($engine) { case 'memcached': $engineConfig = array( 'servers' => $this->_config->get_array('fragmentcache.memcached.servers'), 'persistant' => $this->_config->get_boolean('fragmentcache.memcached.persistant') ); break;
case 'file': $engineConfig = array( 'section' => 'fragment', 'locking' => $this->_config->get_boolean('fragmentcache.file.locking'), 'flush_timelimit' => $this->_config->get_integer('timelimit.cache_flush') ); break;
default: $engineConfig = array(); } $engineConfig['blog_id'] = $blog_id; $engineConfig['module'] = 'fragmentcache'; $engineConfig['host'] = w3_get_host(); $engineConfig['instance_id'] = w3_get_instance_id();
w3_require_once(W3TC_LIB_W3_DIR . '/Cache.php');
$cache[$blog_id] = W3_Cache::instance($engine, $engineConfig); }
return $cache[$blog_id]; }
/** * Check if caching allowed on init * * @return boolean */ function _can_cache() { /** * Skip if disabled */ if (!$this->_config->get_boolean('fragmentcache.enabled')) { $this->cache_reject_reason = __('Fragment caching is disabled', 'w3-total-cache');
return false; }
return true; }
/** * Returns debug info * * @return string */ function _get_debug_info() { $debug_info = "<!-- W3 Total Cache: Fragment Cache debug info:\r\n"; $debug_info .= sprintf("%s%s\r\n", str_pad('Engine: ', 20), w3_get_engine_name($this->_config->get_string('fragmentcache.engine'))); $debug_info .= sprintf("%s%s\r\n", str_pad('Caching: ', 20), ($this->_caching ? 'enabled' : 'disabled'));
if (!$this->_caching) { $debug_info .= sprintf("%s%s\r\n", str_pad('Reject reason: ', 20), $this->cache_reject_reason); }
$debug_info .= sprintf("%s%d\r\n", str_pad('Total calls: ', 20), $this->cache_total); $debug_info .= sprintf("%s%d\r\n", str_pad('Cache hits: ', 20), $this->cache_hits); $debug_info .= sprintf("%s%d\r\n", str_pad('Cache misses: ', 20), $this->cache_misses); $debug_info .= sprintf("%s%.4f\r\n", str_pad('Total time: ', 20), $this->time_total);
$debug_info .= "W3TC Fragment Cache info:\r\n"; $debug_info .= sprintf("%s | %s | %s | %s | %s | %s| %s| %s\r\n", str_pad('#', 5, ' ', STR_PAD_LEFT), str_pad('Status', 15, ' ', STR_PAD_BOTH), str_pad('Source', 15, ' ', STR_PAD_BOTH), str_pad('Data size (b)', 13, ' ', STR_PAD_LEFT), str_pad('Query time (s)', 14, ' ', STR_PAD_LEFT), str_pad('Group', 14, ' ', STR_PAD_LEFT), str_pad('Accessible', 10, ' ', STR_PAD_LEFT), 'Transient ID');
foreach ($this->debug_info as $index => $debug) { list($fragment_group, $fragment_group_expiration) = $this->_fragment_group($debug['id']); $debug_info .= sprintf("%s | %s | %s | %s | %s | %s| %s| %s\r\n", str_pad($index + 1, 5, ' ', STR_PAD_LEFT), str_pad(($debug['cached'] ? 'cached' : 'not cached'), 15, ' ', STR_PAD_BOTH), str_pad(($debug['internal'] ? 'internal' : 'persistent'), 15, ' ', STR_PAD_BOTH), str_pad($debug['data_size'], 13, ' ', STR_PAD_LEFT), str_pad(round($debug['time'], 4), 14, ' ', STR_PAD_LEFT), str_pad($fragment_group, 14, ' ', STR_PAD_LEFT), str_pad(($debug['group'] == 'transient' ? 'site' : 'network'), 10, ' ', STR_PAD_LEFT), $debug['id']); }
$debug_info .= '-->';
return $debug_info; }
/** * Returns the group part of a transient/site-transient id. * Uses registered fragment groups to identify it. * * @param $id * @return string */ private function _fragment_group($id) { if (empty($id)) return 'nogroup'; $groups = $this->_fragmentcache->get_registered_fragment_groups(); $use_group = ''; $length = 0; foreach ($groups as $group => $descriptor) if (strpos($id, $group) !== false) { if (strlen($group)>$length) { $length = strlen($group); $use_group = array($group, $descriptor['expiration']); } } if ($use_group) return $use_group;
$global_groups = $this->_fragmentcache->get_registered_global_fragment_groups(); $use_group = ''; $length = 0; foreach ($global_groups as $group => $descriptor) if (strpos($id, $group) !== false) { if (strlen($group)>$length) { $length = strlen($group); $use_group = array($group, $descriptor['expiration']); } } if ($use_group) return $use_group;
return 'nogroup'; } }
|