PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / trunk
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score vtrunk
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
powered-cache / includes / dropins / page-cache.php

page-cache.php in Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score trunk, at includes/dropins/page-cache.php

689 lines 20.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Forked from https://github.com/tlovett1/simple-cache/
4 */
5
6 defined( 'ABSPATH' ) || exit;
7
8 $powered_cache_start_time = microtime( true );
9
10 // Don't cache robots.txt or htacesss
11 if ( strpos( $_SERVER['REQUEST_URI'], 'robots.txt' ) !== false || strpos( $_SERVER['REQUEST_URI'], '.htaccess' ) !== false ) {
12 powered_cache_add_cache_miss_header( "Uncacheable file" );
13
14 return;
15 }
16
17 // Don't cache non-GET requests
18 if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'GET' !== $_SERVER['REQUEST_METHOD'] ) {
19 powered_cache_add_cache_miss_header( "Invalid request method" );
20
21 return;
22 }
23
24 if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
25 $_SERVER['HTTP_USER_AGENT'] = '';
26 }
27
28 // Don't cache wp-admin
29 if ( is_admin() ) {
30 return;
31 }
32
33 $file_extension = $_SERVER['REQUEST_URI'];
34 $file_extension = preg_replace( '#^(.*?)\?.*$#', '$1', $file_extension );
35 $file_extension = trim( preg_replace( '#^.*\.(.*)$#', '$1', $file_extension ) );
36
37 // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
38 if ( ! preg_match( '#index\.php$#i', $_SERVER['REQUEST_URI'] ) && in_array( $file_extension, array( 'php', 'xml', 'xsl' ), true ) ) {
39 powered_cache_add_cache_miss_header( "Disallowed file extension" );
40
41 return;
42 }
43
44 if ( ! $GLOBALS['powered_cache_options']['enable_page_cache'] ) {
45 powered_cache_add_cache_miss_header( "Page Caching is not enabled" );
46
47 return;
48 }
49
50 if ( ! empty( $GLOBALS['powered_cache_options']['dev_mode'] ) ) {
51 powered_cache_add_cache_miss_header( "Dev mode is enabled" );
52
53 return;
54 }
55
56 if ( isset( $_GET['nopoweredcache'] ) && $_GET['nopoweredcache'] ) {
57 powered_cache_add_cache_miss_header( "Passing nopoweredcache with the query" );
58
59 return;
60 }
61
62 // Don't cache page with these user agents
63 if ( isset( $powered_cache_rejected_user_agents ) && ! empty( $powered_cache_rejected_user_agents ) ) {
64 $rejected_user_agents = implode( '|', $powered_cache_rejected_user_agents );
65 if ( ! empty( $rejected_user_agents ) && isset( $_SERVER['HTTP_USER_AGENT'] ) && @preg_match( '#(' . $rejected_user_agents . ')#', $_SERVER['HTTP_USER_AGENT'] ) ) {
66 powered_cache_add_cache_miss_header( "Rejected user agent" );
67
68 return;
69 }
70 }
71
72 // dont cache mobile
73 if ( empty( $GLOBALS['powered_cache_options']['cache_mobile'] ) ) {
74 global $powered_cache_mobile_browsers, $powered_cache_mobile_prefixes;
75
76 $mobile_browsers = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_browsers ) ), ' ' );
77 $mobile_prefixes = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_prefixes ) ), ' ' );
78 // Don't cache if mobile detection is activated
79 if ( ( preg_match( '#^.*(' . $mobile_browsers . ').*#i', $_SERVER['HTTP_USER_AGENT'] ) || preg_match( '#^(' . $mobile_prefixes . ').*#i', substr( $_SERVER['HTTP_USER_AGENT'], 0, 4 ) ) ) ) {
80 powered_cache_add_cache_miss_header( "Mobile request" );
81
82 return;
83 }
84 }
85
86 // Exclude caching based on HTTP_REFERER
87 if ( ! empty( $powered_cache_rejected_referrers ) && isset( $_SERVER['HTTP_REFERER'] ) && $_SERVER['HTTP_REFERER'] ) {
88 foreach ( $powered_cache_rejected_referrers as $referrer_rule ) {
89 $referrer_rule = trim( $referrer_rule );
90 if ( $referrer_rule === '' ) {
91 continue;
92 }
93 // If rule starts with ^ or contains regex special chars, treat as regex
94 if ( preg_match( '/[\\^$.|?*+()\[\]]/', $referrer_rule ) ) {
95 if ( @preg_match( '#' . $referrer_rule . '#i', $_SERVER['HTTP_REFERER'] ) ) {
96 if ( preg_match( '#' . $referrer_rule . '#i', $_SERVER['HTTP_REFERER'] ) ) {
97 powered_cache_add_cache_miss_header( "Rejected referer: $referrer_rule" );
98
99 return;
100 }
101 }
102 } else {
103 // Plain string match
104 if ( strpos( $_SERVER['HTTP_REFERER'], $referrer_rule ) !== false ) {
105 powered_cache_add_cache_miss_header( "Rejected referer: $referrer_rule" );
106
107 return;
108 }
109 }
110 }
111 }
112
113 if ( ! empty( $_COOKIE ) ) {
114 $wp_cookies = [ 'wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_' ];
115 $comment_cookies = [ 'comment_author_', 'comment_author_email_', 'comment_author_url_' ];
116
117 // Check if logged-in caching is disabled or the user is not logged in
118 if ( empty( $GLOBALS['powered_cache_options']['loggedin_user_cache'] ) || false === powered_cache_get_user_cookie() ) {
119 // Standard check for logged-in status
120 foreach ( $_COOKIE as $key => $value ) {
121 foreach ( $wp_cookies as $cookie ) {
122 if ( strpos( $key, $cookie ) !== false ) {
123 powered_cache_add_cache_miss_header( "User logged-in" );
124 return;
125 }
126 }
127
128 // Check if the user has commented on the site
129 foreach ( $comment_cookies as $cookie ) {
130 if ( strpos( $key, $cookie ) !== false ) {
131 powered_cache_add_cache_miss_header( "User left a comment" );
132 return;
133 }
134 }
135 }
136
137 // Avoid caching pages with specific post comments from users
138 // it's a bit different from $comment_cookies since we are checking the post path
139 if ( ! empty( $_COOKIE['powered_cache_commented_posts'] ) ) {
140 foreach ( $_COOKIE['powered_cache_commented_posts'] as $path ) {
141 if ( rtrim( $path, '/' ) === rtrim( $_SERVER['REQUEST_URI'], '/' ) ) {
142 powered_cache_add_cache_miss_header( "User commented" );
143 return;
144 }
145 }
146 }
147 }
148
149 // Skip caching if there are specific rejected cookies, regardless of logged-in status
150 if ( ! empty( $powered_cache_rejected_cookies ) ) {
151 $rejected_cookies = array_diff( $powered_cache_rejected_cookies, $wp_cookies, $comment_cookies, ['powered_cache_commented_posts'] );
152 $rejected_cookies = implode( '|', $rejected_cookies );
153 if ( @preg_match( '#(' . $rejected_cookies . ')#', var_export( $_COOKIE, true ) ) ) {
154 powered_cache_add_cache_miss_header( "Rejected cookie" );
155 return;
156 }
157 }
158 }
159
160 // Don't cache rejected pages
161 if ( ! empty( $powered_cache_rejected_uri ) ) {
162 foreach ( (array) $powered_cache_rejected_uri as $exception ) {
163 if ( preg_match( '#^[\s]*$#', $exception ) ) {
164 continue;
165 }
166
167 // full url exception
168 if ( preg_match( '#^https?://#', $exception ) ) {
169 $exception = parse_url( $exception, PHP_URL_PATH );
170 }
171
172 if ( empty( $exception ) ) {
173 continue;
174 }
175
176 if ( @preg_match( '#^(' . $exception . ')$#', $_SERVER['REQUEST_URI'] ) ) {
177 powered_cache_add_cache_miss_header( "Rejected page" );
178
179 return;
180 }
181 }
182 }
183
184
185 if ( ! empty( $_GET ) ) {
186 if ( ! isset( $powered_cache_ignored_query_strings ) ) {
187 $powered_cache_ignored_query_strings = [];
188 }
189
190 $query_params = array_diff_key( $_GET, array_flip( $powered_cache_ignored_query_strings ) );
191
192 if ( ! isset( $powered_cache_cache_query_strings ) ) {
193 $powered_cache_cache_query_strings = [];
194 }
195
196 // don't cache when there is not allowed query parameter exists
197 if ( ! empty( $query_params ) && ! array_intersect_key( $_GET, array_flip( $powered_cache_cache_query_strings ) ) ) {
198 powered_cache_add_cache_miss_header( "Disallowed query parameter exists" );
199
200 return;
201 }
202 }
203
204 powered_cache_serve_cache();
205
206 ob_start( 'powered_cache_page_buffer' );
207
208 /**
209 * Cache output before it goes to the browser
210 *
211 * @param string $buffer
212 * @param int $flags
213 *
214 * @return string
215 * @since 1.0
216 */
217 function powered_cache_page_buffer( $buffer, $flags ) {
218 global $powered_cache_start_time, $post;
219
220 if ( strlen( $buffer ) < 255 ) {
221 return $buffer;
222 }
223
224 // maybe we shouldn't cache template file has this constant
225 // dont check DONOTCACHEPAGE strictly some plugins define string instead bool flag
226 if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
227 powered_cache_add_cache_miss_header( "DONOTCACHEPAGE defined" );
228
229 return $buffer;
230 }
231
232 if ( ! empty( $GLOBALS['powered_cache_options']['dev_mode'] ) ) {
233 powered_cache_add_cache_miss_header( "Dev mode is enabled" );
234
235 return $buffer;
236 }
237
238 // Don't cache password protected posts
239 if ( ! empty( $post->post_password ) ) {
240 powered_cache_add_cache_miss_header( "Password protected posts are not cached" );
241
242 return $buffer;
243 }
244
245 // Don't cache 404 results
246 if ( function_exists( 'is_404' ) && is_404() ) {
247 powered_cache_add_cache_miss_header( "404 pages are not cached" );
248
249 return $buffer;
250 }
251
252 // Don't cache search results
253 if ( function_exists( 'is_search' ) && is_search() ) {
254 powered_cache_add_cache_miss_header( "Search result page is not cached" );
255
256 return $buffer;
257 }
258
259 /**
260 * Filter whether to enable page cache for this request
261 *
262 * @hook powered_cache_page_cache_enable
263 *
264 * @param {boolean} $enable true for caching
265 *
266 * @since 1.0
267 */
268 if ( true !== apply_filters( 'powered_cache_page_cache_enable', true ) ) {
269 powered_cache_add_cache_miss_header( "Page Cache not enabled for this post" );
270
271 return $buffer;
272 }
273
274 // only cache when http ok
275 if ( 200 !== http_response_code() ) {
276 powered_cache_add_cache_miss_header( "Response code is not 200" );
277
278 return $buffer;
279 }
280
281 if ( ! function_exists( '\PoweredCache\Utils\get_cache_dir' ) ) {
282 return $buffer;
283 }
284
285 // Make sure we can read/write files and that proper folders exist
286 if ( ! file_exists( untrailingslashit( \PoweredCache\Utils\get_cache_dir() ) ) ) {
287 if ( ! @mkdir( untrailingslashit( \PoweredCache\Utils\get_cache_dir() ) ) ) {
288 // Can not cache!
289 powered_cache_add_cache_miss_header( "The cache directory does not exist for storing cached output" );
290
291 return $buffer;
292 }
293 }
294
295 if ( ! file_exists( \PoweredCache\Utils\get_page_cache_dir() ) ) {
296 if ( ! @mkdir( \PoweredCache\Utils\get_page_cache_dir() ) ) {
297 // Can not cache!
298 powered_cache_add_cache_miss_header( "The page cache directory does not exist for storing cached output" );
299
300 return $buffer;
301 }
302 }
303
304 /**
305 * Filters HTML buffer
306 *
307 * @hook powered_cache_page_caching_buffer
308 *
309 * @param {string} $buffer Output buffer.
310 *
311 * @return {string} New value.
312 * @since 1.0
313 */
314 $buffer = apply_filters( 'powered_cache_page_caching_buffer', $buffer );
315
316 $url_path = powered_cache_get_url_path();
317
318 $dirs = explode( '/', $url_path );
319
320 $path = untrailingslashit( \PoweredCache\Utils\get_page_cache_dir() );
321
322 foreach ( $dirs as $dir ) {
323 if ( ! empty( $dir ) ) {
324 $path .= '/' . $dir;
325
326 if ( ! file_exists( $path ) ) {
327 if ( ! @mkdir( $path ) ) {
328 // Can not cache!
329 return $buffer;
330 }
331 }
332 }
333 }
334
335 $modified_time = time(); // Make sure modified time is consistent
336 $generation_time = number_format( microtime( true ) - $powered_cache_start_time, 3 );
337
338 $home_url = get_home_url();
339 // prevent mixed content
340 if ( ! is_ssl() && 'https' === strtolower( parse_url( $home_url, PHP_URL_SCHEME ) ) ) {
341 $https_home_url = $home_url;
342 $http_home_url = str_replace( 'https://', 'http://', $https_home_url );
343 $buffer = str_replace( esc_url( $http_home_url ), esc_url( $https_home_url ), $buffer );
344 }
345
346 if ( array_key_exists( 'cache_footprint', $GLOBALS['powered_cache_options'] ) && true === $GLOBALS['powered_cache_options']['cache_footprint'] ) {
347 if ( preg_match( '#</html>#i', $buffer ) ) {
348 $buffer .= PHP_EOL;
349 $buffer .= "<!-- Cache served by Powered Cache -->";
350 $buffer .= PHP_EOL;
351 $buffer .= "<!-- If you like fast websites like this, visit: https://poweredcache.com -->";
352 $buffer .= PHP_EOL;
353 $buffer .= "<!-- Last modified: " . gmdate( 'D, d M Y H:i:s', $modified_time ) . " GMT -->";
354 $buffer .= PHP_EOL;
355 $buffer .= "<!-- Dynamic page generated in $generation_time -->";
356 $buffer .= PHP_EOL;
357 if ( false !== stripos( $_SERVER['HTTP_USER_AGENT'], 'Powered Cache Preloader' ) ) {
358 $buffer .= "<!-- This page is preloaded by Powered Cache Preloader -->";
359 $buffer .= PHP_EOL;
360 }
361 }
362 }
363
364
365 $meta_file_name = 'meta.php';
366 $meta_file = '<?php exit; ?>' . PHP_EOL;
367
368 $meta_params = array(); // holds to metadata for cached file
369
370 $response_headers = \PoweredCache\Utils\get_response_headers();
371
372 foreach ( (array) $response_headers as $key => $value ) {
373 $meta_params['headers'][ $key ] = "$key: $value";
374 }
375
376 /**
377 * Filters meta parameters.
378 *
379 * @hook powered_cache_page_cache_meta_params
380 *
381 * @param {array} $meta_params Meta parameters.
382 * @param {array} $response_headers Supported response header list.
383 *
384 * @return {array} New value.
385 * @since 1.2
386 */
387 $meta_params = apply_filters( 'powered_cache_page_cache_meta_params', $meta_params, $response_headers );
388 $meta_file_contents = $meta_file . json_encode( $meta_params );
389
390 /**
391 * Filters meta file contents.
392 *
393 * @hook powered_cache_page_cache_meta_info
394 *
395 * @param {string} $meta_file_contents The content of the meta file.*
396 *
397 * @return {array} New value.
398 * @since 1.2
399 */
400 $meta_file_contents = apply_filters( 'powered_cache_page_cache_meta_info', $meta_file_contents );
401
402 file_put_contents( $path . '/' . $meta_file_name, $meta_file_contents );
403 touch( $path . '/' . $meta_file_name, $modified_time );
404
405 if ( ! empty( $meta_params['headers']['Content-Type'] ) ) {
406 $index_name = powered_cache_index_file( $meta_params['headers']['Content-Type'] );
407 } else {
408 $index_name = powered_cache_index_file();
409 }
410
411 if ( $GLOBALS['powered_cache_options']['gzip_compression'] && function_exists( 'gzencode' ) ) {
412 file_put_contents( $path . '/' . $index_name, gzencode( $buffer, 3 ) );
413 touch( $path . '/' . $index_name, $modified_time );
414 } else {
415 file_put_contents( $path . '/' . $index_name, $buffer );
416 touch( $path . '/' . $index_name, $modified_time );
417 }
418
419 /**
420 * Fires after caching a page.
421 *
422 * @hook powered_cache_page_cached
423 *
424 * @param {string} $buffer HTML Output.
425 *
426 * @since 1.0
427 */
428 do_action( 'powered_cache_page_cached', $buffer );
429
430 header( 'Cache-Control: no-cache' ); // Check back every time to see if re-download is necessary
431
432 header( 'X-Powered-Cache: MISS' );
433
434 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $modified_time ) . ' GMT' );
435
436 if ( function_exists( 'ob_gzhandler' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
437 return ob_gzhandler( $buffer, $flags );
438 } else {
439 return $buffer;
440 }
441 }
442
443
444 /**
445 * Optionally serve cache and exit
446 *
447 * @since 1.0
448 */
449 function powered_cache_serve_cache() {
450 global $powered_cache_slash_check;
451
452 $path = rtrim( $GLOBALS['powered_cache_options']['cache_location'], '/' ) . '/powered-cache/' . rtrim( powered_cache_get_url_path(), '/' ) . '/';
453
454 $meta_file = $path . '/meta.php';
455
456 $header_params = [];
457 $content_type = 'text/html';
458
459 if ( @file_exists( $meta_file ) ) {
460 $meta_contents = trim( file_get_contents( $meta_file ) );
461 $meta_contents = str_replace( '<?php exit; ?>', '', $meta_contents );
462 $meta_params = json_decode( trim( $meta_contents ), true );
463 $header_params = $meta_params['headers'];
464 }
465
466 if ( ! empty( $header_params['Content-Type'] ) ) {
467 $content_type = $header_params['Content-Type'];
468 }
469
470
471 $file_name = powered_cache_index_file( $content_type );
472 $file_path = $path . $file_name;
473
474 // check file exists?
475 if ( ! file_exists( $file_path ) ) {
476 return;
477 }
478
479 $modified_time = (int) @filemtime( $file_path );
480
481 header( 'Cache-Control: no-cache' ); // Check back in an hour
482
483 if ( ! empty( $modified_time ) && ! empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) && strtotime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) === $modified_time ) {
484 header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
485 exit;
486 }
487
488 // trailingslash check
489 if ( isset( $powered_cache_slash_check ) ) {
490 $current_path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
491 if ( $powered_cache_slash_check && ! empty( $current_path ) && '/' !== substr( $current_path, - 1 ) ) {
492 header( 'X-Powered-Cache: Passing to WordPress' );
493
494 return;
495 }
496
497 if ( ! $powered_cache_slash_check && ! empty( $current_path ) && '/' === substr( $current_path, - 1 ) ) {
498 header( 'X-Powered-Cache: Passing to WordPress' );
499
500 return;
501 }
502 }
503
504 if ( @file_exists( $file_path ) && @is_readable( $file_path ) ) {
505
506 if ( ! empty( $header_params ) ) {
507 foreach ( $header_params as $key => $response_header ) {
508 header( $response_header );
509 }
510 }
511
512 header( 'X-Powered-Cache: PHP' );
513 header( 'X-Cache-Enabled: true' );
514 header( sprintf( "age: %d", time() - filemtime( $file_path ) ) );
515
516 if ( function_exists( 'gzencode' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
517 header( 'Content-Encoding: gzip' );
518 }
519
520 @readfile( $file_path );
521
522 exit;
523 }
524 }
525
526 /**
527 * Get URL path for caching
528 *
529 * @return string
530 * @since 1.0
531 * @since 2.0 $request_uri without query string
532 */
533 function powered_cache_get_url_path() {
534 $host = ( isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '' );
535 $request_uri = explode( '?', $_SERVER['REQUEST_URI'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
536 $request_uri = reset( $request_uri );
537 $request_uri = preg_replace( '/(\/+)/', '/', $request_uri );
538 $request_uri = str_replace( '..', '', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $request_uri ) );
539
540 return rtrim( $host, '/' ) . $request_uri;
541 }
542
543 function powered_cache_get_user_cookie() {
544 if ( empty( $_COOKIE ) ) {
545 return false;
546 }
547
548 foreach ( $_COOKIE as $c_key => $val ) {
549 if ( false !== strpos( $c_key, 'wordpress_logged_in_' ) ) {
550 return $val;
551 }
552 }
553
554 return false;
555 }
556
557
558 /**
559 * Determines cache file names
560 *
561 * @param string $content_type
562 *
563 * @return string
564 * @since 1.2 `$content_type`
565 * @since 1.0
566 */
567 function powered_cache_index_file( $content_type = 'text/html' ) {
568 global $powered_cache_mobile_browsers, $powered_cache_mobile_prefixes, $powered_cache_vary_cookies, $powered_cache_cache_query_strings;
569
570 $file_name = 'index';
571
572 if ( is_ssl() ) {
573 $file_name .= '-https';
574 }
575
576 // separate file for mobile cache
577 if ( ! empty( $GLOBALS['powered_cache_options']['cache_mobile'] ) && ! empty( $GLOBALS['powered_cache_options']['cache_mobile_separate_file'] ) ) {
578 $mobile_browsers = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_browsers ) ), ' ' );
579 $mobile_prefixes = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_prefixes ) ), ' ' );
580
581 // Don't cache if mobile detection is activated
582 if ( ( preg_match( '#^.*(' . $mobile_browsers . ').*#i', $_SERVER['HTTP_USER_AGENT'] ) || preg_match( '#^(' . $mobile_prefixes . ').*#i', substr( $_SERVER['HTTP_USER_AGENT'], 0, 4 ) ) ) ) {
583 $file_name .= '-mobile';
584 }
585 }
586
587 if ( ! empty( $GLOBALS['powered_cache_options']['loggedin_user_cache'] ) ) {
588 $usr_cookie = powered_cache_get_user_cookie();
589 if ( false !== $usr_cookie ) {
590 $cookie_info = explode( '|', $usr_cookie );
591
592 // user specific cache index
593 $file_name .= '-user_' . $cookie_info[0] . '-' . substr( sha1( $cookie_info[0] ), 0, 6 );
594 }
595 }
596
597 // change filename based on vary cookies
598 if ( ! empty( $powered_cache_vary_cookies ) ) {
599 $cookie_file_name = '';
600 foreach ( $powered_cache_vary_cookies as $key => $vary_cookie ) {
601 if ( is_array( $vary_cookie ) ) {
602 if ( ! empty( $_COOKIE[ $key ] ) ) {
603 foreach ( $vary_cookie as $vary_sub_cookie ) {
604 if ( isset( $_COOKIE[ $key ][ $vary_sub_cookie ] ) ) {
605 $cookie_value = preg_replace( '/[^A-Za-z0-9. -]/', '', $_COOKIE[ $key ][ $vary_sub_cookie ] );
606 $cookie_file_name .= strtolower( $key . $vary_sub_cookie . $cookie_value );
607 }
608 }
609 }
610
611 continue;
612 }
613
614 if ( isset( $_COOKIE[ $vary_cookie ] ) && ! empty( $_COOKIE[ $vary_cookie ] ) ) {
615 $cookie_value = preg_replace( '/[^A-Za-z0-9. -]/', '', $_COOKIE[ $vary_cookie ] );
616 $cookie_file_name .= strtolower( $vary_cookie . $cookie_value );
617 }
618 }
619
620 if ( ! empty( $cookie_file_name ) ) {
621 /**
622 * Hashing for no particular reason
623 * preg_replace( '/[^a-z0-9_\-]/', '', strtolower( $cookie_file_name ) )
624 * can create a messy filename
625 */
626 $file_name .= '-' . sha1( $cookie_file_name );
627 }
628
629 }
630
631 // change filename for provided cache query string
632 if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
633 parse_str( $_SERVER['QUERY_STRING'], $query_string );
634 $qs_variable = '';
635 sort( $powered_cache_cache_query_strings );
636 foreach ( $powered_cache_cache_query_strings as $query_parameter ) {
637 if ( isset( $query_string[ $query_parameter ] ) ) {
638 $qs_variable .= '_' . $query_parameter;
639 $qs_variable .= is_array( $query_string[ $query_parameter ] ) ? implode( '|', $query_string[ $query_parameter ] ) : $query_string[ $query_parameter ];
640 }
641 }
642
643 if ( ! empty( $qs_variable ) ) {
644 $qs_variable = 'query_' . $qs_variable;
645 $file_name .= '_' . sha1( $qs_variable );
646 }
647 }
648
649
650 /**
651 * Content-Type is not always text/html (like feed, wp-json etc..)
652 * Adding hash by simply escaping from rewrite matches in htaccess or nginx
653 * Different types of content should be serve via PHP, in order to restore header info
654 */
655 if ( false === strpos( $content_type, 'text/html' ) ) {
656 $file_name .= '-' . substr( sha1( $content_type ), 0, 6 );
657 }
658
659
660 $file_name .= '.html';
661
662 if ( function_exists( 'gzencode' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
663 $file_name .= '.gz';
664 }
665
666 return $file_name;
667 }
668
669 /**
670 * Add cache miss header and reason
671 *
672 * @param string $reason Cache Miss info
673 *
674 * @since 2.2
675 */
676 function powered_cache_add_cache_miss_header( $reason ) {
677 if ( headers_sent() ) {
678 return;
679 }
680
681 header( 'X-Powered-Cache: MISS' );
682
683 if ( ( defined( 'POWERED_CACHE_ENABLE_LOG' ) && POWERED_CACHE_ENABLE_LOG )
684 || ( defined( 'POWERED_CACHE_MISS_REASON' ) && POWERED_CACHE_MISS_REASON )
685 ) {
686 header( "X-Powered-Cache-Miss-Reason: $reason" );
687 }
688 }
689