690 lines
19 KiB
PHP
690 lines
19 KiB
PHP
<?php
|
||
namespace WP_Rocket\Buffer;
|
||
|
||
/**
|
||
* Handle page cache.
|
||
*
|
||
* @since 3.3
|
||
*/
|
||
class Cache extends Abstract_Buffer {
|
||
|
||
/**
|
||
* Process identifier used by the logger.
|
||
*
|
||
* @var string
|
||
* @since 3.3
|
||
*/
|
||
protected $process_id = 'caching process';
|
||
|
||
/**
|
||
* Tests instance
|
||
*
|
||
* @var Tests
|
||
*/
|
||
protected $tests;
|
||
|
||
/**
|
||
* Config instance
|
||
*
|
||
* @var Config
|
||
*/
|
||
private $config;
|
||
|
||
/**
|
||
* Path to the directory containing the cache files.
|
||
*
|
||
* @var string
|
||
* @since 3.3
|
||
*/
|
||
private $cache_dir_path;
|
||
|
||
/**
|
||
* Constructor.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param Tests $tests Tests instance.
|
||
* @param Config $config Config instance.
|
||
* @param array $args {
|
||
* An array of arguments.
|
||
*
|
||
* @type string $cache_dir_path Path to the directory containing the cache files.
|
||
* }
|
||
*/
|
||
public function __construct( Tests $tests, Config $config, array $args ) {
|
||
$this->config = $config;
|
||
$this->cache_dir_path = rtrim( $args['cache_dir_path'], '/' ) . '/';
|
||
|
||
parent::__construct( $tests );
|
||
|
||
$this->log( 'CACHING PROCESS STARTED.', [], 'info' );
|
||
}
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** CACHE =================================================================================== */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
|
||
/**
|
||
* Serve the cache file if it exists. If not, init the buffer.
|
||
*
|
||
* @since 3.3
|
||
*/
|
||
public function maybe_init_process() {
|
||
if ( ! $this->tests->can_init_process() ) {
|
||
$this->define_donotoptimize_true();
|
||
$this->log_last_test_error();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* Serve the cache file if it exists.
|
||
*/
|
||
$cache_filepath = $this->get_cache_path();
|
||
|
||
$this->log(
|
||
'Looking for cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
]
|
||
);
|
||
|
||
$cache_filepath_gzip = $cache_filepath . '_gzip';
|
||
$accept_encoding = $this->config->get_server_input( 'HTTP_ACCEPT_ENCODING' );
|
||
$accept_gzip = $accept_encoding && false !== strpos( $accept_encoding, 'gzip' );
|
||
|
||
// Check if cache file exist.
|
||
if ( $accept_gzip && is_readable( $cache_filepath_gzip ) ) {
|
||
$this->serve_gzip_cache_file( $cache_filepath_gzip );
|
||
}
|
||
|
||
if ( is_readable( $cache_filepath ) ) {
|
||
$this->serve_cache_file( $cache_filepath );
|
||
}
|
||
|
||
// Maybe we're looking for a webp file.
|
||
$cache_filename = basename( $cache_filepath );
|
||
|
||
if ( strpos( $cache_filename, '-webp' ) !== false ) {
|
||
// We're looking for a webp file that doesn't exist: try to locate any `.no-webp` file.
|
||
$cache_dir_path = rtrim( dirname( $cache_filepath ), '/\\' ) . DIRECTORY_SEPARATOR;
|
||
|
||
if ( file_exists( $cache_dir_path . '.no-webp' ) ) {
|
||
// We have a `.no-webp` file: try to deliver a non-webp cache file.
|
||
$cache_filepath = $cache_dir_path . str_replace( '-webp', '', $cache_filename );
|
||
$cache_filepath_gzip = $cache_filepath . '_gzip';
|
||
|
||
$this->log(
|
||
'Looking for non-webp cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
]
|
||
);
|
||
|
||
// Try to deliver the non-webp version instead.
|
||
if ( $accept_gzip && is_readable( $cache_filepath_gzip ) ) {
|
||
$this->serve_gzip_cache_file( $cache_filepath_gzip );
|
||
}
|
||
|
||
if ( is_readable( $cache_filepath ) ) {
|
||
$this->serve_cache_file( $cache_filepath );
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* No cache file yet: launch caching process.
|
||
*/
|
||
$this->log(
|
||
'Start buffer.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
]
|
||
);
|
||
|
||
ob_start( [ $this, 'maybe_process_buffer' ] );
|
||
}
|
||
|
||
/**
|
||
* Serve a cache file.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param string $cache_filepath Path to the cache file.
|
||
*/
|
||
private function serve_cache_file( $cache_filepath ) {
|
||
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', filemtime( $cache_filepath ) ) . ' GMT' );
|
||
|
||
$if_modified_since = $this->get_if_modified_since();
|
||
|
||
// Checking if the client is validating his cache and if it is current.
|
||
if ( $if_modified_since && ( strtotime( $if_modified_since ) === @filemtime( $cache_filepath ) ) ) {
|
||
// Client's cache is current, so we just respond '304 Not Modified'.
|
||
header( $this->config->get_server_input( 'SERVER_PROTOCOL', '' ) . ' 304 Not Modified', true, 304 );
|
||
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
|
||
header( 'Cache-Control: no-cache, must-revalidate' );
|
||
|
||
$this->log(
|
||
'Serving `304` cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
'modified' => $if_modified_since,
|
||
],
|
||
'info'
|
||
);
|
||
exit;
|
||
}
|
||
|
||
// Serve the cache if file isn't store in the client browser cache.
|
||
readfile( $cache_filepath );
|
||
|
||
$this->log(
|
||
'Serving cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
'modified' => $if_modified_since,
|
||
],
|
||
'info'
|
||
);
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* Serve a gzipped cache file.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param string $cache_filepath Path to the gzip cache file.
|
||
*/
|
||
private function serve_gzip_cache_file( $cache_filepath ) {
|
||
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', filemtime( $cache_filepath ) ) . ' GMT' );
|
||
|
||
$if_modified_since = $this->get_if_modified_since();
|
||
|
||
// Checking if the client is validating his cache and if it is current.
|
||
if ( $if_modified_since && ( strtotime( $if_modified_since ) === @filemtime( $cache_filepath ) ) ) {
|
||
// Client's cache is current, so we just respond '304 Not Modified'.
|
||
header( $this->config->get_server_input( 'SERVER_PROTOCOL', '' ) . ' 304 Not Modified', true, 304 );
|
||
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
|
||
header( 'Cache-Control: no-cache, must-revalidate' );
|
||
|
||
$this->log(
|
||
'Serving `304` gzip cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
'modified' => $if_modified_since,
|
||
],
|
||
'info'
|
||
);
|
||
exit;
|
||
}
|
||
|
||
// Serve the cache if file isn't store in the client browser cache.
|
||
readgzfile( $cache_filepath );
|
||
|
||
$this->log(
|
||
'Serving gzip cache file.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
'modified' => $if_modified_since,
|
||
],
|
||
'info'
|
||
);
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* Maybe cache the page content.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param string $buffer The buffer content.
|
||
* @return string The buffered content.
|
||
*/
|
||
public function maybe_process_buffer( $buffer ) {
|
||
if ( ! $this->tests->can_process_buffer( $buffer ) ) {
|
||
$this->log_last_test_error();
|
||
return $buffer;
|
||
}
|
||
|
||
$footprint = '';
|
||
$is_html = $this->is_html( $buffer );
|
||
|
||
if ( ! static::can_generate_caching_files() ) {
|
||
// Not allowed to generate cache files.
|
||
if ( $is_html ) {
|
||
$footprint = $this->get_rocket_footprint();
|
||
}
|
||
|
||
$this->log(
|
||
'Page not cached by filter.',
|
||
[
|
||
'filter' => 'do_rocket_generate_caching_files',
|
||
]
|
||
);
|
||
return $buffer . $footprint;
|
||
}
|
||
|
||
$webp_enabled = preg_match( '@<!-- Rocket (has|no) webp -->@', $buffer, $webp_tag );
|
||
$has_webp = ! empty( $webp_tag ) ? 'has' === $webp_tag[1] : false;
|
||
$cache_filepath = $this->get_cache_path( [ 'webp' => $has_webp ] );
|
||
$cache_dir_path = dirname( $cache_filepath );
|
||
|
||
// Create cache folders.
|
||
rocket_mkdir_p( $cache_dir_path );
|
||
|
||
if ( $is_html ) {
|
||
$footprint = $this->get_rocket_footprint( time() );
|
||
}
|
||
|
||
// Webp request.
|
||
if ( $webp_enabled ) {
|
||
$buffer = str_replace( $webp_tag[0], '', $buffer );
|
||
|
||
if ( ! $has_webp ) {
|
||
// The buffer doesn’t contain webp files.
|
||
$cache_dir_path = rtrim( dirname( $cache_filepath ), '/\\' );
|
||
|
||
$this->maybe_create_nowebp_file( $cache_dir_path );
|
||
}
|
||
}
|
||
|
||
$this->write_cache_file( $cache_filepath, $buffer . $footprint );
|
||
$this->maybe_create_nginx_mobile_file( $cache_dir_path );
|
||
|
||
// Send headers with the last modified time of the cache file.
|
||
if ( file_exists( $cache_filepath ) ) {
|
||
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', filemtime( $cache_filepath ) ) . ' GMT' );
|
||
}
|
||
|
||
if ( $is_html ) {
|
||
$footprint = $this->get_rocket_footprint();
|
||
}
|
||
|
||
$this->log(
|
||
'Page cached.',
|
||
[
|
||
'path' => $cache_filepath,
|
||
],
|
||
'info'
|
||
);
|
||
|
||
return $buffer . $footprint;
|
||
}
|
||
|
||
/**
|
||
* Writes the cache file(s)
|
||
*
|
||
* @since 3.5
|
||
*
|
||
* @param string $cache_filepath Absolute path to the cache file.
|
||
* @param string $content Content to write in the cache file.
|
||
* @return void
|
||
*/
|
||
private function write_cache_file( $cache_filepath, $content ) {
|
||
$gzip_filepath = $cache_filepath . '_gzip';
|
||
$temp_filepath = $cache_filepath . '_temp';
|
||
$temp_gzip_filepath = $gzip_filepath . '_temp';
|
||
|
||
if ( rocket_direct_filesystem()->exists( $temp_filepath ) ) {
|
||
return;
|
||
}
|
||
|
||
// Save the cache file.
|
||
if ( ! rocket_put_content( $temp_filepath, $content ) ) {
|
||
return;
|
||
}
|
||
|
||
rocket_direct_filesystem()->move( $temp_filepath, $cache_filepath, true );
|
||
|
||
if ( function_exists( 'gzencode' ) ) {
|
||
/**
|
||
* Filters the Gzip compression level to use for the cache file
|
||
*
|
||
* @param int $compression_level Compression level between 0 and 9.
|
||
*/
|
||
$compression_level = apply_filters( 'rocket_gzencode_level_compression', 6 );
|
||
|
||
if ( ! rocket_put_content( $temp_gzip_filepath, gzencode( $content, $compression_level ) ) ) {
|
||
return;
|
||
}
|
||
|
||
rocket_direct_filesystem()->move( $temp_gzip_filepath, $gzip_filepath, true );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get the path to the cache file.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param array $args {
|
||
* A list of arguments.
|
||
*
|
||
* @type bool $webp Set to false to prevent adding the part related to webp.
|
||
* }
|
||
* @return string
|
||
*/
|
||
public function get_cache_path( $args = [] ) {
|
||
$args = array_merge(
|
||
[
|
||
'webp' => true,
|
||
],
|
||
$args
|
||
);
|
||
$cookies = $this->tests->get_cookies();
|
||
$request_uri_path = $this->get_request_cache_path( $cookies );
|
||
$filename = 'index';
|
||
|
||
$filename = $this->maybe_mobile_filename( $filename );
|
||
|
||
// Rename the caching filename for SSL URLs.
|
||
if ( is_ssl() && $this->config->get_config( 'cache_ssl' ) ) {
|
||
$filename .= '-https';
|
||
}
|
||
|
||
if ( $args['webp'] ) {
|
||
$filename = $this->maybe_webp_filename( $filename );
|
||
}
|
||
|
||
$filename = $this->maybe_dynamic_cookies_filename( $filename, $cookies );
|
||
|
||
// Ensure proper formatting of the path.
|
||
$request_uri_path = preg_replace_callback( '/%[0-9A-F]{2}/', [ $this, 'reset_lowercase' ], $request_uri_path );
|
||
// Directories in Windows can't contain question marks.
|
||
$request_uri_path = str_replace( '?', '#', $request_uri_path );
|
||
// Limit filename max length to 255 characters.
|
||
$request_uri_path .= '/' . substr( $filename, 0, 250 ) . '.html';
|
||
|
||
return $request_uri_path;
|
||
}
|
||
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/** VARIOUS TOOLS =========================================================================== */
|
||
/** ----------------------------------------------------------------------------------------- */
|
||
/**
|
||
* Declares and sets value of constant preventing Optimizations.
|
||
*
|
||
* @since 3.3
|
||
*/
|
||
private function define_donotoptimize_true() {
|
||
if ( ! defined( 'DONOTROCKETOPTIMIZE' ) ) {
|
||
define( 'DONOTROCKETOPTIMIZE', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Gets If-modified-since header value
|
||
*
|
||
* @since 3.3
|
||
* @return string
|
||
*/
|
||
private function get_if_modified_since() {
|
||
if ( function_exists( 'apache_request_headers' ) ) {
|
||
$headers = apache_request_headers();
|
||
|
||
return isset( $headers['If-Modified-Since'] ) ? $headers['If-Modified-Since'] : '';
|
||
}
|
||
|
||
return $this->config->get_server_input( 'HTTP_IF_MODIFIED_SINCE', '' );
|
||
}
|
||
|
||
/**
|
||
* Get WP Rocket footprint
|
||
*
|
||
* @since 3.0.5 White label footprint if WP_ROCKET_WHITE_LABEL_FOOTPRINT is defined.
|
||
* @since 2.0
|
||
*
|
||
* @param int $time UNIX timestamp when the cache file was saved.
|
||
* @return string The footprint that will be printed
|
||
*/
|
||
private function get_rocket_footprint( $time = '' ) {
|
||
$footprint = defined( 'WP_ROCKET_WHITE_LABEL_FOOTPRINT' ) ?
|
||
"\n" . '<!-- Cached for great performance' :
|
||
"\n" . '<!-- This website is like a Rocket, isn\'t it? Performance optimized by ' . WP_ROCKET_PLUGIN_NAME . '. Learn more: https://wp-rocket.me';
|
||
if ( ! empty( $time ) ) {
|
||
$footprint .= ' - Debug: cached@' . $time;
|
||
}
|
||
$footprint .= ' -->';
|
||
return $footprint;
|
||
}
|
||
|
||
/**
|
||
* Create a hidden empty file for mobile detection on NGINX with the Rocket NGINX configuration.
|
||
*
|
||
* @param string $cache_dir_path Path to the current cache directory.
|
||
* @return void
|
||
*/
|
||
private function maybe_create_nginx_mobile_file( $cache_dir_path ) {
|
||
global $is_nginx;
|
||
|
||
if ( ! $this->config->get_config( 'do_caching_mobile_files' ) ) {
|
||
return;
|
||
}
|
||
|
||
if ( ! $is_nginx ) {
|
||
return;
|
||
}
|
||
|
||
$nginx_mobile_detect = $cache_dir_path . '/.mobile-active';
|
||
|
||
if ( rocket_direct_filesystem()->exists( $nginx_mobile_detect ) ) {
|
||
return;
|
||
}
|
||
|
||
rocket_direct_filesystem()->touch( $nginx_mobile_detect );
|
||
}
|
||
|
||
/**
|
||
* Create a hidden empty file when webp is enabled but the buffer doesn’t contain webp files.
|
||
*
|
||
* @since 3.4
|
||
*
|
||
* @param string $cache_dir_path Path to the current cache directory (without trailing slah).
|
||
*/
|
||
private function maybe_create_nowebp_file( $cache_dir_path ) {
|
||
$nowebp_filepath = $cache_dir_path . DIRECTORY_SEPARATOR . '.no-webp';
|
||
|
||
if ( rocket_direct_filesystem()->exists( $nowebp_filepath ) ) {
|
||
return;
|
||
}
|
||
|
||
rocket_direct_filesystem()->touch( $nowebp_filepath );
|
||
}
|
||
|
||
/**
|
||
* Tell if generating cache files is allowed.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @return bool
|
||
*/
|
||
public static function can_generate_caching_files() {
|
||
/**
|
||
* Allow to the generate the caching file.
|
||
*
|
||
* @since 2.5
|
||
*
|
||
* @param bool True will force the cache file generation.
|
||
*/
|
||
return (bool) apply_filters( 'do_rocket_generate_caching_files', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
|
||
}
|
||
|
||
/**
|
||
* Gets the base cache path for the current request
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param array $cookies Cookies for the current request.
|
||
* @return string
|
||
*/
|
||
private function get_request_cache_path( $cookies ) {
|
||
$host = $this->config->get_host();
|
||
|
||
if ( $this->config->get_config( 'url_no_dots' ) ) {
|
||
$host = str_replace( '.', '_', $host );
|
||
}
|
||
|
||
$request_uri = $this->tests->get_clean_request_uri();
|
||
$cookie_hash = $this->config->get_config( 'cookie_hash' );
|
||
$logged_in_cookie = $this->config->get_config( 'logged_in_cookie' );
|
||
$logged_in_cookie_no_hash = str_replace( $cookie_hash, '', $logged_in_cookie );
|
||
|
||
// Get cache folder of host name.
|
||
if ( $logged_in_cookie && isset( $cookies[ $logged_in_cookie ] ) && ! $this->tests->has_rejected_cookie( $logged_in_cookie_no_hash ) ) {
|
||
if ( $this->config->get_config( 'common_cache_logged_users' ) ) {
|
||
return $this->cache_dir_path . $host . '-loggedin-' . $this->config->get_config( 'secret_cache_key' ) . rtrim( $request_uri, '/' );
|
||
}
|
||
|
||
$user_key = explode( '|', $cookies[ $logged_in_cookie ] );
|
||
$user_key = reset( $user_key );
|
||
$user_key = $this->sanitize_key( $user_key . '-' . $this->config->get_config( 'secret_cache_key' ) );
|
||
|
||
// Get cache folder of host name.
|
||
return $this->cache_dir_path . $host . '-' . $user_key . rtrim( $request_uri, '/' );
|
||
}
|
||
|
||
return $this->cache_dir_path . $host . rtrim( $request_uri, '/' );
|
||
}
|
||
|
||
/**
|
||
* Modifies the filename if the request is from a mobile device.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param string $filename Cache filename.
|
||
* @return string
|
||
*/
|
||
private function maybe_mobile_filename( $filename ) {
|
||
$cache_mobile_files_tablet = $this->config->get_config( 'cache_mobile_files_tablet' );
|
||
|
||
if ( ! ( $this->config->get_config( 'cache_mobile' ) && $this->config->get_config( 'do_caching_mobile_files' ) ) ) {
|
||
return $filename;
|
||
}
|
||
|
||
if ( ! $cache_mobile_files_tablet ) {
|
||
return $filename;
|
||
}
|
||
|
||
if ( ! class_exists( 'WP_Rocket_Mobile_Detect' ) ) {
|
||
return $filename;
|
||
}
|
||
|
||
$detect = new \WP_Rocket_Mobile_Detect();
|
||
|
||
if ( $detect->isMobile() && ! $detect->isTablet() && 'desktop' === $cache_mobile_files_tablet || ( $detect->isMobile() || $detect->isTablet() ) && 'mobile' === $cache_mobile_files_tablet ) {
|
||
return $filename .= '-mobile';
|
||
}
|
||
|
||
return $filename;
|
||
}
|
||
|
||
/**
|
||
* Modifies the filename if the request is WebP compatible
|
||
*
|
||
* @since 3.4
|
||
*
|
||
* @param string $filename Cache filename.
|
||
* @return string
|
||
*/
|
||
private function maybe_webp_filename( $filename ) {
|
||
if ( ! $this->config->get_config( 'cache_webp' ) ) {
|
||
return $filename;
|
||
}
|
||
|
||
/**
|
||
* Force WP Rocket to disable its webp cache.
|
||
*
|
||
* @since 3.4
|
||
*
|
||
* @param bool $disable_webp_cache Set to true to disable the webp cache.
|
||
*/
|
||
$disable_webp_cache = apply_filters( 'rocket_disable_webp_cache', false );
|
||
|
||
if ( $disable_webp_cache ) {
|
||
return $filename;
|
||
}
|
||
|
||
$http_accept = $this->config->get_server_input( 'HTTP_ACCEPT', '' );
|
||
|
||
if ( ! $http_accept && function_exists( 'apache_request_headers' ) ) {
|
||
$headers = apache_request_headers();
|
||
$http_accept = isset( $headers['Accept'] ) ? $headers['Accept'] : '';
|
||
}
|
||
|
||
if ( ! $http_accept || false === strpos( $http_accept, 'webp' ) ) {
|
||
if ( preg_match( '#Firefox/(?<version>[0-9]{2})#i', $this->config->get_server_input( 'HTTP_USER_AGENT' ), $matches ) ) {
|
||
if ( 66 <= (int) $matches['version'] ) {
|
||
return $filename . '-webp';
|
||
}
|
||
}
|
||
|
||
return $filename;
|
||
}
|
||
|
||
return $filename . '-webp';
|
||
}
|
||
|
||
/**
|
||
* Modifies the filename if dynamic cookies are set
|
||
*
|
||
* @param string $filename Cache filename.
|
||
* @param array $cookies Cookies for the request.
|
||
* @return string
|
||
*/
|
||
private function maybe_dynamic_cookies_filename( $filename, $cookies ) {
|
||
$cache_dynamic_cookies = $this->config->get_config( 'cache_dynamic_cookies' );
|
||
|
||
if ( ! $cache_dynamic_cookies ) {
|
||
return $filename;
|
||
}
|
||
|
||
foreach ( $cache_dynamic_cookies as $key => $cookie_name ) {
|
||
if ( is_array( $cookie_name ) ) {
|
||
if ( isset( $_COOKIE[ $key ] ) ) {
|
||
foreach ( $cookie_name as $cookie_key ) {
|
||
if ( '' !== $cookies[ $key ][ $cookie_key ] ) {
|
||
$cache_key = $cookies[ $key ][ $cookie_key ];
|
||
$cache_key = preg_replace( '/[^a-z0-9_\-]/i', '-', $cache_key );
|
||
$filename .= '-' . $cache_key;
|
||
}
|
||
}
|
||
}
|
||
continue;
|
||
}
|
||
|
||
if ( isset( $cookies[ $cookie_name ] ) && '' !== $cookies[ $cookie_name ] ) {
|
||
$cache_key = $cookies[ $cookie_name ];
|
||
$cache_key = preg_replace( '/[^a-z0-9_\-]/i', '-', $cache_key );
|
||
$filename .= '-' . $cache_key;
|
||
}
|
||
}
|
||
|
||
return $filename;
|
||
}
|
||
|
||
/**
|
||
* Force lowercase on encoded url strings from different alphabets to prevent issues on some hostings.
|
||
*
|
||
* @since 3.3
|
||
*
|
||
* @param array $matches Cache path.
|
||
* @return string Cache path in lowercase.
|
||
*/
|
||
protected function reset_lowercase( $matches ) {
|
||
return strtolower( $matches[0] );
|
||
}
|
||
|
||
/**
|
||
* Sanitizes a string key.
|
||
*
|
||
* @param string $key String key.
|
||
*
|
||
* @return string
|
||
*/
|
||
private function sanitize_key( string $key ): string {
|
||
$sanitized_key = '';
|
||
$sanitized_key = strtolower( $key );
|
||
|
||
return preg_replace( '/[^a-z0-9_\-]/', '', $sanitized_key );
|
||
}
|
||
}
|