<?php
defined('ABSPATH') || exit;
function flush_rocket_htaccess($remove_rules = false)
{
global $is_apache;
if (!$is_apache || apply_filters('rocket_disable_htaccess', false) && !$remove_rules) {
return false;
}
if (!function_exists('get_home_path')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$htaccess_file = get_home_path() . '.htaccess';
if (!rocket_direct_filesystem()->is_writable($htaccess_file)) {
return false;
}
$ftmp = rocket_direct_filesystem()->get_contents($htaccess_file);
if (false === $ftmp) {
return false;
}
$has_wp_rules = rocket_has_wp_htaccess_rules($ftmp);
$ftmp = preg_replace('/\\s*# BEGIN WP Rocket.*# END WP Rocket\\s*?/isU', PHP_EOL . PHP_EOL, $ftmp);
$ftmp = ltrim($ftmp);
if (!$remove_rules) {
$ftmp = get_rocket_htaccess_marker() . PHP_EOL . $ftmp;
}
if ($has_wp_rules && !rocket_has_wp_htaccess_rules($ftmp)) {
return false;
}
return rocket_put_content($htaccess_file, $ftmp);
}
function rocket_htaccess_rules_test($rules_name)
{
$request_args = apply_filters('rocket_htaccess_rules_test_args', ['redirection' => 0, 'timeout' => 5, 'sslverify' => apply_filters('https_local_ssl_verify', false), 'user-agent' => 'wprocketbot', 'cookies' => $_COOKIE]);
$response = wp_remote_get(site_url(WP_ROCKET_URL . 'tests/' . $rules_name . '/index.html'), $request_args);
if (is_wp_error($response)) {
return $response;
}
return 500 !== wp_remote_retrieve_response_code($response);
}
function get_rocket_htaccess_marker()
{
$marker = '# BEGIN WP Rocket v' . WP_ROCKET_VERSION . PHP_EOL;
$marker .= apply_filters('before_rocket_htaccess_rules', '');
$marker .= get_rocket_htaccess_charset();
$marker .= get_rocket_htaccess_etag();
$marker .= get_rocket_htaccess_web_fonts_access();
$marker .= get_rocket_htaccess_files_match();
$marker .= get_rocket_htaccess_mod_expires();
$marker .= get_rocket_htaccess_mod_deflate();
if (\WP_Rocket\Buffer\Cache::can_generate_caching_files() && !is_rocket_generate_caching_mobile_files()) {
$marker .= get_rocket_htaccess_mod_rewrite();
}
$marker .= apply_filters('after_rocket_htaccess_rules', '');
$marker .= '# END WP Rocket' . PHP_EOL;
$marker = apply_filters('rocket_htaccess_marker', $marker);
return $marker;
}
function get_rocket_htaccess_mod_rewrite()
{
if (is_multisite()) {
return;
}
if (defined('WPLANG') && 'ko_KR' === WPLANG || 'ko_KR' === get_locale()) {
return;
}
$home_root = rocket_extract_url_component(home_url(), PHP_URL_PATH);
$home_root = isset($home_root) ? trailingslashit($home_root) : '/';
$site_root = rocket_extract_url_component(site_url(), PHP_URL_PATH);
$site_root = isset($site_root) ? trailingslashit($site_root) : '';
if (strpos(WP_ROCKET_CACHE_PATH, ABSPATH) === false && isset($_SERVER['DOCUMENT_ROOT'])) {
$cache_root = '/' . ltrim(str_replace(sanitize_text_field(wp_unslash($_SERVER['DOCUMENT_ROOT'])), '', WP_ROCKET_CACHE_PATH), '/');
} else {
$cache_root = '/' . ltrim($site_root . str_replace(ABSPATH, '', WP_ROCKET_CACHE_PATH), '/');
}
$http_host = apply_filters('rocket_url_no_dots', false) ? rocket_remove_url_protocol(home_url()) : '%{HTTP_HOST}';
$is_1and1_or_force = apply_filters('rocket_force_full_path', strpos(sanitize_text_field(wp_unslash($_SERVER['DOCUMENT_ROOT'])), '/kunden/') === 0);
$rules = '';
$gzip_rules = '';
$enc = '';
if ($is_1and1_or_force) {
$cache_dir_path = str_replace('/kunden/', '/', WP_ROCKET_CACHE_PATH) . $http_host . '%{REQUEST_URI}';
} else {
$cache_dir_path = '%{DOCUMENT_ROOT}/' . ltrim($cache_root, '/') . $http_host . '%{REQUEST_URI}';
}
if (function_exists('gzencode') && apply_filters('rocket_force_gzip_htaccess_rules', true)) {
$rules = '<IfModule mod_mime.c>' . PHP_EOL;
$rules .= 'AddType text/html .html_gzip' . PHP_EOL;
$rules .= 'AddEncoding gzip .html_gzip' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '<IfModule mod_setenvif.c>' . PHP_EOL;
$rules .= 'SetEnvIfNoCase Request_URI \\.html_gzip$ no-gzip' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$gzip_rules .= 'RewriteCond %{HTTP:Accept-Encoding} gzip' . PHP_EOL;
$gzip_rules .= 'RewriteRule .* - [E=WPR_ENC:_gzip]' . PHP_EOL;
$enc = '%{ENV:WPR_ENC}';
}
$rules .= '<IfModule mod_rewrite.c>' . PHP_EOL;
$rules .= 'RewriteEngine On' . PHP_EOL;
$rules .= 'RewriteBase ' . $home_root . PHP_EOL;
$rules .= get_rocket_htaccess_ssl_rewritecond();
$rules .= rocket_get_webp_rewritecond($cache_dir_path);
$rules .= $gzip_rules;
$rules .= 'RewriteCond %{REQUEST_METHOD} GET' . PHP_EOL;
$rules .= 'RewriteCond %{QUERY_STRING} =""' . PHP_EOL;
$cookies = get_rocket_cache_reject_cookies();
if ($cookies) {
$rules .= 'RewriteCond %{HTTP:Cookie} !(' . $cookies . ') [NC]' . PHP_EOL;
}
$uri = get_rocket_cache_reject_uri();
if ($uri) {
$rules .= 'RewriteCond %{REQUEST_URI} !^(' . $uri . ')$ [NC]' . PHP_EOL;
}
$rules .= !is_rocket_cache_mobile() ? get_rocket_htaccess_mobile_rewritecond() : '';
$ua = get_rocket_cache_reject_ua();
if ($ua) {
$rules .= 'RewriteCond %{HTTP_USER_AGENT} !^(' . $ua . ').* [NC]' . PHP_EOL;
}
$rules .= 'RewriteCond "' . $cache_dir_path . '/index%{ENV:WPR_SSL}%{ENV:WPR_WEBP}.html' . $enc . '" -f' . PHP_EOL;
$rules .= 'RewriteRule .* "' . $cache_root . $http_host . '%{REQUEST_URI}/index%{ENV:WPR_SSL}%{ENV:WPR_WEBP}.html' . $enc . '" [L]' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules = apply_filters('rocket_htaccess_mod_rewrite', $rules);
return $rules;
}
function get_rocket_htaccess_mobile_rewritecond()
{
if (is_multisite()) {
return;
}
$rules = 'RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\\"]+ [NC]' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP:Profile} !^[a-z0-9\\"]+ [NC]' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP_USER_AGENT} !^.*(2.0\\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\\ Wii|Nitro|Nokia|Opera\\ Mini|Palm|PlayStation\\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\\ Obigo|LGE\\ VX|webOS|Nokia5800).* [NC]' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP_USER_AGENT} !^(w3c\\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\\ |xda-).* [NC]' . PHP_EOL;
$rules = apply_filters('rocket_htaccess_mobile_rewritecond', $rules);
return $rules;
}
function get_rocket_htaccess_ssl_rewritecond()
{
$rules = 'RewriteCond %{HTTPS} on [OR]' . PHP_EOL;
$rules .= 'RewriteCond %{SERVER_PORT} ^443$ [OR]' . PHP_EOL;
$rules .= 'RewriteCond %{HTTP:X-Forwarded-Proto} https' . PHP_EOL;
$rules .= 'RewriteRule .* - [E=WPR_SSL:-https]' . PHP_EOL;
$rules = apply_filters('rocket_htaccess_ssl_rewritecond', $rules);
return $rules;
}
function rocket_get_webp_rewritecond($cache_dir_path)
{
if (!get_rocket_option('cache_webp')) {
return '';
}
$rules = 'RewriteCond %{HTTP_ACCEPT} image/webp' . PHP_EOL;
$rules .= 'RewriteCond "' . $cache_dir_path . '/.no-webp" !-f' . PHP_EOL;
$rules .= 'RewriteRule .* - [E=WPR_WEBP:-webp]' . PHP_EOL;
return apply_filters('rocket_webp_rewritecond', $rules);
}
function get_rocket_htaccess_mod_deflate()
{
$rules = '# Gzip compression' . PHP_EOL;
$rules .= '<IfModule mod_deflate.c>' . PHP_EOL;
$rules .= '# Active compression' . PHP_EOL;
$rules .= 'SetOutputFilter DEFLATE' . PHP_EOL;
$rules .= '# Force deflate for mangled headers' . PHP_EOL;
$rules .= '<IfModule mod_setenvif.c>' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\\s*,?\\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding' . PHP_EOL;
$rules .= 'RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding' . PHP_EOL;
$rules .= '# Don’t compress images and other uncompressible content' . PHP_EOL;
$rules .= 'SetEnvIfNoCase Request_URI \\' . PHP_EOL;
$rules .= '\\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules .= '# Compress all output labeled with one of the following MIME-types' . PHP_EOL;
$rules .= '<IfModule mod_filter.c>' . PHP_EOL;
$rules .= 'AddOutputFilterByType DEFLATE application/atom+xml \\
application/javascript \\
application/json \\
application/rss+xml \\
application/vnd.ms-fontobject \\
application/x-font-ttf \\
application/xhtml+xml \\
application/xml \\
font/opentype \\
image/svg+xml \\
image/x-icon \\
text/css \\
text/html \\
text/plain \\
text/x-component \\
text/xml' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'Header append Vary: Accept-Encoding' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules = apply_filters('rocket_htaccess_mod_deflate', $rules);
return $rules;
}
function get_rocket_htaccess_mod_expires()
{
$rules = <<<HTACCESS
# Expires headers (for better cache control)
<IfModule mod_expires.c>
\tExpiresActive on
\tExpiresDefault "access plus 1 month"
\t# cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
\tExpiresByType text/cache-manifest "access plus 0 seconds"
\t# Your document html
\tExpiresByType text/html "access plus 0 seconds"
\t# Data
\tExpiresByType text/xml "access plus 0 seconds"
\tExpiresByType application/xml "access plus 0 seconds"
\tExpiresByType application/json "access plus 0 seconds"
\t# Feed
\tExpiresByType application/rss+xml "access plus 1 hour"
\tExpiresByType application/atom+xml "access plus 1 hour"
\t# Favicon (cannot be renamed)
\tExpiresByType image/x-icon "access plus 1 week"
\t# Media: images, video, audio
\tExpiresByType image/gif "access plus 4 months"
\tExpiresByType image/png "access plus 4 months"
\tExpiresByType image/jpeg "access plus 4 months"
\tExpiresByType image/webp "access plus 4 months"
\tExpiresByType video/ogg "access plus 4 months"
\tExpiresByType audio/ogg "access plus 4 months"
\tExpiresByType video/mp4 "access plus 4 months"
\tExpiresByType video/webm "access plus 4 months"
\t# HTC files (css3pie)
\tExpiresByType text/x-component "access plus 1 month"
\t# Webfonts
\tExpiresByType font/ttf "access plus 4 months"
\tExpiresByType font/otf "access plus 4 months"
\tExpiresByType font/woff "access plus 4 months"
\tExpiresByType font/woff2 "access plus 4 months"
\tExpiresByType image/svg+xml "access plus 1 month"
\tExpiresByType application/vnd.ms-fontobject "access plus 1 month"
\t# CSS and JavaScript
\tExpiresByType text/css "access plus 1 year"
\tExpiresByType application/javascript "access plus 1 year"
</IfModule>
HTACCESS;
$rules = apply_filters('rocket_htaccess_mod_expires', $rules);
return $rules;
}
function get_rocket_htaccess_charset()
{
$charset = preg_replace('/[^a-zA-Z0-9_\\-\\.:]+/', '', get_bloginfo('charset', 'display'));
$rules = "# Use {$charset} encoding for anything served text/plain or text/html" . PHP_EOL;
$rules .= "AddDefaultCharset {$charset}" . PHP_EOL;
$rules .= "# Force {$charset} for a number of file formats" . PHP_EOL;
$rules .= '<IfModule mod_mime.c>' . PHP_EOL;
$rules .= "AddCharset {$charset} .atom .css .js .json .rss .vtt .xml" . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules = apply_filters('rocket_htaccess_charset', $rules);
return $rules;
}
function get_rocket_htaccess_files_match()
{
$rules = '<IfModule mod_alias.c>' . PHP_EOL;
$rules .= '<FilesMatch "\\.(html|htm|rtf|rtx|txt|xsd|xsl|xml)$">' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'Header set X-Powered-By "WP Rocket/' . WP_ROCKET_VERSION . '"' . PHP_EOL;
$rules .= 'Header unset Pragma' . PHP_EOL;
$rules .= 'Header append Cache-Control "public"' . PHP_EOL;
$rules .= 'Header unset Last-Modified' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</FilesMatch>' . PHP_EOL . PHP_EOL;
$rules .= '<FilesMatch "\\.(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'Header unset Pragma' . PHP_EOL;
$rules .= 'Header append Cache-Control "public"' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</FilesMatch>' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules = apply_filters('rocket_htaccess_files_match', $rules);
return $rules;
}
function get_rocket_htaccess_etag()
{
$rules = '# FileETag None is not enough for every server.' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'Header unset ETag' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules .= '# Since we’re sending far-future expires, we don’t need ETags for static content.' . PHP_EOL;
$rules .= '# developer.yahoo.com/performance/rules.html#etags' . PHP_EOL;
$rules .= 'FileETag None' . PHP_EOL . PHP_EOL;
$rules = apply_filters('rocket_htaccess_etag', $rules);
return $rules;
}
function get_rocket_htaccess_web_fonts_access()
{
if (!get_rocket_option('cdn', false)) {
return;
}
$rules = '# Send CORS headers if browsers request them; enabled by default for images.' . PHP_EOL;
$rules .= '<IfModule mod_setenvif.c>' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= '# mod_headers, y u no match by Content-Type?!' . PHP_EOL;
$rules .= '<FilesMatch "\\.(cur|gif|png|jpe?g|svgz?|ico|webp)$">' . PHP_EOL;
$rules .= 'SetEnvIf Origin ":" IS_CORS' . PHP_EOL;
$rules .= 'Header set Access-Control-Allow-Origin "*" env=IS_CORS' . PHP_EOL;
$rules .= '</FilesMatch>' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL . PHP_EOL;
$rules .= '# Allow access to web fonts from all domains.' . PHP_EOL;
$rules .= '<FilesMatch "\\.(eot|otf|tt[cf]|woff2?)$">' . PHP_EOL;
$rules .= '<IfModule mod_headers.c>' . PHP_EOL;
$rules .= 'Header set Access-Control-Allow-Origin "*"' . PHP_EOL;
$rules .= '</IfModule>' . PHP_EOL;
$rules .= '</FilesMatch>' . PHP_EOL . PHP_EOL;
$rules = apply_filters('rocket_htaccess_web_fonts_access', $rules);
return $rules;
}
function rocket_has_wp_htaccess_rules($content)
{
if (is_multisite()) {
$has_wp_rules = strpos($content, '# add a trailing slash to /wp-admin') !== false;
} else {
$has_wp_rules = strpos($content, '# BEGIN WordPress') !== false;
}
return apply_filters('rocket_has_wp_htaccess_rules', $has_wp_rules, $content);
}
function rocket_check_htaccess_rules()
{
if (!function_exists('get_home_path')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$htaccess_file = get_home_path() . '.htaccess';
if (!rocket_direct_filesystem()->is_readable($htaccess_file)) {
return false;
}
$htaccess = rocket_direct_filesystem()->get_contents($htaccess_file);
if (preg_match('/\\s*# BEGIN WP Rocket.*# END WP Rocket\\s*?/isU', $htaccess)) {
return true;
}
return false;
}