diff --git a/admin/class-wp-super-cache-admin.php b/admin/class-wp-super-cache-admin.php new file mode 100755 index 00000000..f493a9b4 --- /dev/null +++ b/admin/class-wp-super-cache-admin.php @@ -0,0 +1,321 @@ + + */ +class Wp_Super_Cache_Admin { + + /** + * The ID of this plugin. + * + * @since 2.0.0 + * @access private + * @var string $plugin_name The ID of this plugin. + */ + private $plugin_name; + + /** + * The version of this plugin. + * + * @since 2.0.0 + * @access private + * @var string $version The current version of this plugin. + */ + private $version; + + /** + * Configuration object + * + * @since 2.0.0 + * @var object $config + */ + private $config; + + /** + * Setup object + * + * @since 2.0.0 + * @access private + * @var object $config. + */ + private $setup; + + /** + * Initialize the class and set its properties. + * + * @since 2.0.0 + * @param string $plugin_name The name of this plugin. + * @param string $version The version of this plugin. + */ + public function __construct( $plugin_name, $version ) { + + $this->plugin_name = $plugin_name; + $this->version = $version; + $this->config = Wp_Super_Cache_Config::instance(); + $this->setup = Wp_Super_cache_Setup::instance(); + + // Create page environment for cache info like blog_cache_dir. + $page = Wp_Super_Cache_Page::instance(); + } + + /** + * Register the stylesheets for the admin area. + * + * @since 2.0.0 + */ + public function enqueue_styles() { + + /** + * This function is provided for demonstration purposes only. + * + * An instance of this class should be passed to the run() function + * defined in Wp_Super_Cache_Loader as all of the hooks are defined + * in that particular class. + * + * The Wp_Super_Cache_Loader will then create the relationship + * between the defined hooks and the functions defined in this + * class. + */ + + wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wp-super-cache-admin.css', array(), $this->version, 'all' ); + + } + + /** + * Register the JavaScript for the admin area. + * + * @since 2.0.0 + */ + public function enqueue_scripts() { + + /** + * This function is provided for demonstration purposes only. + * + * An instance of this class should be passed to the run() function + * defined in Wp_Super_Cache_Loader as all of the hooks are defined + * in that particular class. + * + * The Wp_Super_Cache_Loader will then create the relationship + * between the defined hooks and the functions defined in this + * class. + */ + + wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wp-super-cache-admin.js', array( 'jquery' ), $this->version, false ); + + } + + /** + * Output network setting menu option + * + * @since 1.7 + */ + public function network_admin_menu() { + add_submenu_page( 'settings.php', esc_html__( 'WP Super Cache', 'wp-super-cache' ), esc_html__( 'WP Super Cache', 'wp-super-cache' ), 'manage_options', 'wp-super-cache', array( $this, 'screen_options' ) ); + } + + /** + * Add options page + * + * @since 1.0 + */ + public function action_admin_menu() { + add_submenu_page( 'options-general.php', esc_html__( 'WP Super Cache', 'wp-super-cache' ), esc_html__( 'WP Super Cache', 'wp-super-cache' ), 'manage_options', 'wp-super-cache', array( $this, 'screen_options' ) ); + } + + /** + * Add purge cache button to admin bar + * + * @since 1,3 + */ + public function admin_bar_menu() { + global $wp_admin_bar; + + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + if ( ( is_singular() || is_archive() || is_front_page() || is_search() ) && current_user_can( 'delete_others_posts' ) ) { + $site_regex = preg_quote( rtrim( (string) wp_parse_url( get_option( 'home' ), PHP_URL_PATH ), '/' ), '`' ); + $req_uri = preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $_SERVER[ 'REQUEST_URI' ] ); // phpcs:ignore + $path = preg_replace( '`^' . $site_regex . '`', '', $req_uri ); + + $wp_admin_bar->add_menu( + array( + 'parent' => '', + 'id' => 'delete-cache', + 'title' => __( 'Delete Cache', 'wp-super-cache' ), + 'meta' => array( 'title' => __( 'Delete cache of the current page', 'wp-super-cache' ) ), + 'href' => wp_nonce_url( admin_url( 'index.php?action=delcachepage&path=' . rawurlencode( $path ) ), 'delete-cache' ), + ) + ); + } + } + + /** + * Output settings + * + * @since 1.0 + */ + public function screen_options() { + // TODO - setup screen to create cache dir. + $setup_done = true; + if ( ! $this->setup->is_wp_cache_constant_defined() ) { + $setup_done = $this->setup->add_wp_cache_constant(); + } + + if ( ! $this->setup->is_wpcachehome_constant_defined() ) { + $setup_done = $this->setup->add_wpcachehome_constant(); + } + + if ( $setup_done && ! $this->setup->advanced_cache_exists() ) { + $setup_done = $this->setup->create_advanced_cache(); + } + + if ( $setup_done && ! $this->setup->plugin_config_exists() ) { + $setup_done = $this->setup->create_config_file(); + } + + if ( $setup_done && ! $this->config->config['wp_cache_home_path'] ) { + $setup_done = $this->setup->set_home_path(); + } + + if ( $setup_done ) { + $setup_done = $this->setup->create_cache_storage(); + } + + if ( ! $setup_done ) { + include_once 'partials/wp-super-cache-admin-setup.php'; + } else { + include_once 'partials/wp-super-cache-admin-screen.php'; + } + } + + /** + * Update settings + * + * @since 2.0 + */ + public function update() { + if ( ! isset( $_GET['page'] ) || 'wp-super-cache' !== $_GET['page'] ) { + return false; + } + + if ( ! isset( $_POST['wp-super-cache_settings_nonce'] ) ) { + return false; + } + + if ( + ! wp_verify_nonce( + sanitize_key( $_POST['wp-super-cache_settings_nonce'] ), + 'wp-super-cache_update_settings' + ) + ) { + return false; + } + + // TODO - switch to update settings for various pages. + + $this->config->update_setting( + 'cache_enabled', + isset( $_POST['cache_enabled'] ) ? 1 : 0 + ); + + $this->config->update_setting( + 'wp_super_cache_debug', + isset( $_POST['wp_super_cache_debug'] ) ? 1 : 0 + ); + + if ( $this->config->config['wp_super_cache_debug'] ) { + $debug = Wp_Super_Cache_Debug::instance(); + if ( + isset( $this->config->config['wp_super_cache_debug_log'] ) && $this->config->config['wp_super_cache_debug_log'] && + isset( $this->config->config['wp_super_cache_debug_username'] ) && $this->config->config['wp_super_cache_debug_username'] + ) { + $debug->create_debug_log( $this->config->config['wp_super_cache_debug_log'], $this->config->config['wp_super_cache_debug_username'] ); + } else { + $debug->create_debug_log(); + } + } + + if ( false === isset( $this->config->config['cache_page_secret'] ) ) { + $cache_page_secret = md5( gmdate( 'H:i:s' ) . wp_rand() ); + $this->config->update_setting( 'cache_page_secret', $cache_page_secret ); + } + + if ( isset( $_POST['action'] ) && 'easysetup' === $_POST['action'] ) { + $_POST['action'] = 'scupdates'; + if ( isset( $_POST['wp_cache_easy_on'] ) && 1 === $_POST['wp_cache_easy_on'] ) { + $_POST['wp_cache_enabled'] = 1; + $_POST['super_cache_enabled'] = 1; + $_POST['cache_rebuild_files'] = 1; + unset( $_POST['cache_compression'] ); + if ( WP_CONTENT_DIR . '/cache/' !== $cache_path ) { + $_POST['wp_cache_location'] = $cache_path; + } + + // set up garbage collection with some default settings. + if ( ( ! isset( $wp_cache_shutdown_gc ) || 0 === $wp_cache_shutdown_gc ) && false === wp_next_scheduled( 'wp_cache_gc' ) ) { + if ( false === isset( $cache_schedule_type ) ) { + $cache_schedule_type = 'interval'; + $cache_time_interval = 600; + $cache_max_time = 1800; + $this->config->update_setting( 'cache_schedule_type', $cache_schedule_type ); + $this->config->update_setting( 'cache_time_interval', $cache_time_interval ); + $this->config->update_setting( 'cache_max_time', $cache_max_time ); + } + wp_schedule_single_event( time() + 600, 'wp_cache_gc' ); + } + } else { + unset( $_POST['wp_cache_enabled'] ); + wp_clear_scheduled_hook( 'wp_cache_check_site_hook' ); + wp_clear_scheduled_hook( 'wp_cache_gc' ); + wp_clear_scheduled_hook( 'wp_cache_gc_watcher' ); + } + $advanced_settings = array( 'wp_super_cache_late_init', 'wp_cache_disable_utf8', 'wp_cache_no_cache_for_get', 'wp_supercache_304', 'wp_cache_mfunc_enabled', 'wp_cache_front_page_checks', 'wp_supercache_cache_list', 'wp_cache_clear_on_post_edit', 'wp_cache_make_known_anon', 'wp_cache_refresh_single_only', 'cache_compression' ); + foreach ( $advanced_settings as $setting ) { + if ( isset( $GLOBALS[ $setting ] ) && 1 === $GLOBALS[ $setting ] ) { + $_POST[ $setting ] = 1; + } + } + $_POST['wp_cache_not_logged_in'] = 2; + } + + } + + /** + * Check if user can use admin page. + * + * @since 1.0 + */ + private function is_super_admin() { + global $wp_version; + + if ( version_compare( $wp_version, '4.8', '>=' ) ) { + return current_user_can( 'setup_network' ); + } + + return is_super_admin(); + } + +} diff --git a/admin/css/wp-super-cache-admin.css b/admin/css/wp-super-cache-admin.css new file mode 100755 index 00000000..00c8c7f7 --- /dev/null +++ b/admin/css/wp-super-cache-admin.css @@ -0,0 +1,4 @@ +/** + * All of the CSS for your admin-specific functionality should be + * included in this file. + */ \ No newline at end of file diff --git a/admin/index.php b/admin/index.php new file mode 100755 index 00000000..7751eb07 --- /dev/null +++ b/admin/index.php @@ -0,0 +1,2 @@ + + + +
+

+
+ + config->config['cache_enabled'] ); ?> />
+ config->config['wp_super_cache_debug'] ); ?> /> + +

+ +

+
+
diff --git a/admin/partials/wp-super-cache-admin-setup.php b/admin/partials/wp-super-cache-admin-setup.php new file mode 100755 index 00000000..8472ae71 --- /dev/null +++ b/admin/partials/wp-super-cache-admin-setup.php @@ -0,0 +1,26 @@ + + + +
+

+

+

+

+

+
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 66636662..2cf18bbf 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -33,7 +33,7 @@ services: volumes: - "./wordpress:/var/www/html" - "./plugins:/var/www/html/wp-content/plugins" - - ..:/var/www/html/wp-content/plugins/wp-super-cache" + - ..:/var/www/html/wp-content/plugins/wp-super-cache - dockerdirectory:/var/www/html/wp-content/plugins/wp-super-cache/docker - ./mu-plugins:/var/www/html/wp-content/mu-plugins - ./logs/apache2/:/var/log/apache2 diff --git a/includes/class-wp-super-cache-activator.php b/includes/class-wp-super-cache-activator.php new file mode 100755 index 00000000..ebfbe1d5 --- /dev/null +++ b/includes/class-wp-super-cache-activator.php @@ -0,0 +1,35 @@ + + */ +class Wp_Super_Cache_Activator { + + /** + * Short Description. (use period) + * + * Long Description. + * + * @since 2.0.0 + */ + public static function activate() { + + } + +} diff --git a/includes/class-wp-super-cache-config.php b/includes/class-wp-super-cache-config.php new file mode 100644 index 00000000..c98fc8e5 --- /dev/null +++ b/includes/class-wp-super-cache-config.php @@ -0,0 +1,254 @@ +get(); + } + + /** + * Get configuration. + * + * @since 1.0 + */ + public function get() { + + if ( ! empty( $this->config ) ) { + return $this->config; + } + + if ( ! file_exists( WP_CONTENT_DIR . '/wp-cache-config.php' ) || ! include WP_CONTENT_DIR . '/wp-cache-config.php' ) { + return false; + } + $this->config = get_defined_vars(); + + return $this->config; + } + + /** + * Update a setting. + * + * @param string $field the name of the setting. + * @param string $value the value of the setting. + * @since 2.0 + */ + public function update_setting( $field, $value ) { + $this->config[ $field ] = $value; + if ( is_numeric( $value ) ) { + return $this->replace_line_in_file( '^ *\$' . $field, "\$$field = $value;", $this->config_filename ); + } elseif ( is_bool( $value ) ) { + $output_value = true === $value ? 'true' : 'false'; + return $this->replace_line_in_file( '^ *\$' . $field, "\$$field = $output_value;", $this->config_filename ); + } elseif ( is_object( $value ) || is_array( $value ) ) { + $text = var_export( $value, true ); // phpcs:ignore + $text = preg_replace( '/[\s]+/', ' ', $text ); + return $this->replace_line_in_file( '^ *\$' . $field, "\$$field = $text;", $this->config_filename ); + } else { + return $this->replace_line_in_file( '^ *\$' . $field, "\$$field = '$value';", $this->config_filename ); + } + } + + /** + * Replace a line in the config file. + * + * @param string $old the old line in the file. + * @param string $new the new line to replace it. + * @param string $filename the filename of the file to write to. + * @since 2.0 + */ + public function replace_line_in_file( $old, $new, $filename ) { + if ( is_file( $filename ) === false ) { + if ( function_exists( 'set_transient' ) ) { + set_transient( 'wpsc_config_error', 'config_file_missing', 10 ); + } + return false; + } + if ( ! $this->is_writeable( $filename ) ) { + if ( function_exists( 'set_transient' ) ) { + set_transient( 'wpsc_config_error', 'config_file_ro', 10 ); + } + return false; + } + + $found = false; + $loaded = false; + $c = 0; + $lines = array(); + while ( ! $loaded ) { + $lines = file( $filename ); + if ( ! empty( $lines ) && is_array( $lines ) ) { + $loaded = true; + } else { + $c++; + if ( $c > 100 ) { + if ( function_exists( 'set_transient' ) ) { + set_transient( 'wpsc_config_error', 'config_file_not_loaded', 10 ); + } + return false; + } + } + } + foreach ( (array) $lines as $line ) { + if ( + trim( $new ) !== '' && + trim( $new ) === trim( $line ) + ) { + wp_cache_debug( "replace_line_in_file: setting not changed - $new" ); + return true; + } elseif ( preg_match( "/$old/", $line ) ) { + wp_cache_debug( 'replace_line_in_file: changing line ' . trim( $line ) . " to *$new*" ); + $found = true; + } + } + + /** + * TODO: The tmp config filename must be put in the cache_path as not all servers have /tmp + * $tmp_config_filename = tempnam( $GLOBALS['cache_path'], 'wpsc' ); + */ + $tmp_config_filename = tempnam( '/tmp/', 'wpsc' ); + rename( $tmp_config_filename, $tmp_config_filename . '.php' ); + $tmp_config_filename .= '.php'; + wp_cache_debug( 'replace_line_in_file: writing to ' . $tmp_config_filename ); + $fd = fopen( $tmp_config_filename, 'w' ); // phpcs:ignore + if ( ! $fd ) { + if ( function_exists( 'set_transient' ) ) { + set_transient( 'wpsc_config_error', 'config_file_ro', 10 ); + } + return false; + } + if ( $found ) { + foreach ( (array) $lines as $line ) { + if ( ! preg_match( "/$old/", $line ) ) { + fputs( $fd, $line ); + } elseif ( '' !== $new ) { + fputs( $fd, "$new\n" ); + } + } + } else { + $done = false; + foreach ( (array) $lines as $line ) { + if ( $done || ! preg_match( '/^(if\ \(\ \!\ )?define|\$|\?>/', $line ) ) { + fputs( $fd, $line ); + } else { + fputs( $fd, "$new\n" ); + fputs( $fd, $line ); + $done = true; + } + } + } + fclose( $fd ); // phpcs:ignore + rename( $tmp_config_filename, $filename ); + wp_cache_debug( 'replace_line_in_file: moved ' . $tmp_config_filename . ' to ' . $filename ); + + if ( function_exists( 'opcache_invalidate' ) ) { + @opcache_invalidate( $filename ); // phpcs:ignore + } + + return true; + } + + /** + * Check if $path is writeable. + * From legolas558 d0t users dot sf dot net at http://www.php.net/is_writable + * + * @param string $path the path to be checked. + * @since 2.0 + */ + private function is_writeable( $path ) { + + // PHP's is_writable does not work with Win32 NTFS. + + if ( '/' === $path[ strlen( $path ) - 1 ] ) { // recursively return a temporary file path. + return $this->is_writeable( $path . uniqid( wp_rand() ) . '.tmp' ); + } elseif ( is_dir( $path ) ) { + return $this->is_writeable( $path . '/' . uniqid( wp_rand() ) . '.tmp' ); + } + + // check tmp file for read/write capabilities. + $rm = file_exists( $path ); + $f = @fopen( $path, 'a' ); // phpcs:ignore + if ( false === $f ) { + return false; + } + fclose( $f ); // phpcs:ignore + if ( ! $rm ) { + unlink( $path ); + } + + return true; + } + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_Config + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} + +/** + * Return the config for the plugin. + * + * @since 2.0 + * @return array of configuration data. + **/ +function wp_super_cache_get_config() { + global $wpsc_config; + + if ( false === isset( $wpsc_config ) ) { + $wpsc_config = Wp_Super_cache_Config::instance(); + } + + return $wpsc_config; +} diff --git a/includes/class-wp-super-cache-deactivator.php b/includes/class-wp-super-cache-deactivator.php new file mode 100755 index 00000000..180c48cf --- /dev/null +++ b/includes/class-wp-super-cache-deactivator.php @@ -0,0 +1,36 @@ + + */ +class Wp_Super_Cache_Deactivator { + + /** + * Short Description. (use period) + * + * Long Description. + * + * @since 2.0.0 + */ + public static function deactivate() { + + } + +} diff --git a/includes/class-wp-super-cache-debug.php b/includes/class-wp-super-cache-debug.php new file mode 100644 index 00000000..f6510dff --- /dev/null +++ b/includes/class-wp-super-cache-debug.php @@ -0,0 +1,237 @@ +config = Wp_Super_Cache_Config::instance(); + } + + /** + * Add a log message to the file, if debugging is turned on + * + * @param string $message The message that should be added to the log. + */ + public function log( $message ) { + static $last_message = ''; + + if ( $last_message === $message ) { + return false; + } + $last_message = $message; + + // If either of the debug or log globals aren't set, then we can stop. + if ( ! isset( $this->config->config['wp_super_cache_debug'] ) || ! isset( $this->config->config['wp_cache_debug_log'] ) ) { + return false; + } + + // If either the debug or log globals are false or empty, we can stop. + if ( false === $this->config->config['wp_super_cache_debug'] || '' === $this->config->config['wp_cache_debug_log'] ) { + return false; + } + + // If the debug_ip has been set, but it doesn't match the ip of the requester + // then we can stop. + if ( + isset( $this->config->config['wp_cache_debug_ip'] ) + && '' !== $this->config->config['wp_cache_debug_ip'] + && $this->config->config['wp_cache_debug_ip'] !== $_SERVER['REMOTE_ADDR'] // phpcs:ignore + ) { + return false; + } + + // Log message: Date URI Message. + $log_message = gmdate( 'H:i:s' ) . ' ' . getmypid() . ' ' . wp_unslash( $_SERVER['REQUEST_URI'] ) . ' ' . $message . PHP_EOL; // phpcs:ignore + // path to the log file in the cache folder. + $log_file = $this->config->config['cache_path'] . str_replace( '/', '', str_replace( '..', '', $this->config->config['wp_cache_debug_log'] ) ); + + if ( ! file_exists( $log_file ) ) { + if ( ! isset( $this->config->config['wp_cache_debug_username'] ) ) { + $this->config->config['wp_cache_debug_username'] = ''; + } + + $this->create_debug_log( $this->config->config['wp_cache_debug_log'], $this->config->config['wp_cache_debug_username'] ); + } + + error_log( $log_message, 3, $log_file ); // phpcs:ignore + } + + /** + * Get a username to use for the debug log. + */ + private function get_debug_username() { + + if ( ! isset( $this->config->config['wp_cache_debug_username'] ) || '' === $this->config->config['wp_cache_debug_username'] ) { + $this->config->update_setting( 'wp_cache_debug_username', md5( time() + wp_rand() ) ); + } + return $wp_cache_debug_username; + } + + /** + * Create a new debug log + * + * @param string $filename The name of the log file. + * @param string $username username and password used to protect the log file. + */ + public function create_debug_log( $filename = '', $username = '' ) { + $debug_setting = $this->config->config['wp_super_cache_debug']; + $this->config->config['wp_super_cache_debug'] = false; + + if ( '' !== $filename ) { + $this->config->update_setting( 'wp_cache_debug_log', $filename ); + } else { + $this->config->update_setting( 'wp_cache_debug_log', md5( time() + wp_rand() ) . '.php' ); + } + if ( '' !== $username ) { + $this->config->update_setting( 'wp_cache_debug_username', $username ); + } else { + $this->get_debug_username(); + } + // phpcs:disable + $msg = 'die( "Please use the viewer" );' . PHP_EOL; + $fp = fopen( $this->config->config['cache_path'] . $this->config->config['wp_cache_debug_log'], 'w' ); + if ( $fp ) { + fwrite( $fp, '<' . "?php\n" ); + fwrite( $fp, $msg ); + fwrite( $fp, '?' . '>
' . PHP_EOL );
+			fwrite( $fp, '<' . '?php // END HEADER ?' . '>' . PHP_EOL );
+			fclose( $fp );
+			$this->config->update_setting( 'wp_cache_debug_log', $this->config->config['wp_cache_debug_log'] );
+			$this->config->update_setting( 'wp_cache_debug_username', $this->config->config['wp_cache_debug_username'] );
+		}
+
+		$msg = '
+if ( !isset( $_SERVER[ "PHP_AUTH_USER" ] ) || ( $_SERVER[ "PHP_AUTH_USER" ] != "' . $this->config->config['wp_cache_debug_username'] . '" && $_SERVER[ "PHP_AUTH_PW" ] != "' . $this->config->config['wp_cache_debug_username'] . '" ) ) {
+	header( "WWW-Authenticate: Basic realm=\"WP-Super-Cache Debug Log\"" );
+	header( $_SERVER[ "SERVER_PROTOCOL" ] . " 401 Unauthorized" );
+	echo "You must login to view the debug log";
+	exit;
+}' . PHP_EOL;
+
+		$fp = fopen( $this->config->config['cache_path'] . 'view_' . $this->config->config['wp_cache_debug_log'], 'w' );
+		if ( $fp ) {
+			fwrite( $fp, '<' . '?php' . PHP_EOL );
+			$msg .= '$debug_log = file( "./' . $this->config->config['wp_cache_debug_log'] . '" );
+$start_log = 1 + array_search( "<" . "?php // END HEADER ?" . ">" . PHP_EOL, $debug_log );
+if ( $start_log > 1 ) {
+	$debug_log = array_slice( $debug_log, $start_log );
+}
+?' . '>
<' . '?php + +$checks = array( "wp-admin", "exclude_filter", "wp-content", "wp-json" ); +foreach( $checks as $check ) { + if ( isset( $_GET[ $check ] ) ) { + $$check = 1; + } else { + $$check = 0; + } +} + +if ( isset( $_GET[ "filter" ] ) ) { + $filter = htmlspecialchars( $_GET[ "filter" ] ); +} else { + $filter = ""; +} + +unset( $checks[1] ); // exclude_filter +?' . '> +

WP Super Cache Log Viewer

+

Warning! Do not copy and paste this log file to a public website!

+

This log file contains sensitive information about your website such as cookies and directories.

+

If you must share it please remove any cookies and remove any directories such as ' . ABSPATH . '.

+Exclude requests:
+<' . '?php foreach ( $checks as $check ) { ?> +
+<' . '?php } ?' . '> +
+Text to filter by: + +
+ /> Exclude by filter instead of include.
+ +
+<' . '?php +$path_to_site = "' . ABSPATH . '"; +foreach ( $debug_log as $t => $line ) { + $line = str_replace( $path_to_site, "ABSPATH/", $line ); + $debug_log[ $t ] = $line; + foreach( $checks as $check ) { + if ( $$check && false !== strpos( $line, " /$check/" ) ) { + unset( $debug_log[ $t ] ); + } + } + if ( $filter ) { + if ( false !== strpos( $line, $filter ) && $exclude_filter ) { + unset( $debug_log[ $t ] ); + } elseif ( false === strpos( $line, $filter ) && ! $exclude_filter ) { + unset( $debug_log[ $t ] ); + } + } +} +foreach( $debug_log as $line ) { + echo htmlspecialchars( $line ) . "
"; +}'; + fwrite( $fp, $msg ); + fclose( $fp ); + } + // phpcs:enable + $this->config->config['wp_super_cache_debug'] = $debug_setting; + + return array( + 'wp_cache_debug_log' => $this->config->config['wp_cache_debug_log'], + 'wp_cache_debug_username' => $this->config->config['wp_cache_debug_username'], + ); + } + + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_Config + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} + +/** + * Add a log message to the file, if debugging is turned on + * + * @param string $message The message that should be added to the log. + * @param int $level deprecated. + */ +function wp_cache_debug( $message, $level = false ) { + return Wp_Super_Cache_Debug::instance()->log( $message ); +} diff --git a/includes/class-wp-super-cache-file-cache.php b/includes/class-wp-super-cache-file-cache.php new file mode 100644 index 00000000..e89eb6d1 --- /dev/null +++ b/includes/class-wp-super-cache-file-cache.php @@ -0,0 +1,1271 @@ +config = Wp_Super_Cache_Config::instance(); + add_filter( 'wpsc_create_cache_storage', array( $this, 'create_cache_storage' ) ); + } + + /** + * Create cache storage + * + * @since 2.0 + */ + public function create_cache_storage( $setup_done ) { + $directory_functions = array( 'create_cache_directory', 'create_supercache_directory', 'create_blogcache_directory' ); + foreach ( $directory_functions as $dir_function ) { + $setup_done = $this->$dir_function(); + if ( ! $setup_done ) { + return false; + } + } + return $setup_done; + } + + /** + * Create WP_CONTENT/cache + * + * @since 2.0.0 + * @return bool if succeeded or not. + */ + public function create_cache_directory() { + if ( ! empty( $this->config->config['cache_path'] ) && ! is_dir( $this->config->config['cache_path'] ) ) { + @mkdir( $this->config->config['cache_path'] ); // phpcs:ignore + } + return is_dir( $this->config->config['cache_path'] ) ? true : false; + } + + /** + * Create WP_CONTENT/cache/supercache + * + * @since 2.0.0 + * @return bool if succeeded or not. + */ + public function create_supercache_directory() { + if ( ! empty( $this->config->config['cache_path'] ) && ! is_dir( $this->config->config['cache_path'] . '/supercache/' ) ) { + @mkdir( $this->config->config['cache_path'] . '/supercache/' ); // phpcs:ignore + } + return is_dir( $this->config->config['cache_path'] . '/supercache/' ) ? true : false; + } + + /** + * Create WP_CONTENT/cache/blogs + * + * @since 2.0.0 + * @return bool if succeeded or not. + */ + public function create_blogcache_directory() { + if ( ! empty( $this->config->config['blog_cache_dir'] ) && ! is_dir( $this->config->config['blog_cache_dir'] ) ) { + @mkdir( $this->config->config['blog_cache_dir'] ); // phpcs:ignore + } + return is_dir( $this->config->config['blog_cache_dir'] ) ? true : false; + } + + /** + * Get cache directory + * + * @since 2.0 + * @return string + */ + public function get_cache_dir() { + if ( isset( $this->config->config['cache_path'] ) ) { + return $this->config->config['cache_path']; + } else { + return ( defined( 'WPSC_CACHE_DIR' ) ) ? rtrim( WPSC_CACHE_DIR, '/' ) : rtrim( WP_CONTENT_DIR, '/' ) . '/cache'; + } + } + + /** + * Cache the query vars that may get destroyed by PHP garbage collection + * + * @since 2.0 + * @return string + */ + public function get_query_vars() { + global $wp_query; + + if ( ! empty( $this->config->query_vars ) ) { + return $this->config->query_vars; + } + + if ( ! is_object( $wp_query ) || ! method_exists( $wp_query, 'get' ) ) { + return false; + } + + if ( is_search() ) { + $this->config->query_vars['is_search'] = 1; + } + if ( is_page() ) { + $this->config->query_vars['is_page'] = 1; + } + if ( is_archive() ) { + $this->config->query_vars['is_archive'] = 1; + } + if ( is_tag() ) { + $this->config->query_vars['is_tag'] = 1; + } + if ( is_single() ) { + $this->config->query_vars['is_single'] = 1; + } + if ( is_category() ) { + $this->config->query_vars['is_category'] = 1; + } + if ( is_front_page() ) { + $this->config->query_vars['is_front_page'] = 1; + } + if ( is_home() ) { + $this->config->query_vars['is_home'] = 1; + } + if ( is_author() ) { + $this->config->query_vars['is_author'] = 1; + } + + // REST API. + if ( + ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || + ( defined( 'JSON_REQUEST' ) && JSON_REQUEST ) || + ( defined( 'WC_API_REQUEST' ) && WC_API_REQUEST ) + ) { + $this->config->query_vars['is_rest'] = 1; + } + + // Feeds, sitemaps and robots.txt. + if ( is_feed() ) { + $this->config->query_vars['is_feed'] = 1; + if ( 'sitemap' === get_query_var( 'feed' ) ) { + $this->config->query_vars['is_sitemap'] = 1; + } + } elseif ( get_query_var( 'sitemap' ) || get_query_var( 'xsl' ) || get_query_var( 'xml_sitemap' ) ) { + $this->config->query_vars['is_feed'] = 1; + $this->config->query_vars['is_sitemap'] = 1; + } elseif ( is_robots() ) { + $this->config->query_vars['is_robots'] = 1; + } + + // Reset everything if it's 404. + if ( is_404() ) { + $this->config->query_vars = array( 'is_404' => 1 ); + } + + return $this->config->query_vars; + } + + /** + * Was there a fatal error in the page? + * + * @since 2.0 + */ + private function is_fatal_error() { + $error = error_get_last(); + if ( null === $error ) { + return false; + } + + if ( $error['type'] & ( E_ERROR | E_CORE_ERROR | E_PARSE | E_COMPILE_ERROR | E_USER_ERROR ) ) { + $this->config->query_vars['is_fatal_error'] = 1; + return true; + } + + return false; + } + + /** + * Create cache file from buffer + * + * @param int $status status code of the current HTTTP request. + * @since 2.0 + */ + private function catch_http_status_code( $status ) { + if ( in_array( intval( $status ), array( 301, 302, 303, 307 ), true ) ) { + $this->config->query_vars['is_redirect'] = 1; + } elseif ( 304 === $status ) { + $this->config->query_vars['is_304'] = 1; + } elseif ( 303 === $status ) { + $this->config->query_vars['is_404'] = 1; + } + + return $status; + } + + /** + * Will we be allowed serve gzip content? + * + * @since 2.0 + */ + public function gzip_encoding() { + static $gzip_accepted = 1; + + if ( 1 !== $gzip_accepted ) { + return $gzip_accepted; + } + + if ( ! $this->config->config['cache_compression'] ) { + $gzip_accepted = false; + return $gzip_accepted; + } + + if ( 1 === ini_get( 'zlib.output_compression' ) || 'on' === strtolower( ini_get( 'zlib.output_compression' ) ) ) { // Don't compress WP-Cache data files when PHP is already doing it. + $gzip_accepted = false; + return $gzip_accepted; + } + + if ( ! isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) || ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) && false === strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) ) ) { + $gzip_accepted = false; + return $gzip_accepted; + } + + $gzip_accepted = 'gzip'; + return $gzip_accepted; + } + + public function get_response_headers() { + static $known_headers = array( + 'Access-Control-Allow-Origin', + 'Accept-Ranges', + 'Age', + 'Allow', + 'Cache-Control', + 'Connection', + 'Content-Encoding', + 'Content-Language', + 'Content-Length', + 'Content-Location', + 'Content-MD5', + 'Content-Disposition', + 'Content-Range', + 'Content-Type', + 'Date', + 'ETag', + 'Expires', + 'Last-Modified', + 'Link', + 'Location', + 'P3P', + 'Pragma', + 'Proxy-Authenticate', + 'Referrer-Policy', + 'Refresh', + 'Retry-After', + 'Server', + 'Status', + 'Strict-Transport-Security', + 'Trailer', + 'Transfer-Encoding', + 'Upgrade', + 'Vary', + 'Via', + 'Warning', + 'WWW-Authenticate', + 'X-Frame-Options', + 'Public-Key-Pins', + 'X-XSS-Protection', + 'Content-Security-Policy', + 'X-Pingback', + 'X-Content-Security-Policy', + 'X-WebKit-CSP', + 'X-Content-Type-Options', + 'X-Powered-By', + 'X-UA-Compatible', + 'X-Robots-Tag', + ); + + if ( ! function_exists( 'headers_list' ) ) { + return array(); + } + + $known_headers = apply_filters( 'wpsc_known_headers', $known_headers ); + + if ( ! isset( $known_headers['age'] ) ) { + $known_headers = array_map( 'strtolower', $known_headers ); + } + + $headers = array(); + foreach ( headers_list() as $hdr ) { + $ptr = strpos( $hdr, ':' ); + + if ( empty( $ptr ) ) { + continue; + } + + $hdr_key = rtrim( substr( $hdr, 0, $ptr ) ); + + if ( in_array( strtolower( $hdr_key ), $known_headers, true ) ) { + $hdr_val = ltrim( substr( $hdr, $ptr + 1 ) ); + + if ( ! empty( $headers[ $hdr_key ] ) ) { + $hdr_val = $headers[ $hdr_key ] . ', ' . $hdr_val; + } + + $headers[ $hdr_key ] = $hdr_val; + } + } + + return $headers; + } + + + /** + * Get meta information about new cache file. + * + * @since 2.0 + * @return array + */ + private function get_cache_meta_information() { + if ( ! function_exists( 'wpsc_init' ) ) { + /* + * If a server has multiple networks the plugin may not have been activated + * on all of them. Give feeds on those blogs a short TTL. + * * ref: https://wordpress.org/support/topic/fatal-error-while-updating-post-or-publishing-new-one/ + */ + $wpsc_feed_ttl = 1; + wp_cache_debug( 'wp_cache_shutdown_callback: Plugin not loaded. Setting feed ttl to 60 seconds.' ); + } + + $wp_cache_meta['uri'] = WPSC_HTTP_HOST . preg_replace('/[ <>\'\"\r\n\t\(\)]/', '', WPSC_URI ); // To avoid XSS attacks + $wp_cache_meta['blog_id'] = $blog_id; + $wp_cache_meta['post'] = $this->config->config['post_id']; + $wp_cache_meta['key'] = $wp_cache_key; + + $wp_cache_meta = apply_filters( 'wp_cache_meta', $wp_cache_meta ); + + $response = $this->get_response_headers(); + foreach( $response as $key => $value ) { + $wp_cache_meta['headers'][ $key ] = "$key: $value"; + } + + wp_cache_debug( 'wp_cache_shutdown_callback: collecting meta data.', 2 ); + + if (!isset( $response['Last-Modified'] )) { + $value = gmdate('D, d M Y H:i:s') . ' GMT'; + /* Dont send this the first time */ + /* @header('Last-Modified: ' . $value); */ + $wp_cache_meta['headers']['Last-Modified'] = "Last-Modified: $value"; + } + $is_feed = false; + if ( !isset( $response['Content-Type'] ) && !isset( $response['Content-type'] ) ) { + // On some systems, headers set by PHP can't be fetched from + // the output buffer. This is a last ditch effort to set the + // correct Content-Type header for feeds, if we didn't see + // it in the response headers already. -- dougal + if ( isset( $this->config->query_vars['is_feed'] ) ) { + if ( isset( $this->config->query_vars['is_sitemap'] ) ) { + $type = 'sitemap'; + $value = 'text/xml'; + } else { + $type = get_query_var( 'feed' ); + $type = str_replace('/','',$type); + switch ($type) { + case 'atom': + $value = 'application/atom+xml'; + break; + case 'rdf': + $value = 'application/rdf+xml'; + break; + case 'rss': + case 'rss2': + default: + $value = 'application/rss+xml'; + } + } + $is_feed = true; + + if ( isset( $wpsc_feed_ttl ) && $wpsc_feed_ttl == 1 ) { + $wp_cache_meta['ttl'] = 60; + } + $is_feed = true; + + wp_cache_debug( "wp_cache_shutdown_callback: feed is type: $type - $value" ); + } elseif ( isset( $this->config->query_vars['is_rest'] ) ) { // json + $value = 'application/json'; + } else { // not a feed + $value = get_option( 'html_type' ); + if( $value == '' ) + $value = 'text/html'; + } + if ( defined( 'WPSC_BLOG_CHARSET' ) ) { + $value .= "; charset=\"" . constant( 'WPSC_BLOG_CHARSET' ) . "\""; + } + + $wp_cache_meta['headers']['Content-Type'] = "Content-Type: $value"; + } + + if ( $cache_enabled && !$supercacheonly && $new_cache ) { + if( !isset( $wp_cache_meta['dynamic'] ) && $wp_cache_gzip_encoding && !in_array( 'Content-Encoding: ' . $wp_cache_gzip_encoding, $wp_cache_meta['headers'] ) ) { + wp_cache_debug( 'Sending gzip headers.', 2 ); + $wp_cache_meta['headers']['Content-Encoding'] = 'Content-Encoding: ' . $wp_cache_gzip_encoding; + if ( defined( 'WPSC_VARY_HEADER' ) ) { + if ( WPSC_VARY_HEADER != '' ) { + $vary_header = WPSC_VARY_HEADER; + } else { + $vary_header = ''; + } + } else { + $vary_header = 'Accept-Encoding, Cookie'; + } + if ( $vary_header ) { + $wp_cache_meta['headers']['Vary'] = 'Vary: ' . $vary_header; + } + } + + $serial = '' . json_encode( $wp_cache_meta ); + $dir = get_current_url_supercache_dir(); + if( @is_dir( $dir ) == false ) + @wp_mkdir_p( $dir ); + + if( wp_cache_writers_entry() ) { + wp_cache_debug( "Writing meta file: {$dir}meta-{$meta_file}", 2 ); + + $tmp_meta_filename = $dir . uniqid( mt_rand(), true ) . '.tmp'; + $final_meta_filename = $dir . "meta-" . $meta_file; + $fr = @fopen( $tmp_meta_filename, 'w'); + if ( $fr ) { + fputs($fr, $serial); + fclose($fr); + @chmod( $tmp_meta_filename, 0666 & ~umask()); + if( !@rename( $tmp_meta_filename, $final_meta_filename ) ) { + @unlink( $dir . $final_meta_filename ); + @rename( $tmp_meta_filename, $final_meta_filename ); + } + } else { + wp_cache_debug( "Problem writing meta file: {$final_meta_filename}" ); + } + wp_cache_writers_exit(); + + // record locations of archive feeds to be updated when the site is updated. + // Only record a maximum of 50 feeds to avoid bloating database. + if ( ( isset( $this->config->query_vars['is_feed'] ) || $is_feed ) && ! isset( $this->config->query_vars['is_single'] ) ) { + $wpsc_feed_list = (array) get_option( 'wpsc_feed_list' ); + if ( count( $wpsc_feed_list ) <= 50 ) { + $wpsc_feed_list[] = $dir . $meta_file; + update_option( 'wpsc_feed_list', $wpsc_feed_list ); + } + } + } + } else { + wp_cache_debug( "Did not write meta file: meta-{$meta_file}\nsupercacheonly: $supercacheonly\nwp_cache_not_logged_in: $wp_cache_not_logged_in\nnew_cache:$new_cache" ); + } + global $time_to_gc_cache; + if ( isset( $time_to_gc_cache ) && $time_to_gc_cache == 1 ) { + wp_cache_debug( 'Executing wp_cache_gc action.', 3 ); + do_action( 'wp_cache_gc' ); + } + + return $wp_cache_meta; + } + + /** + * Get headers for newly created cache file. + * + * @since 2.0 + * @return array + */ + private function send_cache_headers( $wp_cache_meta ) { + if ( isset( $wp_cache_meta['headers']['Content-Type'] ) ) { + wp_cache_debug( "Sending header: $value" ); + @header( $value ); + } + + return true; + } + + /** + * Create cache file from buffer + * + * @param string $buffer the output buffer containing the current page. + * @since 2.0 + */ + public function ob_handler( $buffer ) { + + $cache_this_page = true; + + if ( mb_strlen( $buffer ) < 255 ) { + wp_cache_debug( 'ob_handler: not caching a small page.' ); + $cache_this_page = false; + } + + if ( $this->is_fatal_error() ) { + wp_cache_debug( 'ob_handler: PHP Fatal error occurred. Not caching incomplete page.' ); + $cache_this_page = false; + } elseif ( empty( $this->config->query_vars ) && ! empty( $buffer ) ) { + $this->get_query_vars(); + } elseif ( empty( $this->config->query_vars ) && function_exists( 'http_response_code' ) ) { + $this->catch_http_status_code( http_response_code() ); + } + $buffer = apply_filters( 'ob_handler_filter', $buffer ); + + if ( $cache_this_page ) { + $cache_this_page = WP_Super_cache_Page::instance()->post_cache_checks(); + } + + if ( isset( $this->config->config['wpsc_save_headers'] ) && $this->config->config['wpsc_save_headers'] ) { + $this->config->config['super_cache_enabled'] = false; // use standard caching to record headers. + } + + if ( $cache_this_page ) { + + wp_cache_debug( 'Output buffer callback' ); + + $buffer = $this->write_buffer_to_file( $buffer ); + // TODO. + //wp_cache_shutdown_callback(); + $meta_info = $this->get_cache_meta_information(); + + $this->send_cache_headers( $meta_info ); + + /* + * TODO - rebuild system + */ + if ( ! empty( $wpsc_file_mtimes ) && is_array( $wpsc_file_mtimes ) ) { + foreach ( $wpsc_file_mtimes as $cache_file => $old_mtime ) { + if ( $old_mtime === @filemtime( $cache_file ) ) { // phpcs:ignore + wp_cache_debug( "wp_cache_ob_callback deleting unmodified rebuilt cache file: $cache_file" ); + if ( wp_cache_confirm_delete( $cache_file ) ) { + @unlink( $cache_file ); // phpcs:ignore + } + } + } + } + return $buffer; + } else { + if ( ! empty( $do_rebuild_list ) && is_array( $do_rebuild_list ) ) { + foreach ( $do_rebuild_list as $dir => $n ) { + if ( wp_cache_confirm_delete( $dir ) ) { + wp_cache_debug( 'wp_cache_ob_callback clearing rebuilt files in ' . $dir ); + wpsc_delete_files( $dir ); + } + } + } + return $this->wp_cache_maybe_dynamic( $buffer ); + } + + return $buffer; + } + + /** + * Add text to the buffer + * + * @param string $buffer the output buffer containing the current page. + * @param string $text text to add to the buffer. + * @since 2.0 + * @return bool + */ + private function add_to_buffer( &$buffer, $text ) { + if ( ! isset( $this->config->config['wp_super_cache_debug'] ) || $this->config->config['wp_super_cache_debug'] ) { + return false; + } + + if ( false === isset( $this->config->config['wp_super_cache_comments'] ) ) { + $this->config->config['wp_super_cache_comments'] = 1; + } + + if ( 0 === $this->config->config['wp_super_cache_comments'] ) { + return false; + } + + if ( false === strpos( $buffer, 'config->config['cached_direct_pages'] ) && in_array( $_SERVER['REQUEST_URI'], $this->config->config['cached_direct_pages'] ) ) { // phpcs:ignore + $extra_str = ''; + } + $filename = 'index' . $extra_str . '.html'; + + return $filename; + } + + /** + * If dynamic caching is enabled then run buffer through wpsc_cachedata filter before returning it. + * or we'll return template tags to visitors. + * + * @param string $buffer the output buffer containing the current page. + * @since 2.0 + * @return string + */ + private function wp_cache_maybe_dynamic( &$buffer ) { + if ( 1 === $this->config->config['wp_cache_mfunc_enabled'] && 1 === do_cacheaction( 'wpsc_cachedata_safety', 0 ) ) { + wp_cache_debug( 'wp_cache_maybe_dynamic: filtered $buffer through wpsc_cachedata' ); + return do_cacheaction( 'wpsc_cachedata', $buffer ); // dynamic content for display. + } else { + wp_cache_debug( 'wp_cache_maybe_dynamic: returned $buffer' ); + return $buffer; + } + } + + /** + * Get the supercache directory for the current url or post ID. + * + * @param int $post_id The post_id of the post being queried, or 0 to get URL. + * @since 2.0 + * @return string + */ + public function get_current_url_supercache_dir( $post_id = 0 ) { + global $wpsc_http_host; + static $saved_supercache_dir = array(); + + if ( isset( $saved_supercache_dir[ $post_id ] ) ) { + return $saved_supercache_dir[ $post_id ]; + } + + $do_not_remember = 0; + if ( 0 !== $post_id ) { + $site_url = site_url(); + $permalink = get_permalink( $post_id ); + if ( false === strpos( $permalink, $site_url ) ) { + /* + * Sometimes site_url doesn't return the siteurl. See https://wordpress.org/support/topic/wp-super-cache-not-refreshing-post-after-comments-made + */ + $do_not_remember = 1; + wp_cache_debug( "get_current_url_supercache_dir: WARNING! site_url ($site_url) not found in permalink ($permalink).", 1 ); + if ( preg_match( '`^(https?:)?//([^/]+)(/.*)?$`i', $permalink, $matches ) ) { + if ( $wpsc_http_host !== $matches[2] ) { + wp_cache_debug( "get_current_url_supercache_dir: WARNING! SERVER_NAME ({$wpsc_http_host}) not found in permalink ($permalink).", 1 ); + } + wp_cache_debug( "get_current_url_supercache_dir: Removing SERVER_NAME ({$matches[2]}) from permalink ($permalink). Is the url right?", 1 ); + $uri = isset( $matches[3] ) ? $matches[3] : ''; + } elseif ( preg_match( '`^/([^/]+)(/.*)?$`i', $permalink, $matches ) ) { + wp_cache_debug( "get_current_url_supercache_dir: WARNING! Permalink ($permalink) looks as absolute path. Is the url right?", 1 ); + $uri = $permalink; + } else { + wp_cache_debug( "get_current_url_supercache_dir: WARNING! Permalink ($permalink) could not be understood by parsing url. Using front page.", 1 ); + $uri = ''; + } + } else { + $uri = str_replace( $site_url, '', $permalink ); + if ( strpos( $uri, $wp_cache_home_path ) !== 0 ) { + $uri = rtrim( $wp_cache_home_path, '/' ) . $uri; + } + } + } else { + $uri = strtolower( WPSC_URI ); + } + $uri = wpsc_deep_replace( + array( '..', '\\', 'index.php' ), + preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', preg_replace( '/(\?.*)?(#.*)?$/', '', $uri ) ) + ); + $hostname = $wpsc_http_host; + // Get hostname from wp options for wp-cron, wp-cli and similar requests. + if ( empty( $hostname ) && function_exists( 'get_option' ) ) { + $hostname = (string) wp_parse_url( get_option( 'home' ), PHP_URL_HOST ); + } + $dir = preg_replace( '/:.*$/', '', $hostname ) . $uri; // To avoid XSS attacks. + if ( function_exists( 'apply_filters' ) ) { + $dir = apply_filters( 'supercache_dir', $dir ); + } else { + $dir = do_cacheaction( 'supercache_dir', $dir ); + } + $dir = $this->config->config['cache_path'] . 'supercache/' . $dir . '/'; + if ( is_array( $this->config->config['cached_direct_pages'] ) && in_array( $_SERVER['REQUEST_URI'], $this->config->config['cached_direct_pages'] ) ) { // phpcs:ignore + $dir = ABSPATH . $uri . '/'; + } + $dir = str_replace( '..', '', str_replace( '//', '/', $dir ) ); + wp_cache_debug( "supercache dir: $dir" ); + if ( 0 === $do_not_remember ) { + $saved_supercache_dir[ $post_id ] = $dir; + } + return $dir; + } + + /** + * Create mutex flag for file locking + * + * @since 2.0 + * @return string + */ + public function wp_cache_mutex_init() { + global $mutex, $wp_cache_mutex_disabled, $use_flock, $blog_cache_dir, $mutex_filename, $sem_id; + + if ( defined( 'WPSC_DISABLE_LOCKING' ) || ( isset( $wp_cache_mutex_disabled ) && $wp_cache_mutex_disabled ) ) { + return true; + } + + if ( ! is_bool( $use_flock ) ) { + if ( function_exists( 'sem_get' ) ) { + $use_flock = false; + } else { + $use_flock = true; + } + } + + $mutex = false; + if ( $use_flock ) { + setup_blog_cache_dir(); + wp_cache_debug( "Created mutex lock on filename: {$blog_cache_dir}{$mutex_filename}" ); + $mutex = @fopen( $blog_cache_dir . $mutex_filename, 'w' ); // phpcs:ignore + } else { + wp_cache_debug( "Created mutex lock on semaphore: {$sem_id}" ); + $mutex = @sem_get( $sem_id, 1, 0666, 1 ); // phpcs:ignore + } + } + + /** + * Entry to writer's lock + * + * @since 2.0 + * @return string + */ + private function wp_cache_writers_entry() { + global $mutex, $wp_cache_mutex_disabled, $use_flock; + + if ( defined( 'WPSC_DISABLE_LOCKING' ) || ( isset( $wp_cache_mutex_disabled ) && $wp_cache_mutex_disabled ) ) { + return true; + } + + if ( ! $mutex ) { + wp_cache_debug( '(writers entry) mutex lock not created. not caching.' ); + return false; + } + + if ( $use_flock ) { + wp_cache_debug( 'grabbing lock using flock()' ); + flock( $mutex, LOCK_EX ); + } else { + wp_cache_debug( 'grabbing lock using sem_acquire()' ); + @sem_acquire( $mutex ); // phpcs:ignore + } + + return true; + } + + /** + * Exit to writer's lock + * + * @since 2.0 + * @return string + */ + private function wp_cache_writers_exit() { + global $mutex, $wp_cache_mutex_disabled, $use_flock; + + if ( defined( 'WPSC_DISABLE_LOCKING' ) || ( isset( $wp_cache_mutex_disabled ) && $wp_cache_mutex_disabled ) ) { + return true; + } + + if ( ! $mutex ) { + wp_cache_debug( '(writers exit) mutex lock not created. not caching.' ); + return false; + } + + if ( $use_flock ) { + wp_cache_debug( 'releasing lock using flock()', 5 ); + flock( $mutex, LOCK_UN ); + } else { + wp_cache_debug( 'releasing lock using sem_release() and sem_remove()' ); + @sem_release( $mutex ); // phpcs:ignore + if ( defined( 'WPSC_REMOVE_SEMAPHORE' ) ) { + @sem_remove( $mutex ); // phpcs:ignore + } + } + } + + + /** + * Count the micro seconds between $a and $b + * + * @param string $a the start time. + * @param string $b the end time. + * @since 2.0 + * @return string + */ + private function wp_cache_microtime_diff( $a, $b ) { + list( $a_dec, $a_sec ) = explode( ' ', $a ); + list( $b_dec, $b_sec ) = explode( ' ', $b ); + return (float) $b_sec - (float) $a_sec + (float) $b_dec - (float) $a_dec; + } + + /** + * Write buffer to the cache file. + * + * @param string $buffer the output buffer containing the current page. + * @since 2.0 + * @return string + */ + private function write_buffer_to_file( &$buffer ) { + global $wp_super_cache_start_time; + + if ( false === isset( $this->config->config['wp_cache_mfunc_enabled'] ) ) { + $this->config->config['wp_cache_mfunc_enabled'] = 0; + } + + $new_cache = true; + $wp_cache_meta = array(); + + if ( '' === $buffer ) { + $new_cache = false; + wp_cache_debug( "Buffer is blank. Output buffer may have been corrupted by another plugin or this is a redirected URL. Look for text 'ob_start' in the files of your plugins directory." ); + $this->add_to_buffer( $buffer, 'Page not cached by WP Super Cache. Blank Page. Check output buffer usage by plugins.' ); + } + + if ( isset( $this->config->query_vars['is_404'] ) && false === apply_filters( 'wpsupercache_404', false ) ) { + $new_cache = false; + wp_cache_debug( '404 file not found not cached' ); + $this->add_to_buffer( $buffer, 'Page not cached by WP Super Cache. 404.' ); + } + + if ( ! preg_match( apply_filters( 'wp_cache_eof_tags', '/(<\/html>|<\/rss>|<\/feed>|<\/urlset|<\?xml)/i' ), $buffer ) ) { + $new_cache = false; + wp_cache_debug( 'No closing html tag. Not caching.', 2 ); + $this->add_to_buffer( $buffer, 'Page not cached by WP Super Cache. No closing HTML tag. Check your theme.' ); + } + + if ( ! $new_cache ) { + return $this->wp_cache_maybe_dynamic( $buffer ); + } + + $duration = $this->wp_cache_microtime_diff( $wp_super_cache_start_time, microtime() ); + $duration = sprintf( '%0.3f', $duration ); + $this->add_to_buffer( $buffer, "Dynamic page generated in $duration seconds." ); + + if ( ! $this->wp_cache_writers_entry() ) { + $this->add_to_buffer( $buffer, 'Page not cached by WP Super Cache. Could not get mutex lock.' ); + wp_cache_debug( 'Could not get mutex lock. Not caching.' ); + return $this->wp_cache_maybe_dynamic( $buffer ); + } + + if ( $this->config->config['wp_cache_not_logged_in'] && isset( $this->config->query_vars['is_feed'] ) ) { + wp_cache_debug( 'Feed detected. Writing wpcache cache files.' ); + $wp_cache_not_logged_in = false; + } + + $home_url = wp_parse_url( trailingslashit( get_bloginfo( 'url' ) ) ); + $dir = get_current_url_supercache_dir(); + $supercachedir = $this->config->config['cache_path'] . 'supercache/' . preg_replace( '/:.*$/', '', $home_url['host'] ); + + if ( + ! empty( $_GET ) || // phpcs:ignore + isset( $this->config->query_vars['is_feed'] ) || + ( + $this->config->config['super_cache_enabled'] && + is_dir( substr( $supercachedir, 0, -1 ) . '.disabled' ) + ) + ) { + wp_cache_debug( 'Supercache disabled: GET or feed detected or disabled by config.' ); + $this->config->config['super_cache_enabled'] = false; + } + + $tmp_wpcache_filename = $this->config->config['cache_path'] . uniqid( wp_rand(), true ) . '.tmp'; + + if ( defined( 'WPSC_SUPERCACHE_ONLY' ) ) { + $supercacheonly = true; + wp_cache_debug( 'wp_cache_get_ob: WPSC_SUPERCACHE_ONLY defined. Only creating supercache files.' ); + } else { + $supercacheonly = false; + } + + if ( $this->config->config['super_cache_enabled'] ) { + if ( '' === $this->wp_cache_get_cookies_values() && empty( $_GET ) ) { // phpcs:ignore + wp_cache_debug( 'Anonymous user detected. Only creating Supercache file.' ); + $supercacheonly = true; + } + } + $cache_error = ''; + if ( wpsc_is_caching_user_disabled() ) { + $super_cache_enabled = false; + $cache_enabled = false; + $cache_error = 'Not caching requests by known users. (See Advanced Settings page)'; + wp_cache_debug( 'Not caching for known user.' ); + } + + if ( ! $cache_enabled ) { + wp_cache_debug( 'Cache is not enabled. Sending buffer to browser.' ); + $this->wp_cache_writers_exit(); + $this->add_to_buffer( $buffer, "Page not cached by WP Super Cache. Check your settings page. $cache_error" ); + if ( 1 === $this->config->config['wp_cache_mfunc_enabled'] ) { + if ( + false === isset( $this->config->config['wp_super_cache_late_init'] ) || + ( isset( $this->config->config['wp_super_cache_late_init'] ) && 0 === $this->config->config['wp_super_cache_late_init'] ) + ) { + $this->add_to_buffer( $buffer, 'Super Cache dynamic page detected but $wp_super_cache_late_init not set. See the readme.txt for further details.' ); + } + } + + return $this->wp_cache_maybe_dynamic( $buffer ); + } + + if ( false === @is_dir( $dir ) ) { // phpcs:ignore + @wp_mkdir_p( $dir ); // phpcs:ignore + } + // TODO. + $dir = wpsc_get_realpath( $dir ); + + if ( ! $dir ) { + wp_cache_debug( 'wp_cache_get_ob: not caching as directory does not exist.' ); + return $buffer; + } + + $dir = trailingslashit( $dir ); + + // TODO. + if ( ! wpsc_is_in_cache_directory( $dir ) ) { + wp_cache_debug( "wp_cache_get_ob: not caching as directory is not in cache_path: $dir" ); + return $buffer; + } + + $fr = false; + $fr2 = false; + $gz = false; + + // Open wp-cache cache file. + if ( ! $supercacheonly ) { + $fr = @fopen( $tmp_wpcache_filename, 'w' ); //phpcs:ignore + if ( ! $fr ) { + wp_cache_debug( 'Error. Supercache could not write to ' . str_replace( ABSPATH, '', $this->config->config['cache_path'] ) . $cache_filename ); + $this->add_to_buffer( $buffer, "File not cached! Super Cache Couldn't write to: " . str_replace( ABSPATH, '', $this->config->config['cache_path'] ) . $cache_filename ); + $this->wp_cache_writers_exit(); + return $this->wp_cache_maybe_dynamic( $buffer ); + } + } else { + $user_info = $this->wp_cache_get_cookies_values(); + $do_cache = apply_filters( 'do_createsupercache', $user_info ); + if ( + $super_cache_enabled && + ( + '' === $user_info || + true === $do_cache + ) + ) { + $cache_fname = $dir . $this->supercache_filename(); + $tmp_cache_filename = $dir . uniqid( wp_rand(), true ) . '.tmp'; + + $fr2 = @fopen( $tmp_cache_filename, 'w' ); // phpcs:ignore + if ( ! $fr2 ) { + wp_cache_debug( 'Error. Supercache could not write to ' . str_replace( ABSPATH, '', $tmp_cache_filename ) ); + $this->add_to_buffer( $buffer, "File not cached! Super Cache Couldn't write to: " . str_replace( ABSPATH, '', $tmp_cache_filename ) ); + @fclose( $fr ); // phpcs:ignore + @unlink( $tmp_wpcache_filename ); // phpcs:ignore + $this->wp_cache_writers_exit(); + return $this->wp_cache_maybe_dynamic( $buffer ); + } elseif ( + $this->gzip_encoding() && + 0 === $wp_cache_mfunc_enabled + ) { // don't want to store compressed files if using dynamic content. + $gz = @fopen( $tmp_cache_filename . '.gz', 'w' ); // phpcs:ignore + if ( ! $gz ) { + wp_cache_debug( 'Error. Supercache could not write to ' . str_replace( ABSPATH, '', $tmp_cache_filename ) . '.gz' ); + $this->add_to_buffer( $buffer, "File not cached! Super Cache Couldn't write to: " . str_replace( ABSPATH, '', $tmp_cache_filename ) . '.gz' ); + @fclose( $fr ); // phpcs:ignore + @unlink( $tmp_wpcache_filename ); //phpcs:ignore + @fclose( $fr2 ); // phpcs:ignore + @unlink( $tmp_cache_filename ); //phpcs:ignore + $this->wp_cache_writers_exit(); + return $this->wp_cache_maybe_dynamic( $buffer ); + } + } + } + } + + // TODO. + $added_cache = 0; + $oc_key = get_oc_key(); + $buffer = apply_filters( 'wpsupercache_buffer', $buffer ); + wp_cache_append_tag( $buffer ); + + /* + * Dynamic content enabled: write the buffer to a file and then process any templates found using + * the wpsc_cachedata filter. Buffer is then returned to the visitor. + */ + if ( 1 === $this->config->config['wp_cache_mfunc_enabled'] ) { + if ( preg_match( '//', $buffer ) ) { // Dynamic content. + wp_cache_debug( 'mfunc/mclude/dynamic-cached-content tags have been retired. Please update your theme. See docs for updates.' ); + $this->add_to_buffer( $buffer, 'Warning! Obsolete mfunc/mclude/dynamic-cached-content tags found. Please update your theme. See http://ocaoimh.ie/y/5b for more information.' ); + } + + if ( false === isset( $this->config->config['wp_super_cache_late_init'] ) || ( isset( $this->config->config['wp_super_cache_late_init'] ) && 0 === $this->config->config['wp_super_cache_late_init'] ) ) { + $this->add_to_buffer( $buffer, 'Super Cache dynamic page detected but late init not set. See the readme.txt for further details.' ); + } + + if ( $fr ) { // wpcache caching. + wp_cache_debug( 'Writing dynamic buffer to wpcache file.' ); + $this->add_to_buffer( $buffer, 'Dynamic WPCache Super Cache' ); + fputs( $fr, '' . $buffer ); + } elseif ( isset( $fr2 ) ) { // supercache active. + wp_cache_debug( 'Writing dynamic buffer to supercache file.' ); + $this->add_to_buffer( $buffer, 'Dynamic Super Cache' ); + fputs( $fr2, $buffer ); + } + $wp_cache_meta['dynamic'] = true; + if ( 1 === $wp_cache_mfunc_enabled && 1 === do_cacheaction( 'wpsc_cachedata_safety', 0 ) ) { + $buffer = do_cacheaction( 'wpsc_cachedata', $buffer ); // dynamic content for display. + } + + if ( $this->gzip_encoding() ) { + wp_cache_debug( 'Gzipping dynamic buffer for display.', 5 ); + $this->add_to_buffer( $buffer, 'Compression = gzip' ); + $gzdata = gzencode( $buffer, 6, FORCE_GZIP ); + $gzsize = function_exists( 'mb_strlen' ) ? mb_strlen( $gzdata, '8bit' ) : strlen( $gzdata ); + } + } else { + if ( defined( 'WPSC_VARY_HEADER' ) ) { + if ( '' !== WPSC_VARY_HEADER ) { + $vary_header = WPSC_VARY_HEADER; + } else { + $vary_header = ''; + } + } else { + $vary_header = 'Accept-Encoding, Cookie'; + } + if ( $vary_header ) { + $wp_cache_meta['headers']['Vary'] = 'Vary: ' . $vary_header; + } + if ( $gz || $this->gzip_encoding() ) { + wp_cache_debug( 'Gzipping buffer.' ); + $this->add_to_buffer( $buffer, 'Compression = gzip' ); + $gzdata = gzencode( $buffer, 6, FORCE_GZIP ); + $gzsize = function_exists( 'mb_strlen' ) ? mb_strlen( $gzdata, '8bit' ) : strlen( $gzdata ); + + $wp_cache_meta['headers']['Content-Encoding'] = 'Content-Encoding: ' . $this->gzip_encoding(); + // Return uncompressed data & store compressed for later use. + if ( $fr ) { + wp_cache_debug( 'Writing gzipped buffer to wp-cache cache file.', 5 ); + fputs( $fr, '' . $gzdata ); + } + } else { // no compression. + if ( $fr ) { + wp_cache_debug( 'Writing non-gzipped buffer to wp-cache cache file.' ); + fputs( $fr, '' . $buffer ); + } + } + if ( $fr2 ) { + wp_cache_debug( 'Writing non-gzipped buffer to supercache file.' ); + $this->add_to_buffer( $buffer, 'super cache' ); + fputs( $fr2, $buffer ); + } + if ( isset( $gzdata ) && $gz ) { + wp_cache_debug( 'Writing gzipped buffer to supercache file.' ); + fwrite( $gz, $gzdata ); // phpcs:ignore + } + } + + $new_cache = true; + if ( $fr ) { + $supercacheonly = false; + fclose( $fr ); // phpcs:ignore + if ( 0 === filesize( $tmp_wpcache_filename ) ) { + wp_cache_debug( "Warning! The file $tmp_wpcache_filename was empty. Did not rename to {$dir}{$cache_filename}", 5 ); + @unlink( $tmp_wpcache_filename ); //phpcs:ignore + } else { + if ( ! @rename( $tmp_wpcache_filename, $dir . $cache_filename ) ) { // phpcs:ignore + if ( false === is_dir( $dir ) ) { + @wp_mkdir_p( $dir ); //phpcs:ignore + } + @unlink( $dir . $cache_filename ); // phpcs:ignore + @rename( $tmp_wpcache_filename, $dir . $cache_filename ); // phpcs:ignore + } + if ( file_exists( $dir . $cache_filename ) ) { + wp_cache_debug( "Renamed temp wp-cache file to {$dir}{$cache_filename}", 5 ); + } else { + wp_cache_debug( "FAILED to rename temp wp-cache file to {$dir}{$cache_filename}", 5 ); + } + $added_cache = 1; + } + } + + if ( $fr2 ) { + fclose( $fr2 ); //phpcs:ignore + if ( $wp_cache_front_page_checks && $cache_fname === $supercachedir . $home_url['path'] . $this->supercache_filename() && ! $wp_cache_is_home ) { + $this->wp_cache_writers_exit(); + wp_cache_debug( 'Warning! Not writing another page to front page cache.', 1 ); + return $buffer; + } elseif ( 0 === filesize( $tmp_cache_filename ) ) { + wp_cache_debug( "Warning! The file $tmp_cache_filename was empty. Did not rename to {$cache_fname}", 5 ); + @unlink( $tmp_cache_filename ); // phpcs:ignore + } else { + if ( ! @rename( $tmp_cache_filename, $cache_fname ) ) { // phpcs:ignore + @unlink( $cache_fname ); // phpcs:ignore + @rename( $tmp_cache_filename, $cache_fname ); // phpcs:ignore + } + wp_cache_debug( "Renamed temp supercache file to $cache_fname", 5 ); + $added_cache = 1; + } + } + if ( $gz ) { + fclose( $gz ); // phpcs:ignore + if ( 0 === filesize( $tmp_cache_filename . '.gz' ) ) { + wp_cache_debug( "Warning! The file {$tmp_cache_filename}.gz was empty. Did not rename to {$cache_fname}.gz" ); + @unlink( $tmp_cache_filename . '.gz' ); // phpcs:ignore + } else { + if ( ! @rename( $tmp_cache_filename . '.gz', $cache_fname . '.gz' ) ) { // phpcs:ignore + @unlink( $cache_fname . '.gz' ); // phpcs:ignore + @rename( $tmp_cache_filename . '.gz', $cache_fname . '.gz' ); // phpcs:ignore + } + wp_cache_debug( "Renamed temp supercache gz file to {$cache_fname}.gz" ); + $added_cache = 1; + } + } + + if ( $added_cache && isset( $wp_supercache_cache_list ) && $wp_supercache_cache_list ) { + update_option( 'wpsupercache_count', ( get_option( 'wpsupercache_count' ) + 1 ) ); + $last_urls = (array) get_option( 'supercache_last_cached' ); + if ( count( $last_urls ) >= 10 ) { + $last_urls = array_slice( $last_urls, 1, 9 ); + } + $last_urls[] = array( + 'url' => preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $_SERVER['REQUEST_URI'] ), // phpcs:ignore + 'date' => gmdate( 'Y-m-d H:i:s' ), + ); + update_option( 'supercache_last_cached', $last_urls ); + } + $this->wp_cache_writers_exit(); + if ( ! headers_sent() && $this->gzip_encoding() && $gzdata ) { + wp_cache_debug( 'Writing gzip content headers. Sending buffer to browser', 5 ); + header( 'Content-Encoding: ' . $this->gzip_encoding() ); + if ( defined( 'WPSC_VARY_HEADER' ) ) { + if ( '' !== WPSC_VARY_HEADER ) { + $vary_header = WPSC_VARY_HEADER; + } else { + $vary_header = ''; + } + } else { + $vary_header = 'Accept-Encoding, Cookie'; + } + if ( $vary_header ) { + header( 'Vary: ' . $vary_header ); + } + header( 'Content-Length: ' . $gzsize ); + return $gzdata; + } else { + wp_cache_debug( 'Sending buffer to browser', 5 ); + return $buffer; + } + } + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_File_Cache + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } + +} + +/** + * Create cache file from buffer. + * + * @param string $buffer the output buffer containing the current page. + * @since 2.0 + */ +function wp_super_cache_ob_handler( $buffer ) { + $caching = Wp_Super_cache_File_Cache::instance(); + $buffer = $caching->ob_handler(); + +} diff --git a/includes/class-wp-super-cache-i18n.php b/includes/class-wp-super-cache-i18n.php new file mode 100755 index 00000000..0730ca15 --- /dev/null +++ b/includes/class-wp-super-cache-i18n.php @@ -0,0 +1,46 @@ + + */ +class Wp_Super_Cache_I18n { + + /** + * Load the plugin text domain for translation. + * + * @since 2.0.0 + */ + public function load_plugin_textdomain() { + + load_plugin_textdomain( + 'wp-super-cache', + false, + dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' + ); + + } + + + +} diff --git a/includes/class-wp-super-cache-loader.php b/includes/class-wp-super-cache-loader.php new file mode 100755 index 00000000..8687b024 --- /dev/null +++ b/includes/class-wp-super-cache-loader.php @@ -0,0 +1,128 @@ + + */ +class Wp_Super_Cache_Loader { + + /** + * The array of actions registered with WordPress. + * + * @since 2.0.0 + * @access protected + * @var array $actions The actions registered with WordPress to fire when the plugin loads. + */ + protected $actions; + + /** + * The array of filters registered with WordPress. + * + * @since 2.0.0 + * @access protected + * @var array $filters The filters registered with WordPress to fire when the plugin loads. + */ + protected $filters; + + /** + * Initialize the collections used to maintain the actions and filters. + * + * @since 2.0.0 + */ + public function __construct() { + + $this->actions = array(); + $this->filters = array(); + + } + + /** + * Add a new action to the collection to be registered with WordPress. + * + * @since 2.0.0 + * @param string $hook The name of the WordPress action that is being registered. + * @param object $component A reference to the instance of the object on which the action is defined. + * @param string $callback The name of the function definition on the $component. + * @param int $priority Optional. The priority at which the function should be fired. Default is 10. + * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. + */ + public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { + $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args ); + } + + /** + * Add a new filter to the collection to be registered with WordPress. + * + * @since 2.0.0 + * @param string $hook The name of the WordPress filter that is being registered. + * @param object $component A reference to the instance of the object on which the filter is defined. + * @param string $callback The name of the function definition on the $component. + * @param int $priority Optional. The priority at which the function should be fired. Default is 10. + * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. + */ + public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { + $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args ); + } + + /** + * A utility function that is used to register the actions and hooks into a single + * collection. + * + * @since 2.0.0 + * @access private + * @param array $hooks The collection of hooks that is being registered (that is, actions or filters). + * @param string $hook The name of the WordPress filter that is being registered. + * @param object $component A reference to the instance of the object on which the filter is defined. + * @param string $callback The name of the function definition on the $component. + * @param int $priority The priority at which the function should be fired. + * @param int $accepted_args The number of arguments that should be passed to the $callback. + * @return array The collection of actions and filters registered with WordPress. + */ + private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) { + + $hooks[] = array( + 'hook' => $hook, + 'component' => $component, + 'callback' => $callback, + 'priority' => $priority, + 'accepted_args' => $accepted_args, + ); + + return $hooks; + + } + + /** + * Register the filters and actions with WordPress. + * + * @since 2.0.0 + */ + public function run() { + + foreach ( $this->filters as $hook ) { + add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); + } + + foreach ( $this->actions as $hook ) { + add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); + } + + } + +} diff --git a/includes/class-wp-super-cache-page.php b/includes/class-wp-super-cache-page.php new file mode 100644 index 00000000..d152f3dc --- /dev/null +++ b/includes/class-wp-super-cache-page.php @@ -0,0 +1,499 @@ +config = Wp_Super_Cache_Config::instance(); + + if ( defined( 'DISABLE_SUPERCACHE' ) ) { + wp_cache_debug( 'DISABLE_SUPERCACHE set, super_cache disabled.' ); + $this->config->config['super_cache_enabled'] = 0; + } + + if ( ! defined( 'WPCACHEHOME' ) ) { + define( 'WPCACHEHOME', dirname( dirname( __FILE__ ) ) . '/' ); + } + + // In the future we might have different caching engines. + $this->cache = WP_Super_Cache_File_Cache::instance(); + + // remove authentication cookies so page can be super cached for admin users. + if ( $this->config->config['wp_cache_make_known_anon'] ) { + $this->make_anonymous(); + } + + $this->set_env(); + + do_cacheaction( 'cache_init' ); + } + + /** + * Set up cached environment for caching during shutdown. + * Caching for later use when wpdb is gone. https://wordpress.org/support/topic/224349 + * Details of the current blog being cached. + * + * @since 2.0 + */ + public function set_env() { + // Cache this in case any plugin modifies it. + // Used to be: wp_cache_request_uri. + if ( isset( $_SERVER['REQUEST_URI'] ) ) { + define( 'WPSC_URI', $_SERVER['REQUEST_URI'] ); // phpcs:ignore + } else { + define( 'WPSC_URI', '' ); + } + + if ( isset( $_SERVER['HTTP_HOST'] ) && ! empty( $_SERVER['HTTP_HOST'] ) ) { + $http_host = function_exists( 'mb_strtolower' ) ? mb_strtolower( $_SERVER['HTTP_HOST'] ) : strtolower( $_SERVER['HTTP_HOST'] ); + define( 'WPSC_HTTP_HOST', htmlentities( $http_host ) ); + } elseif ( PHP_SAPI === 'cli' && function_exists( 'get_option' ) ) { + define( 'WPSC_HTTP_HOST', (string) parse_url( get_option( 'home' ), PHP_URL_HOST ) ); + } else { + $this->config->config['cache_enabled'] = false; + define( 'WPSC_HTTP_HOST', '' ); + } + + // We want to be able to identify each blog in a WordPress MU install. + $this->config->config['blogcacheid'] = ''; + $this->config->config['blog_cache_dir'] = $this->config->config['cache_path']; + + if ( is_multisite() ) { + global $current_blog; + + if ( is_object( $current_blog ) && function_exists( 'is_subdomain_install' ) ) { + $this->config->config['blogcacheid'] = is_subdomain_install() ? $current_blog->domain : trim( $current_blog->path, '/' ); + } elseif ( ( defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL ) || ( defined( 'VHOST' ) && VHOST === 'yes' ) ) { + $this->config->config['blogcacheid'] = constant( 'WPSC_HTTP_HOST' ); + } else { + $request_uri = str_replace( '..', '', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $_SERVER['REQUEST_URI'] ) ); + $request_uri = str_replace( '//', '/', $request_uri ); + + $wpsc_path_segs = array_filter( explode( '/', trim( $request_uri, '/' ) ) ); + $wpsc_base_count = defined( 'PATH_CURRENT_SITE' ) ? count( array_filter( explode( '/', trim( PATH_CURRENT_SITE, '/' ) ) ) ) : 0; + if ( '/' !== substr( $request_uri, -1 ) ) { + $wpsc_path_segs = array_slice( $wpsc_path_segs, 0, -1 ); + } + + if ( count( $wpsc_path_segs ) > $wpsc_base_count && + ( ! defined( 'PATH_CURRENT_SITE' ) || 0 === strpos( $request_uri, PATH_CURRENT_SITE ) ) + ) { + $this->config->config['blogcacheid'] = $wpsc_path_segs[ $wpsc_base_count ]; + } + } + + // If blogcacheid is empty then set it to main blog. + if ( empty( $this->config->config['blogcacheid'] ) ) { + $this->config->config['blogcacheid'] = 'blog'; + } + $this->config->config['blog_cache_dir'] = str_replace( '//', '/', $this->config->config['cache_path'] . 'blogs/' . $this->config->config['blogcacheid'] . '/' ); + } + add_action( 'template_redirect', array( $this, 'wp_set_env' ) ); + } + + /** + * Setup environment with blog options. Must be run on "init" when WP has loaded. + * + * @since 2.0 + */ + public function wp_set_env() { + // $wp_cache_gmt_offset. + define( 'WPSC_GMT_OFFSET', get_option( 'gmt_offset' ) ); + // $wp_cache_blog_charset. + define( 'WPSC_BLOG_CHARSET', get_option( 'blog_charset' ) ); + $this->config->config['post_id'] = $this->get_post_id(); + + } + + /** + * Return the post ID from the current page. + * // used to be wp_cache_post_id + * + * @since 2.0 + * @return bool + */ + public function get_post_id() { + global $posts, $comment_post_ID, $post_ID; + + if ( $post_ID > 0 ) { + return $post_ID; + } + + if ( $comment_post_ID > 0 ) { + return $comment_post_ID; + } + + if ( is_singular() && ! empty( $posts ) ) { + return $posts[0]->ID; + } + + if ( isset( $_GET['p'] ) && $_GET['p'] > 0 ) { + return $_GET['p']; + } + + if ( isset( $_POST['p'] ) && $_POST['p'] > 0 ) { + return $_POST['p']; + } + + return 0; + } + + /** + * Can page be cached? + * + * @since 2.0 + * @return bool + */ + public function is_cacheable() { + if ( ! $this->config->config['cache_enabled'] ) { + wp_cache_debug( 'is_cacheable: Caching disabled.' ); + return false; + } + + if ( isset( $_GET['customize_changeset_uuid'] ) ) { //phpcs:ignore + return false; + } + + if ( $this->is_backend() ) { + wp_cache_debug( 'is_cacheable: Not caching backend request.' ); + return false; + } + + if ( ! $this->pre_cache_checks() ) { + return false; + } + + if ( $this->is_user_agent_rejected() ) { + return false; + } + + return true; + } + + /** + * Is page cached? + * + * @since 2.0 + * @return bool + */ + public function is_cached() { + return false; + } + + /** + * Serve the current page from a cache file. + * + * @since 2.0 + * @return bool + */ + public function serve_page() { + return true; + } + + /** + * Store the current page in a cache file. + * + * @since 2.0 + * @return bool + */ + public function cache_page() { + ob_start( array( Wp_Super_Cache_File_Cache::instance(), 'ob_handler' ) ); + + return true; + } + + /** + * Make the current request anonymouse for every type of visitor. + * + * @since 2.0 + * @return bool + */ + public function make_anonymous() { + + // Don't remove cookies for some requests. + if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'GET' !== $_SERVER['REQUEST_METHOD'] ) { + return true; + } + + if ( $this->is_backend() ) { + return true; + } + + if ( isset( $_GET['preview'], $_GET['customize_changeset_uuid'] ) ) { // phpcs:ignore + return true; + } + + if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( stripslashes( $_SERVER['REQUEST_URI'] ), '/wp-json/' ) !== false ) { // WPCS: sanitization ok. + return true; + } + + if ( false === do_cacheaction( 'wp_supercache_remove_cookies', true ) ) { + return true; + } + + $this->removed_cookies = array(); + foreach ( WP_Super_Cache_User::instance()->get_auth_cookies() as $cookie ) { + + $cookies = is_array( $cookie ) ? $cookie : array( $cookie ); + + foreach ( $cookies as $cookie_key ) { + unset( $_COOKIE[ $cookie_key ] ); + $this->removed_cookies[] = $cookie_key; + } + } + + if ( ! empty( $this->removed_cookies ) ) { + wp_cache_debug( 'Removing auth from $_COOKIE to allow caching for logged in user ( ' . implode( ', ', $this->removed_cookies ) . ' )' ); + } + } + + + /** + * Return true if in wp-admin or other admin non cacheable page. + * + * @since 2.0 + * @return bool + */ + public function is_backend() { + static $is_backend; + + if ( isset( $is_backend ) ) { + return $is_backend; + } + + $is_backend = is_admin(); + if ( $is_backend ) { + return $is_backend; + } + + $script = isset( $_SERVER['PHP_SELF'] ) ? basename( $_SERVER['PHP_SELF'] ) : ''; // phpcs:ignore + if ( 'index.php' !== $script ) { + if ( in_array( $script, array( 'wp-login.php', 'xmlrpc.php', 'wp-cron.php' ), true ) ) { + $is_backend = true; + } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) { + $is_backend = true; + } elseif ( 'cli' === PHP_SAPI || ( defined( 'WP_CLI' ) && WP_CLI ) ) { + $is_backend = true; + } + } + + return $is_backend; + } + + /** + * Check if url is on the rejected list. + * + * @param string $url the url to be checked. + * @since 2.0 + */ + public function url_is_rejected( $url ) { + $auto_rejected = array( '/wp-admin/', 'xmlrpc.php', 'wp-app.php' ); + foreach ( $auto_rejected as $u ) { + if ( strstr( $url, $u ) ) { + return true; // we don't allow caching of wp-admin for security reasons. + } + } + + if ( false === is_array( $this->config->config['cache_rejected_uri'] ) ) { + return false; + } + foreach ( $this->config->config['cache_rejected_uri'] as $expr ) { + if ( '' !== $expr && @preg_match( "~$expr~", $uri ) ) { // phpcs:ignore + return true; + } + } + return false; + } + + /** + * Check if user agent is on the rejected list. + * + * @since 2.0 + */ + public function is_user_agent_rejected() { + if ( empty( $this->config->config['cache_rejected_user_agent'] ) || ! is_array( $this->config->config['cache_rejected_user_agent'] ) ) { + return false; + } + + $headers = apache_request_headers(); + if ( empty( $headers['User-Agent'] ) ) { + return false; + } + + foreach ( $this->config->config['cache_rejected_user_agent'] as $user_agent ) { + if ( ! empty( $user_agent ) && stristr( $headers['User-Agent'], $user_agent ) ) { + wp_cache_debug( 'is_user_agent_rejected: found user-agent in list: ' . $headers['User-Agent'] ); + return true; + } + } + + return false; + } + + /** + * Check if we can cache this page. Runs before caching. + * + * @since 2.0 + */ + private function pre_cache_checks() { + $cache_this_page = true; + + if ( ! isset( $_SERVER['REQUEST_METHOD'] ) ) { + $_SERVER['REQUEST_METHOD'] = 'POST'; + } + + if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) { + $_SERVER['HTTP_USER_AGENT'] = ''; + } + + if ( defined( 'DONOTCACHEPAGE' ) ) { + wp_cache_debug( 'DONOTCACHEPAGE defined. Caching disabled.' ); + $cache_this_page = false; + } elseif ( $this->config->config['wp_cache_no_cache_for_get'] && ! empty( $_GET ) ) { // phpcs:ignore + wp_cache_debug( 'Non empty GET request. Caching disabled on settings page. ' . wpsc_dump_get_request() ); + $cache_this_page = false; + } elseif ( 'POST' === $_SERVER['REQUEST_METHOD'] || ! empty( $_POST ) ) { // phpcs:ignore + wp_cache_debug( 'Not caching POST request.' ); + $cache_this_page = false; + } elseif ( 'PUT' === $_SERVER['REQUEST_METHOD'] ) { + wp_cache_debug( 'Not caching PUT request.' ); + $cache_this_page = false; + } elseif ( 'DELETE' === $_SERVER['REQUEST_METHOD'] ) { + wp_cache_debug( 'Not caching DELETE request.' ); + $cache_this_page = false; + } elseif ( isset( $_GET['preview'] ) ) { // phpcs:ignore + wp_cache_debug( 'Not caching preview post.' ); + $cache_this_page = false; + } elseif ( ! in_array( $script, (array) $this->config->config['cache_acceptable_files'], true ) && $this->url_is_rejected( constant( 'WPSC_URI' ) ) ) { + wp_cache_debug( 'URI rejected. Not Caching' ); + $cache_this_page = false; + } elseif ( $this->is_user_agent_rejected() ) { + wp_cache_debug( 'USER AGENT (' . esc_html( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) . ') rejected. Not Caching' ); + $cache_this_page = false; + } + + return $cache_this_page; + } + + /** + * Check if we can cache this page. Uses functions only available after WordPress is loaded. + * + * @since 2.0 + */ + public function post_cache_checks() { + + $cache_this_page = true; + $query_vars = WP_Super_cache_File_Cache::instance()->get_query_vars(); + + if ( isset( $this->config->config['wp_cache_pages']['single'] ) && 1 === $this->config->config['wp_cache_pages']['single'] && isset( $query_vars['is_single'] ) ) { + wp_cache_debug( 'Not caching single post.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['pages'] ) && 1 === $this->config->config['wp_cache_pages']['pages'] && isset( $query_vars['is_page'] ) ) { + wp_cache_debug( 'Not caching single page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['archives'] ) && 1 === $this->config->config['wp_cache_pages']['archives'] && isset( $query_vars['is_archive'] ) ) { + wp_cache_debug( 'Not caching archive page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['tag'] ) && 1 === $this->config->config['wp_cache_pages']['tag'] && isset( $query_vars['is_tag'] ) ) { + wp_cache_debug( 'Not caching tag page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['category'] ) && 1 === $this->config->config['wp_cache_pages']['category'] && isset( $query_vars['is_category'] ) ) { + wp_cache_debug( 'Not caching category page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['frontpage'] ) && 1 === $this->config->config['wp_cache_pages']['frontpage'] && isset( $query_vars['is_front_page'] ) ) { + wp_cache_debug( 'Not caching front page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['home'] ) && 1 === $this->config->config['wp_cache_pages']['home'] && isset( $query_vars['is_home'] ) ) { + wp_cache_debug( 'Not caching home page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['search'] ) && 1 === $this->config->config['wp_cache_pages']['search'] && isset( $query_vars['is_search'] ) ) { + wp_cache_debug( 'Not caching search page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['author'] ) && 1 === $this->config->config['wp_cache_pages']['author'] && isset( $query_vars['is_author'] ) ) { + wp_cache_debug( 'Not caching author page.' ); + $cache_this_page = false; + } elseif ( isset( $this->config->config['wp_cache_pages']['feed'] ) && 1 === $this->config->config['wp_cache_pages']['feed'] && isset( $query_vars['is_feed'] ) ) { + wp_cache_debug( 'Not caching feed.' ); + $cache_this_page = false; + } elseif ( isset( $query_vars['is_rest'] ) ) { + wp_cache_debug( 'REST API detected. Caching disabled.' ); + $cache_this_page = false; + } elseif ( isset( $query_vars['is_robots'] ) ) { + wp_cache_debug( 'robots.txt detected. Caching disabled.' ); + $cache_this_page = false; + } elseif ( isset( $query_vars['is_redirect'] ) ) { + wp_cache_debug( 'Redirect detected. Caching disabled.' ); + $cache_this_page = false; + } elseif ( isset( $query_vars['is_304'] ) ) { + wp_cache_debug( 'HTTP 304 (Not Modified) sent. Caching disabled.' ); + $cache_this_page = false; + } elseif ( empty( $query_vars ) && apply_filters( 'wpsc_only_cache_known_pages', 1 ) ) { + wp_cache_debug( 'ob_handler: query_vars is empty. Not caching unknown page type. Return 0 to the wpsc_only_cache_known_pages filter to cache this page.' ); + $cache_this_page = false; + } elseif ( Wp_Super_Cache_User::instance()->is_caching_disabled() ) { + wp_cache_debug( 'ob_handler: Caching disabled for known user. User logged in or cookie found.' ); + $cache_this_page = false; + } + + return $cache_this_page; + } + + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_Page + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } + +} diff --git a/includes/class-wp-super-cache-setup.php b/includes/class-wp-super-cache-setup.php new file mode 100644 index 00000000..fba792e1 --- /dev/null +++ b/includes/class-wp-super-cache-setup.php @@ -0,0 +1,379 @@ +advanced_cache_filename = untrailingslashit( WP_CONTENT_DIR ) . '/advanced-cache.php'; + $this->plugin_config_filename = untrailingslashit( WP_CONTENT_DIR ) . '/wp-cache-config.php'; + $this->config = Wp_Super_Cache_Config::instance(); + + if ( file_exists( ABSPATH . 'wp-config.php' ) ) { + $this->config_filename = ABSPATH . 'wp-config.php'; + } else { + $this->config_filename = dirname( ABSPATH ) . '/wp-config.php'; + } + + } + + /** + * Create cache storage. + * + * @since 2.0.0 + */ + public function create_cache_storage() { + return apply_filters( 'wpsc_create_cache_storage', true ); + } + + /** + * Create WP_CONTENT/advanced_cache.php + * + * @since 2.0.0 + */ + public function create_advanced_cache() { + // Old plugin loads wp-cache-phase1.php, we load includes/pre-wp-functions.php includes/pre-wp-cache.php. + + // phpcs:disable + $code = <<'; + } +} + +defined( 'ABSPATH' ) || exit; +if ( is_admin() ) { + return; +} + +if ( ! defined( "WPCACHEHOME" ) ) { + define( "WPCACHEHOME", ABSPATH . "wp-content/plugins/wp-super-cache/" ); +} + +if ( false === defined( 'WPCACHEHOME' ) ) { + define( 'ADVANCEDCACHEPROBLEM', 1 ); +} elseif ( ! file_exists( WPCACHEHOME . 'includes/pre-wp-functions.php' ) ) { + define( 'ADVANCEDCACHEPROBLEM', 1 ); +} +if ( defined( 'ADVANCEDCACHEPROBLEM' ) ) { + register_shutdown_function( 'wpcache_broken_message' ); + exit; +} +include_once WPCACHEHOME . '/includes/pre-wp-functions.php'; +include_once WPCACHEHOME . '/includes/pre-wp-cache.php'; +ADVANCEDCACHE; + // phpcs:enable + + if ( ! file_put_contents( $this->advanced_cache_filename, $code ) ) { // phpcs:ignore + return false; + } else { + return true; + } + + } + + /** + * Create WP_CONTENT/wp-cache-config.php + * + * @since 2.0.0 + */ + public function create_config_file() { + $code = << 'bot', 1 => 'ia_archive', 2 => 'slurp', 3 => 'crawl', 4 => 'spider', 5 => 'Yandex' ); + +\$cache_rebuild_files = 1; + +// Disable the file locking system. +// If you are experiencing problems with clearing or creating cache files +// uncommenting this may help. +\$wp_cache_mutex_disabled = 1; + +// Just modify it if you have conflicts with semaphores +\$sem_id = 5419; + +if ( '/' != substr( \$cache_path, -1)) { \$cache_path .= '/'; } + +\$wp_cache_mobile = 0; +\$wp_cache_mobile_whitelist = 'Stand Alone/QNws'; +\$wp_cache_mobile_browsers = 'Android, 2.0 MMP, 240x320, AvantGo, BlackBerry, Blazer, Cellphone, Danger, DoCoMo, Elaine/3.0, EudoraWeb, hiptop, IEMobile, iPhone, iPod, KYOCERA/WX310K, LG/U990, MIDP-2.0, MMEF20, MOT-V, NetFront, Newt, Nintendo Wii, Nitro, Nokia, Opera Mini, Palm, Playstation Portable, portalmmm, Proxinet, ProxiNet, SHARP-TQ-GX10, Small, SonyEricsson, Symbian OS, SymbianOS, TS21i-10, UP.Browser, UP.Link, Windows CE, WinWAP'; + +// change to relocate the supercache plugins directory +\$wp_cache_plugins_dir = WPCACHEHOME . 'plugins'; +// set to 1 to do garbage collection during normal process shutdown instead of wp-cron +\$wp_cache_shutdown_gc = 0; +\$wp_super_cache_late_init = 0; + +// uncomment the next line to enable advanced debugging features +\$wp_super_cache_advanced_debug = 0; +\$wp_super_cache_front_page_text = ''; +\$wp_super_cache_front_page_clear = 0; +\$wp_super_cache_front_page_check = 0; +\$wp_super_cache_front_page_notification = '0'; + +\$wp_cache_anon_only = 0; +\$wp_supercache_cache_list = 0; +\$wp_cache_debug_to_file = 0; +\$wp_super_cache_debug = 0; +\$wp_cache_debug_level = 5; +\$wp_cache_debug_ip = ''; +\$wp_cache_debug_log = ''; +\$wp_cache_debug_email = ''; +\$wp_cache_pages['search'] = 0; +\$wp_cache_pages['feed'] = 0; +\$wp_cache_pages['category'] = 0; +\$wp_cache_pages['home'] = 0; +\$wp_cache_pages['frontpage'] = 0; +\$wp_cache_pages['tag'] = 0; +\$wp_cache_pages['archives'] = 0; +\$wp_cache_pages['pages'] = 0; +\$wp_cache_pages['single'] = 0; +\$wp_cache_pages['author'] = 0; +\$wp_cache_hide_donation = 0; +\$wp_cache_not_logged_in = 0; +\$wp_cache_clear_on_post_edit = 0; +\$wp_cache_hello_world = 0; +\$wp_cache_mobile_enabled = 0; +\$wp_cache_cron_check = 0; +\$wp_cache_mfunc_enabled = 0; +\$wp_cache_make_known_anon = 0; +\$wp_cache_refresh_single_only = 0; +\$wp_cache_mod_rewrite = 0; +\$wp_supercache_304 = 0; +\$wp_cache_front_page_checks = 0; +\$wp_cache_disable_utf8 = 0; +\$wp_cache_no_cache_for_get = 0; +\$cache_scheduled_time = "00:00"; +\$wp_cache_preload_interval = 600; +\$cache_schedule_type = 'interval'; +\$wp_cache_preload_posts = 0; +\$wp_cache_preload_on = 0; +\$wp_cache_preload_taxonomies = 0; +\$wp_cache_preload_email_me = 0; +\$wp_cache_preload_email_volume = 'none'; +\$wp_cache_mobile_prefixes = ''; +\$cached_direct_pages = array(); +\$wpsc_served_header = false; +\$cache_gc_email_me = 0; +\$wpsc_save_headers = 0; +\$cache_schedule_interval = 'daily'; +\$wp_super_cache_comments = 1; +\$wpsc_version = 169; + +CONFIGFILE; + if ( ! file_put_contents( $this->plugin_config_filename, $code ) ) { // phpcs:ignore + return false; + } else { + return true; + } + } + + /** + * Set the homepath setting + * + * @since 2.0.0 + */ + public function set_home_path() { + $home_path = wp_parse_url( site_url() ); + $home_path = trailingslashit( array_key_exists( 'path', $home_path ) ? $home_path['path'] : '' ); + + if ( ! isset( $this->config->config['wp_cache_home_path'] ) ) { + $this->config->update_setting( 'wp_cache_home_path', '/' ); + } + + if ( "$home_path" !== "$wp_cache_home_path" ) { + $this->config->update_setting( 'wp_cache_home_path', $home_path ); + } + + return true; + } + + + /** + * Add WP_CACHE to wp-config.php + * + * @since 2.0.0 + */ + public function add_wp_cache_constant() { + $line = "define( 'WP_CACHE', true );"; + if ( ! defined( 'WP_CACHE' ) ) { + define( 'WP_CACHE', true ); + } + return $this->config->replace_line_in_file( 'define *\( *\'WP_CACHE\'', $line, $this->config_filename ); + } + + /** + * Add WPCACHEHOME to wp-config.php + * + * @since 2.0.0 + */ + public function add_wpcachehome_constant() { + if ( ! defined( 'WPCACHEHOME' ) ) { + define( 'WPCACHEHOME', trailingslashit( dirname( __FILE__ ) ) ); + } + $line = "define( 'WPCACHEHOME', '" . trailingslashit( dirname( dirname( __FILE__ ) ) ) . "' );"; + return $this->config->replace_line_in_file( 'define *\( *\'WPCACHEHOME\'', $line, $this->config_filename ); + } + + /** + * Check if WP_CACHE defined in wp-config.php + * + * @since 2.0.0 + */ + public function is_wp_cache_constant_defined() { + if ( ! defined( 'WP_CACHE' ) ) { + return false; + } + if ( ! strpos( file_get_contents( $this->config_filename ), 'WP_CACHE' ) ) { // phpcs:ignore + return false; + } + + return true; + } + + /** + * Check if WPCACHEHOME defined in wp-config.php + * + * @since 2.0.0 + */ + public function is_wpcachehome_constant_defined() { + if ( ! defined( 'WPCACHEHOME' ) ) { + return false; + } + if ( ! strpos( file_get_contents( $this->config_filename ), 'WPCACHEHOME' ) ) { // phpcs:ignore + return false; + } + + return true; + } + + /** + * Check if advanced-cache.php created. + * + * @since 2.0.0 + */ + public function advanced_cache_exists() { + if ( file_exists( $this->advanced_cache_filename ) ) { + return true; + } else { + return false; + } + } + + /** + * Check if wp-cache-config.php created. + * + * @since 2.0.0 + */ + public function plugin_config_exists() { + if ( file_exists( $this->plugin_config_filename ) ) { + return true; + } else { + return false; + } + } + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_Setup + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} diff --git a/includes/class-wp-super-cache-user.php b/includes/class-wp-super-cache-user.php new file mode 100644 index 00000000..f7c707f0 --- /dev/null +++ b/includes/class-wp-super-cache-user.php @@ -0,0 +1,159 @@ +config = Wp_Super_Cache_Config::instance(); + } + + /** + * Get authentication cookies for visitor. + * + * @since 2.0 + */ + public function get_auth_cookies() { + static $cached_cookies; + + if ( isset( $cached_cookies ) && is_array( $cached_cookies ) ) { + return $cached_cookies; + } + + $cookies = array_keys( $_COOKIE ); + if ( empty( $cookies ) ) { + return array(); + } + + $auth_cookies = array(); + $duplicate_cookies = array(); + + $wp_cookies = array( + 'AUTH_COOKIE' => 'wordpress_', + 'SECURE_AUTH_COOKIE' => 'wordpress_sec_', + 'LOGGED_IN_COOKIE' => 'wordpress_logged_in_', + ); + + foreach ( $wp_cookies as $cookie_const => $cookie_prefix ) { + $cookie_key = strtolower( $cookie_const ); + + if ( defined( $cookie_const ) ) { + if ( in_array( constant( $cookie_const ), $cookies, true ) ) { + $auth_cookies[ $cookie_key ] = constant( $cookie_const ); + } + + continue; + } + + $found_cookies = preg_grep( '`^' . preg_quote( $cookie_prefix, '`' ) . '([0-9a-f]+)$`', $cookies ); + + if ( count( $found_cookies ) === 1 ) { + $auth_cookies[ $cookie_key ] = reset( $found_cookies ); + } elseif ( count( $found_cookies ) > 1 ) { + $duplicate_cookies = array_merge( $duplicate_cookies, $found_cookies ); + $auth_cookies[ $cookie_key ] = $found_cookies; + } + } + + $cookie_hash = defined( 'COOKIEHASH' ) ? COOKIEHASH : ''; + $other_cookies = array( + 'comment_cookie' => 'comment_author_', + 'postpass_cookie' => 'wp-postpass_', + ); + + foreach ( $other_cookies as $cookie_key => $cookie_prefix ) { + + if ( $cookie_hash ) { + if ( in_array( $cookie_prefix . $cookie_hash, $cookies, true ) ) { + $auth_cookies[ $cookie_key ] = $cookie_prefix . $cookie_hash; + } + + continue; + } + + $found_cookies = preg_grep( '`^' . preg_quote( $cookie_prefix, '`' ) . '([0-9a-f]+)$`', $cookies ); + + if ( count( $found_cookies ) === 1 ) { + $auth_cookies[ $cookie_key ] = reset( $found_cookies ); + } elseif ( count( $found_cookies ) > 1 ) { + $duplicate_cookies = array_merge( $duplicate_cookies, $found_cookies ); + $auth_cookies[ $cookie_key ] = $found_cookies; + } + } + + if ( ! $duplicate_cookies ) { + $cached_cookies = $auth_cookies; + } + + if ( empty( $auth_cookies ) ) { + wp_cache_debug( 'get_auth_cookies: no auth cookies detected', 5 ); + } else { + if ( $duplicate_cookies ) { + wp_cache_debug( 'get_auth_cookies: duplicate cookies detected( ' . implode( ', ', $duplicate_cookies ) . ' )', 5 ); + } else { + wp_cache_debug( 'get_auth_cookies: cookies detected: ' . implode( ', ', $auth_cookies ), 5 ); + } + } + + return $auth_cookies; + } + + /** + * Check if caching is disabled for the current visitor based on their cookies + * + * @since 2.0 + */ + public function is_caching_disabled() { + if ( 2 === $this->config->config['wp_cache_not_logged_in'] && $this->get_auth_cookies() ) { + wp_cache_debug( 'User - is_caching_disabled: true because logged in' ); + return true; + } elseif ( 1 === $this->config->config['wp_cache_not_logged_in'] && ! empty( $_COOKIE ) ) { + wp_cache_debug( 'User - is_caching_disabled: true because cookie found' ); + return true; + } else { + wp_cache_debug( 'User - is_caching_disabled: false' ); + return false; + } + } + + /** + * Return an instance of the current class, create one if it doesn't exist + * + * @since 2.0 + * @return Wp_Super_Cache_User + */ + public static function instance() { + + static $instance; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} diff --git a/includes/class-wp-super-cache.php b/includes/class-wp-super-cache.php new file mode 100755 index 00000000..0fea57c6 --- /dev/null +++ b/includes/class-wp-super-cache.php @@ -0,0 +1,244 @@ + + */ +class Wp_Super_Cache { + + /** + * The loader that's responsible for maintaining and registering all hooks that power + * the plugin. + * + * @since 2.0.0 + * @access protected + * @var Wp_Super_Cache_Loader $loader Maintains and registers all hooks for the plugin. + */ + protected $loader; + + /** + * The unique identifier of this plugin. + * + * @since 2.0.0 + * @access protected + * @var string $plugin_name The string used to uniquely identify this plugin. + */ + protected $plugin_name; + + /** + * The current version of the plugin. + * + * @since 2.0.0 + * @access protected + * @var string $version The current version of the plugin. + */ + protected $version; + + /** + * Configuration + * + * @since 2.0.0 + * @access protected + * @var string $config The current configuration of the plugin. + */ + protected $config; + + /** + * Define the core functionality of the plugin. + * + * Set the plugin name and the plugin version that can be used throughout the plugin. + * Load the dependencies, define the locale, and set the hooks for the admin area and + * the public-facing side of the site. + * + * @since 2.0.0 + */ + public function __construct() { + if ( defined( 'WP_SUPER_CACHE_VERSION' ) ) { + $this->version = WP_SUPER_CACHE_VERSION; + } else { + $this->version = '2.0.0'; + } + $this->plugin_name = 'wp-super-cache'; + + $this->load_dependencies(); + $this->set_locale(); + $this->define_admin_hooks(); + $this->define_public_hooks(); + + } + + /** + * Load the required dependencies for this plugin. + * + * Include the following files that make up the plugin: + * + * - Wp_Super_Cache_Loader. Orchestrates the hooks of the plugin. + * - Wp_Super_Cache_i18n. Defines internationalization functionality. + * - Wp_Super_Cache_Admin. Defines all hooks for the admin area. + * - Wp_Super_Cache_Public. Defines all hooks for the public side of the site. + * + * Create an instance of the loader which will be used to register the hooks + * with WordPress. + * + * @since 2.0.0 + * @access private + */ + private function load_dependencies() { + + /** + * Basic functions that are used everywhere, before and after + * WordPress is loaded. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/pre-wp-functions.php'; + + /** + * The class responsible for orchestrating the actions and filters of the + * core plugin. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wp-super-cache-loader.php'; + + /** + * The class responsible for defining internationalization functionality + * of the plugin. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wp-super-cache-i18n.php'; + + /** + * The class responsible for defining all actions that occur in the admin area. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-wp-super-cache-admin.php'; + + /** + * The class responsible for defining all actions that occur in the public-facing + * side of the site. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-wp-super-cache-public.php'; + + /** + * The class responsible for defining configuration functions used by the plugin. + */ + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-wp-super-cache-config.php'; + + $this->config = Wp_Super_cache_Config::instance(); + $this->loader = new Wp_Super_Cache_Loader(); + + } + + /** + * Define the locale for this plugin for internationalization. + * + * Uses the Wp_Super_Cache_i18n class in order to set the domain and to register the hook + * with WordPress. + * + * @since 2.0.0 + * @access private + */ + private function set_locale() { + + $plugin_i18n = new Wp_Super_Cache_i18n(); + + $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' ); + + } + + /** + * Register all of the hooks related to the admin area functionality + * of the plugin. + * + * @since 2.0.0 + * @access private + */ + private function define_admin_hooks() { + + $plugin_admin = new Wp_Super_Cache_Admin( $this->get_plugin_name(), $this->get_version() ); + + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' ); + $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' ); + if ( WPSC_IS_NETWORK ) { + $this->loader->add_action( 'network_admin_menu', $plugin_admin, 'network_admin_menu' ); + } else { + $this->loader->add_action( 'admin_menu', $plugin_admin, 'action_admin_menu' ); + $this->loader->add_action( 'admin_bar_menu', $plugin_admin, 'admin_bar_menu' ); + } + add_action( 'load-settings_page_wp-super-cache', array( $plugin_admin, 'update' ) ); + } + + /** + * Register all of the hooks related to the public-facing functionality + * of the plugin. + * + * @since 2.0.0 + * @access private + */ + private function define_public_hooks() { + + $plugin_public = new Wp_Super_Cache_Public( $this->get_plugin_name(), $this->get_version() ); + + $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' ); + $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' ); + + } + + /** + * Run the loader to execute all of the hooks with WordPress. + * + * @since 2.0.0 + */ + public function run() { + $this->loader->run(); + } + + /** + * The name of the plugin used to uniquely identify it within the context of + * WordPress and to define internationalization functionality. + * + * @since 2.0.0 + * @return string The name of the plugin. + */ + public function get_plugin_name() { + return $this->plugin_name; + } + + /** + * The reference to the class that orchestrates the hooks with the plugin. + * + * @since 2.0.0 + * @return Wp_Super_Cache_Loader Orchestrates the hooks of the plugin. + */ + public function get_loader() { + return $this->loader; + } + + /** + * Retrieve the version number of the plugin. + * + * @since 2.0.0 + * @return string The version number of the plugin. + */ + public function get_version() { + return $this->version; + } + +} diff --git a/includes/index.php b/includes/index.php new file mode 100755 index 00000000..0268c0c4 --- /dev/null +++ b/includes/index.php @@ -0,0 +1,2 @@ +config['cache_page_secret'] ) && $_GET['donotcachepage'] === $wp_super_cache_config->config['cache_page_secret'] +) { + $wp_super_cache_config->config['cache_enabled'] = false; + define( 'DONOTCACHEPAGE', 1 ); +} + +$wp_super_cache_plugins = glob( $wp_super_cache_config->config['wp_cache_plugins_dir'] . '/*.php' ); +if ( is_array( $wp_super_cache_plugins ) ) { + foreach ( $wp_super_cache_plugins as $wp_super_cache_plugin ) { + if ( is_file( $wp_super_cache_plugin ) ) { + require_once $wp_super_cache_plugin; + } + } +} + +if ( isset( $wpsc_plugins ) && is_array( $wpsc_plugins ) ) { + foreach ( $wpsc_plugins as $wp_super_cache_plugin_file ) { + if ( file_exists( ABSPATH . $wp_super_cache_plugin_file ) ) { + include_once ABSPATH . $wp_super_cache_plugin_file; + } + } +} + +if ( + file_exists( WPCACHEHOME . '../wp-super-cache-plugins/' ) && + is_dir( WPCACHEHOME . '../wp-super-cache-plugins/' ) +) { + $wp_super_cache_plugins = glob( WPCACHEHOME . '../wp-super-cache-plugins/*.php' ); + if ( is_array( $wp_super_cache_plugins ) ) { + foreach ( $wp_super_cache_plugins as $wp_super_cache_plugin ) { + if ( is_file( $wp_super_cache_plugin ) ) { + require_once $wp_super_cache_plugin; + } + } + } +} + +$wp_super_cache_start_time = microtime(); + +if ( $wp_super_cache_page->is_cached() ) { + $wp_super_cache_page->serve_page(); +} elseif ( $wp_super_cache_page->is_cacheable() ) { + $wp_super_cache_page->cache_page(); +} diff --git a/includes/pre-wp-functions.php b/includes/pre-wp-functions.php new file mode 100644 index 00000000..47d7e383 --- /dev/null +++ b/includes/pre-wp-functions.php @@ -0,0 +1,55 @@ + + */ +class Wp_Super_Cache_Public { + + /** + * The ID of this plugin. + * + * @since 2.0.0 + * @access private + * @var string $plugin_name The ID of this plugin. + */ + private $plugin_name; + + /** + * The version of this plugin. + * + * @since 2.0.0 + * @access private + * @var string $version The current version of this plugin. + */ + private $version; + + /** + * Initialize the class and set its properties. + * + * @since 2.0.0 + * @param string $plugin_name The name of the plugin. + * @param string $version The version of this plugin. + */ + public function __construct( $plugin_name, $version ) { + + $this->plugin_name = $plugin_name; + $this->version = $version; + + } + + /** + * Register the stylesheets for the public-facing side of the site. + * + * @since 2.0.0 + */ + public function enqueue_styles() { + + /** + * This function is provided for demonstration purposes only. + * + * An instance of this class should be passed to the run() function + * defined in Wp_Super_Cache_Loader as all of the hooks are defined + * in that particular class. + * + * The Wp_Super_Cache_Loader will then create the relationship + * between the defined hooks and the functions defined in this + * class. + */ + + wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wp-super-cache-public.css', array(), $this->version, 'all' ); + + } + + /** + * Register the JavaScript for the public-facing side of the site. + * + * @since 2.0.0 + */ + public function enqueue_scripts() { + + /** + * This function is provided for demonstration purposes only. + * + * An instance of this class should be passed to the run() function + * defined in Wp_Super_Cache_Loader as all of the hooks are defined + * in that particular class. + * + * The Wp_Super_Cache_Loader will then create the relationship + * between the defined hooks and the functions defined in this + * class. + */ + + wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wp-super-cache-public.js', array( 'jquery' ), $this->version, false ); + + } + +} diff --git a/public/css/wp-super-cache-public.css b/public/css/wp-super-cache-public.css new file mode 100755 index 00000000..65bbf963 --- /dev/null +++ b/public/css/wp-super-cache-public.css @@ -0,0 +1,4 @@ +/** + * All of the CSS for your public-facing functionality should be + * included in this file. + */ \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100755 index 00000000..7751eb07 --- /dev/null +++ b/public/index.php @@ -0,0 +1,2 @@ + + + diff --git a/uninstall.php b/uninstall.php new file mode 100755 index 00000000..f29f3d3b --- /dev/null +++ b/uninstall.php @@ -0,0 +1,31 @@ +run(); + +} +run_wp_super_cache();