PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260927
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260927
260927 260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 All 190 releases
s2member / src / includes / classes / no-cache.inc.php

no-cache.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260927, at src/includes/classes/no-cache.inc.php

402 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * No-cache routines.
5 *
6 * Copyright: © 2009-2011
7 * {@link http://websharks-inc.com/ WebSharks, Inc.}
8 * (coded in the USA)
9 *
10 * Released under the terms of the GNU General Public License.
11 * You should have received a copy of the GNU General Public License,
12 * along with this software. In the main directory, see: /licensing/
13 * If not, see: {@link http://www.gnu.org/licenses/}.
14 *
15 * @package s2Member\No_Cache
16 * @since 3.5
17 */
18 if(!defined('WPINC')) // MUST have WordPress.
19 exit ('Do not access this file directly.');
20
21 if(!class_exists('c_ws_plugin__s2member_no_cache'))
22 {
23 /**
24 * No-cache routines.
25 *
26 * @package s2Member\No_Cache
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_no_cache
30 {
31 /**
32 * No-cache headers required?
33 *
34 * @package s2Member\No_Cache
35 * @since 111115
36 *
37 * @var null|bool
38 */
39 public static $headers;
40
41 /**
42 * Sets up no-cache header behavior mode.
43 *
44 * This runs on `init` so s2Member options are available (options are configured after hooks are included).
45 *
46 * @package s2Member\No_Cache
47 * @since 260307
48 *
49 * @attaches-to ``add_action('init');``
50 *
51 * @return void
52 */
53 public static function setup_no_cache_headers_mode()
54 {
55 static $once; // Run only once per request.
56
57 if($once)
58 return;
59
60 $once = TRUE;
61
62 $mode = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_mode']))
63 ? (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_mode']
64 : 'always';
65
66 if($mode === 'evaluative' || !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_debug']))
67 add_filter('wp_headers', 'c_ws_plugin__s2member_no_cache::no_cache_wp_headers', 9999); //260309 Run last; also adds debug header in all modes when enabled.
68
69 if($mode === 'evaluative')
70 {
71 add_filter('ws_plugin__s2member_no_cache_headers_selective', '__return_true');
72 c_ws_plugin__s2member_no_cache::no_cache_constants(FALSE);
73
74 add_action('wp', 'c_ws_plugin__s2member_no_cache::evaluative_no_cache_scan', 3); //260308 Rename staged scan to evaluative scan.
75 }
76 else
77 {
78 if($mode === 'selective')
79 add_filter('ws_plugin__s2member_no_cache_headers_selective', '__return_true');
80
81 c_ws_plugin__s2member_no_cache::no_cache(FALSE);
82 }
83 }
84
85 /**
86 * Evaluative mode: scans queried post content for s2Member shortcodes before headers are sent.
87 *
88 * Shortcodes execute after headers (during rendering), so evaluative mode must pre-detect likely s2Member
89 * shortcodes to ensure no-cache headers are applied when needed.
90 *
91 * @package s2Member\No_Cache
92 * @since 260307
93 *
94 * @attaches-to ``add_action('wp');``
95 *
96 * @return void
97 */
98 public static function evaluative_no_cache_scan()
99 {
100 if(!is_singular())
101 return;
102
103 $post = get_queried_object();
104 if(!is_object($post) || empty($post->post_content) || !is_string($post->post_content))
105 return;
106
107 //260307 Conservative pre-detection of s2Member shortcodes in post content.
108 // This intentionally errs on the safe side (prevents caching) for any `[s2...` usage.
109 if(stripos($post->post_content, '[s2') !== FALSE)
110 c_ws_plugin__s2member_no_cache::no_cache_constants(true);
111 }
112
113 /**
114 * Handles no-cache constants, and no-cache headers.
115 *
116 * @package s2Member\No_Cache
117 * @since 3.5
118 *
119 * @attaches-to ``add_action('init');``
120 * @also-called-by Other routines within s2Member.
121 *
122 * @param bool $no_cache Optional. Defaults to false. If true, force no-cache if at all possible.
123 *
124 * @return bool This function will always return `true`.
125 */
126 public static function no_cache($no_cache = FALSE)
127 {
128 do_action('ws_plugin__s2member_before_no_cache', get_defined_vars());
129
130 c_ws_plugin__s2member_no_cache::no_cache_constants($no_cache).c_ws_plugin__s2member_no_cache::no_cache_headers($no_cache);
131
132 do_action('ws_plugin__s2member_after_no_cache', get_defined_vars());
133
134 return TRUE; // Always return true.
135 }
136
137 /**
138 * Defines no-cache constants/signals for WordPress caching plugins.
139 *
140 * `DONOTCACHEPAGE` is the de facto cross-plugin page-cache bypass signal.
141 * Legacy s2Member cache flags are retained, with explicit runtime APIs/filters
142 * for popular caches that expose their own no-cache mechanisms.
143 *
144 * Disallow caching if the ``$no_cache`` parameter is passed in as ``true``, by other routines.
145 * In addition, always disallow caching for logged in users, and GET requests with: `/?s2member` Systematics.
146 * For clarity on s2Member Systematics, see: {@link s2Member\Systematics\c_ws_plugin__s2member_systematics::is_s2_systematic_use_page()}.
147 *
148 * However, this routine will ALWAYS obey the `?qcAC` query string parameter.
149 * This Quick Cache parameter explicitly allows caching to occur.
150 *
151 * @package s2Member\No_Cache
152 * @since 3.5
153 *
154 * @also-called-by Other routines within s2Member.
155 *
156 * @param bool $no_cache Optional. Defaults to false. If true, force no-cache if at all possible.
157 *
158 * @return bool This function will always return `true`.
159 */
160 public static function no_cache_constants($no_cache = FALSE)
161 {
162 static $once; // We only need to set these constants once.
163
164 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
165 do_action('ws_plugin__s2member_before_no_cache_constants', get_defined_vars());
166 unset($__refs, $__v); // Housekeeping.
167
168 if(!$once && (empty($_GET['qcAC']) || !filter_var($_GET['qcAC'], FILTER_VALIDATE_BOOLEAN))
169 && (
170 $no_cache === TRUE // Forces no-cache constants; if `TRUE` explicitly.
171 || ($no_cache === 'restricted' && (!defined('COMET_CACHE_WHEN_LOGGED_IN') || !COMET_CACHE_WHEN_LOGGED_IN) && (!defined('ZENCACHE_WHEN_LOGGED_IN') || !ZENCACHE_WHEN_LOGGED_IN) && (!defined('QUICK_CACHE_WHEN_LOGGED_IN') || !QUICK_CACHE_WHEN_LOGGED_IN))
172 || (is_user_logged_in() && (!defined('COMET_CACHE_WHEN_LOGGED_IN') || !COMET_CACHE_WHEN_LOGGED_IN) && (!defined('ZENCACHE_WHEN_LOGGED_IN') || !ZENCACHE_WHEN_LOGGED_IN) && (!defined('QUICK_CACHE_WHEN_LOGGED_IN') || !QUICK_CACHE_WHEN_LOGGED_IN))
173 || c_ws_plugin__s2member_systematics::is_s2_systematic_use_page()
174 )
175 )
176 {
177 /**
178 * No-cache DB queries for plugins.
179 *
180 * @package s2Member\No_Cache
181 * @since 111115
182 *
183 * @var bool
184 */
185 if(!defined('DONOTCACHEDB'))
186 define('DONOTCACHEDB', TRUE);
187
188 /**
189 * No-cache Page for plugins.
190 *
191 * @package s2Member\No_Cache
192 * @since 3.5
193 *
194 * @var bool
195 */
196 if(!defined('DONOTCACHEPAGE'))
197 define('DONOTCACHEPAGE', TRUE);
198
199 /**
200 * No-cache Objects for plugins.
201 *
202 * @package s2Member\No_Cache
203 * @since 111115
204 *
205 * @var bool
206 */
207 if(!defined('DONOTCACHEOBJECT'))
208 define('DONOTCACHEOBJECT', TRUE);
209
210 /**
211 * No-cache anything for Comet Cache plugin.
212 *
213 * @package s2Member\No_Cache
214 * @since 160222
215 *
216 * @var bool
217 */
218 if(!defined('COMET_CACHE_ALLOWED'))
219 define('COMET_CACHE_ALLOWED', FALSE);
220
221 /**
222 * No-cache anything for ZenCache plugin.
223 *
224 * @package s2Member\No_Cache
225 * @since 3.5
226 *
227 * @var bool
228 */
229 if(!defined('ZENCACHE_ALLOWED'))
230 define('ZENCACHE_ALLOWED', FALSE);
231
232 /**
233 * No-cache anything for Quick Cache plugin.
234 *
235 * @package s2Member\No_Cache
236 * @since 3.5
237 *
238 * @var bool
239 */
240 if(!defined('QUICK_CACHE_ALLOWED'))
241 define('QUICK_CACHE_ALLOWED', FALSE);
242
243 //260918.2104 Explicit runtime no-cache APIs for popular caches that do not uniformly rely on the generic constants.
244 do_action('litespeed_control_set_nocache', 's2Member dynamic/private content'); // LiteSpeed Cache.
245 add_filter('flying_press_is_cacheable', '__return_false', PHP_INT_MAX); // FlyingPress.
246 add_filter('swcfpc_cache_bypass', '__return_true', PHP_INT_MAX); // Super Page Cache for Cloudflare.
247 if(function_exists('wpfc_exclude_current_page')) // WP Fastest Cache.
248 wpfc_exclude_current_page();
249
250 // Cloudflare APO uses its own edge-cache signal. The filter helps when this runs early;
251 // the response header also overrides APO when headers are still mutable on a later call.
252 add_filter('cloudflare_use_cache', '__return_false', PHP_INT_MAX);
253 if(class_exists('\Cloudflare\APO\WordPress\Hooks', FALSE) && !headers_sent())
254 header('cf-edge-cache: no-cache', TRUE);
255
256 $once = TRUE; // Set these one time only.
257
258 c_ws_plugin__s2member_no_cache::$headers = TRUE;
259
260 do_action('ws_plugin__s2member_during_no_cache_constants', get_defined_vars());
261 }
262 do_action('ws_plugin__s2member_after_no_cache_constants', get_defined_vars());
263
264 return TRUE; // Always return true.
265 }
266
267 /**
268 * Filters HTTP headers (wp_headers) to apply no-cache headers when needed.
269 *
270 * This is used by the `evaluative` no-cache headers mode. It allows s2Member runtime checks/shortcodes
271 * (e.g., `[s2If]`) to set no-cache constants/flags during rendering, while still applying no-cache
272 * headers during WordPress's standard header-sending stage (wp_headers/send_headers).
273 *
274 * Obeys `?qcABC`, `?zcABC`, and `?ccABC` query string parameters, which explicitly allow caching.
275 *
276 * @package s2Member\No_Cache
277 * @since 260307
278 *
279 * @param array $headers An associative array of HTTP headers.
280 *
281 * @return array Possibly modified headers.
282 */
283 public static function no_cache_wp_headers($headers = array())
284 {
285 static $once; // We only need to filter these headers one time.
286
287 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
288 do_action('ws_plugin__s2member_before_no_cache_headers', get_defined_vars());
289 unset($__refs, $__v); // Housekeeping.
290
291 $mode = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_mode']))
292 ? (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_mode']
293 : 'always';
294 $no_cache = (bool)apply_filters('ws_plugin__s2member_no_cache', FALSE, get_defined_vars());
295 $using_selective_behavior = (bool)apply_filters('ws_plugin__s2member_no_cache_headers_selective', FALSE, get_defined_vars());
296
297 if($mode === 'evaluative' && !$no_cache && $using_selective_behavior && !c_ws_plugin__s2member_no_cache::$headers) //260309 Evaluative mode: pre-detect s2 shortcodes in queried content.
298 {
299 global $wp_query;
300
301 if(!empty($wp_query) && !empty($wp_query->post) && is_object($wp_query->post) && !empty($wp_query->post->post_content))
302 if(stripos((string)$wp_query->post->post_content, '[s2') !== FALSE)
303 c_ws_plugin__s2member_no_cache::$headers = TRUE;
304 }
305
306 //260308 Debug header (support use only).
307 if(!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['no_cache_headers_debug']))
308 {
309 $_st = 's2member;desc="mode='.$mode.';no_cache='.(int)$no_cache.';selective='.(int)$using_selective_behavior.';headers='.(int)c_ws_plugin__s2member_no_cache::$headers.'"';
310
311 if(!empty($headers['Server-Timing']))
312 $headers['Server-Timing'] .= ', '.$_st;
313 else
314 $headers['Server-Timing'] = $_st;
315
316 unset($_st); // Housekeeping.
317 }
318
319 if($mode === 'evaluative' && !$once
320 && (empty($_GET['ccABC']) || !filter_var($_GET['ccABC'], FILTER_VALIDATE_BOOLEAN))
321 && (empty($_GET['zcABC']) || !filter_var($_GET['zcABC'], FILTER_VALIDATE_BOOLEAN))
322 && (empty($_GET['qcABC']) || !filter_var($_GET['qcABC'], FILTER_VALIDATE_BOOLEAN))
323 && ($no_cache || !$using_selective_behavior || c_ws_plugin__s2member_no_cache::$headers)
324 )
325 if(!apply_filters('ws_plugin__s2member_disable_no_cache_headers', FALSE, get_defined_vars()))
326 {
327 $nocache_headers = wp_get_nocache_headers();
328
329 foreach(array('Expires', 'Cache-Control', 'Pragma') as $_k)
330 if(isset($headers[$_k])) unset($headers[$_k]);
331
332 foreach((array)$nocache_headers as $_k => $_v)
333 $headers[$_k] = $_v;
334
335 unset($_k, $_v); // Housekeeping.
336
337 $once = TRUE; // This is static var. Only apply once.
338
339 do_action('ws_plugin__s2member_during_no_cache_headers', get_defined_vars());
340 }
341 do_action('ws_plugin__s2member_after_no_cache_headers', get_defined_vars());
342
343 return $headers;
344 }
345
346 /**
347 * Sends Cache-Control (no-cache) headers.
348 *
349 * Disallow browser caching if the ``$no_cache`` parameter is passed in as ``true``, by other routines.
350 * Disallow browser caching when/if no-cache Constants are set by {@link s2Member\No_Cache\c_ws_plugin__s2member_no_cache::no_cache_constants()},
351 * via static variable boolean value for: ``c_ws_plugin__s2member_no_cache::$headers``.
352 *
353 * However, this routine will ALWAYS obey the `?qcABC` query string parameter.
354 * This Quick Cache parameter explicitly allows browser caching to occur.
355 *
356 * @package s2Member\No_Cache
357 * @since 3.5
358 *
359 * @also-called-by Other routines within s2Member.
360 *
361 * @param bool $no_cache Optional. Defaults to false. If true, force no-cache if at all possible.
362 *
363 * @return bool This function will always return `true`.
364 */
365 public static function no_cache_headers($no_cache = FALSE)
366 {
367 static $once; // We only need to set these headers one time.
368
369 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
370 do_action('ws_plugin__s2member_before_no_cache_headers', get_defined_vars());
371 unset($__refs, $__v); // Housekeeping.
372
373 $using_selective_behavior = apply_filters('ws_plugin__s2member_no_cache_headers_selective', FALSE, get_defined_vars());
374
375 if(!$once && !headers_sent() // Only once, and only if possible.
376 && (empty($_GET['ccABC']) || !filter_var($_GET['ccABC'], FILTER_VALIDATE_BOOLEAN))
377 && (empty($_GET['zcABC']) || !filter_var($_GET['zcABC'], FILTER_VALIDATE_BOOLEAN))
378 && (empty($_GET['qcABC']) || !filter_var($_GET['qcABC'], FILTER_VALIDATE_BOOLEAN))
379 && ($no_cache || !$using_selective_behavior || c_ws_plugin__s2member_no_cache::$headers)
380 )
381 if(!apply_filters('ws_plugin__s2member_disable_no_cache_headers', FALSE, get_defined_vars()))
382 {
383 foreach(headers_list() as $header) // No-cache headers already sent? We need to check here.
384 if(stripos($header, 'no-cache') !== FALSE) // No-cache headers already sent?
385 {
386 $no_cache_headers_already_sent = TRUE; // Yep, sent.
387 break; // Break now, no need to continue further.
388 }
389 if(!isset ($no_cache_headers_already_sent)) // Not yet?
390 nocache_headers(); // Only if NOT already sent.
391
392 $once = TRUE; // This is static var. Only send headers once.
393
394 do_action('ws_plugin__s2member_during_no_cache_headers', get_defined_vars());
395 }
396 do_action('ws_plugin__s2member_after_no_cache_headers', get_defined_vars());
397
398 return TRUE; // Always return true.
399 }
400 }
401 }
402