PluginProbe ʕ •ᴥ•ʔ
LiteSpeed Cache / 1.0.15
LiteSpeed Cache v1.0.15
trunk 1.0.15 1.9.1.1 2.9.9.2 3.6.4 4.6 5.7.0.1 6.5.4 7.0.0.1 7.0.1 7.1 7.2 7.3 7.3.0.1 7.4 7.5 7.5.0.1 7.6 7.6.1 7.6.2 7.7 7.8 7.8.0.1 7.8.1
litespeed-cache / includes / class-litespeed-cache.php
litespeed-cache / includes Last commit date
advanced-cache.php 8 years ago class-litespeed-cache-config.php 8 years ago class-litespeed-cache-tags.php 8 years ago class-litespeed-cache.php 8 years ago
class-litespeed-cache.php
2631 lines
1 <?php
2
3
4 /**
5 * The core plugin class.
6 *
7 * This is used to define internationalization, admin-specific hooks, and
8 * public-facing site hooks.
9 *
10 * Also maintains the unique identifier of this plugin as well as the current
11 * version of the plugin.
12 *
13 * @since 1.0.0
14 * @package LiteSpeed_Cache
15 * @subpackage LiteSpeed_Cache/includes
16 * @author LiteSpeed Technologies <info@litespeedtech.com>
17 */
18 class LiteSpeed_Cache
19 {
20
21 private static $instance ;
22 private static $log_path = '';
23
24 const PLUGIN_NAME = 'litespeed-cache' ;
25 const PLUGIN_VERSION = '1.0.15' ;
26
27 const LSCOOKIE_VARY_NAME = 'LSCACHE_VARY_COOKIE' ;
28 const LSCOOKIE_DEFAULT_VARY = '_lscache_vary' ;
29 const LSCOOKIE_VARY_LOGGED_IN = 1;
30 const LSCOOKIE_VARY_COMMENTER = 2;
31
32 const ADMINQS_KEY = 'LSCWP_CTRL';
33 const ADMINQS_DISMISS = 'DISMISS';
34 const ADMINQS_PURGE = 'PURGE';
35 const ADMINQS_PURGEBY = 'PURGEBY';
36 const ADMINQS_PURGEALL = 'PURGEALL';
37 const ADMINQS_PURGESINGLE = 'PURGESINGLE';
38 const ADMINQS_SHOWHEADERS = 'SHOWHEADERS';
39
40 const ADMINNONCE_PURGEALL = 'litespeed-purgeall';
41 const ADMINNONCE_PURGENETWORKALL = 'litespeed-purgeall-network';
42 const ADMINNONCE_PURGEBY = 'litespeed-purgeby';
43 const ADMINNONCE_DISMISS = 'litespeed-dismiss';
44
45 const CACHECTRL_NOCACHE = 0;
46 const CACHECTRL_CACHE = 1;
47 const CACHECTRL_PURGE = 2;
48 const CACHECTRL_PURGESINGLE = 3;
49
50 const CACHECTRL_SHOWHEADERS = 128; // (1<<7)
51 const CACHECTRL_STALE = 64; // (1<<6)
52
53 const WHM_TRANSIENT = 'lscwp_whm_install';
54 const WHM_TRANSIENT_VAL = 'whm_install';
55 const NETWORK_TRANSIENT_COUNT = 'lscwp_network_count';
56
57 protected $plugin_dir ;
58 protected $config ;
59 protected $current_vary;
60 protected $cachectrl = self::CACHECTRL_NOCACHE;
61 protected $pub_purge_tags = array();
62 protected $error_status = false;
63
64 /**
65 * Define the core functionality of the plugin.
66 *
67 * Set the plugin name and the plugin version that can be used throughout the plugin.
68 * Load the dependencies, define the locale, and set the hooks for the admin area and
69 * the public-facing side of the site.
70 *
71 * @since 1.0.0
72 */
73 private function __construct()
74 {
75 $cur_dir = dirname(__FILE__) ;
76 require_once $cur_dir . '/class-litespeed-cache-config.php' ;
77 include_once $cur_dir . '/class-litespeed-cache-tags.php';
78 // Load third party detection.
79 include_once $cur_dir . '/../thirdparty/litespeed-cache-thirdparty-registry.php';
80
81 $theme_root = get_theme_root();
82 $content_dir = dirname($theme_root);
83
84 $should_debug = LiteSpeed_Cache_Config::OPID_ENABLED_DISABLE;
85 self::$log_path = $content_dir . '/debug.log';
86 $this->config = new LiteSpeed_Cache_Config() ;
87 if ($this->config->get_option(LiteSpeed_Cache_Config::OPID_ENABLED)) {
88 $should_debug = intval($this->config->get_option(
89 LiteSpeed_Cache_Config::OPID_DEBUG));
90 }
91
92 switch ($should_debug) {
93 // NOTSET is used as check admin IP here.
94 case LiteSpeed_Cache_Config::OPID_ENABLED_NOTSET:
95 $ips = $this->config->get_option(LiteSpeed_Cache_Config::OPID_ADMIN_IPS);
96 if (strpos($ips, $_SERVER['REMOTE_ADDR']) === false) {
97 break;
98 }
99 // fall through
100 case LiteSpeed_Cache_Config::OPID_ENABLED_ENABLE:
101 define ('LSCWP_LOG', true);
102 break;
103 case LiteSpeed_Cache_Config::OPID_ENABLED_DISABLE:
104 break;
105 default:
106 break;
107 }
108
109 $this->plugin_dir = plugin_dir_path($cur_dir) ;
110 $plugin_file = $this->plugin_dir . 'litespeed-cache.php' ;
111 register_activation_hook($plugin_file, array( $this, 'register_activation' )) ;
112 register_deactivation_hook($plugin_file, array( $this, 'register_deactivation' )) ;
113
114 add_action('after_setup_theme', array( $this, 'init' )) ;
115 }
116
117 /**
118 * The entry point for LiteSpeed Cache.
119 *
120 * @since 1.0.0
121 * @access public
122 */
123 public static function run()
124 {
125 if ( ! isset(self::$instance) ) {
126 self::$instance = new LiteSpeed_Cache() ;
127 }
128 }
129
130 /**
131 * Get the LiteSpeed_Cache object.
132 *
133 * @since 1.0.0
134 * @access public
135 * @return LiteSpeed_Cache Static instance of the LiteSpeed_Cache class.
136 */
137 public static function plugin()
138 {
139 return self::$instance ;
140 }
141
142 /**
143 * Get the LiteSpeed_Cache_Config object. Can be called outside of a
144 * LiteSpeed_Cache object.
145 *
146 * @since 1.0.0
147 * @access public
148 * @param string $opt_id An option ID if getting an option.
149 * @return LiteSpeed_Cache_Config The configurations for the accessed page.
150 */
151 public static function config($opt_id = '')
152 {
153 $conf = self::$instance->config;
154 if ((empty($opt_id)) || (!is_string($opt_id))) {
155 return $conf;
156 }
157 return $conf->get_option($opt_id);
158 }
159
160 /**
161 * Sets up the log tag and creates initial log messages.
162 *
163 * @since 1.0.12
164 * @access private
165 */
166 private static function setup_debug_log()
167 {
168 if (!defined('LSCWP_LOG_TAG')) {
169 define('LSCWP_LOG_TAG',
170 'LSCACHE_WP_blogid_' . get_current_blog_id());
171 }
172 self::log_request();
173
174 }
175
176 /**
177 * Formats the log message with a consistent prefix.
178 *
179 * @since 1.0.12
180 * @access private
181 * @param string $mesg The log message to write.
182 * @return string The formatted log message.
183 */
184 private static function format_message($mesg)
185 {
186 $tag = defined('LSCWP_LOG_TAG') ? constant('LSCWP_LOG_TAG') : 'LSCACHE_WP';
187 $formatted = sprintf("%s [%s:%s] [%s] %s\n", date('r'),
188 $_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_PORT'],
189 $tag, $mesg);
190 return $formatted;
191 }
192
193 /**
194 * Logs a debug message.
195 *
196 * @since 1.0.0
197 * @access public
198 * @param string $mesg The debug message.
199 */
200 public static function debug_log($mesg)
201 {
202 $formatted = self::format_message($mesg);
203 file_put_contents(self::$log_path, $formatted, FILE_APPEND);
204 }
205
206 /**
207 * Create the initial log messages with the request parameters.
208 *
209 * @since 1.0.12
210 * @access private
211 */
212 private static function log_request()
213 {
214 $SERVERVARS = array(
215 'Query String' => '',
216 'HTTP_USER_AGENT' => '',
217 'HTTP_ACCEPT_ENCODING' => '',
218 'HTTP_COOKIE' => '',
219 'X-LSCACHE' => '',
220 'LSCACHE_VARY_COOKIE' => '',
221 'LSCACHE_VARY_VALUE' => ''
222 );
223 $SERVER = array_merge($SERVERVARS, $_SERVER);
224 $params = array(
225 sprintf('%s %s %s', $SERVER['REQUEST_METHOD'],
226 $SERVER['SERVER_PROTOCOL'],
227 strtok($SERVER['REQUEST_URI'], '?')),
228 'Query String: ' . $SERVER['QUERY_STRING'],
229 'User Agent: ' . $SERVER['HTTP_USER_AGENT'],
230 'Accept Encoding: ' . $SERVER['HTTP_ACCEPT_ENCODING'],
231 'Cookie: ' . $SERVER['HTTP_COOKIE'],
232 'X-LSCACHE: ' . ($SERVER['X-LSCACHE'] ? 'true' : 'false'),
233 'LSCACHE_VARY_COOKIE: ' . $SERVER['LSCACHE_VARY_COOKIE'],
234 'LSCACHE_VARY_VALUE: ' . $SERVER['LSCACHE_VARY_VALUE'],
235 );
236
237 $request = array_map('self::format_message', $params);
238 file_put_contents(self::$log_path, $request, FILE_APPEND);
239 }
240
241 /**
242 * The activation hook callback.
243 *
244 * Attempts to set up the advanced cache file. If it fails for any reason,
245 * the plugin will not activate.
246 *
247 * @since 1.0.0
248 * @access public
249 */
250 public function register_activation()
251 {
252 $count = 0;
253 if (!defined('LSCWP_LOG_TAG')) {
254 define('LSCWP_LOG_TAG',
255 'LSCACHE_WP_activate_' . get_current_blog_id());
256 }
257 $this->try_copy_advanced_cache();
258 LiteSpeed_Cache_Config::wp_cache_var_setter(true);
259
260 include_once $this->plugin_dir . '/admin/class-litespeed-cache-admin.php';
261 require_once $this->plugin_dir . '/admin/class-litespeed-cache-admin-display.php';
262 require_once $this->plugin_dir . '/admin/class-litespeed-cache-admin-rules.php';
263 if (is_multisite()) {
264 $count = $this->get_network_count();
265 if ($count !== false) {
266 $count = intval($count) + 1;
267 set_site_transient(self::NETWORK_TRANSIENT_COUNT, $count,
268 DAY_IN_SECONDS);
269 }
270 }
271 do_action('litespeed_cache_detect_thirdparty');
272 $this->config->plugin_activation($count);
273 self::generate_environment_report();
274
275 if (defined('LSCWP_PLUGIN_NAME')) {
276 set_transient(self::WHM_TRANSIENT, self::WHM_TRANSIENT_VAL);
277 }
278 }
279
280 /**
281 * Get the blog ids for the network. Accepts function arguments.
282 *
283 * Will use wp_get_sites for WP versions less than 4.6
284 *
285 * @since 1.0.12
286 * @access private
287 * @param array $args Arguments to pass into get_sites/wp_get_sites.
288 * @return array The array of blog ids.
289 */
290 private static function get_network_ids($args = array())
291 {
292 global $wp_version;
293 if (version_compare($wp_version, '4.6', '<')) {
294 $blogs = wp_get_sites($args);
295 if (!empty($blogs)) {
296 foreach ($blogs as $key => $blog) {
297 $blogs[$key] = $blog['blog_id'];
298 }
299 }
300 }
301 else {
302 $args['fields'] = 'ids';
303 $blogs = get_sites($args);
304 }
305 return $blogs;
306 }
307
308 /**
309 * Gets the count of active litespeed cache plugins on multisite.
310 *
311 * @since 1.0.12
312 * @access private
313 * @return mixed The count on success, false on failure.
314 */
315 private function get_network_count()
316 {
317 $count = get_site_transient(self::NETWORK_TRANSIENT_COUNT);
318 if ($count !== false) {
319 return intval($count);
320 }
321 // need to update
322 $basename = plugin_basename($this->plugin_dir . 'litespeed-cache.php');
323 $default = array();
324 $count = 0;
325
326 $sites = self::get_network_ids(array('deleted' => 0));
327 if (empty($sites)) {
328 return false;
329 }
330
331 foreach ($sites as $site) {
332 $plugins = get_blog_option($site->blog_id, 'active_plugins',
333 $default);
334 if (in_array($basename, $plugins, true)) {
335 $count++;
336 }
337 }
338 if (is_plugin_active_for_network($basename)) {
339 $count++;
340 }
341 return $count;
342 }
343
344 /**
345 * Is this deactivate call the last active installation on the multisite
346 * network?
347 *
348 * @since 1.0.12
349 * @access private
350 * @return bool True if yes, false otherwise.
351 */
352 private function is_deactivate_last()
353 {
354 $count = $this->get_network_count();
355 if ($count === false) {
356 return false;
357 }
358 if ($count !== 1) {
359 // Not deactivating the last one.
360 $count--;
361 set_site_transient(self::NETWORK_TRANSIENT_COUNT, $count,
362 DAY_IN_SECONDS);
363 return false;
364 }
365
366 delete_site_transient(self::NETWORK_TRANSIENT_COUNT);
367 return true;
368 }
369
370 /**
371 * The deactivation hook callback.
372 *
373 * Initializes all clean up functionalities.
374 *
375 * @since 1.0.0
376 * @access public
377 */
378 public function register_deactivation()
379 {
380 require_once $this->plugin_dir
381 . '/admin/class-litespeed-cache-admin-display.php';
382 require_once $this->plugin_dir
383 . '/admin/class-litespeed-cache-admin-rules.php';
384 if (!defined('LSCWP_LOG_TAG')) {
385 define('LSCWP_LOG_TAG',
386 'LSCACHE_WP_deactivate_' . get_current_blog_id());
387 }
388 $this->purge_all();
389
390 if (is_multisite()) {
391 if (is_network_admin()) {
392 $options = get_site_option(
393 LiteSpeed_Cache_Config::OPTION_NAME);
394 if ((isset($options)) && (is_array($options))) {
395 $opt_str = serialize($options);
396 update_site_option(LiteSpeed_Cache_Config::OPTION_NAME,
397 $opt_str);
398 }
399 }
400 if (!$this->is_deactivate_last()) {
401 if ((is_network_admin()) && (isset($opt_str))
402 && ($options[LiteSpeed_Cache_Config::NETWORK_OPID_ENABLED])) {
403 $reset = LiteSpeed_Cache_Config::get_rule_reset_options();
404 $errors = array();
405 LiteSpeed_Cache_Admin_Rules::get_instance()
406 ->validate_common_rewrites($reset, $errors);
407 }
408 return;
409 }
410 }
411
412 $adv_cache_path = dirname(self::$log_path) . '/advanced-cache.php';
413 if (file_exists($adv_cache_path) && is_writable($adv_cache_path) &&
414 ((LiteSpeed_Cache::config(LiteSpeed_Cache_Config::OPID_CHECK_ADVANCEDCACHE) && defined('LSCACHE_ADV_CACHE') )
415 || strpos(file_get_contents($adv_cache_path), 'LSCACHE_ADV_CACHE') !== false ) ) {
416 unlink($adv_cache_path) ;
417 }
418 else {
419 error_log('Failed to remove advanced-cache.php, file does not exist or is not writable!') ;
420 }
421
422 if (!LiteSpeed_Cache_Config::wp_cache_var_setter(false)) {
423 error_log('In wp-config.php: WP_CACHE could not be set to false during deactivation!') ;
424 }
425 LiteSpeed_Cache_Admin_Rules::clear_rules();
426 // delete in case it's not deleted prior to deactivation.
427 delete_transient(self::WHM_TRANSIENT);
428 }
429
430 /**
431 * The plugin initializer.
432 *
433 * This function checks if the cache is enabled and ready to use, then
434 * determines what actions need to be set up based on the type of user
435 * and page accessed. Output is buffered if the cache is enabled.
436 *
437 * @since 1.0.0
438 * @access public
439 */
440 public function init()
441 {
442 $module_enabled = $this->config->is_plugin_enabled();
443 $is_ajax = (defined('DOING_AJAX') && DOING_AJAX);
444
445 if (defined('LSCWP_LOG')) {
446 self::setup_debug_log();
447 }
448
449 if ( is_admin() ) {
450 $this->load_admin_actions($module_enabled, $is_ajax);
451 }
452 else {
453 $this->load_nonadmin_actions($module_enabled);
454 }
455
456 if ((!$module_enabled) || (!defined('LSCACHE_ADV_CACHE'))
457 || (constant('LSCACHE_ADV_CACHE') === false)) {
458 return;
459 }
460
461 define('LITESPEED_CACHE_ENABLED', true);
462 ob_start();
463 //TODO: Uncomment this when esi is implemented.
464 // add_action('init', array($this, 'check_admin_bar'), 0);
465 // $this->add_actions_esi();
466
467 $bad_cookies = $this->setup_cookies();
468
469 if ( $this->check_esi_page()) {
470 return;
471 }
472
473 if (($bad_cookies) || ($this->check_user_logged_in())
474 || ($this->check_cookies())) {
475 $this->load_logged_in_actions() ;
476 }
477 else {
478 $this->load_logged_out_actions();
479 }
480
481 $this->load_public_actions() ;
482 if ($is_ajax) {
483 add_action('init', array($this, 'detect'), 4);
484 }
485 elseif ((is_admin()) || (is_network_admin())) {
486 add_action('admin_init', array($this, 'detect'), 0);
487 }
488 else {
489 add_action('wp', array($this, 'detect'), 4);
490 }
491 }
492
493 /**
494 * Callback used to call the detect third party action.
495 *
496 * The detect action is used by third party plugin integration classes
497 * to determine if they should add the rest of their hooks.
498 *
499 * @since 1.0.5
500 * @access public
501 */
502 public function detect()
503 {
504 do_action('litespeed_cache_detect_thirdparty');
505 }
506
507 /**
508 * Get the LiteSpeed_Cache_Config object.
509 *
510 * @since 1.0.0
511 * @access public
512 * @return LiteSpeed_Cache_Config The configurations for the accessed page.
513 */
514 public function get_config()
515 {
516 return $this->config ;
517 }
518
519 /**
520 * Try to copy our advanced-cache.php file to the wordpress directory.
521 *
522 * @since 1.0.11
523 * @access public
524 * @return boolean True on success, false on failure.
525 */
526 public function try_copy_advanced_cache()
527 {
528 $adv_cache_path = dirname(self::$log_path) . '/advanced-cache.php';
529 if ((file_exists($adv_cache_path))
530 && ((filesize($adv_cache_path) !== 0)
531 || (!is_writable($adv_cache_path)))) {
532 return false;
533 }
534 copy($this->plugin_dir . '/includes/advanced-cache.php',
535 $adv_cache_path);
536 include($adv_cache_path);
537 $ret = defined('LSCACHE_ADV_CACHE');
538 return $ret;
539 }
540 /**
541 * Define the locale for this plugin for internationalization.
542 *
543 * Uses the LiteSpeed_Cache_i18n class in order to set the domain and to register the hook
544 * with WordPress.
545 *
546 * @since 1.0.0
547 * @access private
548 */
549 private function set_locale()
550 {
551 load_plugin_textdomain(self::PLUGIN_NAME, false,
552 dirname(dirname(plugin_basename(__FILE__))) . '/languages/') ;
553 }
554
555 /**
556 * Register all of the hooks related to the admin area functionality
557 * of the plugin.
558 *
559 * @since 1.0.0
560 * @access private
561 * @param boolean $module_enabled Whether the module is enabled or not.
562 * @param boolean $is_ajax Whether the request is an ajax request or not.
563 */
564 private function load_admin_actions( $module_enabled, $is_ajax )
565 {
566 /**
567 * The class responsible for defining all actions that occur in the admin area.
568 */
569 require_once $this->plugin_dir . 'admin/class-litespeed-cache-admin.php' ;
570 require_once $this->plugin_dir . 'admin/class-litespeed-cache-admin-display.php' ;
571 require_once $this->plugin_dir . 'admin/class-litespeed-cache-admin-rules.php' ;
572
573 $admin = new LiteSpeed_Cache_Admin(self::PLUGIN_NAME, self::PLUGIN_VERSION) ;
574
575 add_action('load-litespeed-cache_page_lscache-edit-htaccess',
576 'LiteSpeed_Cache_Admin_Rules::htaccess_editor_save');
577 add_action('load-litespeed-cache_page_lscache-settings',
578 array($admin, 'validate_network_settings'));
579 if (is_multisite()) {
580 add_action('update_site_option_' . LiteSpeed_Cache_Config::OPTION_NAME,
581 'LiteSpeed_Cache::update_environment_report', 10, 2);
582 }
583 else {
584 add_action('update_option_' . LiteSpeed_Cache_Config::OPTION_NAME,
585 'LiteSpeed_Cache::update_environment_report', 10, 2);
586 }
587 $this->set_locale() ;
588 if (!$module_enabled) {
589 return;
590 }
591
592 if ((is_multisite()) && (is_network_admin())) {
593 $manage = 'manage_network_options';
594 }
595 else {
596 $manage = 'manage_options';
597 }
598
599 //register purge_all actions
600 $purge_all_events = array(
601 'switch_theme',
602 'wp_create_nav_menu', 'wp_update_nav_menu', 'wp_delete_nav_menu',
603 'create_term', 'edit_terms', 'delete_term',
604 'add_link', 'edit_link', 'delete_link'
605 );
606 foreach ( $purge_all_events as $event ) {
607 add_action($event, array( $this, 'purge_all' ));
608 }
609 global $pagenow;
610 if ($pagenow === 'plugins.php') {
611 add_action('wp_default_scripts',
612 array($admin, 'set_update_text'), 0);
613 add_action('wp_default_scripts',
614 array($admin, 'unset_update_text'), 20);
615
616 }
617 if ($is_ajax) {
618 add_action('wp_ajax_lscache_cli', array($this, 'check_admin_ip'));
619 add_action('wp_ajax_nopriv_lscache_cli',
620 array($this, 'check_admin_ip'));
621 add_action('wp_ajax_lscache_dismiss_whm', array($this, 'check_admin_ip'));
622 add_action('wp_ajax_nopriv_lscache_dismiss_whm',
623 array($this, 'check_admin_ip'));
624 }
625 else {
626 add_action('admin_init', array($this, 'check_admin_ip'), 6);
627 }
628 if ($this->config->get_option(LiteSpeed_Cache_Config::OPID_PURGE_ON_UPGRADE)) {
629 add_action('upgrader_process_complete', array($this, 'purge_all'));
630 }
631
632 //Checks if WP_CACHE is defined and true in the wp-config.php file.
633 if (!current_user_can($manage)) {
634 return;
635 }
636 add_action('wp_before_admin_bar_render',
637 array($admin, 'add_quick_purge'));
638
639 if ((defined('WP_CACHE')) && (constant('WP_CACHE') == true)) {
640 return;
641 }
642 $add_var = LiteSpeed_Cache_Config::wp_cache_var_setter(true);
643 if ($add_var !== true) {
644 LiteSpeed_Cache_Admin_Error::add_error($add_var);
645 }
646 }
647
648 /**
649 * Register all of the hooks for non admin pages.
650 * of the plugin.
651 *
652 * @since 1.0.7
653 * @access private
654 * @param boolean $module_enabled Whether the module is enabled or not.
655 */
656 private function load_nonadmin_actions( $module_enabled )
657 {
658 if ($module_enabled) {
659 add_action('wp', array($this, 'check_admin_ip'), 6);
660 }
661 }
662
663 /**
664 * Register all the hooks for logged in users.
665 *
666 * @since 1.0.0
667 * @access private
668 */
669 private function load_logged_in_actions()
670 {
671 }
672
673 /**
674 * Register all the hooks for non-logged in users.
675 *
676 * @since 1.0.0
677 * @access private
678 */
679 private function load_logged_out_actions()
680 {
681 // user is not logged in
682 add_action('wp', array( $this, 'check_cacheable' ), 5) ;
683 add_action('login_init', array( $this, 'check_login_cacheable' ), 5) ;
684 add_filter('status_header', array($this, 'check_error_codes'), 10, 2);
685
686 $cache_res = $this->config->get_option(
687 LiteSpeed_Cache_Config::OPID_CACHE_RES);
688 if ($cache_res) {
689 require_once $this->plugin_dir . 'admin/class-litespeed-cache-admin-rules.php';
690 $uri = esc_url($_SERVER["REQUEST_URI"]);
691 $pattern = '!' . LiteSpeed_Cache_Admin_Rules::$RW_PATTERN_RES . '!';
692 if (preg_match($pattern, $uri)) {
693 add_action('wp_loaded', array( $this, 'check_cacheable' ), 5) ;
694 }
695 }
696 }
697
698 /**
699 * Register all of the hooks related to the all users
700 * of the plugin.
701 *
702 * @since 1.0.0
703 * @access private
704 */
705 private function load_public_actions()
706 {
707 //register purge actions
708 $purge_post_events = array(
709 'edit_post',
710 'save_post',
711 'deleted_post',
712 'trashed_post',
713 'delete_attachment',
714 ) ;
715 foreach ( $purge_post_events as $event ) {
716 // this will purge all related tags
717 add_action($event, array( $this, 'purge_post' ), 10, 2) ;
718 }
719
720 add_action('wp_update_comment_count',
721 array($this, 'purge_feeds'));
722
723 add_action('shutdown', array($this, 'send_headers'), 0);
724 // purge_single_post will only purge that post by tag
725 add_action('lscwp_purge_single_post', array($this, 'purge_single_post'));
726
727 // register recent posts widget tag before theme renders it to make it work
728 add_filter('widget_posts_args', array($this, 'register_tag_widget_recent_posts'));
729
730 // TODO: private purge?
731 // TODO: purge by category, tag?
732 }
733
734 /**
735 * Register purge tag for pages with recent posts widget
736 * of the plugin.
737 *
738 * @since 1.0.15
739 * @access public
740 * @param array $params [wordpress params for widget_posts_args]
741 */
742 public function register_tag_widget_recent_posts($params){
743 LiteSpeed_Cache_Tags::add_cache_tag(LiteSpeed_Cache_Tags::TYPE_PAGES_WITH_RECENT_POSTS);
744 return $params;
745 }
746
747 /**
748 * Adds the actions used for setting up cookies on log in/out.
749 *
750 * Also checks if the database matches the rewrite rule.
751 *
752 * @since 1.0.4
753 * @access private
754 * @return boolean True if cookies are bad, false otherwise.
755 */
756 private function setup_cookies()
757 {
758 $ret = false;
759 // Set vary cookie for logging in user, unset for logging out.
760 add_action('set_logged_in_cookie', array( $this, 'set_user_cookie'), 10, 5);
761 add_action('clear_auth_cookie', array( $this, 'set_user_cookie'), 10, 5);
762
763 if (!$this->config->get_option(LiteSpeed_Cache_Config::OPID_CACHE_COMMENTERS)) {
764 // Set vary cookie for commenter.
765 add_action('set_comment_cookies', array( $this, 'set_comment_cookie'), 10, 2);
766 }
767 if (is_multisite()) {
768 $options = $this->get_config()->get_site_options();
769 if (is_array($options)) {
770 $db_cookie = $options[
771 LiteSpeed_Cache_Config::OPID_LOGIN_COOKIE];
772 }
773 }
774 else {
775 $db_cookie = $this->get_config()
776 ->get_option(LiteSpeed_Cache_Config::OPID_LOGIN_COOKIE);
777 }
778
779 if (!isset($_SERVER[self::LSCOOKIE_VARY_NAME])) {
780 if (!empty($db_cookie)) {
781 $ret = true;
782 if (is_multisite() ? is_network_admin() : is_admin()) {
783 LiteSpeed_Cache_Admin_Display::show_error_cookie();
784 }
785 }
786 $this->current_vary = self::LSCOOKIE_DEFAULT_VARY;
787 return $ret;
788 }
789 elseif (empty($db_cookie)) {
790 $this->current_vary = self::LSCOOKIE_DEFAULT_VARY;
791 return $ret;
792 }
793 // beyond this point, need to do more processing.
794 $vary_arr = explode(',', $_SERVER[self::LSCOOKIE_VARY_NAME]);
795
796 if (in_array($db_cookie, $vary_arr)) {
797 $this->current_vary = $db_cookie;
798 return $ret;
799 }
800 elseif ((is_multisite() ? is_network_admin() : is_admin())) {
801 LiteSpeed_Cache_Admin_Display::show_error_cookie();
802 }
803 $ret = true;
804 $this->current_vary = self::LSCOOKIE_DEFAULT_VARY;
805 return $ret;
806 }
807
808 /**
809 * Do the action of setting the vary cookie.
810 *
811 * Since we are using bitwise operations, if the resulting cookie has
812 * value zero, we need to set the expire time appropriately.
813 *
814 * @since 1.0.4
815 * @access private
816 * @param integer $update_val The value to update.
817 * @param integer $expire Expire time.
818 * @param boolean $ssl True if ssl connection, false otherwise.
819 * @param boolean $httponly True if the cookie is for http requests only, false otherwise.
820 */
821 private function do_set_cookie($update_val, $expire, $ssl = false, $httponly = false)
822 {
823 $curval = 0;
824 if (isset($_COOKIE[$this->current_vary]))
825 {
826 $curval = intval($_COOKIE[$this->current_vary]);
827 }
828
829 // not, remove from curval.
830 if ($update_val < 0) {
831 // If cookie will no longer exist, delete the cookie.
832 if (($curval == 0) || ($curval == (~$update_val))) {
833 // Use a year in case of bad local clock.
834 $expire = time() - 31536001;
835 }
836 $curval &= $update_val;
837 }
838 else { // add to curval.
839 $curval |= $update_val;
840 }
841 setcookie($this->current_vary, $curval, $expire, COOKIEPATH,
842 COOKIE_DOMAIN, $ssl, $httponly);
843 }
844
845 /**
846 * Sets cookie denoting logged in/logged out.
847 *
848 * This will notify the server on next page request not to serve from cache.
849 *
850 * @since 1.0.1
851 * @access public
852 * @param mixed $logged_in_cookie
853 * @param string $expire Expire time.
854 * @param integer $expiration Expire time.
855 * @param integer $user_id The user's id.
856 * @param string $action Whether the user is logging in or logging out.
857 */
858 public function set_user_cookie($logged_in_cookie = false, $expire = ' ',
859 $expiration = 0, $user_id = 0, $action = 'logged_out')
860 {
861 if ($action == 'logged_in') {
862 $this->do_set_cookie(self::LSCOOKIE_VARY_LOGGED_IN, $expire, is_ssl(), true);
863 }
864 else {
865 $this->do_set_cookie(~self::LSCOOKIE_VARY_LOGGED_IN,
866 time() + apply_filters( 'comment_cookie_lifetime', 30000000 ));
867 }
868 }
869
870 /**
871 * Sets a cookie that marks the user as a commenter.
872 *
873 * This will notify the server on next page request not to serve
874 * from cache if that setting is enabled.
875 *
876 * @since 1.0.4
877 * @access public
878 * @param mixed $comment Comment object
879 * @param mixed $user The visiting user object.
880 */
881 public function set_comment_cookie($comment, $user)
882 {
883 if ( $user->exists() ) {
884 return;
885 }
886 $comment_cookie_lifetime = time() + apply_filters( 'comment_cookie_lifetime', 30000000 );
887 $this->do_set_cookie(self::LSCOOKIE_VARY_COMMENTER, $comment_cookie_lifetime);
888 }
889
890 /**
891 * Adds new purge tags to the array of purge tags for the request.
892 *
893 * @since 1.0.1
894 * @access private
895 * @param mixed $tags Tags to add to the list.
896 * @param boolean $is_public Whether to add public or private purge tags.
897 */
898 private function add_purge_tags($tags, $is_public = true)
899 {
900 //TODO: implement private tag add
901 if (is_array($tags)) {
902 $this->pub_purge_tags = array_merge($this->pub_purge_tags, $tags);
903 }
904 else {
905 $this->pub_purge_tags[] = $tags;
906 }
907 $this->pub_purge_tags = array_unique($this->pub_purge_tags);
908 }
909
910 /**
911 * Alerts LiteSpeed Web Server to purge all pages.
912 *
913 * For multisite installs, if this is called by a site admin (not network admin),
914 * it will only purge all posts associated with that site.
915 *
916 * @since 1.0.0
917 * @access public
918 */
919 public function purge_all()
920 {
921 $this->add_purge_tags('*');
922 }
923
924 /**
925 * Alerts LiteSpeed Web Server to purge the front page.
926 *
927 * @since 1.0.3
928 * @access public
929 */
930 public function purge_front()
931 {
932 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_FRONTPAGE);
933 }
934
935 /**
936 * Alerts LiteSpeed Web Server to purge pages.
937 *
938 * @since 1.0.15
939 * @access public
940 */
941 public function purge_pages()
942 {
943 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_PAGES);
944 }
945
946 /**
947 * Alerts LiteSpeed Web Server to purge error pages.
948 *
949 * @since 1.0.14
950 * @access public
951 */
952 public function purge_errors()
953 {
954 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_ERROR);
955 if (!isset($_POST[LiteSpeed_Cache_Config::OPTION_NAME])) {
956 return;
957 }
958 $input = $_POST[LiteSpeed_Cache_Config::OPTION_NAME];
959 if (isset($input['include_403'])) {
960 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_ERROR . '403');
961 }
962 if (isset($input['include_404'])) {
963 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_ERROR . '404');
964 }
965 if (isset($input['include_500'])) {
966 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_ERROR . '500');
967 }
968 }
969
970 /**
971 * The purge by callback used to purge a list of tags.
972 *
973 * @access public
974 * @since 1.0.15
975 * @param string $tags A comma delimited list of tags.
976 */
977 public function purgeby_cb($tags)
978 {
979 $tag_arr = explode(',', $tags);
980 self::add_purge_tags($tag_arr);
981 }
982
983 /**
984 * Callback to add purge tags if admin selects to purge selected category pages.
985 *
986 * @since 1.0.7
987 * @access public
988 * @param string $value The category slug.
989 * @param string $key Unused.
990 */
991 public function purgeby_cat_cb($value, $key)
992 {
993 $val = trim($value);
994 if (empty($val)) {
995 return;
996 }
997 if (preg_match('/^[a-zA-Z0-9-]+$/', $val) == 0) {
998 LiteSpeed_Cache_Admin_Error::add_error(
999 LiteSpeed_Cache_Admin_Error::E_PURGEBY_CAT_INV
1000 );
1001 return;
1002 }
1003 $cat = get_category_by_slug($val);
1004 if ($cat == false) {
1005 LiteSpeed_Cache_Admin_Error::add_error(
1006 LiteSpeed_Cache_Admin_Error::E_PURGEBY_CAT_DNE, $val);
1007 return;
1008 }
1009
1010 LiteSpeed_Cache_Admin_Display::get_instance()->add_notice(
1011 LiteSpeed_Cache_Admin_Display::NOTICE_GREEN,
1012 sprintf(__('Purge category %s', 'litespeed-cache'), $val));
1013
1014 LiteSpeed_Cache_Tags::add_purge_tag(
1015 LiteSpeed_Cache_Tags::TYPE_ARCHIVE_TERM . $cat->term_id);
1016 }
1017
1018 /**
1019 * Callback to add purge tags if admin selects to purge selected post IDs.
1020 *
1021 * @since 1.0.7
1022 * @access public
1023 * @param string $value The post ID.
1024 * @param string $key Unused.
1025 */
1026 public function purgeby_pid_cb($value, $key)
1027 {
1028 $val = trim($value);
1029 if (empty($val)) {
1030 return;
1031 }
1032 if (!is_numeric($val)) {
1033 LiteSpeed_Cache_Admin_Error::add_error(
1034 LiteSpeed_Cache_Admin_Error::E_PURGEBY_PID_NUM, $val
1035 );
1036 return;
1037 }
1038 elseif (get_post_status($val) !== 'publish') {
1039 LiteSpeed_Cache_Admin_Error::add_error(
1040 LiteSpeed_Cache_Admin_Error::E_PURGEBY_PID_DNE, $val
1041 );
1042 return;
1043 }
1044 LiteSpeed_Cache_Admin_Display::get_instance()->add_notice(
1045 LiteSpeed_Cache_Admin_Display::NOTICE_GREEN,
1046 sprintf(__('Purge Post ID %s', 'litespeed-cache'), $val));
1047
1048 LiteSpeed_Cache_Tags::add_purge_tag(
1049 LiteSpeed_Cache_Tags::TYPE_POST . $val);
1050 }
1051
1052 /**
1053 * Callback to add purge tags if admin selects to purge selected tag pages.
1054 *
1055 * @since 1.0.7
1056 * @access public
1057 * @param string $value The tag slug.
1058 * @param string $key Unused.
1059 */
1060 public function purgeby_tag_cb($value, $key)
1061 {
1062 $val = trim($value);
1063 if (empty($val)) {
1064 return;
1065 }
1066 if (preg_match('/^[a-zA-Z0-9-]+$/', $val) == 0) {
1067 LiteSpeed_Cache_Admin_Error::add_error(
1068 LiteSpeed_Cache_Admin_Error::E_PURGEBY_TAG_INV
1069 );
1070 return;
1071 }
1072 $term = get_term_by('slug', $val, 'post_tag');
1073 if ($term == 0) {
1074 LiteSpeed_Cache_Admin_Error::add_error(
1075 LiteSpeed_Cache_Admin_Error::E_PURGEBY_TAG_DNE, $val
1076 );
1077 return;
1078 }
1079
1080 LiteSpeed_Cache_Admin_Display::get_instance()->add_notice(
1081 LiteSpeed_Cache_Admin_Display::NOTICE_GREEN,
1082 sprintf(__('Purge tag %s', 'litespeed-cache'), $val));
1083
1084 LiteSpeed_Cache_Tags::add_purge_tag(
1085 LiteSpeed_Cache_Tags::TYPE_ARCHIVE_TERM . $term->term_id);
1086 }
1087
1088 /**
1089 * Callback to add purge tags if admin selects to purge selected urls.
1090 *
1091 * @since 1.0.7
1092 * @access public
1093 * @param string $value A url to purge.
1094 * @param string $key Unused.
1095 */
1096 public function purgeby_url_cb($value, $key)
1097 {
1098 $val = trim($value);
1099 if (empty($val)) {
1100 return;
1101 }
1102
1103 if (strpos($val, '<') !== false) {
1104 LiteSpeed_Cache_Admin_Error::add_error(
1105 LiteSpeed_Cache_Admin_Error::E_PURGEBY_URL_BAD
1106 );
1107 return;
1108 }
1109
1110 $hash = self::get_uri_hash($val);
1111
1112 if ($hash === false) {
1113 LiteSpeed_Cache_Admin_Error::add_error(
1114 LiteSpeed_Cache_Admin_Error::E_PURGEBY_URL_INV,
1115 $val
1116 );
1117 return;
1118 }
1119
1120 LiteSpeed_Cache_Admin_Display::get_instance()->add_notice(
1121 LiteSpeed_Cache_Admin_Display::NOTICE_GREEN,
1122 sprintf(__('Purge url %s', 'litespeed-cache'), $val));
1123
1124 LiteSpeed_Cache_Tags::add_purge_tag(
1125 LiteSpeed_Cache_Tags::TYPE_URL . $hash);
1126 return;
1127 }
1128
1129 /**
1130 * Purge a list of pages when selected by admin. This method will
1131 * look at the post arguments to determine how and what to purge.
1132 *
1133 * @since 1.0.7
1134 * @access public
1135 */
1136 public function purge_list()
1137 {
1138 if (!isset($_POST[LiteSpeed_Cache_Config::OPTION_NAME])) {
1139 LiteSpeed_Cache_Admin_Error::add_error(
1140 LiteSpeed_Cache_Admin_Error::E_PURGE_FORM
1141 );
1142 return;
1143 }
1144 $conf = $_POST[LiteSpeed_Cache_Config::OPTION_NAME];
1145 $sel = $conf[LiteSpeed_Cache_Admin_Display::PURGEBYOPT_SELECT];
1146 $list_buf = $conf[LiteSpeed_Cache_Admin_Display::PURGEBYOPT_LIST];
1147 if (empty($list_buf)) {
1148 LiteSpeed_Cache_Admin_Error::add_error(
1149 LiteSpeed_Cache_Admin_Error::E_PURGEBY_EMPTY
1150 );
1151 return;
1152 }
1153 $list = explode("\n", $list_buf);
1154 switch($sel) {
1155 case LiteSpeed_Cache_Admin_Display::PURGEBY_CAT:
1156 $cb = 'purgeby_cat_cb';
1157 break;
1158 case LiteSpeed_Cache_Admin_Display::PURGEBY_PID:
1159 $cb = 'purgeby_pid_cb';
1160 break;
1161 case LiteSpeed_Cache_Admin_Display::PURGEBY_TAG:
1162 $cb = 'purgeby_tag_cb';
1163 break;
1164 case LiteSpeed_Cache_Admin_Display::PURGEBY_URL:
1165 $cb = 'purgeby_url_cb';
1166 break;
1167 default:
1168 LiteSpeed_Cache_Admin_Error::add_error(
1169 LiteSpeed_Cache_Admin_Error::E_PURGEBY_BAD
1170 );
1171 return;
1172 }
1173 array_walk($list, Array($this, $cb));
1174 }
1175
1176 /**
1177 * Purges a post on update.
1178 *
1179 * This function will get the relevant purge tags to add to the response
1180 * as well.
1181 *
1182 * @since 1.0.0
1183 * @access public
1184 * @param integer $id The post id to purge.
1185 */
1186 public function purge_post( $id )
1187 {
1188 $post_id = intval($id);
1189 // ignore the status we don't care
1190 if ( ! in_array(get_post_status($post_id), array( 'publish', 'trash', 'private' )) ) {
1191 return ;
1192 }
1193
1194 $purge_tags = $this->get_purge_tags($post_id) ;
1195 if ( empty($purge_tags) ) {
1196 return;
1197 }
1198 if ( in_array('*', $purge_tags) ) {
1199 $this->add_purge_tags('*');
1200 }
1201 else {
1202 $this->add_purge_tags($purge_tags);
1203 }
1204 $this->cachectrl |= self::CACHECTRL_STALE;
1205 // $this->send_purge_headers();
1206 }
1207
1208 /**
1209 * Purge a single post.
1210 *
1211 * If a third party plugin needs to purge a single post, it can send
1212 * a purge tag using this function.
1213 *
1214 * @since 1.0.1
1215 * @access public
1216 * @param integer $id The post id to purge.
1217 */
1218 public function purge_single_post($id)
1219 {
1220 $post_id = intval($id);
1221 if ( ! in_array(get_post_status($post_id), array( 'publish', 'trash' )) ) {
1222 return ;
1223 }
1224 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_POST . $post_id);
1225 // $this->send_purge_headers();
1226 }
1227
1228 /**
1229 * Purges feeds on comment count update.
1230 *
1231 * @since 1.0.9
1232 * @access public
1233 */
1234 public function purge_feeds()
1235 {
1236 if ($this->config->get_option(LiteSpeed_Cache_Config::OPID_FEED_TTL) > 0) {
1237 $this->add_purge_tags(LiteSpeed_Cache_Tags::TYPE_FEED);
1238 }
1239 }
1240
1241 /**
1242 * Checks if the user is logged in. If the user is logged in, does an
1243 * additional check to make sure it's using the correct login cookie.
1244 *
1245 * @return boolean True if logged in, false otherwise.
1246 */
1247 private function check_user_logged_in()
1248 {
1249 if (!is_user_logged_in()) {
1250 // If the cookie is set, unset it.
1251 if ((isset($_COOKIE)) && (isset($_COOKIE[$this->current_vary]))
1252 && (intval($_COOKIE[$this->current_vary])
1253 & self::LSCOOKIE_VARY_LOGGED_IN)) {
1254 $this->do_set_cookie(~self::LSCOOKIE_VARY_LOGGED_IN,
1255 time() + apply_filters( 'comment_cookie_lifetime', 30000000 ));
1256 $_COOKIE[$this->current_vary] &= ~self::LSCOOKIE_VARY_LOGGED_IN;
1257 }
1258 return false;
1259 }
1260 elseif (!isset($_COOKIE[$this->current_vary])) {
1261 $this->do_set_cookie(self::LSCOOKIE_VARY_LOGGED_IN,
1262 time() + 2 * DAY_IN_SECONDS, is_ssl(), true);
1263 }
1264 return true;
1265 }
1266
1267 /**
1268 * Check if the user accessing the page has the commenter cookie.
1269 *
1270 * If the user does not want to cache commenters, just check if user is commenter.
1271 * Otherwise if the vary cookie is set, unset it. This is so that when
1272 * the page is cached, the page will appear as if the user was a normal user.
1273 * Normal user is defined as not a logged in user and not a commenter.
1274 *
1275 * @since 1.0.4
1276 * @access private
1277 * @return boolean True if do not cache for commenters and user is a commenter. False otherwise.
1278 */
1279 private function check_cookies()
1280 {
1281 if (!$this->config->get_option(LiteSpeed_Cache_Config::OPID_CACHE_COMMENTERS))
1282 {
1283 // If do not cache commenters, check cookie for commenter value.
1284 if ((isset($_COOKIE[$this->current_vary]))
1285 && ($_COOKIE[$this->current_vary] & self::LSCOOKIE_VARY_COMMENTER)) {
1286 return true;
1287 }
1288 // If wp commenter cookie exists, need to set vary and do not cache.
1289 foreach($_COOKIE as $cookie_name => $cookie_value) {
1290 if ((strlen($cookie_name) >= 15)
1291 && (strncmp($cookie_name, 'comment_author_', 15) == 0)) {
1292 $user = wp_get_current_user();
1293 $this->set_comment_cookie(NULL, $user);
1294 return true;
1295 }
1296 }
1297 return false;
1298 }
1299
1300 // If vary cookie is set, need to change the value.
1301 if (isset($_COOKIE[$this->current_vary])) {
1302 $this->do_set_cookie(~self::LSCOOKIE_VARY_COMMENTER, 14 * DAY_IN_SECONDS);
1303 unset($_COOKIE[$this->current_vary]);
1304 }
1305
1306 // If cache commenters, unset comment cookies for caching.
1307 foreach($_COOKIE as $cookie_name => $cookie_value) {
1308 if ((strlen($cookie_name) >= 15)
1309 && (strncmp($cookie_name, 'comment_author_', 15) == 0)) {
1310 unset($_COOKIE[$cookie_name]);
1311 }
1312 }
1313 return false;
1314 }
1315
1316 /**
1317 * Check admin configuration to see if the uri accessed is excluded from cache.
1318 *
1319 * @since 1.0.1
1320 * @access private
1321 * @param array $excludes_list List of excluded URIs
1322 * @return boolean True if excluded, false otherwise.
1323 */
1324 private function is_uri_excluded($excludes_list)
1325 {
1326 $uri = esc_url($_SERVER["REQUEST_URI"]);
1327 $uri_len = strlen( $uri ) ;
1328 if (is_multisite()) {
1329 $blog_details = get_blog_details(get_current_blog_id());
1330 $blog_path = $blog_details->path;
1331 $blog_path_len = strlen($blog_path);
1332 if (($uri_len >= $blog_path_len)
1333 && (strncmp($uri, $blog_path, $blog_path_len) == 0)) {
1334 $uri = substr($uri, $blog_path_len - 1);
1335 $uri_len = strlen( $uri ) ;
1336 }
1337 }
1338 foreach( $excludes_list as $excludes_rule )
1339 {
1340 $rule_len = strlen( $excludes_rule );
1341 if (($excludes_rule[$rule_len - 1] == '$')) {
1342 if ($uri_len != (--$rule_len)) {
1343 continue;
1344 }
1345 }
1346 elseif ( $uri_len < $rule_len ) {
1347 continue;
1348 }
1349
1350 if ( strncmp( $uri, $excludes_rule, $rule_len ) == 0 ){
1351 return true ;
1352 }
1353 }
1354 return false;
1355 }
1356
1357 /**
1358 * Check if a page is cacheable.
1359 *
1360 * This will check what we consider not cacheable as well as what
1361 * third party plugins consider not cacheable.
1362 *
1363 * @since 1.0.0
1364 * @access private
1365 * @return boolean True if cacheable, false otherwise.
1366 */
1367 private function is_cacheable()
1368 {
1369 // logged_in users already excluded, no hook added
1370 $method = $_SERVER["REQUEST_METHOD"] ;
1371 $conf = $this->config;
1372
1373 if ( 'GET' !== $method ) {
1374 return $this->no_cache_for('not GET method') ;
1375 }
1376
1377 if (($conf->get_option(LiteSpeed_Cache_Config::OPID_FEED_TTL) === 0)
1378 && (is_feed())) {
1379 return $this->no_cache_for('feed') ;
1380 }
1381
1382 if ( is_trackback() ) {
1383 return $this->no_cache_for('trackback') ;
1384 }
1385
1386 if (($conf->get_option(LiteSpeed_Cache_Config::OPID_404_TTL) === 0)
1387 && (is_404())) {
1388 return $this->no_cache_for('404 pages') ;
1389 }
1390
1391 if ( is_search() ) {
1392 return $this->no_cache_for('search') ;
1393 }
1394
1395 // if ( !defined('WP_USE_THEMES') || !WP_USE_THEMES ) {
1396 // return $this->no_cache_for('no theme used') ;
1397 // }
1398
1399 $cacheable = apply_filters('litespeed_cache_is_cacheable', true);
1400 if (!$cacheable) {
1401 global $wp_filter;
1402 if ((!defined('LSCWP_LOG'))
1403 || (empty($wp_filter['litespeed_cache_is_cacheable']))) {
1404 return $this->no_cache_for(
1405 'Third Party Plugin determined not cacheable.');
1406 }
1407 $funcs = array();
1408 foreach ($wp_filter['litespeed_cache_is_cacheable'] as $hook_level) {
1409 foreach ($hook_level as $func=>$params) {
1410 $funcs[] = $func;
1411 }
1412 }
1413 $this->no_cache_for('One of the following functions '
1414 . "determined that this page is not cacheable:\n\t\t"
1415 . implode("\n\t\t", $funcs));
1416 return false;
1417 }
1418
1419 $excludes = $conf->get_option(LiteSpeed_Cache_Config::OPID_EXCLUDES_URI);
1420 if (( ! empty($excludes))
1421 && ( $this->is_uri_excluded(explode("\n", $excludes))))
1422 {
1423 return $this->no_cache_for('Admin configured URI Do not cache: '
1424 . $_SERVER['REQUEST_URI']);
1425 }
1426
1427 $excludes = $conf->get_option(LiteSpeed_Cache_Config::OPID_EXCLUDES_CAT);
1428 if (( ! empty($excludes))
1429 && (has_category(explode(',', $excludes)))) {
1430 return $this->no_cache_for('Admin configured Category Do not cache.');
1431 }
1432
1433 $excludes = $conf->get_option(LiteSpeed_Cache_Config::OPID_EXCLUDES_TAG);
1434 if (( ! empty($excludes))
1435 && (has_tag(explode(',', $excludes)))) {
1436 return $this->no_cache_for('Admin configured Tag Do not cache.');
1437 }
1438
1439 $excludes = $conf->get_option(LiteSpeed_Cache_Config::ID_NOCACHE_COOKIES);
1440 if ((!empty($excludes)) && (!empty($_COOKIE))) {
1441 $exclude_list = explode('|', $excludes);
1442
1443 foreach( $_COOKIE as $key=>$val) {
1444 if (in_array($key, $exclude_list)) {
1445 return $this->no_cache_for('Admin configured Cookie Do not cache.');
1446 }
1447 }
1448 }
1449
1450 $excludes = $conf->get_option(LiteSpeed_Cache_Config::ID_NOCACHE_USERAGENTS);
1451 if ((!empty($excludes)) && (isset($_SERVER['HTTP_USER_AGENT']))) {
1452 $pattern = '/' . $excludes . '/';
1453 $nummatches = preg_match($pattern, $_SERVER['HTTP_USER_AGENT']);
1454 if ($nummatches) {
1455 return $this->no_cache_for('Admin configured User Agent Do not cache.');
1456 }
1457 }
1458
1459 return true;
1460 }
1461
1462 /**
1463 * Check if the page returns 403 and 500 errors.
1464 *
1465 * @since 1.0.13.1
1466 * @access public
1467 * @param $header, $code.
1468 * @return $eeror_status.
1469 */
1470 public function check_error_codes($header, $code)
1471 {
1472 $ttl_403 = $this->config->get_option(LiteSpeed_Cache_Config::OPID_403_TTL);
1473 $ttl_500 = $this->config->get_option(LiteSpeed_Cache_Config::OPID_500_TTL);
1474 if ($code == 403) {
1475 if ($ttl_403 <= 30) {
1476 LiteSpeed_Cache_Tags::set_noncacheable();
1477 }
1478 else {
1479 $this->error_status = $code;
1480 }
1481 }
1482 elseif ($code >= 500 && $code < 600) {
1483 if ($ttl_500 <= 30) {
1484 LiteSpeed_Cache_Tags::set_noncacheable();
1485 }
1486 }
1487 elseif ($code > 400) {
1488 $this->error_status = $code;
1489 }
1490 return $this->error_status;
1491 }
1492
1493 /**
1494 * Write a debug message for if a page is not cacheable.
1495 *
1496 * @since 1.0.0
1497 * @access private
1498 * @param string $reason An explanation for why the page is not cacheable.
1499 * @return boolean Return false.
1500 */
1501 private function no_cache_for( $reason )
1502 {
1503 if (defined('LSCWP_LOG')) {
1504 $this->debug_log('Do not cache - ' . $reason);
1505 }
1506 return false ;
1507 }
1508
1509 /**
1510 * Check if the post is cacheable. If so, set the cacheable member variable.
1511 *
1512 * @since 1.0.0
1513 * @access public
1514 */
1515 public function check_cacheable()
1516 {
1517 if ((LiteSpeed_Cache_Tags::is_noncacheable() == false)
1518 && ($this->is_cacheable())) {
1519 $this->cachectrl = self::CACHECTRL_CACHE;
1520 }
1521 }
1522
1523 /**
1524 * Check if the login page is cacheable.
1525 * If not, unset the cacheable member variable.
1526 *
1527 * @since 1.0.0
1528 * @access public
1529 */
1530 public function check_login_cacheable()
1531 {
1532 if ($this->config->get_option(LiteSpeed_Cache_Config::OPID_CACHE_LOGIN)
1533 === false) {
1534 return;
1535 }
1536 $this->check_cacheable();
1537 if ($this->cachectrl !== self::CACHECTRL_CACHE) {
1538 return;
1539 }
1540 if (!empty($_GET)) {
1541
1542 if (defined('LSCWP_LOG')) {
1543 $this->no_cache_for('Not a get request');
1544 }
1545 $this->cachectrl = self::CACHECTRL_NOCACHE;
1546 return;
1547 }
1548
1549 LiteSpeed_Cache_Tags::add_cache_tag(LiteSpeed_Cache_Tags::TYPE_LOGIN);
1550
1551 $list = headers_list();
1552 if (empty($list)) {
1553 return;
1554 }
1555 foreach ($list as $hdr) {
1556 if (strncasecmp($hdr, 'set-cookie:', 11) == 0) {
1557 $cookie = substr($hdr, 12);
1558 @header('lsc-cookie: ' . $cookie, false);
1559 }
1560 }
1561 return;
1562 }
1563
1564 /**
1565 * After a LSCWP_CTRL action, need to redirect back to the same page
1566 * without the nonce and action in the query string.
1567 *
1568 * @since 1.0.12
1569 * @access private
1570 * @global string $pagenow
1571 */
1572 private function admin_ctrl_redirect()
1573 {
1574 global $pagenow;
1575 $qs = '';
1576
1577 if (!empty($_GET)) {
1578 if (isset($_GET['LSCWP_CTRL'])) {
1579 unset($_GET['LSCWP_CTRL']);
1580 }
1581 if (isset($_GET['_wpnonce'])) {
1582 unset($_GET['_wpnonce']);
1583 }
1584 if (!empty($_GET)) {
1585 $qs = '?' . http_build_query($_GET);
1586 }
1587 }
1588 if (is_network_admin()) {
1589 $url = network_admin_url($pagenow . $qs);
1590 }
1591 else {
1592 $url = admin_url($pagenow . $qs);
1593 }
1594 wp_redirect($url);
1595 exit();
1596 }
1597
1598 /**
1599 * On admin cache actions, verify the nonce to make sure the request is valid.
1600 *
1601 * @access private
1602 * @since 1.0.15
1603 * @param string $nonce The nonce used by the request.
1604 * @return bool True if the nonce is valid, false otherwise.
1605 */
1606 private static function verify_admin_nonce($nonce)
1607 {
1608 $valid_nonces = array(
1609 self::ADMINNONCE_PURGEALL,
1610 self::ADMINNONCE_PURGENETWORKALL,
1611 self::ADMINNONCE_PURGEBY,
1612 self::ADMINNONCE_DISMISS
1613 );
1614
1615 foreach ($valid_nonces as $valid_nonce) {
1616 if (wp_verify_nonce($nonce, $valid_nonce)) {
1617 return true;
1618 }
1619 }
1620 return false;
1621 }
1622
1623 /**
1624 * Check the query string to see if it contains a LSCWP_CTRL.
1625 * Also will compare IPs to see if it is a valid command.
1626 *
1627 * @since 1.0.7
1628 * @access public
1629 */
1630 public function check_admin_ip()
1631 {
1632 // Not set, ignore.
1633 if (!isset($_GET[self::ADMINQS_KEY])) {
1634 return;
1635 }
1636 $action = $_GET[self::ADMINQS_KEY];
1637 if ((is_admin()) || (is_network_admin())) {
1638 if ((empty($_GET)) || (empty($_GET['_wpnonce']))
1639 || (self::verify_admin_nonce($_GET['_wpnonce']) === false)) {
1640 return;
1641 }
1642 }
1643 elseif (!defined('DOING_AJAX')) {
1644 $ips = $this->config->get_option(LiteSpeed_Cache_Config::OPID_ADMIN_IPS);
1645
1646 if (strpos($ips, $_SERVER['REMOTE_ADDR']) === false) {
1647 if (defined('LSCWP_LOG')) {
1648 $this->no_cache_for('LSCWP_CTRL query string - did not match admin IP');
1649 }
1650 $this->cachectrl = self::CACHECTRL_NOCACHE;
1651 return;
1652 }
1653 }
1654
1655 if (defined('LSCWP_LOG')) {
1656 self::debug_log('LSCWP_CTRL query string action is ' . $action);
1657 }
1658
1659 switch ($action[0]) {
1660 case 'P':
1661 if ($action == self::ADMINQS_PURGE) {
1662 $this->cachectrl = self::CACHECTRL_PURGE;
1663 }
1664 elseif ($action == self::ADMINQS_PURGESINGLE) {
1665 $this->cachectrl = self::CACHECTRL_PURGESINGLE;
1666 }
1667 elseif ($action == self::ADMINQS_PURGEALL) {
1668 $this->cachectrl = self::CACHECTRL_NOCACHE;
1669 $this->purge_all();
1670 }
1671 elseif (($action == self::ADMINQS_PURGEBY)
1672 && (isset($_GET['purge_tags']))) {
1673 $this->cachectrl = self::CACHECTRL_NOCACHE;
1674 $this->purgeby_cb($_GET['purge_tags']);
1675 }
1676 else {
1677 break;
1678 }
1679 if (((!is_admin()) && (!is_network_admin()))
1680 || ((defined('DOING_AJAX') && DOING_AJAX))) {
1681 return;
1682 }
1683 $this->admin_ctrl_redirect();
1684 return;
1685 case 'S':
1686 if ($action == self::ADMINQS_SHOWHEADERS) {
1687 $this->cachectrl |= self::CACHECTRL_SHOWHEADERS;
1688 return;
1689 }
1690 break;
1691 case 'D':
1692 if ($action == self::ADMINQS_DISMISS) {
1693 delete_transient(self::WHM_TRANSIENT);
1694 $this->admin_ctrl_redirect();
1695 }
1696 break;
1697 default:
1698 break;
1699 }
1700
1701 if (defined('LSCWP_LOG')) {
1702 $this->no_cache_for('LSCWP_CTRL query string should not cache.');
1703 }
1704 $this->cachectrl = self::CACHECTRL_NOCACHE;
1705 }
1706
1707 /**
1708 * Gathers all the purge headers.
1709 *
1710 * This will collect all site wide purge tags as well as
1711 * third party plugin defined purge tags.
1712 *
1713 * @since 1.0.1
1714 * @access private
1715 * @param boolean $stale Whether to add header as a stale header or not.
1716 * @return string The purge header
1717 */
1718 private function build_purge_headers($stale)
1719 {
1720 $cache_purge_header = LiteSpeed_Cache_Tags::HEADER_PURGE . ': ';
1721 $purge_tags = array_merge($this->pub_purge_tags,
1722 LiteSpeed_Cache_Tags::get_purge_tags());
1723 $purge_tags = array_unique($purge_tags);
1724
1725 if (empty($purge_tags)) {
1726 return '';
1727 }
1728
1729 $prefix = $this->config->get_option(
1730 LiteSpeed_Cache_Config::OPID_TAG_PREFIX);
1731 if (empty($prefix)) {
1732 $prefix = '';
1733 }
1734
1735 if (!in_array('*', $purge_tags )) {
1736 $tags = array_map(array($this,'prefix_apply'), $purge_tags);
1737 }
1738 elseif (isset($_POST['clearcache'])) {
1739 $tags = array('*');
1740 }
1741 // Would only use multisite and network admin except is_network_admin
1742 // is false for ajax calls, which is used by wordpress updates v4.6+
1743 elseif ((is_multisite()) && ((is_network_admin())
1744 || ((defined('DOING_AJAX'))
1745 && ((check_ajax_referer('updates', false, false))
1746 || (check_ajax_referer('litespeed-purgeall-network',
1747 false, false)))))) {
1748 $blogs = self::get_network_ids();
1749 if (empty($blogs)) {
1750 if (defined('LSCWP_LOG')) {
1751 self::debug_log('blog list is empty');
1752 }
1753 return '';
1754 }
1755 $tags = array();
1756 foreach ($blogs as $blog_id) {
1757 $tags[] = sprintf('%sB%s_', $prefix, $blog_id);
1758 }
1759 }
1760 else {
1761 $tags = array($prefix . 'B' . get_current_blog_id() . '_');
1762 }
1763
1764 if ($stale) {
1765 $cache_purge_header .= 'stale,';
1766 }
1767
1768 $cache_purge_header .= 'tag=' . implode(',', $tags);
1769 return $cache_purge_header;
1770 // TODO: private cache headers
1771 // $cache_purge_header = LiteSpeed_Cache_Tags::HEADER_PURGE
1772 // . ': private,tag=' . implode(',', $this->ext_purge_private_tags);
1773 // @header($cache_purge_header, false);
1774 }
1775
1776 /**
1777 * Builds the vary header.
1778 *
1779 * Currently, this only checks post passwords.
1780 *
1781 * @since 1.0.13
1782 * @access private
1783 * @global $post
1784 * @return mixed false if the user has the postpass cookie. Empty string
1785 * if the post is not password protected. Vary header otherwise.
1786 */
1787 private function build_vary_headers()
1788 {
1789 global $post;
1790 $tp_cookies = LiteSpeed_Cache_Tags::get_vary_cookies();
1791 if (!empty($post->post_password)) {
1792 if (isset($_COOKIE['wp-postpass_' . COOKIEHASH])) {
1793 // If user has password cookie, do not cache
1794 return false;
1795 }
1796 else {
1797 $tp_cookies[] = 'cookie=wp-postpass_' . COOKIEHASH;
1798 }
1799 }
1800
1801 if (empty($tp_cookies)) {
1802 return '';
1803 }
1804 return LiteSpeed_Cache_Tags::HEADER_CACHE_VARY
1805 . ': ' . implode(',', $tp_cookies);
1806 }
1807
1808 /**
1809 * The mode determines if the page is cacheable. This function filters
1810 * out the possible show header admin control.
1811 *
1812 * @since 1.0.7
1813 * @access private
1814 * @param boolean $showhdr Whether the show header command was selected.
1815 * @param boolean $stale Whether to make the purge headers stale.
1816 * @return integer The integer corresponding to the selected
1817 * cache control value.
1818 */
1819 private function validate_mode(&$showhdr, &$stale)
1820 {
1821 $mode = $this->cachectrl;
1822 if ($mode & self::CACHECTRL_SHOWHEADERS) {
1823 $showhdr = true;
1824 $mode &= ~self::CACHECTRL_SHOWHEADERS;
1825 }
1826
1827 if ($mode & self::CACHECTRL_STALE) {
1828 $stale = true;
1829 $mode &= ~self::CACHECTRL_STALE;
1830 }
1831
1832 if ($mode != self::CACHECTRL_CACHE) {
1833 return $mode;
1834 }
1835 elseif ((is_admin()) || (is_network_admin())) {
1836 return self::CACHECTRL_NOCACHE;
1837 }
1838
1839 if (((defined('LSCACHE_NO_CACHE')) && (constant('LSCACHE_NO_CACHE')))
1840 || (LiteSpeed_Cache_Tags::is_noncacheable())) {
1841 return self::CACHECTRL_NOCACHE;
1842 }
1843
1844 if ($this->config->get_option(
1845 LiteSpeed_Cache_Config::OPID_MOBILEVIEW_ENABLED) == false) {
1846 return (LiteSpeed_Cache_Tags::is_mobile() ? self::CACHECTRL_NOCACHE
1847 : $mode);
1848 }
1849
1850 if ((isset($_SERVER['LSCACHE_VARY_VALUE']))
1851 && ($_SERVER['LSCACHE_VARY_VALUE'] === 'ismobile')) {
1852 if ((!wp_is_mobile()) && (!LiteSpeed_Cache_Tags::is_mobile())) {
1853 return self::CACHECTRL_NOCACHE;
1854 }
1855 }
1856 elseif ((wp_is_mobile()) || (LiteSpeed_Cache_Tags::is_mobile())) {
1857 return self::CACHECTRL_NOCACHE;
1858 }
1859
1860 return $mode;
1861 }
1862
1863 /**
1864 * Send out the LiteSpeed Cache headers. If show headers is true,
1865 * will send out debug header.
1866 *
1867 * @since 1.0.7
1868 * @access private
1869 * @param boolean $showhdr True to show debug header, false if real headers.
1870 * @param string $cache_ctrl The cache control header to send out.
1871 * @param string $purge_hdr The purge tag header to send out.
1872 * @param string $cache_hdr The cache tag header to send out.
1873 * @param string $vary_hdr The cache vary header to send out.
1874 */
1875 private function header_out($showhdr, $cache_ctrl, $purge_hdr,
1876 $cache_hdr = '', $vary_hdr = '')
1877 {
1878 $hdr_content = array();
1879 if ((!is_null($cache_ctrl)) && (!empty($cache_ctrl))) {
1880 $hdr_content[] = $cache_ctrl;
1881 }
1882 if ((!is_null($purge_hdr)) && (!empty($purge_hdr))) {
1883 $hdr_content[] = $purge_hdr;
1884 }
1885 if ((!is_null($cache_hdr)) && (!empty($cache_hdr))) {
1886 $hdr_content[] = $cache_hdr;
1887 }
1888 if ((!is_null($vary_hdr)) && (!empty($vary_hdr))) {
1889 $hdr_content[] = $vary_hdr;
1890 }
1891
1892 if (!empty($hdr_content)) {
1893 if ($showhdr) {
1894 @header(LiteSpeed_Cache_Tags::HEADER_DEBUG . ': '
1895 . implode('; ', $hdr_content));
1896 }
1897 else {
1898 foreach($hdr_content as $hdr) {
1899 @header($hdr);
1900 }
1901 }
1902 }
1903
1904 if (defined('LSCWP_LOG')) {
1905 if(!defined('DOING_AJAX')){
1906 echo '<!-- Page generated by LiteSpeed Cache on '.date('Y-m-d H:i:s').' -->';
1907 }
1908 if($cache_hdr){
1909 $this->debug_log($cache_hdr);
1910 if(!defined('DOING_AJAX')){
1911 echo "\n<!-- ".$cache_hdr." -->";
1912 }
1913 }
1914 if($cache_ctrl) {
1915 $this->debug_log($cache_ctrl);
1916 if(!defined('DOING_AJAX')){
1917 echo "\n<!-- ".$cache_ctrl." -->";
1918 }
1919 }
1920 if($purge_hdr) {
1921 $this->debug_log($purge_hdr);
1922 if(!defined('DOING_AJAX')){
1923 echo "\n<!-- ".$purge_hdr." -->";
1924 }
1925 }
1926 $this->debug_log("End response.\n");
1927 }
1928 }
1929
1930 /**
1931 * Sends the headers out at the end of processing the request.
1932 *
1933 * This will send out all LiteSpeed Cache related response headers
1934 * needed for the post.
1935 *
1936 * @since 1.0.5
1937 * @access public
1938 */
1939 public function send_headers()
1940 {
1941 global $GLOBALS;
1942 global $wpforo;
1943 $zz = $GLOBALS['wpforo'];
1944 $cache_control_header = '';
1945 $cache_tag_header = '';
1946 $vary_headers = '';
1947 $cache_tags = null;
1948 $showhdr = false;
1949 $stale = false;
1950 do_action('litespeed_cache_add_purge_tags');
1951
1952 $mode = $this->validate_mode($showhdr, $stale);
1953
1954 if ($mode != self::CACHECTRL_NOCACHE) {
1955 do_action('litespeed_cache_add_cache_tags');
1956 $vary_headers = $this->build_vary_headers();
1957 $cache_tags = $this->get_cache_tags();
1958 if ($mode === self::CACHECTRL_CACHE) {
1959 $cache_tags[] = ''; //add blank entry to add blog tag.
1960 }
1961 }
1962
1963 if (empty($cache_tags) || ($vary_headers === false)) {
1964 $cache_control_header =
1965 LiteSpeed_Cache_Tags::HEADER_CACHE_CONTROL . ': no-cache' /*. ',esi=on'*/ ;
1966 $purge_headers = $this->build_purge_headers($stale);
1967 $this->header_out($showhdr, $cache_control_header, $purge_headers);
1968 return;
1969 }
1970 $prefix_tags = array_map(array($this,'prefix_apply'), $cache_tags);
1971
1972 switch ($mode) {
1973 case self::CACHECTRL_CACHE:
1974 $feed_ttl = $this->config->get_option(LiteSpeed_Cache_Config::OPID_FEED_TTL);
1975 $ttl_403 = $this->config->get_option(LiteSpeed_Cache_Config::OPID_403_TTL);
1976 $ttl_404 = $this->config->get_option(LiteSpeed_Cache_Config::OPID_404_TTL);
1977 $ttl_500 = $this->config->get_option(LiteSpeed_Cache_Config::OPID_500_TTL);
1978 if ((LiteSpeed_Cache_Tags::get_use_frontpage_ttl())
1979 || (is_front_page())){
1980 $ttl = $this->config->get_option(LiteSpeed_Cache_Config::OPID_FRONT_PAGE_TTL);
1981 }
1982 elseif ((is_feed()) && ($feed_ttl > 0)) {
1983 $ttl = $feed_ttl;
1984 }
1985 elseif ((is_404()) && ($ttl_404 > 0)) {
1986 $ttl = $ttl_404;
1987 }
1988 elseif ($this->error_status === 403) {
1989 $ttl = $ttl_403;
1990 }
1991 elseif ($this->error_status >= 500) {
1992 $ttl = $ttl_500;
1993 }
1994 else {
1995 $ttl = $this->config->get_option(LiteSpeed_Cache_Config::OPID_PUBLIC_TTL) ;
1996 }
1997 $cache_control_header = LiteSpeed_Cache_Tags::HEADER_CACHE_CONTROL
1998 . ': public,max-age=' . $ttl /*. ',esi=on'*/ ;
1999 $cache_tag_header = LiteSpeed_Cache_Tags::HEADER_CACHE_TAG
2000 . ': ' . implode(',', $prefix_tags) ;
2001 break;
2002 case self::CACHECTRL_PURGESINGLE:
2003 $cache_tags = $cache_tags[0];
2004 // fall through
2005 case self::CACHECTRL_PURGE:
2006 $cache_control_header =
2007 LiteSpeed_Cache_Tags::HEADER_CACHE_CONTROL . ': no-cache' /*. ',esi=on'*/ ;
2008 LiteSpeed_Cache_Tags::add_purge_tag($cache_tags);
2009 break;
2010
2011 }
2012 $purge_headers = $this->build_purge_headers($stale);
2013 $this->header_out($showhdr, $cache_control_header, $purge_headers,
2014 $cache_tag_header, $vary_headers);
2015 }
2016
2017 /**
2018 * Callback function that applies a prefix to cache/purge tags.
2019 *
2020 * The first call to this method will build the prefix. Subsequent calls
2021 * will use the already set prefix.
2022 *
2023 * @since 1.0.9
2024 * @access private
2025 * @staticvar string $prefix The prefix to use for each tag.
2026 * @param string $tag The tag to prefix.
2027 * @return string The amended tag.
2028 */
2029 private function prefix_apply($tag)
2030 {
2031 static $prefix = null;
2032 if (is_null($prefix)) {
2033 $prefix = $this->config->get_option(
2034 LiteSpeed_Cache_Config::OPID_TAG_PREFIX);
2035 if (empty($prefix)) {
2036 $prefix = '';
2037 }
2038 $prefix .= 'B' . get_current_blog_id() . '_';
2039 }
2040 return $prefix . $tag;
2041 }
2042
2043 /**
2044 * Gets the cache tags to set for the page.
2045 *
2046 * This includes site wide post types (e.g. front page) as well as
2047 * any third party plugin specific cache tags.
2048 *
2049 * @since 1.0.0
2050 * @access private
2051 * @return array The list of cache tags to set.
2052 */
2053 private function get_cache_tags()
2054 {
2055 global $post ;
2056 global $wp_query ;
2057
2058 $queried_obj_id = get_queried_object_id() ;
2059 $cache_tags = array();
2060
2061 $hash = self::get_uri_hash(urldecode($_SERVER['REQUEST_URI']));
2062
2063 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_URL . $hash;
2064
2065 if ( is_front_page() ) {
2066 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_FRONTPAGE ;
2067 }
2068 elseif ( is_home() ) {
2069 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_HOME ;
2070 }
2071
2072 if ($this->error_status !== false) {
2073 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ERROR . $this->error_status;
2074 }
2075
2076 if ( is_archive() ) {
2077 //An Archive is a Category, Tag, Author, Date, Custom Post Type or Custom Taxonomy based pages.
2078
2079 if ( is_category() || is_tag() || is_tax() ) {
2080 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_TERM . $queried_obj_id ;
2081 }
2082 elseif ( is_post_type_archive() ) {
2083 $post_type = $wp_query->get('post_type') ;
2084 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_POSTTYPE . $post_type ;
2085 }
2086 elseif ( is_author() ) {
2087 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_AUTHOR . $queried_obj_id ;
2088 }
2089 elseif ( is_date() ) {
2090 $date = $post->post_date ;
2091 $date = strtotime($date) ;
2092 if ( is_day() ) {
2093 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Ymd', $date) ;
2094 }
2095 elseif ( is_month() ) {
2096 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Ym', $date) ;
2097 }
2098 elseif ( is_year() ) {
2099 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Y', $date) ;
2100 }
2101 }
2102 }
2103 elseif ( is_singular() ) {
2104 //$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
2105 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_POST . $queried_obj_id ;
2106
2107 if ( is_page() ) {
2108 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_PAGES;
2109 }
2110 }
2111 elseif ( is_feed() ) {
2112 $cache_tags[] = LiteSpeed_Cache_Tags::TYPE_FEED;
2113 }
2114
2115 return array_merge($cache_tags, LiteSpeed_Cache_Tags::get_cache_tags());
2116 }
2117
2118 /**
2119 * Gets all the purge tags correlated with the post about to be purged.
2120 *
2121 * If the purge all pages configuration is set, all pages will be purged.
2122 *
2123 * This includes site wide post types (e.g. front page) as well as
2124 * any third party plugin specific post tags.
2125 *
2126 * @since 1.0.0
2127 * @access private
2128 * @param integer $post_id The id of the post about to be purged.
2129 * @return array The list of purge tags correlated with the post.
2130 */
2131 private function get_purge_tags( $post_id )
2132 {
2133 // If this is a valid post we want to purge the post, the home page and any associated tags & cats
2134 // If not, purge everything on the site.
2135
2136 $purge_tags = array() ;
2137 $config = $this->config() ;
2138
2139 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_ALL_PAGES) ) {
2140 // ignore the rest if purge all
2141 return array( '*' ) ;
2142 }
2143
2144 do_action('litespeed_cache_on_purge_post', $post_id);
2145
2146 // post
2147 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_POST . $post_id ;
2148 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_URL
2149 . self::get_uri_hash(wp_make_link_relative(get_post_permalink($post_id)));
2150
2151 // for archive of categories|tags|custom tax
2152 global $post;
2153 $post = get_post($post_id) ;
2154 $post_type = $post->post_type ;
2155
2156 // get adjacent posts id as related post tag
2157 if($post_type == 'post'){
2158 $prev_post = get_previous_post();
2159 $next_post = get_next_post();
2160 if(!empty($prev_post->ID)) {
2161 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_POST . $prev_post->ID;
2162 if(defined('LSCWP_LOG')){
2163 self::debug_log('--------purge_tags prev is: '.$prev_post->ID);
2164 }
2165 }
2166 if(!empty($next_post->ID)) {
2167 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_POST . $next_post->ID;
2168 if(defined('LSCWP_LOG')){
2169 self::debug_log('--------purge_tags next is: '.$next_post->ID);
2170 }
2171 }
2172 }
2173
2174 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_TERM) ) {
2175 $taxonomies = get_object_taxonomies($post_type) ;
2176 //$this->debug_log('purge by post, check tax = ' . print_r($taxonomies, true)) ;
2177 foreach ( $taxonomies as $tax ) {
2178 $terms = get_the_terms($post_id, $tax) ;
2179 if ( ! empty($terms) ) {
2180 foreach ( $terms as $term ) {
2181 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_TERM . $term->term_id ;
2182 }
2183 }
2184 }
2185 }
2186
2187 if ($config->get_option(LiteSpeed_Cache_Config::OPID_FEED_TTL) > 0) {
2188 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_FEED;
2189 }
2190
2191 // author, for author posts and feed list
2192 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_AUTHOR) ) {
2193 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_AUTHOR . get_post_field('post_author', $post_id) ;
2194 }
2195
2196 // archive and feed of post type
2197 // todo: check if type contains space
2198 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_POST_TYPE) ) {
2199 if ( get_post_type_archive_link($post_type) ) {
2200 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_POSTTYPE . $post_type ;
2201 }
2202 }
2203
2204 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_FRONT_PAGE) ) {
2205 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_FRONTPAGE ;
2206 }
2207
2208 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_HOME_PAGE) ) {
2209 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_HOME ;
2210 }
2211
2212 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_PAGES) ) {
2213 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_PAGES ;
2214 }
2215
2216 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_PAGES_WITH_RECENT_POSTS) ) {
2217 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_PAGES_WITH_RECENT_POSTS ;
2218 }
2219
2220 // if configured to have archived by date
2221 $date = $post->post_date ;
2222 $date = strtotime($date) ;
2223
2224 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_DATE) ) {
2225 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Ymd', $date) ;
2226 }
2227
2228 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_MONTH) ) {
2229 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Ym', $date) ;
2230 }
2231
2232 if ( $config->purge_by_post(LiteSpeed_Cache_Config::PURGE_YEAR) ) {
2233 $purge_tags[] = LiteSpeed_Cache_Tags::TYPE_ARCHIVE_DATE . date('Y', $date) ;
2234 }
2235
2236 return array_unique($purge_tags) ;
2237 }
2238
2239 /**
2240 * Will get a hash of the URI. Removes query string and appends a '/' if
2241 * it is missing.
2242 *
2243 * @since 1.0.12
2244 * @access private
2245 * @param string $uri The uri to get the hash of.
2246 * @return bool|string False on input error, hash otherwise.
2247 */
2248 private static function get_uri_hash($uri)
2249 {
2250 $no_qs = strtok($uri, '?');
2251 if (empty($no_qs)) {
2252 return false;
2253 }
2254 $slashed = trailingslashit($no_qs);
2255 return md5($slashed);
2256 }
2257
2258 /**
2259 * Creates a part of the environment report based on a section header
2260 * and an array for the section parameters.
2261 *
2262 * @since 1.0.12
2263 * @access private
2264 * @param string $section_header The section heading
2265 * @param array $section An array of information to output
2266 * @return string The created report block.
2267 */
2268 private static function format_report_section($section_header, $section)
2269 {
2270 $tab = ' '; // four spaces
2271 $nl = "\n";
2272
2273 if (empty($section)) {
2274 return 'No matching ' . $section_header . $nl . $nl;
2275 }
2276 $buf = $section_header;
2277 foreach ($section as $key=>$val) {
2278 $buf .= $nl . $tab;
2279 if (!is_numeric($key)) {
2280 $buf .= $key . ' = ';
2281 }
2282 if (!is_string($val)) {
2283 $buf .= print_r($val, true);
2284 }
2285 else {
2286 $buf .= $val;
2287 }
2288 }
2289 return $buf . $nl . $nl;
2290 }
2291
2292 /**
2293 * Builds the environment report buffer with the given parameters
2294 *
2295 * @param array $server - server variables
2296 * @param array $options - cms options
2297 * @param array $extras - cms specific attributes
2298 * @param array $htaccess_paths - htaccess paths to check.
2299 * @return string The Environment Report buffer.
2300 */
2301 public static function build_environment_report($server, $options,
2302 $extras = array(), $htaccess_paths = array())
2303 {
2304 $server_keys = array(
2305 'DOCUMENT_ROOT'=>'',
2306 'SERVER_SOFTWARE'=>'',
2307 'X-LSCACHE'=>'',
2308 'HTTP_X_LSCACHE'=>''
2309 );
2310 $server_vars = array_intersect_key($server, $server_keys);
2311 $buf = self::format_report_section('Server Variables', $server_vars);
2312
2313 $buf .= self::format_report_section('LSCache Plugin Options',
2314 $options);
2315
2316 $buf .= self::format_report_section('Wordpress Specific Extras',
2317 $extras);
2318
2319 if (empty($htaccess_paths)) {
2320 return $buf;
2321 }
2322
2323 foreach ($htaccess_paths as $path) {
2324 if ((!file_exists($path)) || (!is_readable($path))) {
2325 $buf .= $path . " does not exist or is not readable.\n";
2326 continue;
2327 }
2328 $content = file_get_contents($path);
2329 if ($content === false) {
2330 $buf .= $path . " returned false for file_get_contents.\n";
2331 continue;
2332 }
2333 $buf .= $path . " contents:\n" . $content . "\n\n";
2334 }
2335 return $buf;
2336 }
2337
2338 /**
2339 * Write the environment report to the report location.
2340 *
2341 * @since 1.0.12
2342 * @access public
2343 * @param string $content What to write to the environment report.
2344 */
2345 public function write_environment_report($content)
2346 {
2347 $content = "<"."?php die();?".">\n\n".$content;
2348
2349 $ret = LiteSpeed_Cache_Admin_Rules::file_save($content, false,
2350 untrailingslashit($this->plugin_dir) . '/environment_report.php', false);
2351 if (($ret !== true) && (defined('LSCWP_LOG'))) {
2352 self::debug_log('LSCache wordpress plugin attempted to write '
2353 . 'env report but did not have permissions.');
2354 }
2355 }
2356
2357 /**
2358 * Gathers the environment details and creates the report.
2359 * Will write to the environment report file.
2360 *
2361 * @since 1.0.12
2362 * @access public
2363 * @param mixed $options Array of options to output. If null, will skip
2364 * the options section.
2365 * @return string The built report.
2366 */
2367 public static function generate_environment_report($options = null)
2368 {
2369 global $wp_version, $_SERVER;
2370 $home = LiteSpeed_Cache_Admin_Rules::get_home_path();
2371 $site = LiteSpeed_Cache_Admin_Rules::get_site_path();
2372 $paths = array($home);
2373 if ($home != $site) {
2374 $paths[] = $site;
2375 }
2376
2377 if (is_multisite()) {
2378 $active_plugins = get_site_option('active_sitewide_plugins');
2379 if (!empty($active_plugins)) {
2380 $active_plugins = array_keys($active_plugins);
2381 }
2382 }
2383 else {
2384 $active_plugins = get_option('active_plugins');
2385 }
2386
2387 if (function_exists('wp_get_theme')) {
2388 $theme_obj = wp_get_theme();
2389 $active_theme = $theme_obj->get('Name');
2390 }
2391 else {
2392 $active_theme = get_current_theme();
2393 }
2394
2395 $extras = array(
2396 'wordpress version' => $wp_version,
2397 'locale' => get_locale(),
2398 'active theme' => $active_theme,
2399 'active plugins' => $active_plugins,
2400
2401 );
2402 if (is_null($options)) {
2403 $options = self::config()->get_options();
2404 }
2405
2406 if ((!is_null($options)) && (is_multisite())) {
2407 $blogs = self::get_network_ids();
2408 if (!empty($blogs)) {
2409 foreach ($blogs as $blog_id) {
2410 $opts = get_blog_option($blog_id,
2411 LiteSpeed_Cache_Config::OPTION_NAME, array());
2412 if (isset($opts[LiteSpeed_Cache_Config::OPID_ENABLED_RADIO])) {
2413 $options['blog ' . $blog_id . ' radio select']
2414 = $opts[LiteSpeed_Cache_Config::OPID_ENABLED_RADIO];
2415 }
2416 }
2417 }
2418 }
2419
2420 $report = self::build_environment_report($_SERVER, $options, $extras,
2421 $paths);
2422 self::plugin()->write_environment_report($report);
2423 return $report;
2424 }
2425
2426 /**
2427 * Hooked to the update options/site options actions. Whenever our options
2428 * are updated, update the environment report with the new options.
2429 *
2430 * @since 1.0.12
2431 * @access public
2432 * @param $unused
2433 * @param mixed $options The updated options. May be array or string.
2434 */
2435 public static function update_environment_report($unused, $options)
2436 {
2437 if (is_array($options)) {
2438 self::generate_environment_report($options);
2439 }
2440 }
2441
2442
2443
2444 /* BEGIN ESI CODE, not fully implemented for now */
2445 /**
2446 *
2447 *
2448 * @since 1.0.1
2449 */
2450 public function esi_admin_bar_render()
2451 {
2452 echo '<!-- lscwp admin esi start -->'
2453 . '<esi:include src="/lscwp_admin_bar.php" onerror=\"continue\"/>'
2454 . '<!-- lscwp admin esi end -->';
2455 }
2456
2457 /**
2458 *
2459 *
2460 * @since 1.0.1
2461 */
2462 public function check_admin_bar()
2463 {
2464 if (is_admin_bar_showing()) {
2465 remove_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
2466 remove_action( 'in_admin_header', 'wp_admin_bar_render', 0 );
2467 add_action('wp_footer', array($this, 'esi_admin_bar_render'), 1000);
2468 }
2469 }
2470
2471 /**
2472 *
2473 *
2474 * @since 1.0.1
2475 */
2476 public function check_storefront_cart()
2477 {
2478 if (has_action('storefront_header', 'storefront_header_cart')) {
2479 remove_action('storefront_header', 'storefront_header_cart', 60);
2480 echo '<!-- lscwp cart esi start -->'
2481 . '<esi:include src="/lscwp_cart.php" onerror=\"continue\"/>'
2482 . '<!-- lscwp cart esi end -->';
2483 }
2484 }
2485
2486 /**
2487 *
2488 *
2489 * @since 1.0.1
2490 */
2491 public function check_sidebar()
2492 {
2493 if (has_action('storefront_sidebar', 'storefront_get_sidebar')) {
2494 remove_action('storefront_sidebar', 'storefront_get_sidebar', 10);
2495 echo '<!-- lscwp sidebar esi start -->'
2496 . '<esi:include src="/lscwp_sidebar.php" onerror=\"continue\"/>'
2497 . '<!-- lscwp sidebar esi end -->';
2498 }
2499 }
2500
2501 /**
2502 *
2503 *
2504 * @since 1.0.1
2505 */
2506 private function add_actions_esi()
2507 {
2508 add_action('storefront_header',
2509 array($this, 'check_storefront_cart'), 59);
2510 add_action('storefront_sidebar', array($this, 'check_sidebar'), 0);
2511 }
2512
2513 /**
2514 *
2515 *
2516 * @since 1.0.1
2517 */
2518 public function send_esi()
2519 {
2520 status_header(200);
2521 die();
2522 }
2523
2524 /**
2525 *
2526 *
2527 * @since 1.0.1
2528 */
2529 private function is_esi_admin_bar($uri, $urilen)
2530 {
2531 $admin = 'admin_bar.php';
2532 $adminlen = strlen($admin);
2533
2534 if (($urilen != $adminlen)
2535 || (strncmp($uri, $admin, $adminlen) != 0)) {
2536 return false;
2537 }
2538 add_action( 'init', '_wp_admin_bar_init', 0 );
2539 add_action( 'init', 'wp_admin_bar_render', 0 );
2540 add_action('init', array($this, 'send_esi'), 0);
2541 return true;
2542 }
2543
2544 /**
2545 *
2546 *
2547 * @since 1.0.1
2548 */
2549 private function is_esi_cart($uri, $urilen)
2550 {
2551 $cart = 'cart.php';
2552 $cartlen = strlen($cart);
2553
2554 if (($urilen != $cartlen)
2555 || (strncmp($uri, $cart, $cartlen) != 0)) {
2556 return false;
2557 }
2558 register_widget( 'WC_Widget_Cart' );
2559 add_action('init', 'storefront_cart_link_fragment', 0);
2560 add_action('init', 'storefront_header_cart', 0);
2561 add_action('init', array($this, 'send_esi'), 0);
2562 return true;
2563 }
2564
2565 /**
2566 *
2567 *
2568 * @since 1.0.1
2569 */
2570 public function load_sidebar_widgets()
2571 {
2572 do_action('widgets_init');
2573 do_action('register_sidebar');
2574 do_action('wp_register_sidebar_widget');
2575 }
2576
2577 /**
2578 *
2579 *
2580 * @since 1.0.1
2581 */
2582 private function is_esi_sidebar($uri, $urilen)
2583 {
2584 $sidebar = 'sidebar.php';
2585 $sidebarlen = strlen($sidebar);
2586
2587 if (($urilen != $sidebarlen)
2588 || (strncmp($uri, $sidebar, $sidebarlen) != 0)) {
2589 return false;
2590 }
2591 add_action('widgets_init', 'storefront_widgets_init', 10);
2592 add_action('wp_loaded', array($this, 'load_sidebar_widgets'), 0);
2593 add_action('wp_loaded', 'storefront_get_sidebar', 0);
2594 add_action('wp_loaded', array($this, 'send_esi'), 0);
2595 return true;
2596 }
2597
2598 /**
2599 *
2600 *
2601 * @since 1.0.1
2602 */
2603 private function check_esi_page()
2604 {
2605 $prefix = '/lscwp_';
2606 $prefixlen = 7;
2607 $uri = esc_url($_SERVER['REQUEST_URI']);
2608 $urilen = strlen($uri);
2609
2610 if (($urilen <= $prefixlen) || (strncmp($uri, $prefix, $prefixlen) != 0 )) {
2611 return false;
2612 }
2613
2614 $uri = substr($uri, $prefixlen);
2615 $urilen -= $prefixlen;
2616
2617 switch ($uri[0]) {
2618 case 'a':
2619 return $this->is_esi_admin_bar($uri, $urilen);
2620 case 'c':
2621 return $this->is_esi_cart($uri, $urilen);
2622 case 's':
2623 return $this->is_esi_sidebar($uri, $urilen);
2624 default:
2625 break;
2626 }
2627 return false;
2628 }
2629 /*END ESI CODE*/
2630 }
2631