PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.21
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.21
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.21, at cache/file-based-page-cache-functions.php

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