Created
January 4, 2012 18:25
-
-
Save mintindeed/1561344 to your computer and use it in GitHub Desktop.
Modified W3TC PgCache.php file to work with nginx-memcached interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Look for "@custom" to see customizations | |
// Sourced from W3TC v0.9.2.4 | |
// Full path: /w3-total-cache/lib/W3/PgCache.php | |
/** | |
* W3 PgCache | |
*/ | |
/** | |
* Class W3_PgCache | |
*/ | |
class W3_PgCache { | |
/** | |
* Advanced cache config | |
* | |
* @var W3_Config | |
*/ | |
var $_config = null; | |
/** | |
* Caching flag | |
* | |
* @var boolean | |
*/ | |
var $_caching = false; | |
/** | |
* Time start | |
* | |
* @var double | |
*/ | |
var $_time_start = 0; | |
/** | |
* Lifetime | |
* @var integer | |
*/ | |
var $_lifetime = 0; | |
/** | |
* Enhanced mode flag | |
* | |
* @var boolean | |
*/ | |
var $_enhanced_mode = false; | |
/** | |
* Debug flag | |
* | |
* @var boolean | |
*/ | |
var $_debug = false; | |
/** | |
* Request URI | |
* @var string | |
*/ | |
var $_request_uri = ''; | |
/** | |
* Page key | |
* @var string | |
*/ | |
var $_page_key = ''; | |
/** | |
* Shutdown buffer | |
* @var string | |
*/ | |
var $_shutdown_buffer = ''; | |
/** | |
* Shutdown compression | |
* @var string | |
*/ | |
var $_shutdown_compression = ''; | |
/** | |
* Mobile object | |
* @var W3_Mobile | |
*/ | |
var $_mobile = null; | |
/** | |
* Referrer object | |
* @var W3_Referrer | |
*/ | |
var $_referrer = null; | |
/** | |
* Cache reject reason | |
* | |
* @var string | |
*/ | |
var $cache_reject_reason = ''; | |
/** | |
* Returns instance. | |
* For backward compatibility with 0.9.2.3 version of /wp-content files | |
* | |
* @return W3_PgCache | |
*/ | |
function &instance() { | |
$i = & w3_instance('W3_PgCache'); | |
$i->_legacy = true; | |
return $i; | |
} | |
/** | |
* PHP5 Constructor | |
*/ | |
function __construct() { | |
$this->_config = & w3_instance('W3_Config'); | |
$this->_debug = $this->_config->get_boolean('pgcache.debug'); | |
$this->_request_uri = $_SERVER['REQUEST_URI']; | |
$this->_lifetime = $this->_config->get_integer('browsercache.html.lifetime'); | |
$this->_enhanced_mode = ($this->_config->get_string('pgcache.engine') == 'file_generic'); | |
if ($this->_config->get_boolean('mobile.enabled')) { | |
$this->_mobile = & w3_instance('W3_Mobile'); | |
} | |
if ($this->_config->get_boolean('referrer.enabled')) { | |
$this->_referrer = & w3_instance('W3_Referrer'); | |
} | |
} | |
/** | |
* PHP4 Constructor | |
*/ | |
function W3_PgCache() { | |
$this->__construct(); | |
} | |
/** | |
* Do cache logic | |
*/ | |
function process() { | |
/** | |
* Skip caching for some pages | |
*/ | |
switch (true) { | |
case defined('DONOTCACHEPAGE'): | |
case defined('DOING_AJAX'): | |
case defined('DOING_CRON'): | |
case defined('APP_REQUEST'): | |
case defined('XMLRPC_REQUEST'): | |
case defined('WP_ADMIN'): | |
case (defined('SHORTINIT') && SHORTINIT): | |
return; | |
} | |
/* | |
* Legacy mode with 0.9.2.3 version of /wp-content add-ins | |
*/ | |
if (isset($this->_legacy)) { | |
$redirect = & w3_instance('W3_Redirect'); | |
$redirect->process(); | |
} | |
/** | |
* Do page cache logic | |
*/ | |
if ($this->_debug) { | |
$this->_time_start = w3_microtime(); | |
} | |
$this->_caching = $this->_can_cache(); | |
/** | |
* Work with nginx memcache | |
* @custom 2011-09-07 Gabriel Koen | |
* @version 2011-09-07 Gabriel Koen | |
*/ | |
if ($this->_caching && !$this->_enhanced_mode) { | |
$cache = & $this->_get_cache(); | |
$mobile_group = $this->_get_mobile_group(); | |
$referrer_group = $this->_get_referrer_group(); | |
$encryption = $this->_get_encryption(); | |
$compression = false; | |
$raw = true; | |
$this->_page_key = $this->_get_page_key($this->_request_uri, $mobile_group, $referrer_group, $encryption, $compression); | |
/** | |
* Check if page is cached | |
*/ | |
$data = $cache->get($this->_page_key); | |
/** | |
* If cache exists | |
*/ | |
if ($data) { | |
/** | |
* Do Bad Behavior check | |
*/ | |
$this->_bad_behavior(); | |
if ( '_404' === substr($str, -4) ) { | |
$is_404 = true; | |
} | |
$headers = ''; | |
$time = time(); | |
$content = & $data; | |
/** | |
* Calculate content etag | |
*/ | |
$etag = md5($content); | |
/** | |
* Send headers | |
*/ | |
$this->_send_headers($is_404, $time, $etag, $compression, $headers); | |
/** | |
* Do manual compression for uncompressed page | |
*/ | |
if ($raw) { | |
/** | |
* Append debug info | |
*/ | |
if ($this->_debug) { | |
$time_total = w3_microtime() - $this->_time_start; | |
$debug_info = $this->_get_debug_info(true, '', true, $time_total); | |
$content .= "\r\n\r\n" . $debug_info; | |
} | |
/** | |
* Parse dynamic tags | |
*/ | |
$this->_parse_dynamic($content); | |
/** | |
* Compress content | |
*/ | |
$this->_compress($content, $compression); | |
} | |
echo $content; | |
exit(); | |
} | |
} | |
// @custom end | |
/** | |
* Start output buffering | |
*/ | |
ob_start(array( | |
&$this, | |
'ob_callback' | |
)); | |
} | |
/** | |
* Output buffering callback | |
* | |
* @param string $buffer | |
* @return string | |
*/ | |
function ob_callback(&$buffer) { | |
if ($buffer != '' && w3_is_xml($buffer)) { | |
$compression = false; | |
$has_dynamic = $this->_has_dynamic($buffer); | |
$can_cache = $this->_can_cache2($buffer); | |
/** | |
* Work with nginx memcache | |
* @custom 2011-09-07 Gabriel Koen | |
* @version 2011-09-07 Gabriel Koen | |
*/ | |
if ($can_cache) { | |
$mobile_group = $this->_get_mobile_group(); | |
$referrer_group = $this->_get_referrer_group(); | |
$encryption = $this->_get_encryption(); | |
/** | |
* Don't use compression for debug mode or dynamic tags | |
* because we need to modify buffer before send it to client | |
*/ | |
// Force raw / no gzip | |
$raw = true; | |
$compression = false; | |
$time = time(); | |
$cache = & $this->_get_cache(); | |
$content_type = ''; | |
$cached_headers = $this->_get_cached_headers(); | |
//$is_404 = (function_exists('is_404') ? is_404() : false); | |
$_page_key = $this->_get_page_key($this->_request_uri, $mobile_group, $referrer_group, $encryption, $compression); | |
$cache->set($_page_key, $buffer, $this->_lifetime); | |
/** | |
* Calculate content etag | |
*/ | |
$etag = ''; | |
if ($raw) { | |
if ($this->_debug) { | |
/** | |
* Set page key for debug | |
*/ | |
$this->_page_key = $this->_get_page_key( | |
$this->_request_uri, $mobile_group, | |
$referrer_group, $encryption, $compression, | |
$content_type); | |
/** | |
* Append debug info | |
*/ | |
$time_total = w3_microtime() - $this->_time_start; | |
$debug_info = $this->_get_debug_info(true, '', false, $time_total); | |
$buffer .= "\r\n\r\n" . $debug_info; | |
} | |
} | |
} elseif ($this->_debug) { | |
$mobile_group = $this->_get_mobile_group(); | |
$referrer_group = $this->_get_referrer_group(); | |
$encryption = $this->_get_encryption(); | |
/** | |
* Set page key for debug | |
*/ | |
$this->_page_key = $this->_get_page_key($this->_request_uri, $mobile_group, $referrer_group, $encryption, $compression); | |
/** | |
* Append debug info | |
*/ | |
$time_total = w3_microtime() - $this->_time_start; | |
$debug_info = $this->_get_debug_info(false, $this->cache_reject_reason, false, $time_total); | |
$buffer .= "\r\n\r\n" . $debug_info; | |
} | |
// @custom end | |
/** | |
* We can't capture output in ob_callback | |
* so we use shutdown function | |
*/ | |
if ($has_dynamic) { | |
$this->_shutdown_buffer = $buffer; | |
$this->_shutdown_compression = $compression; | |
$buffer = ''; | |
register_shutdown_function(array( | |
&$this, | |
'shutdown' | |
)); | |
} | |
} | |
return $buffer; | |
} | |
/** | |
* Shutdown callback | |
* @return void | |
*/ | |
function shutdown() { | |
/** | |
* Parse dynamic content | |
*/ | |
$this->_parse_dynamic($this->_shutdown_buffer); | |
/** | |
* Compress page | |
*/ | |
$this->_compress($this->_shutdown_buffer, $this->_shutdown_compression); | |
echo $this->_shutdown_buffer; | |
} | |
/** | |
* Checks if can we do cache logic | |
* | |
* @return boolean | |
*/ | |
function _can_cache() { | |
/** | |
* Don't cache in console mode | |
*/ | |
if (PHP_SAPI === 'cli') { | |
$this->cache_reject_reason = 'Console mode'; | |
return false; | |
} | |
/** | |
* Skip if session defined | |
*/ | |
if (defined('SID') && SID != '') { | |
$this->cache_reject_reason = 'Session started'; | |
return false; | |
} | |
/** | |
* Skip if posting | |
*/ | |
if ($_SERVER['REQUEST_METHOD'] == 'POST') { | |
$this->cache_reject_reason = 'Requested method is POST'; | |
return false; | |
} | |
/** | |
* Skip if there is query in the request uri | |
*/ | |
if (!$this->_config->get_boolean('pgcache.cache.query') && strstr($this->_request_uri, '?') !== false) { | |
$this->cache_reject_reason = 'Requested URI contains query'; | |
return false; | |
} | |
/** | |
* Check request URI | |
*/ | |
if (!in_array($_SERVER['PHP_SELF'], $this->_config->get_array('pgcache.accept.files')) && !$this->_check_request_uri()) { | |
$this->cache_reject_reason = 'Requested URI is rejected'; | |
return false; | |
} | |
/** | |
* Check User Agent | |
*/ | |
if (!$this->_check_ua()) { | |
$this->cache_reject_reason = 'User agent is rejected'; | |
return false; | |
} | |
/** | |
* Check WordPress cookies | |
*/ | |
if (!$this->_check_cookies()) { | |
$this->cache_reject_reason = 'Cookie is rejected'; | |
return false; | |
} | |
/** | |
* Skip if user is logged in | |
*/ | |
if ($this->_config->get_boolean('pgcache.reject.logged') && !$this->_check_logged_in()) { | |
$this->cache_reject_reason = 'User is logged in'; | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Checks if can we do cache logic | |
* | |
* @param string $buffer | |
* @return boolean | |
*/ | |
function _can_cache2(&$buffer) { | |
/** | |
* Skip if caching is disabled | |
*/ | |
if (!$this->_caching) { | |
return false; | |
} | |
/** | |
* Check for database error | |
*/ | |
if (w3_is_database_error($buffer)) { | |
$this->cache_reject_reason = 'Database error occurred'; | |
return false; | |
} | |
/** | |
* Check for DONOTCACHEPAGE constant | |
*/ | |
if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { | |
$this->cache_reject_reason = 'DONOTCACHEPAGE constant is defined'; | |
return false; | |
} | |
/** | |
* Check hostname | |
*/ | |
if ($this->_config->get_boolean('pgcache.check.domain') && w3_get_host() != w3_get_home_domain()) { | |
$this->cache_reject_reason = 'Hostname mismatch'; | |
return false; | |
} | |
/** | |
* Don't cache 404 pages | |
*/ | |
if (!$this->_config->get_boolean('pgcache.cache.404') && function_exists('is_404') && is_404()) { | |
$this->cache_reject_reason = 'Page is 404'; | |
return false; | |
} | |
/** | |
* Don't cache homepage | |
*/ | |
if (!$this->_config->get_boolean('pgcache.cache.home') && function_exists('is_home') && is_home()) { | |
$this->cache_reject_reason = 'Page is home'; | |
return false; | |
} | |
/** | |
* Don't cache feed | |
*/ | |
if (!$this->_config->get_boolean('pgcache.cache.feed') && function_exists('is_feed') && is_feed()) { | |
$this->cache_reject_reason = 'Page is feed'; | |
return false; | |
} | |
/** | |
* Check if page contains dynamic tags | |
*/ | |
if ($this->_enhanced_mode && $this->_has_dynamic($buffer)) { | |
$this->cache_reject_reason = 'Page contains dynamic tags (mfunc or mclude) can not be cached in enhanced mode'; | |
return false; | |
} | |
/** | |
* Custom cache reject rules | |
* @custom 2011-09-07 Gabriel Koen | |
* @version 2011-09-07 Gabriel Koen | |
*/ | |
// Only try to cache if less than 1MB | |
// @see http://stackoverflow.com/questions/2384260/how-do-i-find-the-number-of-bytes-within-utf-8-string-with-php | |
if ( function_exists('mb_strlen') ) { | |
$one_megabyte = 1048576; | |
$byte_length = mb_strlen($buffer, 'latin1'); | |
} else { | |
$one_megabyte = 900000; // < 1MB to give us some margin for error, since we can't check the actual byte length | |
$byte_length = strlen($buffer); | |
} | |
if ( $one_megabyte < $byte_length ) { | |
$this->cache_reject_reason = 'Page is too big to fit in a memcached slab: ' . $byte_length . ' bytes'; | |
return false; | |
} | |
// If this is an HTML page, it must have a closing html tag | |
if ( false === stristr($buffer, '<?xml') && false !== stristr($buffer, '<html') && false === stristr($buffer, '</html>') ) { | |
$this->cache_reject_reason = 'No closing HTML tag detected'; | |
return false; | |
} | |
// Can't cache 404s, nginx doesn't know about sending a 404 header | |
if ( function_exists('is_404') && is_404() ) { | |
$this->cache_reject_reason = 'Cannot cache 404 pages'; | |
return false; | |
} | |
// @custom end | |
return true; | |
} | |
/** | |
* Returns cache object | |
* | |
* @return W3_Cache_Base | |
*/ | |
function &_get_cache() { | |
static $cache = array(); | |
if (!isset($cache[0])) { | |
$engine = $this->_config->get_string('pgcache.engine'); | |
switch ($engine) { | |
case 'memcached': | |
$engineConfig = array( | |
'servers' => $this->_config->get_array('pgcache.memcached.servers'), | |
'persistant' => $this->_config->get_boolean('pgcache.memcached.persistant') | |
); | |
break; | |
case 'file': | |
$engineConfig = array( | |
'cache_dir' => W3TC_CACHE_FILE_PGCACHE_DIR, | |
'locking' => $this->_config->get_boolean('pgcache.file.locking'), | |
'flush_timelimit' => $this->_config->get_integer('timelimit.cache_flush') | |
); | |
break; | |
case 'file_generic': | |
$engineConfig = array( | |
'exclude' => array( | |
'.htaccess' | |
), | |
'expire' => $this->_lifetime, | |
'cache_dir' => W3TC_CACHE_FILE_PGCACHE_DIR, | |
'locking' => $this->_config->get_boolean('pgcache.file.locking'), | |
'flush_timelimit' => $this->_config->get_integer('timelimit.cache_flush') | |
); | |
break; | |
default: | |
$engineConfig = array(); | |
} | |
require_once W3TC_LIB_W3_DIR . '/Cache.php'; | |
@$cache[0] = & W3_Cache::instance($engine, $engineConfig); | |
} | |
return $cache[0]; | |
} | |
/** | |
* Checks request URI | |
* | |
* @return boolean | |
*/ | |
function _check_request_uri() { | |
$auto_reject_uri = array( | |
'wp-login', | |
'wp-register' | |
); | |
foreach ($auto_reject_uri as $uri) { | |
if (strstr($this->_request_uri, $uri) !== false) { | |
return false; | |
} | |
} | |
$reject_uri = $this->_config->get_array('pgcache.reject.uri'); | |
$reject_uri = array_map('w3_parse_path', $reject_uri); | |
foreach ($reject_uri as $expr) { | |
$expr = trim($expr); | |
if ($expr != '' && preg_match('~' . $expr . '~i', $this->_request_uri)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Checks User Agent | |
* | |
* @return boolean | |
*/ | |
function _check_ua() { | |
require_once W3TC_LIB_W3_DIR . '/Request.php'; | |
$uas = $this->_config->get_array('pgcache.reject.ua'); | |
$preload = W3_Request::get_boolean('w3tc_preload'); | |
if (! $preload) { | |
$uas = array_merge($uas, array(W3TC_POWERED_BY)); | |
} | |
foreach ($uas as $ua) { | |
if (isset($_SERVER['HTTP_USER_AGENT']) && stristr($_SERVER['HTTP_USER_AGENT'], $ua) !== false) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Checks WordPress cookies | |
* | |
* @return boolean | |
*/ | |
function _check_cookies() { | |
foreach (array_keys($_COOKIE) as $cookie_name) { | |
if ($cookie_name == 'wordpress_test_cookie') { | |
continue; | |
} | |
if (preg_match('/^(wp-postpass|comment_author)/', $cookie_name)) { | |
return false; | |
} | |
} | |
foreach ($this->_config->get_array('pgcache.reject.cookie') as $reject_cookie) { | |
foreach (array_keys($_COOKIE) as $cookie_name) { | |
if (strstr($cookie_name, $reject_cookie) !== false) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
/** | |
* Check if user is logged in | |
* | |
* @return boolean | |
*/ | |
function _check_logged_in() { | |
foreach (array_keys($_COOKIE) as $cookie_name) { | |
if ($cookie_name == 'wordpress_test_cookie') { | |
continue; | |
} | |
if (strpos($cookie_name, 'wordpress') === 0) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Compress data | |
* | |
* @param string $data | |
* @param string $compression | |
* @return string | |
*/ | |
function _compress(&$data, $compression) { | |
switch ($compression) { | |
case 'gzip': | |
$data = gzencode($data); | |
break; | |
case 'deflate': | |
$data = gzdeflate($data); | |
break; | |
} | |
} | |
/** | |
* Returns current mobile group | |
* | |
* @return string | |
*/ | |
function _get_mobile_group() { | |
if ($this->_mobile) { | |
return $this->_mobile->get_group(); | |
} | |
return ''; | |
} | |
/** | |
* Returns current referrer group | |
* | |
* @return string | |
*/ | |
function _get_referrer_group() { | |
if ($this->_referrer) { | |
return $this->_referrer->get_group(); | |
} | |
return ''; | |
} | |
/** | |
* Returns current encryption | |
* | |
* @return string | |
*/ | |
function _get_encryption() { | |
if (w3_is_https()) { | |
return 'ssl'; | |
} | |
return ''; | |
} | |
/** | |
* Returns current compression | |
* | |
* @return boolean | |
*/ | |
function _get_compression() { | |
/** | |
* No storing multiple compressions when using nginx memcache layer | |
* @custom 2011-09-07 Gabriel Koen | |
* @version 2011-09-07 Gabriel Koen | |
*/ | |
return false; | |
// @custom end | |
if (!w3_zlib_output_compression() && !headers_sent() && !$this->_is_buggy_ie()) { | |
$compressions = $this->_get_compressions(); | |
foreach ($compressions as $compression) { | |
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && stristr($_SERVER['HTTP_ACCEPT_ENCODING'], $compression) !== false) { | |
return $compression; | |
} | |
} | |
} | |
return false; | |
} | |
/** | |
* Returns array of compressions | |
* | |
* @return array | |
*/ | |
function _get_compressions() { | |
$compressions = array( | |
false | |
); | |
if ($this->_config->get_boolean('browsercache.enabled') && $this->_config->get_boolean('browsercache.html.compression') && function_exists('gzencode')) { | |
$compressions[] = 'gzip'; | |
} | |
return $compressions; | |
} | |
/** | |
* Returns array of response headers | |
* | |
* @return array | |
*/ | |
function _get_response_headers() { | |
$headers = array(); | |
if (function_exists('headers_list')) { | |
$headers_list = headers_list(); | |
if ($headers_list) { | |
foreach ($headers_list as $header) { | |
list ($header_name, $header_value) = explode(': ', $header, 2); | |
$headers[$header_name] = $header_value; | |
} | |
} | |
} | |
return $headers; | |
} | |
/** | |
* Checks for buggy IE6 that doesn't support compression | |
* | |
* @return boolean | |
*/ | |
function _is_buggy_ie() { | |
if (isset($_SERVER['HTTP_USER_AGENT'])) { | |
$ua = $_SERVER['HTTP_USER_AGENT']; | |
if (strpos($ua, 'Mozilla/4.0 (compatible; MSIE ') === 0 && strpos($ua, 'Opera') === false) { | |
$version = (float) substr($ua, 30); | |
return ($version < 6 || ($version == 6 && strpos($ua, 'SV1') === false)); | |
} | |
} | |
return false; | |
} | |
/** | |
* Returns array of data headers | |
* | |
* @return array | |
*/ | |
function _get_cached_headers() { | |
$data_headers = array(); | |
$cache_headers = $this->_config->get_array('pgcache.cache.headers'); | |
$response_headers = $this->_get_response_headers(); | |
foreach ($response_headers as $header_name => $header_value) { | |
foreach ($cache_headers as $cache_header_name) { | |
if (strcasecmp($header_name, $cache_header_name) == 0) { | |
$data_headers[$header_name] = $header_value; | |
} | |
} | |
} | |
return $data_headers; | |
} | |
/** | |
* Returns page key | |
* | |
* @param string $request_uri | |
* @param string $mobile_group | |
* @param string $referrer_group | |
* @param string $encryption | |
* @param string $compression | |
* @return string | |
*/ | |
function _get_page_key($request_uri, $mobile_group = '', $referrer_group = '', | |
$encryption = false, $compression = false, $content_type = false) { | |
/** | |
* Make our own nginx-memcached compliant key. Remove any querystring params that aren't whitelisted | |
* @see class WP->public_query_vars | |
* @custom 2011-04-20 Gabriel Koen | |
* @version 2011-09-01 Gabriel Koen | |
*/ | |
$key_parts = parse_url($_SERVER['REQUEST_URI']); | |
$key = $_SERVER['HTTP_HOST'] . $key_parts['path']; | |
if ( isset($key_parts['query']) ) { | |
parse_str($key_parts['query'], $querystring); | |
// It's too early to instantiate WP or access $wp->public_query_vars so just maintain a copy of the array. | |
$public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'debug', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type'); | |
$whitelist = array_intersect(array_keys($querystring), $public_query_vars); | |
$whitelisted_querystring = array(); | |
foreach ( $whitelist as $whitelisted_key ) { | |
$whitelisted_querystring[$whitelisted_key] = $querystring[$whitelisted_key]; | |
} | |
if ( !empty($whitelisted_querystring) ) { | |
$key .= '?' . http_build_query($whitelisted_querystring); | |
} | |
} | |
if ( function_exists('is_404') && is_404() ) { | |
$key .= '_404'; | |
} | |
return $key; | |
// @custom end | |
// replace fragment | |
$key = preg_replace('~#.*$~', '', $request_uri); | |
if ($this->_enhanced_mode) { | |
// URL decode | |
$key = urldecode($key); | |
// replace double slashes | |
$key = preg_replace('~[/\\\]+~', '/', $key); | |
// replace query string | |
$key = preg_replace('~\?.*$~', '', $key); | |
// replace index.php | |
$key = str_replace('/index.php', '/', $key); | |
// trim slash | |
$key = ltrim($key, '/'); | |
if ($key && substr($key, -1) != '/') { | |
$key .= '/'; | |
} | |
$key .= '_index'; | |
} else { | |
$key = sprintf('w3tc_%s_page_%s', w3_get_host_id(), md5($key)); | |
} | |
/** | |
* Append mobile group | |
*/ | |
if ($mobile_group) { | |
$key .= '_' . $mobile_group; | |
} | |
/** | |
* Append referrer group | |
*/ | |
if ($referrer_group) { | |
$key .= '_' . $referrer_group; | |
} | |
/** | |
* Append encryption | |
*/ | |
if ($encryption) { | |
$key .= '_' . $encryption; | |
} | |
if ($this->_enhanced_mode) { | |
/** | |
* Append HTML extension | |
*/ | |
if (substr($content_type, 0, 8) == 'text/xml') | |
$key .= '.xml'; | |
else | |
$key .= '.html'; | |
} | |
/** | |
* Append compression | |
*/ | |
if ($compression) { | |
$key .= '_' . $compression; | |
} | |
/** | |
* Allow to modify page key by W3TC plugins | |
*/ | |
$key = w3tc_do_action('w3tc_pgcache_cache_key', $key); | |
return $key; | |
} | |
/** | |
* Returns debug info | |
* | |
* @param boolean $cache | |
* @param string $reason | |
* @param boolean $status | |
* @param double $time | |
* @return string | |
*/ | |
function _get_debug_info($cache, $reason, $status, $time) { | |
$debug_info = "<!-- W3 Total Cache: Page cache debug info:\r\n"; | |
$debug_info .= sprintf("%s%s\r\n", str_pad('Engine: ', 20), w3_get_engine_name($this->_config->get_string('pgcache.engine'))); | |
$debug_info .= sprintf("%s%s\r\n", str_pad('Cache key: ', 20), $this->_page_key); | |
$debug_info .= sprintf("%s%s\r\n", str_pad('Caching: ', 20), ($cache ? 'enabled' : 'disabled')); | |
if (!$cache) { | |
$debug_info .= sprintf("%s%s\r\n", str_pad('Reject reason: ', 20), $reason); | |
} | |
$debug_info .= sprintf("%s%s\r\n", str_pad('Status: ', 20), ($status ? 'cached' : 'not cached')); | |
$debug_info .= sprintf("%s%.3fs\r\n", str_pad('Creation Time: ', 20), $time); | |
$headers = $this->_get_response_headers(); | |
if (count($headers)) { | |
$debug_info .= "Header info:\r\n"; | |
foreach ($headers as $header_name => $header_value) { | |
$debug_info .= sprintf("%s%s\r\n", str_pad($header_name . ': ', 20), w3_escape_comment($header_value)); | |
} | |
} | |
$debug_info .= '-->'; | |
return $debug_info; | |
} | |
/** | |
* Sends headers | |
* | |
* @param array $headers | |
* @return boolean | |
*/ | |
function _headers($headers) { | |
if (!headers_sent()) { | |
foreach ($headers as $name => $value) { | |
$header = ($name == 'Status' ? $value : $name . ': ' . $value); | |
@header($header); | |
} | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Sends headers | |
* @param boolean $is_404 | |
* @param string $etag | |
* @param integer $time | |
* @param string $compression | |
* @param array $custom_headers | |
* @return boolean | |
*/ | |
function _send_headers($is_404, $time, $etag, $compression, $custom_headers = array()) { | |
$exit = false; | |
$headers = array(); | |
$curr_time = time(); | |
$expires = $time + $this->_lifetime; | |
$max_age = ($expires > $curr_time ? $expires - $curr_time : 0); | |
if ($is_404) { | |
/** | |
* Add 404 header | |
*/ | |
$headers = array_merge($headers, array( | |
'Status' => 'HTTP/1.1 404 Not Found' | |
)); | |
} elseif ($this->_check_modified_since($time) || $this->_check_match($etag)) { | |
/** | |
* Add 304 header | |
*/ | |
$headers = array_merge($headers, array( | |
'Status' => 'HTTP/1.1 304 Not Modified' | |
)); | |
/** | |
* Don't send content if it isn't modified | |
*/ | |
$exit = true; | |
} | |
/** | |
* Add default headers | |
*/ | |
$headers = array_merge($headers, array( | |
'Last-Modified' => w3_http_date($time), | |
'Vary' => 'Cookie' | |
)); | |
if ($this->_config->get_boolean('browsercache.enabled')) { | |
if ($this->_config->get_boolean('browsercache.html.expires')) { | |
$headers = array_merge($headers, array( | |
'Expires' => w3_http_date($expires) | |
)); | |
} | |
if ($this->_config->get_boolean('browsercache.html.cache.control')) { | |
switch ($this->_config->get_string('browsercache.html.cache.policy')) { | |
case 'cache': | |
$headers = array_merge($headers, array( | |
'Pragma' => 'public', | |
'Cache-Control' => 'public' | |
)); | |
break; | |
case 'cache_validation': | |
$headers = array_merge($headers, array( | |
'Pragma' => 'public', | |
'Cache-Control' => 'public, must-revalidate, proxy-revalidate' | |
)); | |
break; | |
case 'cache_noproxy': | |
$headers = array_merge($headers, array( | |
'Pragma' => 'public', | |
'Cache-Control' => 'public, must-revalidate' | |
)); | |
break; | |
case 'cache_maxage': | |
$headers = array_merge($headers, array( | |
'Pragma' => 'public', | |
'Cache-Control' => sprintf('max-age=%d, public, must-revalidate, proxy-revalidate', $max_age) | |
)); | |
break; | |
case 'no_cache': | |
$headers = array_merge($headers, array( | |
'Pragma' => 'no-cache', | |
'Cache-Control' => 'max-age=0, private, no-store, no-cache, must-revalidate' | |
)); | |
break; | |
} | |
} | |
if ($this->_config->get_boolean('browsercache.html.etag')) { | |
$headers = array_merge($headers, array( | |
'Etag' => $etag | |
)); | |
} | |
if ($this->_config->get_boolean('browsercache.html.w3tc')) { | |
$headers = array_merge($headers, array( | |
'X-Powered-By' => W3TC_POWERED_BY | |
)); | |
} | |
} | |
if ($compression) { | |
/** | |
* Add Content-Encoding header | |
*/ | |
$headers = array_merge($headers, array( | |
'Vary' => 'Accept-Encoding, Cookie', | |
'Content-Encoding' => $compression | |
)); | |
} | |
/** | |
* Add custom headers | |
*/ | |
$headers = array_merge($headers, $custom_headers); | |
/** | |
* Disable caching for preview mode | |
*/ | |
if (w3_is_preview_mode()) { | |
$headers = array_merge($headers, array( | |
'Pragma' => 'private', | |
'Cache-Control' => 'private' | |
)); | |
} | |
/** | |
* Send headers to client | |
*/ | |
$result = $this->_headers($headers); | |
if ($exit) { | |
exit(); | |
} | |
return $result; | |
} | |
/** | |
* Check if content was modified by time | |
* @param integer $time | |
* @return boolean | |
*/ | |
function _check_modified_since($time) { | |
if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { | |
$if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; | |
// IE has tacked on extra data to this header, strip it | |
if (($semicolon = strrpos($if_modified_since, ';')) !== false) { | |
$if_modified_since = substr($if_modified_since, 0, $semicolon); | |
} | |
return ($time == strtotime($if_modified_since)); | |
} | |
return false; | |
} | |
/** | |
* Check if content was modified by etag | |
* @param string $etag | |
* @return boolean | |
*/ | |
function _check_match($etag) { | |
if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) { | |
$if_none_match = (get_magic_quotes_gpc() ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : $_SERVER['HTTP_IF_NONE_MATCH']); | |
$client_etags = explode(',', $if_none_match); | |
foreach ($client_etags as $client_etag) { | |
$client_etag = trim($client_etag); | |
if ($etag == $client_etag) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
/** | |
* Bad Behavior support | |
* @return void | |
*/ | |
function _bad_behavior() { | |
if (file_exists(WP_CONTENT_DIR . '/plugins/bad-behavior/bad-behavior-generic.php')) { | |
$bb_file = WP_CONTENT_DIR . '/plugins/bad-behavior/bad-behavior-generic.php'; | |
} elseif (file_exists(WP_CONTENT_DIR . '/plugins/Bad-Behavior/bad-behavior-generic.php')) { | |
$bb_file = WP_CONTENT_DIR . '/plugins/Bad-Behavior/bad-behavior-generic.php'; | |
} else { | |
$bb_file = false; | |
} | |
if ($bb_file) { | |
require_once $bb_file; | |
} | |
} | |
/** | |
* Parses dynamic tags | |
* @return string | |
*/ | |
function _parse_dynamic(&$buffer) { | |
$buffer = preg_replace_callback('~<!--\s*mfunc(.*)-->(.*)<!--\s*/mfunc\s*-->~Uis', array( | |
&$this, | |
'_parse_dynamic_mfunc' | |
), $buffer); | |
$buffer = preg_replace_callback('~<!--\s*mclude(.*)-->(.*)<!--\s*/mclude\s*-->~Uis', array( | |
&$this, | |
'_parse_dynamic_mclude' | |
), $buffer); | |
} | |
/** | |
* Parse dynamic mfunc callback | |
* @param array $matches | |
* @return string | |
*/ | |
function _parse_dynamic_mfunc($matches) { | |
$code1 = trim($matches[1]); | |
$code2 = trim($matches[2]); | |
$code = ($code1 ? $code1 : $code2); | |
if ($code) { | |
$code = trim($code, ';') . ';'; | |
ob_start(); | |
$result = eval($code); | |
$output = ob_get_contents(); | |
ob_end_clean(); | |
if ($result === false) { | |
$output = sprintf('Unable to execute code: %s', htmlspecialchars($code)); | |
} | |
} else { | |
$output = htmlspecialchars('Invalid mfunc tag syntax. The correct format is: <!-- mfunc PHP code --><!-- /mfunc --> or <!-- mfunc -->PHP code<!-- /mfunc -->.'); | |
} | |
return $output; | |
} | |
/** | |
* Parse dynamic mclude callback | |
* @param array $matches | |
* @return string | |
*/ | |
function _parse_dynamic_mclude($matches) { | |
$file1 = trim($matches[1]); | |
$file2 = trim($matches[2]); | |
$file = ($file1 ? $file1 : $file2); | |
if ($file) { | |
$file = ABSPATH . $file; | |
if (file_exists($file) && is_readable($file)) { | |
ob_start(); | |
include $file; | |
$output = ob_get_contents(); | |
ob_end_clean(); | |
} else { | |
$output = sprintf('Unable to open file: %s', htmlspecialchars($file)); | |
} | |
} else { | |
$output = htmlspecialchars('Incorrect mclude tag syntax. The correct format is: <!-- mclude path/to/file.php --><!-- /mclude --> or <!-- mclude -->path/to/file.php<!-- /mclude -->.'); | |
} | |
return $output; | |
} | |
/** | |
* Checks if buffer has dynamic tags | |
* | |
* @param string $buffer | |
* @return boolean | |
*/ | |
function _has_dynamic(&$buffer) { | |
return preg_match('~<!--\s*m(func|clude)(.*)-->(.*)<!--\s*/m(func|clude)\s*-->~Uis', $buffer); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment