Changeset 1260794
- Timestamp:
- 10/07/2015 05:28:37 AM (10 years ago)
- Location:
- batcache/tags/1.2
- Files:
-
- 3 edited
-
advanced-cache.php (modified) (18 diffs)
-
batcache.php (modified) (2 diffs)
-
readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
batcache/tags/1.2/advanced-cache.php
r634460 r1260794 1 1 <?php 2 if ( is_readable( dirname( __FILE__ ) . '/batcache-stats.php' ) ) 3 require_once dirname( __FILE__ ) . '/batcache-stats.php'; 4 5 if ( !function_exists( 'batcache_stats' ) ) { 6 function batcache_stats( $name, $value, $num = 1, $today = FALSE, $hour = FALSE ) { } 7 } 2 8 3 9 // nananananananananananananananana BATCACHE!!! … … 8 14 if ( is_object($batcache) ) 9 15 $batcache->cancel = true; 16 } 17 18 // Variants can be set by functions which use early-set globals like $_SERVER to run simple tests. 19 // Functions defined in WordPress, plugins, and themes are not available and MUST NOT be used. 20 // Example: vary_cache_on_function('return preg_match("/feedburner/i", $_SERVER["HTTP_USER_AGENT"]);'); 21 // This will cause batcache to cache a variant for requests from Feedburner. 22 // Tips for writing $function: 23 // X_X DO NOT use any functions from your theme or plugins. Those files have not been included. Fatal error. 24 // X_X DO NOT use any WordPress functions except is_admin() and is_multisite(). Fatal error. 25 // X_X DO NOT include or require files from anywhere without consulting expensive professionals first. Fatal error. 26 // X_X DO NOT use $wpdb, $blog_id, $current_user, etc. These have not been initialized. 27 // ^_^ DO understand how create_function works. This is how your code is used: create_function('', $function); 28 // ^_^ DO remember to return something. The return value determines the cache variant. 29 function vary_cache_on_function($function) { 30 global $batcache; 31 32 if ( preg_match('/include|require|echo|print|dump|export|open|sock|unlink|`|eval/i', $function) ) 33 die('Illegal word in variant determiner.'); 34 35 if ( !preg_match('/\$_/', $function) ) 36 die('Variant determiner should refer to at least one $_ variable.'); 37 38 $batcache->add_variant($function); 10 39 } 11 40 … … 13 42 // This is the base configuration. You can edit these variables or move them into your wp-config.php file. 14 43 var $max_age = 300; // Expire batcache items aged this many seconds (zero to disable batcache) 15 44 16 45 var $remote = 0; // Zero disables sending buffers to remote datacenters (req/sec is never sent) 17 46 18 47 var $times = 2; // Only batcache a page after it is accessed this many times... (two or more) 19 48 var $seconds = 120; // ...in this many seconds (zero to ignore this and use batcache immediately) 20 49 21 50 var $group = 'batcache'; // Name of memcached group. You can simulate a cache flush by changing this. 22 51 23 52 var $unique = array(); // If you conditionally serve different content, put the variable values here. 24 25 var $headers = array(); // Add headers here. These will be sent with every response from the cache. 53 54 var $vary = array(); // Array of functions for create_function. The return value is added to $unique above. 55 56 var $headers = array(); // Add headers here as name=>value or name=>array(values). These will be sent with every response from the cache. 26 57 27 58 var $cache_redirects = false; // Set true to enable redirect caching. … … 37 68 var $cancel = false; // Change this to cancel the output buffer. Use batcache_cancel(); 38 69 39 var $genlock; // Used internally 40 var $do; // Used internally 70 var $noskip_cookies = array( 'wordpress_test_cookie' ); // Names of cookies - if they exist and the cache would normally be bypassed, don't bypass it 71 72 var $genlock = false; 73 var $do = false; 41 74 42 75 function batcache( $settings ) { … … 57 90 } 58 91 59 function status_header( $status_header ) {92 function status_header( $status_header, $status_code ) { 60 93 $this->status_header = $status_header; 94 $this->status_code = $status_code; 61 95 62 96 return $status_header; … … 70 104 71 105 return $status; 106 } 107 108 function do_headers( $headers1, $headers2 = array() ) { 109 // Merge the arrays of headers into one 110 $headers = array(); 111 $keys = array_unique( array_merge( array_keys( $headers1 ), array_keys( $headers2 ) ) ); 112 foreach ( $keys as $k ) { 113 $headers[$k] = array(); 114 if ( isset( $headers1[$k] ) && isset( $headers2[$k] ) ) 115 $headers[$k] = array_merge( (array) $headers2[$k], (array) $headers1[$k] ); 116 elseif ( isset( $headers2[$k] ) ) 117 $headers[$k] = (array) $headers2[$k]; 118 else 119 $headers[$k] = (array) $headers1[$k]; 120 $headers[$k] = array_unique( $headers[$k] ); 121 } 122 // These headers take precedence over any previously sent with the same names 123 foreach ( $headers as $k => $values ) { 124 $clobber = true; 125 foreach ( $values as $v ) { 126 header( "$k: $v", $clobber ); 127 $clobber = false; 128 } 129 } 72 130 } 73 131 … … 110 168 return; 111 169 170 // Do not cache 5xx responses 171 if ( isset( $this->status_code ) && intval($this->status_code / 100) == 5 ) 172 return $output; 173 174 $this->do_variants($this->vary); 175 $this->generate_keys(); 176 112 177 // Construct and save the batcache 113 $ cache = array(178 $this->cache = array( 114 179 'output' => $output, 115 180 'time' => time(), 116 181 'timer' => $this->timer_stop(false, 3), 182 'headers' => array(), 117 183 'status_header' => $this->status_header, 118 184 'redirect_status' => $this->redirect_status, … … 121 187 ); 122 188 123 if ( function_exists( 'headers_list' ) ) { 124 foreach ( headers_list() as $header ) { 125 list($k, $v) = array_map('trim', explode(':', $header, 2)); 126 $cache['headers'][$k] = $v; 127 } 128 } elseif ( function_exists( 'apache_response_headers' ) ) { 129 $cache['headers'] = apache_response_headers(); 130 } 131 132 if ( $cache['headers'] && !empty( $this->uncached_headers ) ) { 133 foreach ( $cache['headers'] as $header => $value ) { 134 if ( in_array( strtolower( $header ), $this->uncached_headers ) ) 135 unset( $cache['headers'][$header] ); 136 } 137 } 138 139 wp_cache_set($this->key, $cache, $this->group, $this->max_age + $this->seconds + 30); 189 foreach ( headers_list() as $header ) { 190 list($k, $v) = array_map('trim', explode(':', $header, 2)); 191 $this->cache['headers'][$k][] = $v; 192 } 193 194 if ( !empty( $this->cache['headers'] ) && !empty( $this->uncached_headers ) ) { 195 foreach ( $this->uncached_headers as $header ) 196 unset( $this->cache['headers'][$header] ); 197 } 198 199 foreach ( $this->cache['headers'] as $header => $values ) { 200 // Do not cache if cookies were set 201 if ( strtolower( $header ) === 'set-cookie' ) 202 return $output; 203 204 foreach ( (array) $values as $value ) 205 if ( preg_match('/^Cache-Control:.*max-?age=(\d+)/i', "$header: $value", $matches) ) 206 $this->max_age = intval($matches[1]); 207 } 208 209 $this->cache['max_age'] = $this->max_age; 210 211 wp_cache_set($this->key, $this->cache, $this->group, $this->max_age + $this->seconds + 30); 140 212 141 213 // Unlock regeneration … … 143 215 144 216 if ( $this->cache_control ) { 145 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $cache['time'] ) . ' GMT', true ); 146 header("Cache-Control: max-age=$this->max_age, must-revalidate", false); 147 } 148 149 if ( !empty($this->headers) ) foreach ( $this->headers as $k => $v ) { 150 if ( is_array( $v ) ) 151 header("{$v[0]}: {$v[1]}", false); 152 else 153 header("$k: $v", true); 154 } 155 156 // Add some debug info just before </head> 217 // Don't clobber Last-Modified header if already set, e.g. by WP::send_headers() 218 if ( !isset($this->cache['headers']['Last-Modified']) ) 219 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $this->cache['time'] ) . ' GMT', true ); 220 if ( !isset($this->cache['headers']['Cache-Control']) ) 221 header("Cache-Control: max-age=$this->max_age, must-revalidate", false); 222 } 223 224 $this->do_headers( $this->headers ); 225 226 // Add some debug info just before <head 157 227 if ( $this->debug ) { 158 $tag = "<!--\n\tgenerated in " . $cache['timer'] . " seconds\n\t" . strlen(serialize($cache)) . " bytes batcached for " . $this->max_age . " seconds\n-->\n"; 159 if ( false !== $tag_position = strpos($output, '</head>') ) { 160 $tag = "<!--\n\tgenerated in " . $cache['timer'] . " seconds\n\t" . strlen(serialize($cache)) . " bytes batcached for " . $this->max_age . " seconds\n-->\n"; 161 $output = substr($output, 0, $tag_position) . $tag . substr($output, $tag_position); 228 $this->add_debug_just_cached(); 229 } 230 231 // Pass output to next ob handler 232 batcache_stats( 'batcache', 'total_page_views' ); 233 return $this->cache['output']; 234 } 235 236 function add_variant($function) { 237 $key = md5($function); 238 $this->vary[$key] = $function; 239 } 240 241 function do_variants($dimensions = false) { 242 // This function is called without arguments early in the page load, then with arguments during the OB handler. 243 if ( $dimensions === false ) 244 $dimensions = wp_cache_get("{$this->url_key}_vary", $this->group); 245 else 246 wp_cache_set("{$this->url_key}_vary", $dimensions, $this->group, $this->max_age + 10); 247 248 if ( is_array($dimensions) ) { 249 ksort($dimensions); 250 foreach ( $dimensions as $key => $function ) { 251 $fun = create_function('', $function); 252 $value = $fun(); 253 $this->keys[$key] = $value; 162 254 } 163 255 } 164 165 // Pass output to next ob handler 166 return $output; 167 } 168 } 256 } 257 258 function generate_keys() { 259 // ksort($this->keys); // uncomment this when traffic is slow 260 $this->key = md5(serialize($this->keys)); 261 $this->req_key = $this->key . '_req'; 262 } 263 264 function add_debug_just_cached() { 265 $generation = $this->cache['timer']; 266 $bytes = strlen( serialize( $this->cache ) ); 267 $html = <<<HTML 268 <!-- 269 generated in $generation seconds 270 $bytes bytes batcached for {$this->max_age} seconds 271 --> 272 273 HTML; 274 $this->add_debug_html_to_output( $html ); 275 } 276 277 function add_debug_from_cache() { 278 $seconds_ago = time() - $this->cache['time']; 279 $generation = $this->cache['timer']; 280 $serving = $this->timer_stop( false, 3 ); 281 $expires = $this->cache['max_age'] - time() + $this->cache['time']; 282 $html = <<<HTML 283 <!-- 284 generated $seconds_ago seconds ago 285 generated in $generation seconds 286 served from batcache in $serving seconds 287 expires in $expires seconds 288 --> 289 290 HTML; 291 $this->add_debug_html_to_output( $html ); 292 } 293 294 function add_debug_html_to_output( $debug_html ) { 295 // Casing on the Content-Type header is inconsistent 296 foreach ( array( 'Content-Type', 'Content-type' ) as $key ) { 297 if ( isset( $this->cache['headers'][ $key ][0] ) && 0 !== strpos( $this->cache['headers'][ $key ][0], 'text/html' ) ) 298 return; 299 } 300 301 $head_position = strpos( $this->cache['output'], '<head' ); 302 if ( false === $head_position ) { 303 return; 304 } 305 $this->cache['output'] .= "\n$debug_html"; 306 } 307 } 308 169 309 global $batcache; 170 310 // Pass in the global variable which may be an array of settings to override defaults. … … 180 320 'wp-app.php', 181 321 'xmlrpc.php', 182 'ms-files.php',183 322 ) ) ) 184 323 return; … … 193 332 194 333 // Never batcache when cookies indicate a cache-exempt visitor. 195 if ( is_array( $_COOKIE) && ! empty( $_COOKIE ) ) 196 foreach ( array_keys( $_COOKIE ) as $batcache->cookie ) 197 if ( $batcache->cookie != 'wordpress_test_cookie' && ( substr( $batcache->cookie, 0, 2 ) == 'wp' || substr( $batcache->cookie, 0, 9 ) == 'wordpress' || substr( $batcache->cookie, 0, 14 ) == 'comment_author' ) ) 334 if ( is_array( $_COOKIE) && ! empty( $_COOKIE ) ) { 335 foreach ( array_keys( $_COOKIE ) as $batcache->cookie ) { 336 if ( ! in_array( $batcache->cookie, $batcache->noskip_cookies ) && ( substr( $batcache->cookie, 0, 2 ) == 'wp' || substr( $batcache->cookie, 0, 9 ) == 'wordpress' || substr( $batcache->cookie, 0, 14 ) == 'comment_author' ) ) { 337 batcache_stats( 'batcache', 'cookie_skip' ); 198 338 return; 339 } 340 } 341 } 199 342 200 343 if ( ! include_once( WP_CONTENT_DIR . '/object-cache.php' ) ) … … 218 361 219 362 /* Example: batcache everything on this host regardless of traffic level 220 if ( $_SERVER['HTTP_HOST'] == 'always-batcache-me.com' ) { 221 $batcache->max_age = 600; // Cache for 10 minutes 222 $batcache->seconds = $batcache->times = 0; // No need to wait till n number of people have accessed the page, cache instantly 223 } 363 if ( $_SERVER['HTTP_HOST'] == 'always-batcache-me.com' ) 364 return; 224 365 */ 225 366 … … 243 384 if ( isset( $_SERVER['QUERY_STRING'] ) ) 244 385 parse_str($_SERVER['QUERY_STRING'], $batcache->query); 386 245 387 $batcache->keys = array( 246 388 'host' => $_SERVER['HTTP_HOST'], … … 254 396 $batcache->keys['ssl'] = true; 255 397 398 // Recreate the permalink from the URL 399 $batcache->permalink = 'http://' . $batcache->keys['host'] . $batcache->keys['path'] . ( isset($batcache->keys['query']['p']) ? "?p=" . $batcache->keys['query']['p'] : '' ); 400 $batcache->url_key = md5($batcache->permalink); 256 401 $batcache->configure_groups(); 257 258 // Generate the batcache key 259 $batcache->key = md5(serialize($batcache->keys)); 260 261 // Generate the traffic threshold measurement key 262 $batcache->req_key = $batcache->key . '_req'; 402 $batcache->url_version = (int) wp_cache_get("{$batcache->url_key}_version", $batcache->group); 403 $batcache->do_variants(); 404 $batcache->generate_keys(); 263 405 264 406 // Get the batcache 265 407 $batcache->cache = wp_cache_get($batcache->key, $batcache->group); 266 408 267 // Are we only caching frequently-requested pages? 268 if ( $batcache->seconds < 1 || $batcache->times < 2 ) { 409 if ( isset($batcache->cache['version']) && $batcache->cache['version'] < $batcache->url_version ) { 410 // Always refresh the cache if a newer version is available. 411 $batcache->do = true; 412 } else if ( $batcache->seconds < 1 || $batcache->times < 2 ) { 413 // Are we only caching frequently-requested pages? 269 414 $batcache->do = true; 270 415 } else { … … 281 426 } 282 427 283 // Recreate the permalink from the URL284 $batcache->permalink = 'http://' . $batcache->keys['host'] . $batcache->keys['path'] . ( isset($batcache->keys['query']['p']) ? "?p=" . $batcache->keys['query']['p'] : '' );285 $batcache->url_key = md5($batcache->permalink);286 $batcache->url_version = (int) wp_cache_get("{$batcache->url_key}_version", $batcache->group);287 288 428 // If the document has been updated and we are the first to notice, regenerate it. 289 if ( $batcache->do !== false && isset($batcache->cache['version']) && $batcache->cache['version'] < $batcache->url_version ) 290 $batcache->genlock = wp_cache_add("{$batcache->url_key}_genlock", 1, $batcache->group); 429 if ( $batcache->do ) 430 $batcache->genlock = wp_cache_add("{$batcache->url_key}_genlock", 1, $batcache->group, 10); 431 432 // Temporary: remove after 2010-11-12. I added max_age to the cache. This upgrades older caches on the fly. 433 if ( !isset($batcache->cache['max_age']) ) 434 $batcache->cache['max_age'] = $batcache->max_age; 435 291 436 292 437 // Did we find a batcached page that hasn't expired? 293 if ( isset($batcache->cache['time']) && ! $batcache->genlock && time() < $batcache->cache['time'] + $batcache-> max_age) {438 if ( isset($batcache->cache['time']) && ! $batcache->genlock && time() < $batcache->cache['time'] + $batcache->cache['max_age'] ) { 294 439 // Issue redirect if cached and enabled 295 440 if ( $batcache->cache['redirect_status'] && $batcache->cache['redirect_location'] && $batcache->cache_redirects ) { … … 298 443 // From vars.php 299 444 $is_IIS = (strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false); 445 446 $batcache->do_headers( $batcache->headers ); 300 447 if ( $is_IIS ) { 301 448 header("Refresh: 0;url=$location"); … … 325 472 } 326 473 327 // Issue "304 Not Modified" only if the dates match exactly. 328 if ( $batcache->cache_control && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) { 329 $since = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); 330 if ( isset($batcache->cache['headers']['Last-Modified']) ) 331 $batcache->cache['time'] = strtotime( $batcache->cache['headers']['Last-Modified'] ); 332 if ( $batcache->cache['time'] == $since ) { 333 header('Last-Modified: ' . $_SERVER['HTTP_IF_MODIFIED_SINCE'], true, 304); 334 exit; 335 } 336 } 337 338 // Use the batcache save time for Last-Modified so we can issue "304 Not Modified" 339 if ( $batcache->cache_control ) { 474 // Respect ETags served with feeds. 475 $three04 = false; 476 if ( isset( $SERVER['HTTP_IF_NONE_MATCH'] ) && isset( $batcache->cache['headers']['ETag'][0] ) && $_SERVER['HTTP_IF_NONE_MATCH'] == $batcache->cache['headers']['ETag'][0] ) 477 $three04 = true; 478 479 // Respect If-Modified-Since. 480 elseif ( $batcache->cache_control && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) { 481 $client_time = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); 482 if ( isset($batcache->cache['headers']['Last-Modified'][0]) ) 483 $cache_time = strtotime($batcache->cache['headers']['Last-Modified'][0]); 484 else 485 $cache_time = $batcache->cache['time']; 486 487 if ( $client_time >= $cache_time ) 488 $three04 = true; 489 } 490 491 // Use the batcache save time for Last-Modified so we can issue "304 Not Modified" but don't clobber a cached Last-Modified header. 492 if ( $batcache->cache_control && !isset($batcache->cache['headers']['Last-Modified'][0]) ) { 340 493 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $batcache->cache['time'] ) . ' GMT', true ); 341 header('Cache-Control: max-age=' . ($batcache-> max_age- time() + $batcache->cache['time']) . ', must-revalidate', true);494 header('Cache-Control: max-age=' . ($batcache->cache['max_age'] - time() + $batcache->cache['time']) . ', must-revalidate', true); 342 495 } 343 496 344 497 // Add some debug info just before </head> 345 498 if ( $batcache->debug ) { 346 if ( false !== $tag_position = strpos($batcache->cache['output'], '</head>') ) { 347 $tag = "<!--\n\tgenerated " . (time() - $batcache->cache['time']) . " seconds ago\n\tgenerated in " . $batcache->cache['timer'] . " seconds\n\tserved from batcache in " . $batcache->timer_stop(false, 3) . " seconds\n\texpires in " . ($batcache->max_age - time() + $batcache->cache['time']) . " seconds\n-->\n"; 348 $batcache->cache['output'] = substr($batcache->cache['output'], 0, $tag_position) . $tag . substr($batcache->cache['output'], $tag_position); 349 } 350 } 351 352 if ( !empty($batcache->cache['headers']) ) foreach ( $batcache->cache['headers'] as $k => $v ) 353 header("$k: $v", true); 354 355 if ( !empty($batcache->headers) ) foreach ( $batcache->headers as $k => $v ) { 356 if ( is_array( $v ) ) 357 header("{$v[0]}: {$v[1]}", false); 358 else 359 header("$k: $v", true); 499 $batcache->add_debug_from_cache(); 500 } 501 502 $batcache->do_headers( $batcache->headers, $batcache->cache['headers'] ); 503 504 if ( $three04 ) { 505 header("HTTP/1.1 304 Not Modified", true, 304); 506 die; 360 507 } 361 508 … … 371 518 return; 372 519 373 $wp_filter['status_header'][10]['batcache'] = array( 'function' => array(&$batcache, 'status_header'), 'accepted_args' => 1);520 $wp_filter['status_header'][10]['batcache'] = array( 'function' => array(&$batcache, 'status_header'), 'accepted_args' => 2 ); 374 521 $wp_filter['wp_redirect_status'][10]['batcache'] = array( 'function' => array(&$batcache, 'redirect_status'), 'accepted_args' => 2 ); 375 522 -
batcache/tags/1.2/batcache.php
r636875 r1260794 10 10 11 11 // Do not load if our advanced-cache.php isn't loaded 12 if ( ! is _object($batcache) || ! method_exists( $wp_object_cache, 'incr' ) )12 if ( ! isset( $batcache ) || ! is_object($batcache) || ! method_exists( $wp_object_cache, 'incr' ) ) 13 13 return; 14 14 … … 27 27 28 28 $post = get_post($post_id); 29 if ( $post->post_type == 'revision' || get_post_status($post_id) != 'publish' )29 if ( empty( $post ) || $post->post_type == 'revision' || get_post_status($post_id) != 'publish' ) 30 30 return; 31 31 -
batcache/tags/1.2/readme.txt
r636874 r1260794 3 3 Tags: cache, memcache, memcached, speed, performance, load, server 4 4 Requires at least: 3.2 5 Tested up to: 3.55 Tested up to: 4.3.1 6 6 Stable tag: 1.2 7 7
Note: See TracChangeset
for help on using the changeset viewer.