PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.7
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.7
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / cache / file-based-page-cache-functions.php

file-based-page-cache-functions.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.7, at cache/file-based-page-cache-functions.php

1,377 lines 41.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 /**
6 * Extensions directory.
7 */
8 if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions');
9
10 /**
11 * Holds utility functions used by file based cache
12 */
13
14 /**
15 * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above.
16 *
17 * @param String $buffer Page HTML.
18 * @param Int $flags OB flags to be passed through.
19 *
20 * @return String
21 */
22 if (!function_exists('wpo_cache')) :
23 function wpo_cache($buffer, $flags) {
24
25 // This case appears to happen for unclear reasons without WP being fully loaded, e.g. https://wordpress.org/support/topic/fatal-error-since-wp-5-8-update/ . It is simplest just to short-circuit it.
26 if ('' === $buffer) return '';
27
28 // This array records reasons why no cacheing took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately.
29 $no_cache_because = array();
30
31 if (strlen($buffer) < 255) {
32 $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth caching', 'wp-optimize'), 255);
33 }
34
35 // Don't cache pages for logged in users.
36 if (empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && (!function_exists('wpo_we_cache_per_role') || !wpo_we_cache_per_role()) && (!function_exists('is_user_logged_in') || (function_exists('wp_get_current_user') && is_user_logged_in()))) {
37 $no_cache_because[] = __('User is logged in', 'wp-optimize');
38 }
39
40 $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false);
41 if ($restricted_page_type_cache) {
42 $no_cache_because[] = $restricted_page_type_cache;
43 }
44
45 $conditional_tag_exceptions = apply_filters('wpo_url_in_conditional_tags_exceptions', false);
46 if ($conditional_tag_exceptions) {
47 $no_cache_because[] = $conditional_tag_exceptions;
48 }
49
50 // No root cache folder, so short-circuit here
51 if (!file_exists(WPO_CACHE_DIR)) {
52 $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')';
53 } elseif (!file_exists(WPO_CACHE_FILES_DIR)) {
54 // Try creating a folder for cached files, if it was flushed recently
55 if (!mkdir(WPO_CACHE_FILES_DIR)) {
56 $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')';
57 } else {
58 wpo_disable_cache_directories_viewing();
59 }
60 }
61
62 // If comments are opened and the user has saved his information.
63 if (function_exists('comments_open') && function_exists('get_post') && get_post() && comments_open()) {
64 $commenter = wp_get_current_commenter();
65 // if any of the fields contain something, do not save to cache
66 if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) {
67 $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize');
68 }
69 }
70
71 $can_cache_page = true;
72
73 if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) {
74 $can_cache_page = false;
75 }
76
77 /**
78 * Defines if the page can be cached or not
79 *
80 * @param boolean $can_cache_page
81 */
82 $can_cache_page_filter = apply_filters('wpo_can_cache_page', $can_cache_page);
83
84 if (!$can_cache_page_filter) {
85 if ($can_cache_page) {
86 $can_cache_page = false;
87 $no_cache_because[] = __('wpo_can_cache_page filter forbade it', 'wp-optimize');
88 } else {
89 $no_cache_because[] = __('DONOTCACHEPAGE constant forbade it and wpo_can_cache_page filter did not over-ride it', 'wp-optimize');
90 }
91 }
92
93 if (defined('REST_REQUEST') && REST_REQUEST) {
94 $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize');
95 }
96
97 // Don't cache with fatal error pages.
98 $last_error = error_get_last();
99 if (is_array($last_error) && E_ERROR == $last_error['type']) {
100 $no_cache_because[] = __('This page has a fatal error', 'wp-optimize');
101 }
102
103 if (http_response_code() >= 500) {
104 $no_cache_because[] = sprintf(__('This page has a critical error (HTTP code %s)', 'wp-optimize'), http_response_code());
105 } elseif (http_response_code() >= 400) {
106 $no_cache_because[] = sprintf(__('This page returned an HTTP unauthorised response code (%s)', 'wp-optimize'), http_response_code());
107 }
108
109 if (empty($no_cache_because)) {
110
111 $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags);
112
113 $url_path = wpo_get_url_path();
114
115 $dirs = explode('/', $url_path);
116
117 $path = WPO_CACHE_FILES_DIR;
118
119 foreach ($dirs as $dir) {
120 if (!empty($dir)) {
121 $path .= '/' . $dir;
122
123 if (!file_exists($path)) {
124 if (!mkdir($path)) {
125 $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)";
126 break;
127 }
128 }
129 }
130 }
131 }
132
133 if (!empty($no_cache_because)) {
134
135 $message = implode(', ', $no_cache_because);
136
137 // Add http headers
138 wpo_cache_add_nocache_http_header($message);
139
140 // Only output if the user has turned on debugging output
141 if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) {
142 $buffer .= "\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached because: ".htmlspecialchars($message)." -->\n";
143 }
144
145 return $buffer;
146
147 } else {
148
149 // Prevent mixed content when there's an http request but the site URL uses https.
150 $home_url = get_home_url();
151
152 if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) {
153 $https_home_url = $home_url;
154 $http_home_url = str_ireplace('https://', 'http://', $https_home_url);
155 $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer);
156 }
157
158 $modified_time = time(); // Take this as soon before writing as possible
159
160 $add_to_footer = '';
161
162 /**
163 * Filter wether to display the html comment <!-- Cached by WP-Optimize ... -->
164 *
165 * @param boolean $show - Wether to display the html comment
166 * @return boolean
167 */
168 if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) {
169 if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) {
170 $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n";
171 } else {
172 $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n";
173 }
174 }
175
176 // Create an empty index.php file in the cache directory for disable directory viewing.
177 if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', '');
178
179 /**
180 * Save $buffer into cache file.
181 */
182 $file_ext = '.html';
183
184 if (wpo_feeds_caching_enabled()) {
185 if (is_feed()) {
186 $file_ext = '.rss-xml';
187 }
188 }
189
190 $cache_filename = wpo_cache_filename($file_ext);
191 $cache_file = $path . '/' .$cache_filename;
192
193 if (defined('WPO_CACHE_FILENAME_DEBUG') && WPO_CACHE_FILENAME_DEBUG) {
194 $add_to_footer .= "\n<!-- WP Optimize page cache debug information -->\n";
195 if (!empty($GLOBALS['wpo_cache_filename_debug']) && is_array($GLOBALS['wpo_cache_filename_debug'])) {
196 $add_to_footer .= "<!-- \n" . join("\n", array_map('htmlspecialchars', $GLOBALS['wpo_cache_filename_debug'])) . "\n --->";
197 }
198 }
199
200 // if we can then cache gzipped content in .gz file.
201 if (function_exists('gzencode') && apply_filters('wpo_allow_cache_gzip_files', true)) {
202 // Only replace inside the addition, not inside the main buffer (e.g. post content)
203 file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6)));
204 }
205
206 file_put_contents($cache_file, $buffer.$add_to_footer);
207
208 if (is_callable('WP_Optimize')) {
209 // delete cached information about cache size.
210 WP_Optimize()->get_page_cache()->delete_cache_size_information();
211 } else {
212 // If the shutdown occurs before plugins are loaded,
213 // then this will trigger a fatal error, so, we check first
214 if (!doing_action('shutdown')) {
215 error_log('[WPO_CACHE] WP_Optimize() is not callable.');
216 $message = 'Please report this to WP-O support: ';
217 if (function_exists('wp_debug_backtrace_summary')) {
218 $message .= wp_debug_backtrace_summary();
219 } else {
220 $message .= wpo_debug_backtrace_summary();
221 }
222 error_log($message);
223 }
224 }
225
226 header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary.
227 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT');
228 header('WPO-Cache-Status: saving to cache');
229
230 if (wpo_cache_can_output_gzip_content()) {
231
232 if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) {
233 header('Content-Encoding: gzip');
234 }
235
236 // disable php gzip to avoid double compression.
237 ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set
238
239 return ob_gzhandler($buffer, $flags);
240 } else {
241 return $buffer;
242 }
243 }
244 }
245 endif;
246
247 /**
248 * Load files for support plugins.
249 */
250 if (!function_exists('wpo_cache_load_extensions')) :
251 function wpo_cache_load_extensions() {
252 $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php');
253
254 // Add external extensions
255 if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) {
256 $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php'));
257 }
258
259 if (empty($extensions)) return;
260
261 foreach ($extensions as $extension) {
262 if (is_file($extension)) require_once $extension;
263 }
264 }
265 endif;
266
267 if (!function_exists('wpo_restricted_cache_page_type')) {
268 function wpo_restricted_cache_page_type($restricted) {
269 global $post;
270
271 // Don't cache search or password protected.
272 if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) {
273 $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize');
274 }
275
276 // Don't cache the front page if option is set.
277 if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) {
278
279 $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize');
280 }
281
282 // Don't cache htacesss. Remember to properly escape any output to prevent injection.
283 if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) {
284 $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')';
285 }
286
287 // Don't cache feeds.
288 if (function_exists('is_feed') && is_feed() && !wpo_feeds_caching_enabled()) {
289 $restricted = __('We don\'t cache RSS feeds', 'wp-optimize');
290 }
291
292 return $restricted;
293 }
294 }
295
296 /**
297 * Returns true if we need cache content for loggedin users.
298 *
299 * @return bool
300 */
301 if (!function_exists('wpo_cache_loggedin_users')) :
302 function wpo_cache_loggedin_users() {
303 return !empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) || (function_exists('wpo_we_cache_per_role') && wpo_we_cache_per_role());
304 }
305 endif;
306
307 /**
308 * Returns true if we need to cache content for loggedin users.
309 *
310 * @return bool
311 */
312 if (!function_exists('wpo_user_specific_cache_enabled')) :
313 function wpo_user_specific_cache_enabled() {
314 return !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_auth']) && !empty($GLOBALS['wpo_cache_config']['wp_salt_logged_in']);
315 }
316 endif;
317
318 /**
319 * Get filename for store cache, depending on gzip, mobile and cookie settings.
320 *
321 * @param string $ext
322 * @return string
323 */
324 if (!function_exists('wpo_cache_filename')) :
325 function wpo_cache_filename($ext = '.html') {
326
327 $wpo_cache_filename_debug = array();
328
329 $filename = 'index';
330
331 if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) {
332 $filename = 'mobile.' . $filename;
333 }
334
335 if (wpo_webp_images_enabled() && !wpo_is_using_webp_images_redirection() && wpo_is_using_alter_html()) {
336 $filename = $filename . '.webp';
337 }
338
339 $cookies = wpo_cache_cookies();
340
341 $cache_key = '';
342
343 /**
344 * Add cookie values to filename if need.
345 * This section was inspired by things learned from WP-Rocket.
346 */
347 if (!empty($cookies)) {
348 foreach ($cookies as $key => $cookie_name) {
349 if (is_array($cookie_name) && isset($_COOKIE[$key])) {
350 foreach ($cookie_name as $cookie_key) {
351 if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) {
352 $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key];
353 $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key);
354 $cache_key .= '-' . $_cache_key;
355 $wpo_cache_filename_debug[] = 'Cookie: name: ' . $key . '[' . $cookie_key . '], value: *** , cache_key:' . $_cache_key;
356 }
357 }
358 continue;
359 }
360
361 if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) {
362 $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name];
363 $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key);
364 $cache_key .= '-' . $_cache_key;
365 $wpo_cache_filename_debug[] = 'Cookie: name: ' . $cookie_name . ', value: *** , cache_key:' . $_cache_key;
366 }
367 }
368 }
369
370 $query_variables = wpo_cache_query_variables();
371
372 /**
373 * Add GET variables to cache file name if need.
374 */
375 if (!empty($query_variables)) {
376 foreach ($query_variables as $variable) {
377 if (isset($_GET[$variable]) && !empty($_GET[$variable])) {
378 $_cache_key = $variable.'='.$_GET[$variable];
379 $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key);
380 $cache_key .= '-' . $_cache_key;
381 $wpo_cache_filename_debug[] = 'GET parameter: name: ' . $variable . ', value:' . htmlentities($_GET[$variable]) . ', cache_key:' . $_cache_key;
382 }
383 }
384 }
385
386 // add hash of queried cookies and variables to cache file name.
387 if ('' !== $cache_key) {
388 $hash = md5($cache_key);
389 $filename .= '-'.$hash;
390 $wpo_cache_filename_debug[] = 'Hash: ' . $hash;
391 }
392
393 $filename = apply_filters('wpo_cache_filename', $filename);
394
395 $wpo_cache_filename_debug[] = 'Extension: ' . $ext;
396 $wpo_cache_filename_debug[] = 'Filename: ' . $filename.$ext;
397
398 $GLOBALS['wpo_cache_filename_debug'] = $wpo_cache_filename_debug;
399
400 return $filename . $ext;
401 }
402 endif;
403
404 /**
405 * Returns site url from site_url() function or if it is not available from cache configuration.
406 */
407 if (!function_exists('wpo_site_url')) :
408 function wpo_site_url() {
409 if (is_callable('site_url')) return site_url('/');
410
411 $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url'];
412 return $site_url;
413 }
414 endif;
415
416 /**
417 * Get cookie names which impact on cache file name.
418 *
419 * @return array
420 */
421 if (!function_exists('wpo_cache_cookies')) :
422 function wpo_cache_cookies() {
423 $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies'];
424 return $cookies;
425 }
426 endif;
427
428 /**
429 * Get GET variable names which impact on cache file name.
430 *
431 * @return array
432 */
433 if (!function_exists('wpo_cache_query_variables')) :
434 function wpo_cache_query_variables() {
435 if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) {
436 $variables = array_keys($_GET);
437 } else {
438 $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables'];
439 }
440
441 if (!empty($variables)) {
442 sort($variables);
443 }
444
445 return wpo_cache_maybe_ignore_query_variables($variables);
446 }
447 endif;
448
449 /**
450 * Get list of all received HTTP headers.
451 *
452 * @return array
453 */
454 if (!function_exists('wpo_get_http_headers')) :
455 function wpo_get_http_headers() {
456
457 static $headers;
458
459 if (!empty($headers)) return $headers;
460
461 $headers = array();
462
463 // if is apache server then use get allheaders() function.
464 if (function_exists('getallheaders')) {
465 $headers = getallheaders();
466 } else {
467 // https://www.php.net/manual/en/function.getallheaders.php
468 foreach ($_SERVER as $key => $value) {
469
470 $key = strtolower($key);
471
472 if ('HTTP_' == substr($key, 0, 5)) {
473 $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value;
474 } elseif ('content_type' == $key) {
475 $headers["Content-Type"] = $value;
476 } elseif ('content_length' == $key) {
477 $headers["Content-Length"] = $value;
478 }
479 }
480 }
481
482 return $headers;
483 }
484 endif;
485
486 /**
487 * Check if requested Accept-Encoding headers has gzip value.
488 *
489 * @return bool
490 */
491 if (!function_exists('wpo_cache_gzip_accepted')) :
492 function wpo_cache_gzip_accepted() {
493 $headers = wpo_get_http_headers();
494
495 if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true;
496
497 return false;
498 }
499 endif;
500
501 /**
502 * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value
503 * and function ob_gzhandler is available.
504 *
505 * @return bool
506 */
507 if (!function_exists('wpo_cache_can_output_gzip_content')) :
508 function wpo_cache_can_output_gzip_content() {
509 return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler');
510 }
511 endif;
512
513 /**
514 * Check if header with certain name exists in already prepared headers and has value comparable with $header_value.
515 *
516 * @param string $header_name header name
517 * @param string $header_value header value as regexp.
518 *
519 * @return bool
520 */
521 if (!function_exists('wpo_cache_is_in_response_headers_list')) :
522 function wpo_cache_is_in_response_headers_list($header_name, $header_value) {
523 $headers_list = headers_list();
524
525 if (!empty($headers_list)) {
526 $header_name = strtolower($header_name);
527
528 foreach ($headers_list as $value) {
529 $value = explode(':', $value);
530
531 if (strtolower($value[0]) == $header_name) {
532 if (preg_match('/'.$header_value.'/', $value[1])) {
533 return true;
534 } else {
535 return false;
536 }
537 }
538 }
539 }
540
541 return false;
542 }
543 endif;
544
545 /**
546 * Check if mobile cache is enabled and current request is from moblile device.
547 *
548 * @return bool
549 */
550 if (!function_exists('wpo_cache_mobile_caching_enabled')) :
551 function wpo_cache_mobile_caching_enabled() {
552 if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true;
553 return false;
554 }
555 endif;
556
557 /**
558 * Check if webp images enabled
559 *
560 * @return bool
561 */
562 if (!function_exists('wpo_webp_images_enabled')) :
563 function wpo_webp_images_enabled() {
564 if (!empty($GLOBALS['wpo_cache_config']['use_webp_images'])) return true;
565 return false;
566 }
567 endif;
568
569 /**
570 * Check whether webp images using alter html method or not
571 *
572 * @return bool
573 */
574 if (!function_exists('wpo_is_using_alter_html')) :
575 function wpo_is_using_alter_html() {
576 return (isset($_SERVER['HTTP_ACCEPT']) && false !== strpos($_SERVER['HTTP_ACCEPT'], 'image/webp'));
577 }
578 endif;
579
580 /**
581 * Check whether webp images are served using redirect
582 *
583 * @return bool
584 */
585 if (!function_exists('wpo_is_using_webp_images_redirection')) :
586 function wpo_is_using_webp_images_redirection() {
587 if (empty($GLOBALS['wpo_cache_config']['uploads'])) return false;
588
589 $uploads_dir = $GLOBALS['wpo_cache_config']['uploads'];
590 $htaccess_file = $uploads_dir . '/.htaccess';
591 if (!file_exists($htaccess_file)) return false;
592 $htaccess_content = file_get_contents($htaccess_file);
593 $comment_sections = array('Register webp mime type', 'WP-Optimize WebP Rules');
594
595 if (function_exists('str_contains')) {
596 return str_contains($htaccess_content, $comment_sections[0]) && str_contains($htaccess_content, $comment_sections[1]);
597 } else {
598 return strpos($htaccess_content, $comment_sections[0]) && strpos($htaccess_content, $comment_sections[1]);
599 }
600 }
601 endif;
602
603 /**
604 * Serves the cache and exits
605 */
606 if (!function_exists('wpo_serve_cache')) :
607 function wpo_serve_cache() {
608 $file_name = wpo_cache_filename();
609
610 $file_name_rss_xml = wpo_cache_filename('.rss-xml');
611 $send_as_feed = false;
612
613 $path_dir = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/';
614 $path = $path_dir . $file_name;
615
616 if (wpo_feeds_caching_enabled()) {
617 // check for .xml cache file if .html cache file doesn't exist
618 if (!file_exists($path_dir . $file_name) && file_exists($path_dir . $file_name_rss_xml)) {
619 $path = $path_dir . $file_name_rss_xml;
620 $send_as_feed = true;
621 }
622 }
623
624 $use_gzip = false;
625
626 // if we can use gzip and gzipped file exist in cache we use it.
627 // if headers already sent we don't use gzipped file content.
628 if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) {
629 $path .= '.gz';
630 $use_gzip = true;
631 }
632
633 $modified_time = file_exists($path) ? (int) filemtime($path) : time();
634
635 // Cache has expired, purge and exit.
636 if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) {
637 if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) {
638 wpo_delete_files($path);
639 return;
640 }
641 }
642
643 // disable zlib output compression to avoid double content compression.
644 if ($use_gzip) {
645 ini_set('zlib.output_compression', 'Off'); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set
646 }
647
648 $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip');
649
650 header('Cache-Control: no-cache'); // Check back later
651
652 if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) {
653 if ($use_gzip && !$gzip_header_already_sent) {
654 header('Content-Encoding: gzip');
655 }
656
657 if ($send_as_feed) {
658 header('Content-type: application/rss+xml');
659 }
660
661 header('WPO-Cache-Status: cached');
662 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT');
663 header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
664 exit;
665 }
666
667 if (file_exists($path) && is_readable($path)) {
668
669 if (wpo_is_canonical_redirection_needed()) return;
670
671 if ($use_gzip && !$gzip_header_already_sent) {
672 header('Content-Encoding: gzip');
673 }
674
675 // send correct headers for xml and txt files
676 $filename = basename(dirname($path));
677
678 if (preg_match('/\.xml$/i', $filename)) {
679 header('Content-type: text/xml');
680 }
681
682 if (preg_match('/\.txt$/i', $filename)) {
683 header('Content-type: text/plain');
684 }
685
686 if ($send_as_feed) {
687 header('Content-type: application/rss+xml');
688 }
689
690 header('WPO-Cache-Status: cached');
691 if (!empty($modified_time)) {
692 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT');
693 }
694
695 readfile($path);
696
697 exit;
698 }
699 }
700 endif;
701
702 /**
703 * Checks and does redirection, if needed
704 *
705 * @return bool
706 */
707 if (!function_exists('wpo_is_canonical_redirection_needed')) :
708 function wpo_is_canonical_redirection_needed() {
709 $permalink_structure = isset($GLOBALS['wpo_cache_config']['permalink_structure']) ? $GLOBALS['wpo_cache_config']['permalink_structure'] : '';
710 $site_url = $GLOBALS['wpo_cache_config']['site_url'];
711
712 $schema = isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS'] ? "https" : "http";
713 $url_part = "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
714 $requested_url = $schema . $url_part;
715 $url_parts = parse_url($requested_url);
716 $extension = pathinfo($url_parts['path'], PATHINFO_EXTENSION);
717
718 if (!empty($permalink_structure) && $requested_url != $site_url) {
719 if ('/' == substr($permalink_structure, -1) && empty($extension) && empty($url_parts['query']) && empty($url_parts['fragment'])) {
720 $url = preg_replace('/(.+?)([\/]*)(\[\?\#][^\/]+|$)/', '$1/$3', $_SERVER['REQUEST_URI']);
721 if (0 !== strcmp($_SERVER['REQUEST_URI'], $url)) return true;
722 } else {
723 $url = rtrim($_SERVER['REQUEST_URI'], '/');
724 if (0 !== strcmp($_SERVER['REQUEST_URI'], $url)) return true;
725 }
726 }
727 return false;
728 }
729 endif;
730
731 /**
732 * Clears the cache
733 */
734 if (!function_exists('wpo_cache_flush')) :
735 function wpo_cache_flush() {
736
737 if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR);
738
739 if (function_exists('wp_cache_flush')) {
740 wp_cache_flush();
741 }
742
743 do_action('wpo_cache_flush');
744 }
745 endif;
746
747 /**
748 * Get URL path for caching
749 *
750 * @since 1.0
751 * @return string
752 */
753 if (!function_exists('wpo_get_url_path')) :
754 function wpo_get_url_path($url = '') {
755 $url = '' == $url ? wpo_current_url() : $url;
756 $url_parts = parse_url($url);
757
758 if (isset($url_parts['path']) && false !== stripos($url_parts['path'], '/index.php')) {
759 $url_parts['path'] = preg_replace('/(.*?)index\.php(\/.+)/i', '$1index-php$2', $url_parts['path']);
760 }
761
762 if (!isset($url_parts['host'])) $url_parts['host'] = '';
763 if (!isset($url_parts['path'])) $url_parts['path'] = '';
764
765 return $url_parts['host'].$url_parts['path'];
766 }
767 endif;
768
769 /**
770 * Get requested url.
771 *
772 * @return string
773 */
774 if (!function_exists('wpo_current_url')) :
775 function wpo_current_url() {
776 // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot).
777 // Otherwise this function would return a different URL at the begining and end of the cache process.
778 static $url = '';
779 if ('' != $url) return $url;
780 $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
781 $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) ||
782 isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' )
783 . '://' . $http_host.$_SERVER['REQUEST_URI'], '/');
784 return $url;
785 }
786 endif;
787
788 /**
789 * Return list of conditional tag exceptions.
790 *
791 * @return array
792 */
793 if (!function_exists('wpo_get_conditional_tags_exceptions')) :
794 function wpo_get_conditional_tags_exceptions() {
795 static $exceptions = null;
796
797 if (null !== $exceptions) return $exceptions;
798
799 if (!empty($GLOBALS['wpo_cache_config'])) {
800 if (empty($GLOBALS['wpo_cache_config']['cache_exception_conditional_tags'])) {
801 $exceptions = array();
802
803 } else {
804
805 $exceptions = $GLOBALS['wpo_cache_config']['cache_exception_conditional_tags'];
806
807 }
808
809 } elseif (class_exists('WPO_Page_Cache')) {
810
811 $config = WPO_Page_Cache::instance()->config->get();
812
813 if (is_array($config) && array_key_exists('cache_exception_conditional_tags', $config)) {
814 $exceptions = $config['cache_exception_conditional_tags'];
815 } else {
816 $exceptions = array();
817 }
818
819 $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r|\r\n)#', $exceptions);
820 $exceptions = array_filter($exceptions, 'trim');
821
822 } else {
823 $exceptions = array();
824 }
825
826 return $exceptions;
827 }
828 endif;
829
830 /**
831 * Return list of url exceptions.
832 *
833 * @return array
834 */
835 if (!function_exists('wpo_get_url_exceptions')) :
836 function wpo_get_url_exceptions() {
837 static $exceptions = null;
838
839 if (null !== $exceptions) return $exceptions;
840
841 // if called from file-based-page-cache.php when WP loading
842 // and cache settings exists then use it otherwise get settings from database.
843 if (!empty($GLOBALS['wpo_cache_config'])) {
844 if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) {
845 $exceptions = array();
846 } else {
847 $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']);
848 }
849 } elseif (class_exists('WPO_Page_Cache')) {
850 $config = WPO_Page_Cache::instance()->config->get();
851
852 if (is_array($config) && array_key_exists('cache_exception_urls', $config)) {
853 $exceptions = $config['cache_exception_urls'];
854 } else {
855 $exceptions = array();
856 }
857
858 $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions);
859 $exceptions = array_filter($exceptions, 'trim');
860 } else {
861 $exceptions = array();
862 }
863
864 return apply_filters('wpo_get_url_exceptions', $exceptions);
865 }
866 endif;
867
868 /**
869 * Return true of exception url matches current url
870 *
871 * @param string $exception Exceptions to check URL against.
872 * @param bool $regex Whether to check with regex or not.
873 * @return bool true if matched, false otherwise
874 */
875 if (!function_exists('wpo_current_url_exception_match')) :
876 function wpo_current_url_exception_match($exception) {
877
878 return wpo_url_exception_match(wpo_current_url(), $exception);
879 }
880 endif;
881
882 /**
883 * Check if url in conditional tags exceptions list.
884 *
885 * @return string
886 */
887 if (!function_exists('wpo_url_in_conditional_tags_exceptions')) :
888 function wpo_url_in_conditional_tags_exceptions() {
889
890 $exceptions = wpo_get_conditional_tags_exceptions();
891 $restricted = '';
892 $allowed_functions = array('is_single', 'is_page', 'is_front_page', 'is_home', 'is_archive', 'is_tag', 'is_category', 'is_feed', 'is_search', 'is_author', 'is_woocommerce', 'is_shop', 'is_product', 'is_account_page', 'is_product_category', 'is_product_tag', 'is_wc_endpoint_url', 'is_bbpress', 'bbp_is_forum_archive', 'bbp_is_topic_archive', 'bbp_is_topic_tag', 'bbp_is_single_forum', 'bbp_is_single_topic', 'bbp_is_single_view', 'bbp_is_single_user', 'bbp_is_user_home', 'bbp_is_search');
893 //Filter for add more conditional tags to whitelist in the exceptions list.
894 $allowed_functions = apply_filters('wpo_allowed_conditional_tags_exceptions', $allowed_functions);
895 if (!empty($exceptions)) {
896 foreach ($exceptions as $exception) {
897 if (false !== strpos($exception, 'is_')) {
898 $exception_function = $exception;
899 if ('()' == substr($exception, -2)) {
900 $exception_function = substr($exception, 0, -2);
901 }
902
903 if (in_array($exception_function, $allowed_functions) && function_exists($exception_function) && call_user_func($exception_function)) {
904 $restricted = sprintf(__('In the settings, caching is disabled for %s', 'wp-optimize'), $exception_function);
905 }
906 }
907 }
908 }
909 return $restricted;
910 }
911 endif;
912
913
914 /**
915 * Check if url in exceptions list.
916 *
917 * @param string $url
918 *
919 * @return bool
920 */
921 if (!function_exists('wpo_url_in_exceptions')) :
922 function wpo_url_in_exceptions($url) {
923 $exceptions = wpo_get_url_exceptions();
924
925 if (!empty($exceptions)) {
926 foreach ($exceptions as $exception) {
927
928 // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type()
929 if ('/' == $exception) continue;
930
931 if (wpo_url_exception_match($url, $exception)) {
932 // Exception match.
933 return true;
934 }
935 }
936 }
937
938 return false;
939 }
940 endif;
941
942 /**
943 * Check if url string match with exception.
944 *
945 * @param string $url - complete url string i.e. http(s):://domain/path
946 * @param string $exception - complete url or absolute path, can consist (.*) wildcards
947 *
948 * @return bool
949 */
950 if (!function_exists('wpo_url_exception_match')) :
951 function wpo_url_exception_match($url, $exception) {
952 if (preg_match('#^[\s]*$#', $exception)) {
953 return false;
954 }
955
956 $exception = str_replace('*', '.*', $exception);
957
958 $exception = trim($exception);
959
960 // used to test websites placed in subdirectories.
961 $sub_dir = '';
962
963 // if exception defined from root i.e. /page1 then remove domain part in url.
964 if (preg_match('/^\//', $exception)) {
965 // get site sub directory.
966 $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url());
967 // add prefix slash and remove slash.
968 $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/');
969 // get relative path
970 $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url);
971 }
972
973 $url = rtrim($url, '/') . '/';
974 $exception = rtrim($exception, '/');
975
976 // if we have no wildcat in the end of exception then add slash.
977 if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/';
978
979 $exception = preg_quote($exception);
980
981 // fix - unescape possible escaped mask .*
982 $exception = str_replace('\\.\\*', '.*', $exception);
983
984 return preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url);
985 }
986 endif;
987
988 /**
989 * Checks if its a mobile device
990 *
991 * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/
992 */
993 if (!function_exists('wpo_is_mobile')) :
994 function wpo_is_mobile() {
995 if (empty($_SERVER['HTTP_USER_AGENT'])) {
996 $is_mobile = false;
997 // many mobile devices (all iPhone, iPad, etc.)
998 } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false
999 || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false
1000 || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false
1001 || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false
1002 || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false
1003 || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false
1004 || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false
1005 ) {
1006 $is_mobile = true;
1007 } else {
1008 $is_mobile = false;
1009 }
1010
1011 return $is_mobile;
1012 }
1013 endif;
1014
1015 /**
1016 * Check if current browser agent is not disabled in options.
1017 *
1018 * @return bool
1019 */
1020 if (!function_exists('wpo_is_accepted_user_agent')) :
1021 function wpo_is_accepted_user_agent($user_agent) {
1022
1023 $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']);
1024
1025 if (!empty($exceptions)) {
1026 foreach ($exceptions as $exception) {
1027 if ('' == trim($exception)) continue;
1028
1029 if (preg_match('#'.$exception.'#i', $user_agent)) return false;
1030 }
1031 }
1032
1033 return true;
1034 }
1035 endif;
1036
1037 /**
1038 * Delete function that deals with directories recursively
1039 *
1040 * @param string $src Path of the folder
1041 * @param boolean $recursive If $src is a folder, recursively delete the inner folders. If set to false, only the files will be deleted.
1042 *
1043 * @return bool
1044 */
1045 if (!function_exists('wpo_delete_files')) :
1046 function wpo_delete_files($src, $recursive = true) {
1047 if (!file_exists($src) || '' == $src || '/' == $src) {
1048 return true;
1049 }
1050
1051 if (is_file($src)) {
1052 return unlink($src);
1053 }
1054
1055 $success = true;
1056 $has_dir = false;
1057
1058 if ($recursive) {
1059 // N.B. If opendir() fails, then a false positive (i.e. true) will be returned
1060 if (false !== ($dir = opendir($src))) {
1061 $file = readdir($dir);
1062 while (false !== $file) {
1063 if ('.' == $file || '..' == $file) {
1064 $file = readdir($dir);
1065 continue;
1066 }
1067 if (is_dir($src . '/' . $file)) {
1068 if (!wpo_delete_files($src . '/' . $file)) {
1069 $success = false;
1070 }
1071 } else {
1072 if (!unlink($src . '/' . $file)) {
1073 $success = false;
1074 }
1075 }
1076
1077 $file = readdir($dir);
1078 }
1079 closedir($dir);
1080 }
1081 } else {
1082 // Not recursive, so we only delete the files
1083 // scan directories recursively.
1084 $handle = opendir($src);
1085
1086 if (false === $handle) return false;
1087
1088 $file = readdir($handle);
1089
1090 while (false !== $file) {
1091
1092 if ('.' != $file && '..' != $file) {
1093 if (is_dir($src . '/' . $file)) {
1094 $has_dir = true;
1095 } elseif (!unlink($src . '/' . $file)) {
1096 $success = false;
1097 }
1098 }
1099
1100 $file = readdir($handle);
1101
1102 }
1103 }
1104
1105 if ($success && !$has_dir) {
1106 // Success of this operation is not recorded; we only ultimately care about emptying, not removing entirely (empty folders in our context are harmless)
1107 rmdir($src);
1108 }
1109
1110 // delete cached information about cache size.
1111 WP_Optimize()->get_page_cache()->delete_cache_size_information();
1112
1113 return $success;
1114 }
1115 endif;
1116
1117 if (!function_exists('wpo_is_empty_dir')) :
1118 /**
1119 * Check if selected directory is empty or has only index.php which we added for security reasons.
1120 *
1121 * @param string $dir
1122 *
1123 * @return bool
1124 */
1125 function wpo_is_empty_dir($dir) {
1126 if (!file_exists($dir) || !is_dir($dir)) return false;
1127
1128 $handle = opendir($dir);
1129
1130 if (false === $handle) return false;
1131
1132 $is_empty = true;
1133 $file = readdir($handle);
1134
1135 while (false !== $file) {
1136
1137 if ('.' != $file && '..' != $file && 'index.php' != $file) {
1138 $is_empty = false;
1139 break;
1140 }
1141
1142 $file = readdir($handle);
1143 }
1144
1145 closedir($handle);
1146 return $is_empty;
1147 }
1148 endif;
1149
1150 /**
1151 * Either store for later output, or output now. Only the most-recent call will be effective.
1152 *
1153 * @param String|Null $output - if not null, then the string to use when called by the shutdown action.
1154 */
1155 if (!function_exists('wpo_cache_add_footer_output')) :
1156 function wpo_cache_add_footer_output($output = null) {
1157
1158 static $buffered = null;
1159
1160 if (function_exists('current_filter') && 'shutdown' == current_filter()) {
1161 // Only add the line if it was a page, not something else (e.g. REST response)
1162 if (function_exists('did_action') && did_action('wp_footer')) {
1163 echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".$buffered." -->\n";
1164 } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG) {
1165 error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered);
1166 }
1167 } else {
1168 if (null == $buffered && function_exists('add_action')) add_action('shutdown', 'wpo_cache_add_footer_output', 11);
1169 $buffered = $output;
1170 }
1171
1172 }
1173 endif;
1174
1175 /**
1176 * Remove variable names that shouldn't influence cache.
1177 *
1178 * @param array $variables List of variable names.
1179 *
1180 * @return array
1181 */
1182 if (!function_exists('wpo_cache_maybe_ignore_query_variables')) :
1183 function wpo_cache_maybe_ignore_query_variables($variables) {
1184
1185 /**
1186 * Filters the current $_GET variables that will be used when caching or excluding from cache.
1187 * Currently:
1188 * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set)
1189 * - 'doing_wp_cron' (alternative cron)
1190 * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap)
1191 * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap)
1192 * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap)
1193 */
1194 $exclude_variables = array(
1195 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set
1196 'doing_wp_cron', // alternative cron
1197 'aiosp_sitemap_path', // All in one SEO sitemap
1198 'aiosp_sitemap_page',
1199 'xml_sitemap', // SEOPress sitemap
1200 'seopress_sitemap',
1201 'seopress_news',
1202 'seopress_video',
1203 'seopress_cpt',
1204 'seopress_paged',
1205 'sitemap', // YOAST SEO sitemap
1206 'sitemap_n',
1207 );
1208 $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables;
1209
1210 if (empty($exclude_variables)) return $variables;
1211
1212 foreach ($exclude_variables as $variable) {
1213 $exclude = array_search($variable, $variables);
1214 if (false !== $exclude) {
1215 array_splice($variables, $exclude, 1);
1216 }
1217 }
1218
1219 return $variables;
1220 }
1221 endif;
1222
1223 /**
1224 * Get cache config
1225 *
1226 * @param string $key - The config item
1227 * @param mixed $default - The default value
1228 *
1229 * @return mixed
1230 */
1231 if (!function_exists('wpo_cache_config_get')) :
1232 function wpo_cache_config_get($key, $default = false) {
1233 $config = $GLOBALS['wpo_cache_config'];
1234
1235 if (!$config) return false;
1236
1237 if (isset($config[$key])) {
1238 return $config[$key];
1239 } else {
1240 return $default;
1241 }
1242 }
1243 endif;
1244
1245 if (!function_exists('wpo_disable_cache_directories_viewing')) :
1246 function wpo_disable_cache_directories_viewing() {
1247 global $is_apache, $is_IIS, $is_iis7;
1248
1249 if (!is_dir(WPO_CACHE_FILES_DIR)) return;
1250
1251 // Create .htaccess file for apache server.
1252 if ($is_apache) {
1253 $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess';
1254
1255 // CS does not like heredoc
1256 // phpcs:disable
1257 $htaccess_content = <<<EOF
1258 # Disable directory browsing
1259 Options -Indexes
1260
1261 # Disable access to any files
1262 <FilesMatch ".*">
1263 Order allow,deny
1264 Deny from all
1265 </FilesMatch>
1266 EOF;
1267 // phpcs:enable
1268
1269 if (!is_file($htaccess_filename)) @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1270 }
1271
1272 // Create web.config file for IIS servers.
1273 if ($is_IIS || $is_iis7) {
1274 $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config';
1275 $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n";
1276
1277 if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1278 }
1279
1280 // Create empty index.php file for all servers.
1281 if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', '');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1282 }
1283 endif;
1284
1285 /**
1286 * Add the headers indicating why the page is not cached or served from cache
1287 *
1288 * @param string $message - The headers
1289 *
1290 * @return void
1291 */
1292 if (!function_exists('wpo_cache_add_nocache_http_header')) :
1293 function wpo_cache_add_nocache_http_header($message = '') {
1294 static $buffered_message = null;
1295
1296 if (function_exists('current_filter') && 'send_headers' === current_filter() && $buffered_message && !headers_sent()) {
1297 header('WPO-Cache-Status: not cached');
1298 header('WPO-Cache-Message: '. trim(str_replace(array("\r", "\n", ':'), ' ', strip_tags($buffered_message))));
1299 } else {
1300 if (!$buffered_message && function_exists('add_action')) add_action('send_headers', 'wpo_cache_add_nocache_http_header', 11);
1301 $buffered_message = $message;
1302 }
1303 }
1304 endif;
1305
1306 /**
1307 * Check if feeds caching enabled
1308 *
1309 * @return bool
1310 */
1311 if (!function_exists('wpo_feeds_caching_enabled')) :
1312 function wpo_feeds_caching_enabled() {
1313 return apply_filters('wpo_feeds_caching_enabled', true);
1314 }
1315 endif;
1316
1317 if (!function_exists('wpo_debug_backtrace_summary')) {
1318 function wpo_debug_backtrace_summary($ignore_class = null, $skip_frames = 0, $pretty = true) {
1319 static $truncate_paths;
1320
1321 $trace = debug_backtrace(false);
1322 $caller = array();
1323 $check_class = !is_null($ignore_class);
1324 $skip_frames++; // Skip this function.
1325
1326 if (!isset($truncate_paths)) {
1327 $truncate_paths = array(
1328 wpo_normalize_path(WP_CONTENT_DIR),
1329 wpo_normalize_path(ABSPATH),
1330 );
1331 }
1332
1333 foreach ($trace as $call) {
1334 if ($skip_frames > 0) {
1335 $skip_frames--;
1336 } elseif (isset($call['class'])) {
1337 if ($check_class && $ignore_class == $call['class']) {
1338 continue; // Filter out calls.
1339 }
1340
1341 $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
1342 } else {
1343 if (in_array($call['function'], array('do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array'), true)) {
1344 $caller[] = "{$call['function']}('{$call['args'][0]}')";
1345 } elseif (in_array($call['function'], array('include', 'include_once', 'require', 'require_once'), true)) {
1346 $filename = isset($call['args'][0]) ? $call['args'][0] : '';
1347 $caller[] = $call['function'] . "('" . str_replace($truncate_paths, '', wpo_normalize_path($filename)) . "')";
1348 } else {
1349 $caller[] = $call['function'];
1350 }
1351 }
1352 }
1353 if ($pretty) {
1354 return implode(', ', array_reverse($caller));
1355 } else {
1356 return $caller;
1357 }
1358 }
1359 }
1360
1361 if (!function_exists('wpo_normalize_path')) {
1362 function wpo_normalize_path($path) {
1363 // Standardise all paths to use '/'.
1364 $path = str_replace('\\', '/', $path);
1365
1366 // Replace multiple slashes down to a singular, allowing for network shares having two slashes.
1367 $path = preg_replace('|(?<=.)/+|', '/', $path);
1368
1369 // Windows paths should uppercase the drive letter.
1370 if (':' === substr($path, 1, 1)) {
1371 $path = ucfirst($path);
1372 }
1373
1374 return $path;
1375 }
1376 }
1377