wp_config_add_directive();
} catch (FilesystemOperationException $ex) {
$exs->push($ex);
}
}
$this->fix_folders($config, $exs);
if ($config->get_boolean('config.check') || $force_all_checks) {
if ($config->get_boolean('pgcache.enabled') &&
$config->get_string('pgcache.engine') == 'file_generic') {
$this->rules_core_add($config, $exs);
$this->rules_cache_add($config, $exs);
} else {
$this->rules_core_remove($exs);
$this->rules_cache_remove($exs);
}
}
// if no errors so far - check if rewrite actually works
if (count($exs->exceptions()) <= 0) {
try {
if ($config->get_boolean('pgcache.enabled') &&
$config->get_string('pgcache.engine') == 'file_generic') {
$this->verify_file_generic_compatibility();
if ($config->get_boolean('pgcache.debug'))
$this->verify_file_generic_rewrite_working();
}
} catch (Exception $ex) {
$exs->push($ex);
}
}
if (count($exs->exceptions()) > 0)
throw $exs;
}
/**
* Fixes environment once event occurs
*
* @param W3_Config $config
* @param string $event
* @param null|W3_Config $old_config
* @throws SelfTestExceptions
**/
public function fix_on_event($config, $event, $old_config = null) {
// Schedules events
if ($config->get_boolean('pgcache.enabled') &&
($config->get_string('pgcache.engine') == 'file' ||
$config->get_string('pgcache.engine') == 'file_generic')) {
if ($old_config != null &&
$config->get_integer('pgcache.file.gc') !=
$old_config->get_integer('pgcache.file.gc')) {
$this->unschedule_gc();
}
if (!wp_next_scheduled('w3_pgcache_cleanup')) {
wp_schedule_event(time(),
'w3_pgcache_cleanup', 'w3_pgcache_cleanup');
}
} else {
$this->unschedule_gc();
}
// Schedule prime event
if ($config->get_boolean('pgcache.enabled') &&
$config->get_boolean('pgcache.prime.enabled')) {
if ($old_config != null &&
$config->get_integer('pgcache.prime.interval') !=
$old_config->get_integer('pgcache.prime.interval')) {
$this->unschedule_prime();
}
if (!wp_next_scheduled('w3_pgcache_prime')) {
wp_schedule_event(time(),
'w3_pgcache_prime', 'w3_pgcache_prime');
}
} else {
$this->unschedule_prime();
}
}
/**
* Fixes environment after plugin deactivation
* @throws SelfTestExceptions
*/
public function fix_after_deactivation() {
$exs = new SelfTestExceptions();
try {
$this->wp_config_remove_directive($exs);
} catch (FilesystemOperationException $ex) {
$exs->push($ex);
}
$this->rules_core_remove($exs);
$this->rules_cache_remove($exs);
$this->unschedule_gc();
$this->unschedule_prime();
if (count($exs->exceptions()) > 0)
throw $exs;
}
/**
* Returns required rules for module
*
* @param W3_Config $config
* @return array
*/
public function get_required_rules($config) {
if (!$config->get_boolean('pgcache.enabled') ||
$config->get_string('pgcache.engine') != 'file_generic')
return null;
$rewrite_rules = array();
$pgcache_rules_core_path = w3_get_pgcache_rules_core_path();
$rewrite_rules[] = array(
'filename' => $pgcache_rules_core_path,
'content' => $this->rules_core_generate($config),
'last' => true
);
$pgcache_rules_cache_path = w3_get_pgcache_rules_cache_path();
$rewrite_rules[] = array(
'filename' => $pgcache_rules_cache_path,
'content' => $this->rules_cache_generate($config)
);
return $rewrite_rules;
}
/**
* Fixes folders
*
* @param W3_Config $config
* @param SelfTestExceptions $exs
*/
private function fix_folders($config, $exs) {
if (!$config->get_boolean('pgcache.enabled'))
return;
// folder that we delete if exists and not writeable
if ($config->get_string('pgcache.engine') == 'file_generic')
$dir = W3TC_CACHE_PAGE_ENHANCED_DIR;
else if ($config->get_string('pgcache.engine') != 'file')
$dir = W3TC_CACHE_DIR . '/page';
else
return;
try{
if (file_exists($dir) && !is_writeable($dir))
w3_wp_delete_folder($dir, '', $_SERVER['REQUEST_URI']);
} catch (FilesystemRmdirException $ex) {
$exs->push($ex);
}
}
/**
* Checks if mode can be used
**/
private function verify_file_generic_compatibility() {
$permalink_structure = get_option('permalink_structure');
if ($permalink_structure == '') {
throw new SelfTestFailedException('Disk Enchanced mode ' .
'can\'t work with "Default" permalinks structure');
}
}
/*
* Fixes environment for enabled pgcache
* @param $config
* @throws SelfTestExceptions
**/
private function verify_file_generic_rewrite_working() {
$url = w3_get_home_url() . '/w3tc_rewrite_test';
if (!$this->test_rewrite($url)) {
$key = sprintf('w3tc_rewrite_test_result_%s', substr(md5($url), 0, 16));
$result = get_transient($key);
$home_url = w3_get_home_url();
$tech_message =
(w3_is_nginx() ? 'nginx configuration file' : '.htaccess file') .
' contains rules to rewrite url ' .
$home_url . '/w3tc_rewrite_test into ' .
$home_url . '/?w3tc_rewrite_test which, if handled by ' .
'plugin, return "OK" message.
';
$tech_message .= 'The plugin made a request to ' .
$home_url . '/w3tc_rewrite_test but received:
' .
$result . '
';
$tech_message .= 'instead of "OK" response.
';
$error = 'W3 Total Cache error: ' .
'It appears Page Cache ' .
'URL ' .
'rewriting is not working. ';
if (w3_is_preview_mode()) {
$error .= ' This could be due to using Preview mode. Click here to manually verify its working. It should say OK.
';
}
if (w3_is_nginx()) {
$error .= 'Please verify that all configuration files are ' .
'included in the configuration file ' .
'(and that you have reloaded / restarted nginx).';
} else {
$error .= 'Please verify that the server configuration ' .
'allows .htaccess';
}
$error .= '
Unfortunately disk enhanced page caching will ' .
'not function without custom rewrite rules. ' .
'Please ask your server administrator for assistance. ' .
'Also refer to the install page for the rules for your server.';
throw new SelfTestFailedException($error, $tech_message);
}
}
/**
* Perform rewrite test
*
* @param string $url
* @return boolean
*/
private function test_rewrite($url) {
$key = sprintf('w3tc_rewrite_test_%s', substr(md5($url), 0, 16));
$result = get_transient($key);
if ($result === false) {
w3_require_once(W3TC_INC_FUNCTIONS_DIR . '/http.php');
$response = w3_http_get($url);
$result = (!is_wp_error($response) && $response['response']['code'] == 200 && trim($response['body']) == 'OK');
if ($result) {
set_transient($key, $result, 30);
} else {
$key_result = sprintf('w3tc_rewrite_test_result_%s', substr(md5($url), 0, 16));
set_transient($key_result, is_wp_error($response)? $response->get_error_message(): implode(' ', $response['response']), 30);
}
}
return $result;
}
/**
* scheduling stuff
**/
private function unschedule_gc() {
if (wp_next_scheduled('w3_pgcache_cleanup'))
wp_clear_scheduled_hook('w3_pgcache_cleanup');
}
private function unschedule_prime() {
if (wp_next_scheduled('w3_pgcache_prime'))
wp_clear_scheduled_hook('w3_pgcache_prime');
}
/**
* wp-config modification
**/
/**
* Enables WP_CACHE
*
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function wp_config_add_directive() {
$config_path = w3_get_wp_config_path();
$config_data = @file_get_contents($config_path);
if ($config_data === false)
return;
$new_config_data = $this->wp_config_remove_from_content($config_data);
$new_config_data = preg_replace(
'~<\?(php)?~',
"\\0\r\n" . $this->wp_config_addon(),
$new_config_data,
1);
if ($new_config_data != $config_data) {
try {
w3_wp_write_to_file($config_path, $new_config_data);
} catch (FilesystemOperationException $ex) {
throw new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
'Edit file ' . $config_path .
' and add next lines:', $config_path,
$this->wp_config_addon());
}
}
}
/**
* Disables WP_CACHE
*
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function wp_config_remove_directive() {
$config_path = w3_get_wp_config_path();
$config_data = @file_get_contents($config_path);
if ($config_data === false)
return;
$new_config_data = $this->wp_config_remove_from_content($config_data);
if ($new_config_data != $config_data) {
try {
w3_wp_write_to_file($config_path, $new_config_data);
} catch (FilesystemOperationException $ex) {
throw new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
'Edit file ' . $config_path .
' and remove next lines:',
$config_path, $this->wp_config_addon());
}
}
}
/**
* @return string Addon required for plugin in wp-config
**/
private function wp_config_addon() {
return "/** Enable W3 Total Cache */\r\n" .
"define('WP_CACHE', true); // Added by W3 Total Cache\r\n";
}
/**
* Disables WP_CACHE
*
* @param string $config_data wp-config.php content
* @return string
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function wp_config_remove_from_content($config_data) {
$config_data = preg_replace(
"~\\/\\*\\* Enable W3 Total Cache \\*\\*?\\/.*?\\/\\/ Added by W3 Total Cache(\r\n)*~s",
'', $config_data);
$config_data = preg_replace(
"~(\\/\\/\\s*)?define\\s*\\(\\s*['\"]?WP_CACHE['\"]?\\s*,.*?\\)\\s*;+\\r?\\n?~is",
'', $config_data);
return $config_data;
}
/**
* rules core modification
**/
/**
* Writes directives to WP .htaccess
*
* @param W3_Config $config
* @param SelfTestExceptions $exs
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function rules_core_add($config, $exs) {
$path = w3_get_pgcache_rules_core_path();
if ($path === false)
return;
$original_data = @file_get_contents($path);
if ($original_data === false)
$original_data = '';
$data = $original_data;
if ($has_legacy = w3_has_rules($data, W3TC_MARKER_BEGIN_PGCACHE_LEGACY, W3TC_MARKER_END_PGCACHE_LEGACY))
$data = w3_erase_rules($data, W3TC_MARKER_BEGIN_PGCACHE_LEGACY, W3TC_MARKER_END_PGCACHE_LEGACY);
if ($has_wpsc = w3_has_rules($data, W3TC_MARKER_BEGIN_PGCACHE_WPSC, W3TC_MARKER_END_PGCACHE_WPSC))
$data = w3_erase_rules($data, W3TC_MARKER_BEGIN_PGCACHE_WPSC, W3TC_MARKER_END_PGCACHE_WPSC);
$rules = $this->rules_core_generate($config);
$rules_missing = (strstr(w3_clean_rules($data), w3_clean_rules($rules)) === false);
if (!$has_legacy && !$has_wpsc && !$rules_missing)
return; // modification of file not required
$replace_start = strpos($data, W3TC_MARKER_BEGIN_PGCACHE_CORE);
$replace_end = strpos($data, W3TC_MARKER_END_PGCACHE_CORE);
if ($replace_start !== false && $replace_end !== false && $replace_start < $replace_end) {
$replace_length = $replace_end - $replace_start +
strlen(W3TC_MARKER_END_PGCACHE_CORE) + 1;
} else {
$replace_start = false;
$replace_length = 0;
$search = array(
W3TC_MARKER_BEGIN_BROWSERCACHE_NO404WP => 0,
W3TC_MARKER_BEGIN_WORDPRESS => 0,
W3TC_MARKER_END_MINIFY_CORE =>
strlen(W3TC_MARKER_END_MINIFY_CORE) + 1,
W3TC_MARKER_END_BROWSERCACHE_CACHE =>
strlen(W3TC_MARKER_END_BROWSERCACHE_CACHE) + 1,
W3TC_MARKER_END_PGCACHE_CACHE =>
strlen(W3TC_MARKER_END_PGCACHE_CACHE) + 1,
W3TC_MARKER_END_MINIFY_CACHE =>
strlen(W3TC_MARKER_END_MINIFY_CACHE) + 1
);
foreach ($search as $string => $length) {
$replace_start = strpos($data, $string);
if ($replace_start !== false) {
$replace_start += $length;
break;
}
}
}
if ($replace_start !== false) {
$data = w3_trim_rules(substr_replace($data, $rules,
$replace_start, $replace_length));
} else {
$data = w3_trim_rules($data . $rules);
}
try {
w3_wp_write_to_file($path, $data);
} catch (FilesystemOperationException $ex) {
if ($has_legacy)
$exs->push(new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
sprintf(__('Edit file %s and remove all lines between and including
%s and %s markers.', 'w3-total-cache')
, $path
, W3TC_MARKER_BEGIN_PGCACHE_LEGACY
, W3TC_MARKER_END_PGCACHE_LEGACY
), $path));
if ($has_wpsc)
$exs->push(new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
sprintf(__('Edit file %s and remove all lines between and including
%s and %s markers.', 'w3-total-cache')
, $path
, W3TC_MARKER_BEGIN_PGCACHE_WPSC
, W3TC_MARKER_END_PGCACHE_WPSC
), $path));
if ($rules_missing) {
if ($replace_start !== false)
$exs->push(new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
sprintf(__('Edit file %s and replace all lines between and including
%s and %s markers with:','w3-total-cache')
, $path
, W3TC_MARKER_BEGIN_PGCACHE_CORE
, W3TC_MARKER_END_PGCACHE_CORE
), $path, $rules));
else
$exs->push(new FilesystemModifyException(
$ex->getMessage(), $ex->credentials_form(),
sprintf(__('Edit file %s and add the following rules above the WordPress
directives:')
, $path
), $path, $rules));
}
}
}
/**
* Removes Page Cache core directives
*
* @param SelfTestExceptions $exs
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function rules_core_remove($exs) {
w3_remove_rules($exs, w3_get_pgcache_rules_core_path(),
W3TC_MARKER_BEGIN_PGCACHE_CORE,
W3TC_MARKER_END_PGCACHE_CORE
);
}
/**
* Generates rules for WP dir
*
* @param W3_Config $config
* @return string
*/
private function rules_core_generate($config) {
switch (true) {
case w3_is_apache():
case w3_is_litespeed():
return $this->rules_core_generate_apache($config);
case w3_is_nginx():
return $this->rules_core_generate_nginx($config);
}
return '';
}
/**
* Generates rules for WP dir
*
* @param W3_Config $config
* @return string
*/
private function rules_core_generate_apache($config) {
$is_network = w3_is_network();
$base_path = w3_get_base_path();
$home_path = w3_get_home_path();
$rewrite_base = ($is_network ? $base_path : $home_path);
$cache_dir = w3_path(W3TC_CACHE_PAGE_ENHANCED_DIR);
$permalink_structure = get_option('permalink_structure');
$current_user = get_currentuserinfo();
/**
* Auto reject cookies
*/
$reject_cookies = array(
'comment_author',
'wp-postpass'
);
if ($config->get_string('pgcache.engine') == 'file_generic') {
$reject_cookies[] = 'w3tc_logged_out';
}
/**
* Reject cache for logged in users
* OR
* Reject cache for roles if any
*/
if ($config->get_boolean('pgcache.reject.logged')) {
$reject_cookies = array_merge($reject_cookies, array(
'wordpress_logged_in'
));
} elseif($config->get_boolean('pgcache.reject.logged_roles')) {
$new_cookies = array();
foreach( $config->get_array('pgcache.reject.roles') as $role ) {
$new_cookies[] = 'w3tc_logged_' . md5(NONCE_KEY . $role);
}
$reject_cookies = array_merge($reject_cookies, $new_cookies);
}
/**
* Custom config
*/
$reject_cookies = array_merge($reject_cookies, $config->get_array('pgcache.reject.cookie'));
w3_array_trim($reject_cookies);
$reject_user_agents = $config->get_array('pgcache.reject.ua');
if ($config->get_boolean('pgcache.compatibility')) {
$reject_user_agents = array_merge(array(W3TC_POWERED_BY), $reject_user_agents);
}
w3_array_trim($reject_user_agents);
/**
* Generate directives
*/
$env_W3TC_UA = '';
$env_W3TC_REF = '';
$env_W3TC_SSL = '';
$env_W3TC_ENC = '';
$rules = '';
$rules .= W3TC_MARKER_BEGIN_PGCACHE_CORE . "\n";
$rules .= "\n";
$rules .= " RewriteEngine On\n";
$rules .= " RewriteBase " . $rewrite_base . "\n";
if ($config->get_boolean('pgcache.debug')) {
$rules .= " RewriteRule ^(.*\\/)?w3tc_rewrite_test/?$ $1?w3tc_rewrite_test=1 [L]\n";
}
/**
* Check for mobile redirect
*/
if ($config->get_boolean('mobile.enabled')) {
$mobile_groups = $config->get_array('mobile.rgroups');
foreach ($mobile_groups as $mobile_group => $mobile_config) {
$mobile_enabled = (isset($mobile_config['enabled']) ? (boolean) $mobile_config['enabled'] : false);
$mobile_agents = (isset($mobile_config['agents']) ? (array) $mobile_config['agents'] : '');
$mobile_redirect = (isset($mobile_config['redirect']) ? $mobile_config['redirect'] : '');
if ($mobile_enabled && count($mobile_agents) && $mobile_redirect) {
$rules .= " RewriteCond %{HTTP_USER_AGENT} (" . implode('|', $mobile_agents) . ") [NC]\n";
$rules .= " RewriteRule .* " . $mobile_redirect . " [R,L]\n";
}
}
}
/**
* Check for referrer redirect
*/
if ($config->get_boolean('referrer.enabled')) {
$referrer_groups = $config->get_array('referrer.rgroups');
foreach ($referrer_groups as $referrer_group => $referrer_config) {
$referrer_enabled = (isset($referrer_config['enabled']) ? (boolean) $referrer_config['enabled'] : false);
$referrer_referrers = (isset($referrer_config['referrers']) ? (array) $referrer_config['referrers'] : '');
$referrer_redirect = (isset($referrer_config['redirect']) ? $referrer_config['redirect'] : '');
if ($referrer_enabled && count($referrer_referrers) && $referrer_redirect) {
$rules .= " RewriteCond %{HTTP_COOKIE} w3tc_referrer=.*(" . implode('|', $referrer_referrers) . ") [NC]\n";
$rules .= " RewriteRule .* " . $referrer_redirect . " [R,L]\n";
}
}
}
/**
* Set mobile groups
*/
if ($config->get_boolean('mobile.enabled')) {
$mobile_groups = array_reverse($config->get_array('mobile.rgroups'));
foreach ($mobile_groups as $mobile_group => $mobile_config) {
$mobile_enabled = (isset($mobile_config['enabled']) ? (boolean) $mobile_config['enabled'] : false);
$mobile_agents = (isset($mobile_config['agents']) ? (array) $mobile_config['agents'] : '');
$mobile_redirect = (isset($mobile_config['redirect']) ? $mobile_config['redirect'] : '');
if ($mobile_enabled && count($mobile_agents) && !$mobile_redirect) {
$rules .= " RewriteCond %{HTTP_USER_AGENT} (" . implode('|', $mobile_agents) . ") [NC]\n";
$rules .= " RewriteRule .* - [E=W3TC_UA:_" . $mobile_group . "]\n";
$env_W3TC_UA = '%{ENV:W3TC_UA}';
}
}
}
/**
* Set referrer groups
*/
if ($config->get_boolean('referrer.enabled')) {
$referrer_groups = array_reverse($config->get_array('referrer.rgroups'));
foreach ($referrer_groups as $referrer_group => $referrer_config) {
$referrer_enabled = (isset($referrer_config['enabled']) ? (boolean) $referrer_config['enabled'] : false);
$referrer_referrers = (isset($referrer_config['referrers']) ? (array) $referrer_config['referrers'] : '');
$referrer_redirect = (isset($referrer_config['redirect']) ? $referrer_config['redirect'] : '');
if ($referrer_enabled && count($referrer_referrers) && !$referrer_redirect) {
$rules .= " RewriteCond %{HTTP_COOKIE} w3tc_referrer=.*(" . implode('|', $referrer_referrers) . ") [NC]\n";
$rules .= " RewriteRule .* - [E=W3TC_REF:_" . $referrer_group . "]\n";
$env_W3TC_REF = '%{ENV:W3TC_REF}';
}
}
}
/**
* Set HTTPS
*/
if ($config->get_boolean('pgcache.cache.ssl')) {
$rules .= " RewriteCond %{HTTPS} =on\n";
$rules .= " RewriteRule .* - [E=W3TC_SSL:_ssl]\n";
$rules .= " RewriteCond %{SERVER_PORT} =443\n";
$rules .= " RewriteRule .* - [E=W3TC_SSL:_ssl]\n";
$env_W3TC_SSL = '%{ENV:W3TC_SSL}';
}
$cache_path = str_replace(w3_get_document_root(), '', $cache_dir);
/**
* Set Accept-Encoding
*/
if ($config->get_boolean('browsercache.enabled') && $config->get_boolean('browsercache.html.compression')) {
$rules .= " RewriteCond %{HTTP:Accept-Encoding} gzip\n";
$rules .= " RewriteRule .* - [E=W3TC_ENC:_gzip]\n";
$env_W3TC_ENC = '%{ENV:W3TC_ENC}';
}
$rules .= " RewriteCond %{HTTP_COOKIE} w3tc_preview [NC]\n";
$rules .= " RewriteRule .* - [E=W3TC_PREVIEW:_preview]\n";
$env_W3TC_PREVIEW = '%{ENV:W3TC_PREVIEW}';
$use_cache_rules = '';
/**
* Don't accept POSTs
*/
$use_cache_rules .= " RewriteCond %{REQUEST_METHOD} !=POST\n";
/**
* Query string should be empty
*/
$use_cache_rules .= " RewriteCond %{QUERY_STRING} =\"\"\n";
/**
* Check permalink structure trailing slash
*/
if (substr($permalink_structure, -1) == '/') {
$use_cache_rules .= " RewriteCond %{REQUEST_URI} \\/$\n";
}
/**
* Check for rejected cookies
*/
$use_cache_rules .= " RewriteCond %{HTTP_COOKIE} !(" . implode('|', array_map('w3_preg_quote', $reject_cookies)) . ") [NC]\n";
/**
* Check for rejected user agents
*/
if (count($reject_user_agents)) {
$use_cache_rules .= " RewriteCond %{HTTP_USER_AGENT} !(" . implode('|', array_map('w3_preg_quote', $reject_user_agents)) . ") [NC]\n";
}
/**
* Make final rewrites for specific files
*/
$uri_prefix = $cache_path . '/%{HTTP_HOST}/%{REQUEST_URI}/' .
'_index' . $env_W3TC_UA . $env_W3TC_REF . $env_W3TC_SSL . $env_W3TC_PREVIEW;
$switch = " -" . ($config->get_boolean('pgcache.file.nfs') ? 'F' : 'f');
// support for GoDaddy servers configuration which uses
// SUBDOMAIN_DOCUMENT_ROOT variable
if (isset($_SERVER['SUBDOMAIN_DOCUMENT_ROOT']) &&
$_SERVER['SUBDOMAIN_DOCUMENT_ROOT'] != $_SERVER['DOCUMENT_ROOT'])
$document_root = '%{ENV:SUBDOMAIN_DOCUMENT_ROOT}';
elseif (isset($_SERVER['PHP_DOCUMENT_ROOT']) &&
$_SERVER['PHP_DOCUMENT_ROOT'] != $_SERVER['DOCUMENT_ROOT'])
$document_root = '%{ENV:PHP_DOCUMENT_ROOT}';
else
$document_root = '%{DOCUMENT_ROOT}';
// write rule to rewrite to .html file
$ext = '.html';
$rules .= $use_cache_rules;
$rules .= " RewriteCond \"" . $document_root . $uri_prefix . $ext .
$env_W3TC_ENC . "\"" . $switch . "\n";
$rules .= " RewriteRule .* \"" . $uri_prefix . $ext .
$env_W3TC_ENC . "\" [L]\n";
$rules .= "\n";
$rules .= W3TC_MARKER_END_PGCACHE_CORE . "\n";
return $rules;
}
/**
* Generates rules for WP dir
*
* @param W3_Config $config
* @return string
*/
private function rules_core_generate_nginx($config) {
$is_network = w3_is_network();
$base_path = w3_get_base_path();
$cache_dir = w3_path(W3TC_CACHE_PAGE_ENHANCED_DIR);
$permalink_structure = get_option('permalink_structure');
/**
* Auto reject cookies
*/
$reject_cookies = array(
'comment_author',
'wp-postpass'
);
if ($config->get_string('pgcache.engine') == 'file_generic') {
$reject_cookies[] = 'w3tc_logged_out';
}
/**
* Reject cache for logged in users
* OR
* Reject cache for roles if any
*/
if ($config->get_boolean('pgcache.reject.logged')) {
$reject_cookies = array_merge($reject_cookies, array(
'wordpress_logged_in'
));
} elseif ($config->get_boolean('pgcache.reject.logged_roles')) {
$new_cookies = array();
foreach( $config->get_array('pgcache.reject.roles') as $role ) {
$new_cookies[] = 'w3tc_logged_' . md5(NONCE_KEY . $role);
}
$reject_cookies = array_merge($reject_cookies, $new_cookies);
}
/**
* Custom config
*/
$reject_cookies = array_merge($reject_cookies, $config->get_array('pgcache.reject.cookie'));
w3_array_trim($reject_cookies);
$reject_user_agents = $config->get_array('pgcache.reject.ua');
if ($config->get_boolean('pgcache.compatibility')) {
$reject_user_agents = array_merge(array(W3TC_POWERED_BY), $reject_user_agents);
}
w3_array_trim($reject_user_agents);
/**
* Generate rules
*/
$env_w3tc_ua = '';
$env_w3tc_ref = '';
$env_w3tc_ssl = '';
$env_w3tc_ext = '';
$env_w3tc_enc = '';
$rules = '';
$rules .= W3TC_MARKER_BEGIN_PGCACHE_CORE . "\n";
if ($config->get_boolean('pgcache.debug')) {
$rules .= "rewrite ^(.*\\/)?w3tc_rewrite_test/?$ $1?w3tc_rewrite_test=1 last;\n";
}
/**
* Check for mobile redirect
*/
if ($config->get_boolean('mobile.enabled')) {
$mobile_groups = $config->get_array('mobile.rgroups');
foreach ($mobile_groups as $mobile_group => $mobile_config) {
$mobile_enabled = (isset($mobile_config['enabled']) ? (boolean) $mobile_config['enabled'] : false);
$mobile_agents = (isset($mobile_config['agents']) ? (array) $mobile_config['agents'] : '');
$mobile_redirect = (isset($mobile_config['redirect']) ? $mobile_config['redirect'] : '');
if ($mobile_enabled && count($mobile_agents) && $mobile_redirect) {
$rules .= "if (\$http_user_agent ~* \"(" . implode('|', $mobile_agents) . ")\") {\n";
$rules .= " rewrite .* " . $mobile_redirect . " last;\n";
$rules .= "}\n";
}
}
}
/**
* Check for referrer redirect
*/
if ($config->get_boolean('referrer.enabled')) {
$referrer_groups = $config->get_array('referrer.rgroups');
foreach ($referrer_groups as $referrer_group => $referrer_config) {
$referrer_enabled = (isset($referrer_config['enabled']) ? (boolean) $referrer_config['enabled'] : false);
$referrer_referrers = (isset($referrer_config['referrers']) ? (array) $referrer_config['referrers'] : '');
$referrer_redirect = (isset($referrer_config['redirect']) ? $referrer_config['redirect'] : '');
if ($referrer_enabled && count($referrer_referrers) && $referrer_redirect) {
$rules .= "if (\$http_cookie ~* \"w3tc_referrer=.*(" . implode('|', $referrer_referrers) . ")\") {\n";
$rules .= " rewrite .* " . $referrer_redirect . " last;\n";
$rules .= "}\n";
}
}
}
/**
* Don't accept POSTs
*/
$rules .= "set \$w3tc_rewrite 1;\n";
$rules .= "if (\$request_method = POST) {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
/**
* Query string should be empty
*/
$rules .= "if (\$query_string != \"\") {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
/**
* Check permalink structure trailing slash
*/
if (substr($permalink_structure, -1) == '/') {
$rules .= "if (\$request_uri !~ \\/$) {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
}
/**
* Check for rejected cookies
*/
$rules .= "if (\$http_cookie ~* \"(" . implode('|', array_map('w3_preg_quote', $reject_cookies)) . ")\") {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
/**
* Check for rejected user agents
*/
if (count($reject_user_agents)) {
$rules .= "if (\$http_user_agent ~* \"(" . implode('|', array_map('w3_preg_quote', $reject_user_agents)) . ")\") {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
}
/**
* Check mobile groups
*/
if ($config->get_boolean('mobile.enabled')) {
$mobile_groups = array_reverse($config->get_array('mobile.rgroups'));
$set_ua_var = true;
foreach ($mobile_groups as $mobile_group => $mobile_config) {
$mobile_enabled = (isset($mobile_config['enabled']) ? (boolean) $mobile_config['enabled'] : false);
$mobile_agents = (isset($mobile_config['agents']) ? (array) $mobile_config['agents'] : '');
$mobile_redirect = (isset($mobile_config['redirect']) ? $mobile_config['redirect'] : '');
if ($mobile_enabled && count($mobile_agents) && !$mobile_redirect) {
if ($set_ua_var) {
$rules .= "set \$w3tc_ua \"\";\n";
$set_ua_var = false;
}
$rules .= "if (\$http_user_agent ~* \"(" . implode('|', $mobile_agents) . ")\") {\n";
$rules .= " set \$w3tc_ua _" . $mobile_group . ";\n";
$rules .= "}\n";
$env_w3tc_ua = "\$w3tc_ua";
}
}
}
/**
* Check for preview cookie
*/
$rules .= "if (\$http_cookie ~* \"(w3tc_preview)\") {\n";
$rules .= " set \$w3tc_rewrite _preview;\n";
$rules .= "}\n";
$env_w3tc_preview = "\$w3tc_rewrite";
/**
* Check referrer groups
*/
if ($config->get_boolean('referrer.enabled')) {
$referrer_groups = array_reverse($config->get_array('referrer.rgroups'));
$set_ref_var = true;
foreach ($referrer_groups as $referrer_group => $referrer_config) {
$referrer_enabled = (isset($referrer_config['enabled']) ? (boolean) $referrer_config['enabled'] : false);
$referrer_referrers = (isset($referrer_config['referrers']) ? (array) $referrer_config['referrers'] : '');
$referrer_redirect = (isset($referrer_config['redirect']) ? $referrer_config['redirect'] : '');
if ($referrer_enabled && count($referrer_referrers) && !$referrer_redirect) {
if ($set_ref_var) {
$rules .= "set \$w3tc_ref \"\";\n";
$set_ref_var = false;
}
$rules .= "if (\$http_cookie ~* \"w3tc_referrer=.*(" . implode('|', $referrer_referrers) . ")\") {\n";
$rules .= " set \$w3tc_ref _" . $referrer_group . ";\n";
$rules .= "}\n";
$env_w3tc_ref = "\$w3tc_ref";
}
}
}
if ($config->get_boolean('pgcache.cache.ssl')) {
$rules .= "set \$w3tc_ssl \"\";\n";
$rules .= "if (\$scheme = https) {\n";
$rules .= " set \$w3tc_ssl _ssl;\n";
$rules .= "}\n";
$env_w3tc_ssl = "\$w3tc_ssl";
}
if ($config->get_boolean('browsercache.enabled') && $config->get_boolean('browsercache.html.compression')) {
$rules .= "set \$w3tc_enc \"\";\n";
$rules .= "if (\$http_accept_encoding ~ gzip) {\n";
$rules .= " set \$w3tc_enc _gzip;\n";
$rules .= "}\n";
$env_w3tc_enc = "\$w3tc_enc";
}
$cache_path = str_replace(w3_get_document_root(), '', $cache_dir);
$uri_prefix = $cache_path . "/\$http_host/" .
"\$request_uri/_index" . $env_w3tc_ua . $env_w3tc_ref . $env_w3tc_ssl . $env_w3tc_preview;
if (!$config->get_boolean('pgcache.cache.nginx_handle_xml')) {
$env_w3tc_ext = '.html';
$rules .= "if (!-f \"\$document_root" . $uri_prefix . ".html" .
$env_w3tc_enc . "\") {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
} else {
$env_w3tc_ext = "\$w3tc_ext";
$rules .= "set \$w3tc_ext \"\";\n";
$rules .= "if (-f \"\$document_root" . $uri_prefix . ".html" .
$env_w3tc_enc . "\") {\n";
$rules .= " set \$w3tc_ext .html;\n";
$rules .= "}\n";
$rules .= "if (-f \"\$document_root" . $uri_prefix . ".xml" .
$env_w3tc_enc . "\") {\n";
$rules .= " set \$w3tc_ext .xml;\n";
$rules .= "}\n";
$rules .= "if (\$w3tc_ext = \"\") {\n";
$rules .= " set \$w3tc_rewrite 0;\n";
$rules .= "}\n";
}
$rules .= "if (\$w3tc_rewrite = 1) {\n";
$rules .= " rewrite .* \"" . $uri_prefix . $env_w3tc_ext . $env_w3tc_enc . "\" last;\n";
$rules .= "}\n";
$rules .= W3TC_MARKER_END_PGCACHE_CORE . "\n";
return $rules;
}
/**
* cache rules
**/
/**
* Writes directives to file cache .htaccess
* Throws exception on error
* @param W3_Config $config
* @param SelfTestExceptions $exs
*/
private function rules_cache_add($config, $exs) {
w3_add_rules($exs,
w3_get_pgcache_rules_cache_path(),
$this->rules_cache_generate($config),
W3TC_MARKER_BEGIN_PGCACHE_CACHE,
W3TC_MARKER_END_PGCACHE_CACHE,
array(
W3TC_MARKER_BEGIN_BROWSERCACHE_CACHE => 0,
W3TC_MARKER_BEGIN_MINIFY_CORE => 0,
W3TC_MARKER_BEGIN_PGCACHE_CORE => 0,
W3TC_MARKER_BEGIN_BROWSERCACHE_NO404WP => 0,
W3TC_MARKER_BEGIN_WORDPRESS => 0,
W3TC_MARKER_END_MINIFY_CACHE => strlen(W3TC_MARKER_END_MINIFY_CACHE) + 1
)
);
}
/**
* Removes Page Cache cache directives
*
* @param SelfTestExceptions $exs
* @throws FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
* @throws FileOperationException
*/
private function rules_cache_remove($exs) {
// apache's cache files are not used when core rules disabled
if (!w3_is_nginx())
return;
w3_remove_rules($exs,
w3_get_pgcache_rules_cache_path(),
W3TC_MARKER_BEGIN_PGCACHE_CACHE,
W3TC_MARKER_END_PGCACHE_CACHE);
}
/**
* Generates directives for file cache dir
*
* @param W3_Config $config
* @return string
*/
public function rules_cache_generate($config) {
switch (true) {
case w3_is_apache():
case w3_is_litespeed():
return $this->rules_cache_generate_apache($config);
case w3_is_nginx():
return $this->rules_cache_generate_nginx($config);
}
return '';
}
/**
* Generates directives for file cache dir
*
* @param W3_Config $config
* @return string
*/
private function rules_cache_generate_apache($config) {
$charset = get_option('blog_charset');
$pingback_url = get_bloginfo('pingback_url');
$browsercache = $config->get_boolean('browsercache.enabled');
$compression = ($browsercache && $config->get_boolean('browsercache.html.compression'));
$expires = ($browsercache && $config->get_boolean('browsercache.html.expires'));
$lifetime = ($browsercache ? $config->get_integer('browsercache.html.lifetime') : 0);
$cache_control = ($browsercache && $config->get_boolean('browsercache.html.cache.control'));
$etag = ($browsercache && $config->get_integer('browsercache.html.etag'));
$w3tc = ($browsercache && $config->get_integer('browsercache.html.w3tc'));
$compatibility = $config->get_boolean('pgcache.compatibility');
$rules = '';
$rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n";
if ($compatibility) {
$rules .= "Options -MultiViews\n";
// allow to read files by apache if they are blocked at some level above
$rules .= "\n";
$rules .= " Allow from all\n";
$rules .= "\n";
if (!$etag) {
$rules .= "FileETag None\n";
}
}
if ($config->get_boolean('pgcache.file.nfs')) {
$rules .= "EnableSendfile Off \n";
}
if (!$config->get_boolean('pgcache.remove_charset')) {
$rules .= "AddDefaultCharset " . ($charset ? $charset : 'UTF-8') . "\n";
}
if ($etag) {
$rules .= "FileETag MTime Size\n";
}
if ($compression) {
$rules .= "\n";
$rules .= " AddType text/html .html_gzip\n";
$rules .= " AddEncoding gzip .html_gzip\n";
$rules .= " AddType text/xml .xml_gzip\n";
$rules .= " AddEncoding gzip .xml_gzip\n";
$rules .= "\n";
$rules .= "\n";
$rules .= " SetEnvIfNoCase Request_URI \\.html_gzip$ no-gzip\n";
$rules .= " SetEnvIfNoCase Request_URI \\.xml_gzip$ no-gzip\n";
$rules .= "\n";
}
if ($expires) {
$rules .= "\n";
$rules .= " ExpiresActive On\n";
$rules .= " ExpiresByType text/html M" . $lifetime . "\n";
$rules .= "\n";
}
$header_rules = '';
if ($compatibility) {
$header_rules .= " Header set X-Pingback \"" . $pingback_url . "\"\n";
}
if ($w3tc) {
$header_rules .= " Header set X-Powered-By \"" . W3TC_POWERED_BY . "\"\n";
}
if ($compression) {
$header_rules .= " Header set Vary \"Accept-Encoding, Cookie\"\n";
} else {
if ($compatibility) {
$header_rules .= " Header set Vary \"Cookie\"\n";
}
}
$set_last_modified = $config->get_boolean('browsercache.html.last_modified');
if (!$set_last_modified && $config->get_boolean('browsercache.enabled')) {
$header_rules .= " Header unset Last-Modified\n";
}
if ($cache_control) {
$cache_policy = $config->get_string('browsercache.html.cache.policy');
switch ($cache_policy) {
case 'cache':
$header_rules .= " Header set Pragma \"public\"\n";
$header_rules .= " Header set Cache-Control \"public\"\n";
break;
case 'cache_public_maxage':
$header_rules .= " Header set Pragma \"public\"\n";
if ($expires) {
$header_rules .= " Header append Cache-Control \"public\"\n";
} else {
$header_rules .= " Header set Cache-Control \"max-age=" . $lifetime . ", public\"\n";
}
break;
case 'cache_validation':
$header_rules .= " Header set Pragma \"public\"\n";
$header_rules .= " Header set Cache-Control \"public, must-revalidate, proxy-revalidate\"\n";
break;
case 'cache_noproxy':
$header_rules .= " Header set Pragma \"public\"\n";
$header_rules .= " Header set Cache-Control \"private, must-revalidate\"\n";
break;
case 'cache_maxage':
$header_rules .= " Header set Pragma \"public\"\n";
if ($expires) {
$header_rules .= " Header append Cache-Control \"public, must-revalidate, proxy-revalidate\"\n";
} else {
$header_rules .= " Header set Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\"\n";
}
break;
case 'no_cache':
$header_rules .= " Header set Pragma \"no-cache\"\n";
$header_rules .= " Header set Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\"\n";
break;
}
}
if (strlen($header_rules) > 0) {
$rules .= "\n";
$rules .= $header_rules;
$rules .= "\n";
}
$rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n";
return $rules;
}
/**
* Generates directives for file cache dir
*
* @param W3_Config $config
* @return string
*/
private function rules_cache_generate_nginx($config) {
$cache_root = w3_path(W3TC_CACHE_PAGE_ENHANCED_DIR);
$cache_dir = rtrim(str_replace(w3_get_document_root(), '', $cache_root), '/');
if (w3_is_network()) {
$cache_dir = preg_replace('~/w3tc.*?/~', '/w3tc.*?/', $cache_dir, 1);
}
$browsercache = $config->get_boolean('browsercache.enabled');
$compression = ($browsercache && $config->get_boolean('browsercache.html.compression'));
$expires = ($browsercache && $config->get_boolean('browsercache.html.expires'));
$lifetime = ($browsercache ? $config->get_integer('browsercache.html.lifetime') : 0);
$cache_control = ($browsercache && $config->get_boolean('browsercache.html.cache.control'));
$w3tc = ($browsercache && $config->get_integer('browsercache.html.w3tc'));
$common_rules = '';
if ($expires) {
$common_rules .= " expires modified " . $lifetime . "s;\n";
}
if ($w3tc) {
$common_rules .= " add_header X-Powered-By \"" . W3TC_POWERED_BY . "\";\n";
}
if ($compression) {
$common_rules .= " add_header Vary \"Accept-Encoding, Cookie\";\n";
} else {
$common_rules .= " add_header Vary Cookie;\n";
}
if ($cache_control) {
$cache_policy = $config->get_string('browsercache.html.cache.policy');
switch ($cache_policy) {
case 'cache':
$common_rules .= " add_header Pragma \"public\";\n";
$common_rules .= " add_header Cache-Control \"public\";\n";
break;
case 'cache_public_maxage':
$common_rules .= " add_header Pragma \"public\";\n";
$common_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
break;
case 'cache_validation':
$common_rules .= " add_header Pragma \"public\";\n";
$common_rules .= " add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n";
break;
case 'cache_noproxy':
$common_rules .= " add_header Pragma \"public\";\n";
$common_rules .= " add_header Cache-Control \"private, must-revalidate\";\n";
break;
case 'cache_maxage':
$common_rules .= " add_header Pragma \"public\";\n";
$common_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
break;
case 'no_cache':
$common_rules .= " add_header Pragma \"no-cache\";\n";
$common_rules .= " add_header Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\";\n";
break;
}
}
$rules = '';
$rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n";
$rules .= "location ~ " . $cache_dir . ".*html$ {\n";
$rules .= $common_rules;
$rules .= "}\n";
if ($compression) {
$rules .= "location ~ " . $cache_dir . ".*gzip$ {\n";
$rules .= " gzip off;\n";
$rules .= " types {}\n";
$rules .= " default_type text/html;\n";
$rules .= $common_rules;
$rules .= " add_header Content-Encoding gzip;\n";
$rules .= "}\n";
}
$rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n";
return $rules;
}
}