bibhamrokhanpin/wp-content/__plugins/wp-optimize/cache/class-wpo-page-cache.php
2024-04-10 17:46:06 +05:45

1229 lines
37 KiB
PHP

<?php
/**
* Page caching functionality
*
* Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache
*/
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* Base cache directory, everything else goes under here
*/
if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache');
/**
* Extensions directory.
*/
if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions');
/**
* Directory that stores config and related files
*/
if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config');
/**
* Directory that stores the cache, including gzipped files and mobile specifc cache
*/
if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache');
if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php');
if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php');
if (!class_exists('WP_Optimize_Detect_Cache_Plugins')) require_once(dirname(__FILE__) . '/class-wpo-detect-cache-plugins.php');
if (!class_exists('WP_Optimize_Page_Cache_Preloader')) require_once(dirname(__FILE__) . '/class-wpo-cache-preloader.php');
if (!class_exists('WPO_Cache_Config')) require_once(dirname(__FILE__) . '/class-wpo-cache-config.php');
if (!class_exists('WPO_Cache_Rules')) require_once(dirname(__FILE__) . '/class-wpo-cache-rules.php');
if (!class_exists('Updraft_Abstract_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-abstract-logger.php');
if (!class_exists('Updraft_PHP_Logger')) require_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-php-logger.php');
require_once dirname(__FILE__) . '/file-based-page-cache-functions.php';
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
require_once dirname(__FILE__) . '/php-5.3-functions.php';
}
wpo_cache_load_extensions();
if (!class_exists('WPO_Page_Cache')) :
class WPO_Page_Cache {
/**
* Cache config object
*
* @var mixed
*/
public $config;
/**
* Logger for this class
*
* @var mixed
*/
public $logger;
/**
* Instance of this class
*
* @var mixed
*/
public static $instance;
/**
* Store last advanced cache file writing status
* If true then last writing finished with error
*
* @var bool
*/
public $advanced_cache_file_writing_error;
/**
* Store errors
*
* @var array
*/
private $_errors = array();
/**
* Last advanced cache file content
*
* @var string
*/
public $advanced_cache_file_content;
/**
* Store the latest advanced-cache.php version required
*
* @var string
*/
private $_minimum_advanced_cache_file_version = '3.0.17';
/**
* Set everything up here
*/
public function __construct() {
$this->config = WPO_Cache_Config::instance();
$this->rules = WPO_Cache_Rules::instance();
$this->logger = new Updraft_PHP_Logger();
add_action('activate_plugin', array($this, 'activate_deactivate_plugin'));
add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin'));
/**
* Regenerate config file on cache flush.
*/
add_action('wpo_cache_flush', array($this, 'update_cache_config'));
add_action('wpo_cache_flush', array($this, 'delete_cache_size_information'));
// Add purge cache link to admin bar.
add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1);
// Handle single page purge.
add_action('wp_loaded', array($this, 'handle_purge_single_page_cache'));
add_action('admin_init', array($this, 'admin_init'));
$this->check_compatibility_issues();
}
/**
* Do required actions on activate/deactivate any plugin.
*/
public function activate_deactivate_plugin() {
$this->update_cache_config();
/**
* Filters whether activating / deactivating a plugin will purge the cache.
*/
if (apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true)) {
$this->purge();
}
}
/**
* Check if current user can purge cache.
*
* @return bool
*/
public function can_purge_cache() {
if (is_multisite()) return $this->is_enabled() && (current_user_can('manage_network_options') || WP_Optimize()->can_purge_the_cache());
return $this->is_enabled() && (current_user_can('manage_options') || WP_Optimize()->can_purge_the_cache());
}
/**
* Add Purge from cache in admin bar.
*
* @param array $menu_items
* @return array
*/
public function admin_bar_purge_cache($menu_items) {
global $pagenow;
if (!$this->can_purge_cache()) return $menu_items;
$act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged'));
$cache_size = $this->get_cache_size();
$cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>';
$cache_size_info .= '<span>'.__('Cache size:', 'wp-optimize').' '. WP_Optimize()->format_size($cache_size['size']).' '.sprintf(__('(%d files)', 'wp-optimize'), $cache_size['file_count']).'</span>';
$menu_items[] = array(
'id' => 'wpo_cache_stats',
'title' => $cache_size_info,
'meta' => array(
'class' => 'wpo-cache-stats',
),
'parent' => 'wpo_purge_cache',
);
$menu_items[] = array(
'id' => 'wpo_purge_all_pages_cache',
'title' => __('Purge cache for all pages', 'wp-optimize'),
'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url),
'meta' => array(
'title' => __('Purge cache for all pages', 'wp-optimize'),
),
'parent' => 'wpo_purge_cache',
);
if (!is_admin() || 'post.php' == $pagenow) {
$menu_items[] = array(
'id' => 'wpo_purge_this_page_cache',
'title' => __('Purge cache for this page', 'wp-optimize'),
'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url),
'meta' => array(
'title' => __('Purge cache for this page', 'wp-optimize'),
),
'parent' => 'wpo_purge_cache',
);
}
return $menu_items;
}
/**
* Check if purge single page action sent and purge cache.
*/
public function handle_purge_single_page_cache() {
if (!$this->can_purge_cache()) return;
if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) {
if (isset($_GET['wpo_single_page_cache_purged'])) {
$notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error';
} else {
$notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error';
}
add_action('admin_notices', array($this, $notice_function));
return;
}
if (!isset($_GET['_wpo_purge'])) return;
if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) {
$success = false;
if (is_admin()) {
$post = isset($_GET['post']) ? (int) $_GET['post'] : 0;
if ($post > 0) {
$success = self::delete_single_post_cache($post);
}
} else {
$success = self::delete_cache_by_url(wpo_current_url());
}
// remove nonce from url and reload page.
wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge')));
exit;
} elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) {
$success = self::purge();
// remove nonce from url and reload page.
wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge')));
exit;
}
}
/**
* Show notification when page cache purged successfully.
*/
public function notice_purge_single_page_cache_success() {
$this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success');
}
/**
* Show notification when page cache wasn't purged.
*/
public function notice_purge_single_page_cache_error() {
$this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error');
}
/**
* Show notification when all pages cache purged successfully.
*/
public function notice_purge_all_pages_cache_success() {
$this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success');
}
/**
* Show notification when all pages cache wasn't purged.
*/
public function notice_purge_all_pages_cache_error() {
$this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error');
}
/**
* Show notification in WordPress admin.
*
* @param string $message HTML (no further escaping is performed)
* @param string $type error, warning, success, or info
*/
public function show_notice($message, $type) {
global $current_screen;
if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?>
<script>
window.addEventListener('load', function() {
(function(wp) {
if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) {
wp.data.dispatch('core/notices').createNotice(
'<?php echo $type; ?>',
'<?php echo $message; ?>',
{
isDismissible: true,
}
);
}
})(window.wp);
});
</script>
<?php else : ?>
<div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible">
<p><?php echo $message; ?></p>
</div>
<?php
endif;
}
/**
* Enables page cache
*
* @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings
*
* @return WP_Error|bool - true on success, error otherwise
*/
public function enable($force_enable = false) {
static $already_ran_enable = false;
if ($already_ran_enable) return $already_ran_enable;
$folders_created = $this->create_folders();
if (is_wp_error($folders_created)) {
$already_ran_enable = $folders_created;
return $already_ran_enable;
}
// if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration
if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) {
$force_enable = true;
}
if (!$force_enable) {
$already_ran_enable = true;
return true;
}
if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) {
$message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename()));
$message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize');
if (!defined('WP_CLI') || !WP_CLI) {
$message .= "\n\n".sprintf(__('1. Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename())));
$message .= "\n".__('2. Edit or create a file with the name advanced-cache.php', 'wp-optimize');
$message .= "\n".__('3. Copy and paste the following lines into the file:', 'wp-optimize');
}
$already_ran_enable = new WP_Error("write_advanced_cache", $message);
return $already_ran_enable;
}
if (!$this->write_wp_config(true)) {
$already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions.");
return $already_ran_enable;
}
if (!$this->verify_cache()) {
$errors = $this->get_errors();
$already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors));
return $already_ran_enable;
}
$already_ran_enable = true;
return true;
}
/**
* Disables page cache
*
* @return bool - true on success, false otherwise
*/
public function disable() {
$ret = true;
$advanced_cache_file = $this->get_advanced_cache_filename();
// N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem.
$disabled_wp_config = $this->write_wp_config(false);
if (!$disabled_wp_config) {
$this->log("Could not turn off the WP_CACHE constant in wp-config.php");
$this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize'));
}
$disabled_advanced_cache = true;
// First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed')
// We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php
if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) {
if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) {
$disabled_advanced_cache = false;
$this->log("The request to the filesystem to remove or empty advanced-cache.php failed");
$this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize'));
}
}
// If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled.
if (!$disabled_wp_config && !$disabled_advanced_cache) {
$ret = new WP_Error('error_disabling_cache', __('The page caching could not be disabled: the WP_CACHE constant could not be removed from wp-config.php and the request to the filesystem to remove or empty advanced-cache.php failed.', 'wp-optimize'));
}
// Delete cache to avoid stale cache on next activation
$this->purge();
return $ret;
}
/**
* Purges the cache
*
* @return bool - true on success, false otherwise
*/
public function purge() {
if (!self::delete(WPO_CACHE_FILES_DIR)) {
$this->log("The request to the filesystem to delete the cache failed");
return false;
}
/**
* Fires after purging the cache
*/
do_action('wpo_cache_flush');
return true;
}
/**
* Purges the cache
*
* @return bool - true on success, false otherwise
*/
public function clean_up() {
$this->disable();
if (!self::delete(WPO_CACHE_DIR, true)) {
$this->log("The request to the filesystem to clean up the cache failed");
return false;
}
return true;
}
/**
* Check if cache is enabled and working
*
* @return bool - true on success, false otherwise
*/
public function is_enabled() {
if (!defined('WP_CACHE') || !WP_CACHE) {
return false;
}
if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) {
return false;
}
if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) {
return false;
}
return true;
}
/**
* Create the folder structure needed for cache to work
*
* @return bool - true on success, false otherwise
*/
private function create_folders() {
if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) {
return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR)));
}
if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) {
return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR)));
}
if (!is_dir(WPO_CACHE_FILES_DIR)) {
if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) {
return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s. Please check your file permissions.'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR)));
} else {
wpo_disable_cache_directories_viewing();
}
}
return true;
}
/**
* Get advanced-cache.php file name with full path.
*
* @return string
*/
public function get_advanced_cache_filename() {
return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php';
}
/**
* Get advanced-cache.php file name with full path.
*
* @return string
*/
public function get_cache_config_filename() {
$url = parse_url(network_site_url());
if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) {
return 'config-'.$url['host'].'-port'.$url['port'].'.php';
} else {
return 'config-'.$url['host'].'.php';
}
}
/**
* Writes advanced-cache.php
*
* @param boolean $update_required - Whether the update is required or not.
* @return bool
*/
private function write_advanced_cache($update_required = false) {
$config_file_basename = $this->get_cache_config_filename();
$cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__));
$plugin_basename = basename(WPO_PLUGIN_MAIN_PATH);
$cache_path = '/wpo-cache';
$cache_files_path = '/cache/wpo-cache';
$cache_extensions_path = WPO_CACHE_EXT_DIR;
$wpo_version = WPO_VERSION;
$wpo_home_url = trailingslashit(home_url());
// CS does not like heredoc
// phpcs:disable
$this->advanced_cache_file_content = <<<EOF
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
// WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks)
if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true);
\$possible_plugin_locations = array(
defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false,
defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false,
dirname(__FILE__).'/plugins/$plugin_basename/cache',
'$cache_file_basename',
);
\$plugin_location = false;
foreach (\$possible_plugin_locations as \$possible_location) {
if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) {
\$plugin_location = \$possible_location;
break;
}
}
if (false === \$plugin_location) {
if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', true);
\$protocol = \$_SERVER['REQUEST_SCHEME'];
\$host = \$_SERVER['HTTP_HOST'];
\$request_uri = \$_SERVER['REQUEST_URI'];
if (strcasecmp('$wpo_home_url', \$protocol . '://' . \$host . \$request_uri) === 0) {
error_log('WP-Optimize: No caching took place, because the plugin location could not be found');
}
} else {
if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', false);
}
if (is_admin()) { return; }
if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path');
if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config');
if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path');
if (false !== \$plugin_location) {
if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions');
} else {
if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path');
}
if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; }
\$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true);
if (empty(\$GLOBALS['wpo_cache_config'])) {
include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename');
}
if (empty(\$GLOBALS['wpo_cache_config']) || empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; }
if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); }
EOF;
// phpcs:enable
$advanced_cache_filename = $this->get_advanced_cache_filename();
// If the file content is already up to date, success
if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) {
$this->advanced_cache_file_writing_error = false;
return true;
}
// check if we can't write the advanced cache file
// case 1: the directory is read-only and the file doesn't exist
if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) {
$this->advanced_cache_file_writing_error = true;
return false;
}
// case 2: the file already exists but it's read-only
if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) {
if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) {
$this->advanced_cache_file_writing_error = true;
return false;
} else {
$this->advanced_cache_file_writing_error = false;
return true;
}
}
if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) {
$this->advanced_cache_file_writing_error = true;
return false;
}
$this->advanced_cache_file_writing_error = false;
return true;
}
/**
* Update advanced cache version if needed.
*/
public function maybe_update_advanced_cache() {
if (!$this->is_enabled()) return;
if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND') || (defined('WPO_PLUGIN_LOCATION_NOT_FOUND') && true === WPO_PLUGIN_LOCATION_NOT_FOUND)) {
if (!$this->write_advanced_cache(true)) {
add_action('admin_notices', array($this, 'show_admin_notice_advanced_cache'));
}
}
// from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php
$advanced_cache_current_version = $this->get_advanced_cache_version();
if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return;
if (!$this->write_advanced_cache()) {
add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error'));
} else {
$this->update_cache_config();
}
}
/**
* Show notification when advanced-cache.php could not be updated.
*/
public function notice_advanced_cache_autoupdate_error() {
$this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp-optimize').
' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to disable and then re-enable the WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error');
}
/**
* Get WPO version number from advanced-cache.php file.
*
* @return bool|mixed
*/
public function get_advanced_cache_version() {
if (!is_file($this->get_advanced_cache_filename())) return false;
$version = false;
$content = file_get_contents($this->get_advanced_cache_filename());
if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) {
$version = $match[1];
}
return $version;
}
/**
* Set WP_CACHE on or off in wp-config.php
*
* @param boolean $status value of WP_CACHE.
* @return boolean true if the value was set, false otherwise
*/
private function write_wp_config($status = true) {
// If we changed the value in wp-config, save it, in case we need to change it again in the same run.
static $changed = false;
if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) {
return true;
}
$config_path = $this->_get_wp_config();
// Couldn't find wp-config.php.
if (!$config_path) {
return false;
}
$config_file_string = file_get_contents($config_path);
// Config file is empty. Maybe couldn't read it?
if (empty($config_file_string)) {
return false;
}
$config_file = preg_split("#(\n|\r\n)#", $config_file_string);
$line_key = false;
foreach ($config_file as $key => $line) {
if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) {
continue;
}
if ('WP_CACHE' === $match[2]) {
$line_key = $key;
}
}
if (false !== $line_key) {
unset($config_file[$line_key]);
}
if ($status) {
array_shift($config_file);
array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache");
}
foreach ($config_file as $key => $line) {
if ('' === $line) {
unset($config_file[$key]);
}
}
if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) {
return false;
}
$changed = true;
return true;
}
/**
* Verify we can write to the file system
*
* @return boolean
*/
private function verify_cache() {
if (function_exists('clearstatcache')) {
clearstatcache();
}
$errors = 0;
// First check wp-config.php.
if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) {
$this->log("Unable to write to or find wp-config.php; please check file/folder permissions");
$this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize'));
}
$advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php';
// Now check wp-content. We need to be able to create files of the same user as this file.
if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) {
$this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions");
$this->add_error('verify_cache', __("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions", 'wp-optimize'));
$errors++;
}
if (file_exists(WPO_CACHE_FILES_DIR)) {
if (!is_writable(WPO_CACHE_FILES_DIR)) {
$this->log("Unable to write inside the cache files folder; please check file/folder permissions");
$this->add_warning('verify_cache', sprintf(__("Unable to write inside the cache files folder (%s); please check file/folder permissions (no cache files will be able to be created otherwise)", 'wp-optimize'), WPO_CACHE_FILES_DIR));
}
}
if (file_exists(WPO_CACHE_CONFIG_DIR)) {
if (!is_writable(WPO_CACHE_CONFIG_DIR)) {
$this->log("Unable to write inside the cache configuration folder; please check file/folder permissions");
// If the config exists, only send a warning. Otherwise send an error.
$type = 'warning';
if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->get_cache_config_filename())) {
$type = 'error';
$errors++;
}
$this->add_error('verify_cache', sprintf(__("Unable to write inside the cache configuration folder (%s); please check file/folder permissions", 'wp-optimize'), WPO_CACHE_CONFIG_DIR), $type);
}
}
return !$errors;
}
/**
* Update cache config. Used to support 3d party plugins.
*/
public function update_cache_config() {
// get current cache settings.
$current_config = $this->config->get();
// and call update to change if need cookies and query variable names.
$this->config->update($current_config, true);
}
/**
* Delete information about cache size.
*/
public function delete_cache_size_information() {
delete_transient('wpo_get_cache_size');
}
/**
* Get current cache size.
*
* @return array
*/
public function get_cache_size() {
$cache_size = get_transient('wpo_get_cache_size');
if (!empty($cache_size)) return $cache_size;
$infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR);
$cache_size = array(
'size' => $infos['size'],
'file_count' => $infos['file_count']
);
set_transient('wpo_get_cache_size', $cache_size);
return $cache_size;
}
/**
* Fetch directory informations.
*
* @param string $dir
* @return array
*/
private function get_dir_infos($dir) {
$dir_size = 0;
$file_count = 0;
$handle = is_dir($dir) ? opendir($dir) : false;
if (false === $handle) {
return array('size' => 0, 'file_count' => 0);
}
$file = readdir($handle);
while (false !== $file) {
if ('.' != $file && '..' != $file) {
$current_file = $dir.'/'.$file;
if (is_dir($current_file)) {
$sub_dir_infos = $this->get_dir_infos($current_file);
$dir_size += $sub_dir_infos['size'];
$file_count += $sub_dir_infos['file_count'];
} elseif (is_file($current_file)) {
$dir_size += filesize($current_file);
$file_count++;
}
}
$file = readdir($handle);
}
return array('size' => $dir_size, 'file_count' => $file_count);
}
/**
* Returns the path to wp-config
*
* @return string|boolean wp-config.php path.
*/
private function _get_wp_config() {
$config_path = false;
foreach (get_included_files() as $filename) {
if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) {
$config_path = $filename;
break;
}
}
// WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file.
if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) {
$config_path = wpo_wp_cli_locate_wp_config();
}
return $config_path;
}
/**
* Util to delete folders and/or files
*
* @param string $src
* @return boolean
*/
public static function delete($src) {
return wpo_delete_files($src);
}
/**
* Delete cached files for specific url.
*
* @param string $url
* @param bool $recursive If true child elements will deleted too
*
* @return bool
*/
public static function delete_cache_by_url($url, $recursive = false) {
if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return;
$path = self::get_full_path_from_url($url);
do_action('wpo_delete_cache_by_url', $url, $recursive);
return wpo_delete_files($path, $recursive);
}
/**
* Delete cached files for single post.
*
* @param integer $post_id The post ID
*
* @return bool
*/
public static function delete_single_post_cache($post_id) {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$post_url = get_permalink($post_id);
$path = self::get_full_path_from_url($post_url);
// for posts with pagination run purging cache recursively.
$post = get_post($post_id);
$recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false;
do_action('wpo_delete_cache_by_url', $post_url, $recursive);
return wpo_delete_files($path, $recursive);
}
/**
* Delete cached home page files.
*/
public static function delete_homepage_cache() {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$homepage_url = get_home_url(get_current_blog_id());
$path = self::get_full_path_from_url($homepage_url);
do_action('wpo_delete_cache_by_url', $homepage_url, false);
wpo_delete_files($path, false);
}
/**
* Delete sitemap cahche.
*/
public static function delete_sitemap_cache() {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$homepage_url = get_home_url(get_current_blog_id());
$path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($homepage_url));
if (!is_dir($path)) return;
$handle = opendir($path);
if (false !== $handle) {
$file = readdir($handle);
while (false !== $file) {
if ('.' != $file && '..' != $file && is_dir($path . $file) && preg_match('/.*sitemap.*\.xml/i', $file)) {
do_action('wpo_delete_cache_by_url', $path . $file, false);
wpo_delete_files($path . $file, true);
}
$file = readdir($handle);
}
}
closedir($handle);
}
/**
* Delete feed from cache.
*/
public static function delete_feed_cache() {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$homepage_url = get_home_url(get_current_blog_id());
$path = self::get_full_path_from_url($homepage_url) . 'feed/';
do_action('wpo_delete_cache_by_url', $path, true);
wpo_delete_files($path, true);
}
/**
* Delete post feed from cache.
*/
public static function delete_post_feed_cache($post_id) {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$post_url = get_permalink($post_id);
$path = self::get_full_path_from_url($post_url) . 'feed/';
do_action('wpo_delete_cache_by_url', $path, true);
wpo_delete_files($path, true);
}
/**
* Delete comments feed from cache.
*/
public static function delete_comments_feed() {
if (!defined('WPO_CACHE_FILES_DIR')) return;
$comments_feed_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/feed/';
$path = self::get_full_path_from_url($comments_feed_url);
do_action('wpo_delete_cache_by_url', $comments_feed_url, true);
wpo_delete_files($path, true);
// delete empty comments dir from the cache
$comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/';
$path = self::get_full_path_from_url($comments_url);
if (wpo_is_empty_dir($path)) {
wpo_delete_files($path, true);
}
}
/**
* Returns full path to the cache folder by url.
*
* @param string $url
* @return string
*/
private static function get_full_path_from_url($url) {
return trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url));
}
/**
* Admin actions
*
* @return void
*/
public function admin_init() {
// Maybe update the advanced cache.
if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) {
$this->maybe_update_advanced_cache();
}
}
/**
* Logs error messages
*
* @param string $message
* @return null|void
*/
public function log($message) {
if (isset($this->logger)) {
$this->logger->log($message, 'error');
} else {
error_log($message);
}
}
/**
* Returns an instance of the current class, creates one if it doesn't exist
*
* @return object
*/
public static function instance() {
if (empty(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Adds an error to the error store
*
* @param string $code - The error code
* @param string $message - The error's message
* @param string $type - The error's type (error, warning)
* @return void
*/
public function add_error($code, $message, $type = 'error') {
if (!isset($this->_errors[$type])) {
$this->_errors[$type] = new WP_Error($code, $message);
} else {
$this->_errors[$type]->add($code, $message);
}
}
/**
* Adds a warning to the error store
*
* @param string $code - The error code
* @param string $message - The error's message
* @return void
*/
public function add_warning($code, $message) {
$this->add_error($code, $message, 'warning');
}
/**
* Get all recorded errors
*
* @param string $type - The error type
* @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object
* @return boolean|array|WP_Error
*/
public function get_errors($type = 'error', $get_messages_only = true) {
if (!$this->has_errors($type)) return false;
$errors = $this->_errors[$type];
if ($get_messages_only) {
return $errors->get_error_messages();
}
return $errors;
}
/**
* Check if any errors were recorded
*
* @param string $type - The error type
* @return boolean
*/
public function has_errors($type = 'error') {
return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors();
}
/**
* Check if any warnings were recorded
*
* @return boolean
*/
public function has_warnings() {
return $this->has_errors('warning');
}
/**
* Check the cache compatibility issues.
*/
public function check_compatibility_issues() {
if (!$this->is_enabled()) return;
if ($this->is_pagespeedninja_gzip_active()) add_action('admin_notices', array($this, 'show_pagespeedninja_gzip_notice'));
if ($this->is_farfutureexpiration_gzip_active()) add_action('admin_notices', array($this, 'show_farfutureexpiration_gzip_notice'));
}
/**
* Check if PageSpeed Ninja is active and GZIP compression option is enabled.
*
* @return bool
*/
public function is_pagespeedninja_gzip_active() {
if (!class_exists('PagespeedNinja')) return false;
$options = get_option('pagespeedninja_config');
$gzip = !empty($options) ? (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip'] : false;
return $gzip;
}
/**
* Output PageSpeed Ninja Gzip notice.
*/
public function show_pagespeedninja_gzip_notice() {
echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in PageSpeed Ninja to prevent conflicts.', 'wp-optimize').'</p></div>';
}
/**
* Check if Far Future Expiration is active and GZIP compression option is enabled.
*
* @return bool
*/
public function is_farfutureexpiration_gzip_active() {
if (!class_exists('farFutureExpiration')) return false;
$options = get_option('far_future_expiration_settings');
$gzip = !empty($options) ? (bool) $options['enable_gzip'] : false;
return $gzip;
}
/**
* Output Far Future Expiration Gzip notice.
*/
public function show_farfutureexpiration_gzip_notice() {
echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in Far Future Expiration to prevent conflicts.', 'wp-optimize').'</p></div>';
}
/**
* This is a notice to show users that writing `advanced-cache.php` failed
*/
public function show_admin_notice_advanced_cache() {
$message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename()));
$message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize');
WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message));
}
}
endif;