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

sc-if-conds-in.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260917, at src/includes/classes/sc-if-conds-in.inc.php

451 lines 17.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Shortcode `[s2If /]` (inner processing 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\s2If
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_sc_if_conds_in'))
22 {
23 /**
24 * Shortcode `[s2If /]` (inner processing routines).
25 *
26 * @package s2Member\s2If
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_sc_if_conds_in
30 {
31 /**
32 * Handles the Shortcode for: `[s2If /]`.
33 *
34 * These Shortcodes are also safe to use on a Multisite Blog Farm.
35 *
36 * Is Multisite Networking enabled? Please keep the following in mind.
37 * ``current_user_can()``, will ALWAYS return true for a Super Admin!
38 * *(this can be confusing when testing conditionals)*.
39 *
40 * If you're running a Multisite Blog Farm, you can Filter this array:
41 * `ws_plugin__s2member_sc_if_conditionals_blog_farm_safe`
42 * ``$blog_farm_safe``
43 *
44 * @package s2Member\s2If
45 * @since 3.5
46 *
47 * @attaches-to ``add_shortcode('s2If')`` + _s2If, __s2If, ___s2If for nesting.
48 *
49 * @param array $attr An array of Attributes.
50 * @param string $content Content inside the Shortcode.
51 * @param string $shortcode The actual Shortcode name itself.
52 *
53 * @return string The ``$content`` if true, else an empty string.
54 *
55 * @todo Add support for nested AND/OR conditionals inside the ONE Shortcode.
56 * @todo Address possible security issue on sites with multiple editors, some of which should not have access to this feature.
57 */
58 public static function sc_if_conditionals($attr = array(), $content = '', $shortcode = '')
59 {
60 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
61 do_action('ws_plugin__s2member_before_sc_if_conditionals', get_defined_vars());
62 unset($__refs, $__v); // Allows variables to be modified by reference.
63
64 c_ws_plugin__s2member_no_cache::no_cache_constants(true);
65
66 $pro_is_installed = c_ws_plugin__s2member_utils_conds::pro_is_installed(); // Has pro version?
67
68 //230811 Whitelist of conditional functions
69 $blog_farm_safe = array(
70 'comments_open',
71 'current_user_can',
72 'current_user_can_for_blog',
73 'current_user_cannot',
74 'current_user_cannot_for_blog',
75 'current_user_days_to_eot_less_than',
76 'current_user_gateway_is',
77 'current_user_is',
78 'current_user_is_for_blog',
79 'current_user_is_not',
80 'current_user_is_not_for_blog',
81 'has_excerpt',
82 'has_post_thumbnail',
83 'has_tag',
84 'has_term',
85 'in_category',
86 'in_the_loop',
87 'is_404',
88 'is_active_sidebar',
89 'is_admin',
90 'is_archive',
91 'is_attachment',
92 'is_author',
93 'is_blog_admin',
94 'is_category',
95 'is_child_theme',
96 'is_comments_popup',
97 'is_customize_preview',
98 'is_date',
99 'is_day',
100 'is_feed',
101 'is_front_page',
102 'is_home',
103 'is_main_site',
104 'is_month',
105 'is_multi_author',
106 'is_multisite',
107 'is_network_admin',
108 'is_page',
109 'is_page_template',
110 'is_paged',
111 'is_preview',
112 'is_rtl',
113 'is_search',
114 'is_single',
115 'is_singular',
116 'is_sticky',
117 'is_super_admin',
118 'is_tag',
119 'is_tax',
120 'is_time',
121 'is_trackback',
122 'is_user_admin',
123 'is_user_logged_in',
124 'is_user_not_logged_in',
125 'is_year',
126 'pings_open',
127 'user_can',
128 'user_cannot',
129 'user_is',
130 'user_is_not',
131 );
132 $blog_farm_safe = apply_filters('ws_plugin__s2member_sc_if_conditionals_blog_farm_safe', $blog_farm_safe, get_defined_vars());
133
134 //230814 Custom whitelist (pro)
135 if ($pro_is_installed && !empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sc_conds_whitelist"])) {
136 $sc_conds_whitelist = explode(',', $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sc_conds_whitelist"]);
137 foreach ($sc_conds_whitelist as $white_func) {
138 $white_func = trim(strtolower($white_func));
139 if (function_exists($white_func)) {
140 $blog_farm_safe[] = $white_func;
141 }
142 }
143 }
144
145 $sc_conds_allow_arbitrary_php = $GLOBALS['WS_PLUGIN__']['s2member']['o']['sc_conds_allow_arbitrary_php'];
146 if(!$pro_is_installed || (is_multisite() && c_ws_plugin__s2member_utils_conds::is_multisite_farm() && !is_main_site()))
147 $sc_conds_allow_arbitrary_php = FALSE; // Always disallow on child blogs of a blog farm.
148
149 $attr = // Trim quote entities to prevent issues in messy editors.
150 c_ws_plugin__s2member_utils_strings::trim_qts_deep((array)$attr);
151
152 $content_if = $content_else = NULL; // Initialize.
153 $shortcode_depth = strspn($shortcode, '_'); // Based on a zero index.
154 $else_tag = '['.str_repeat('_', $shortcode_depth).'else]'; // e.g., [else], [_else], [__else]
155
156 if(strpos($content, $else_tag) !== FALSE && $pro_is_installed)
157 list($content_if, $content_else) = explode($else_tag, $content, 2);
158
159 # Arbitrary PHP code via the `php` attribute...
160
161 if($sc_conds_allow_arbitrary_php && isset($attr['php']))
162 {
163 $attr['php'] = str_replace(array('&lt;', '&gt;', '&amp;'), array('<', '>', '&'), $attr['php']);
164
165 if(($condition_succeeded = c_ws_plugin__s2member_sc_if_conds_in::evl($attr['php'])))
166 $condition_content = isset($content_if) ? $content_if : $content;
167 else $condition_content = isset($content_else) ? $content_else : '';
168
169 if($condition_content) $condition_content = c_ws_plugin__s2member_utils_strings::trim_html($condition_content);
170
171 return do_shortcode(apply_filters('ws_plugin__s2member_sc_if_conditionals', $condition_content, get_defined_vars()));
172 }
173 else if(isset($attr['php'])) // Site owner is trying to use `php`, but it's NOT allowed on this installation.
174 {
175 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If syntax error. Simple Conditionals are not currently configured to allow arbitrary PHP code evaluation.');
176 return ''; // Return now; empty string in this case.
177 }
178 # Default behavior otherwise...
179
180 foreach($attr as $attr_key => $attr_value) // Detects and removes logical attributes.
181 // It's NOT possible to mix logic. You MUST stick to one type of logic or another.
182 // If both types of logic are needed, you MUST use two different Shortcodes.
183 if(preg_match('/^(&&|&amp;&amp;|&#038;&#038;|AND|\|\||OR|[\!\=\<\>]+)$/i', $attr_value))
184 { // Stick with AND/OR. Ampersands are corrupted by the Visual Editor.
185
186 $logicals[] = strtolower($attr_value); // Place all logicals into an array here.
187 unset($attr[$attr_key]); // ^ Detect logic here. We'll use the first key #0.
188
189 if(preg_match('/^[\!\=\<\>]+$/i', $attr_value)) // Error on these operators.
190 {
191 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, invalid operator [ '.$attr_value.' ]. Simple Conditionals cannot process operators like ( == != <> ). Please use Advanced (PHP) Conditionals instead.');
192 return ''; // Return now; empty string in this case.
193 }
194 }
195 if(!empty($logicals) && is_array($logicals) && count(array_unique($logicals)) > 1)
196 {
197 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, AND/OR malformed conditional logic. It\'s NOT possible to mix logic using AND/OR combinations. You MUST stick to one type of logic or another. If both types of logic are needed, you MUST use two different Shortcode expressions. Or, use Advanced (PHP) Conditionals instead.');
198 return ''; // Return now; empty string in this case.
199 }
200 $conditional_logic = (!empty($logicals) && is_array($logicals) && preg_match('/^(\|\||OR)$/i', $logicals[0])) ? 'OR' : 'AND';
201
202 foreach(array_keys(get_defined_vars()) as $__v) $__refs[$__v] =& $$__v;
203 do_action('ws_plugin__s2member_before_sc_if_conditionals_after_conditional_logic', get_defined_vars());
204 unset($__refs, $__v); // Allows variables to be modified by reference.
205
206 if($conditional_logic === 'AND') // This is the AND variation. This routine analyzes conditionals using AND logic (the default behavior).
207 {
208 foreach($attr as $attr_value) // This is the AND variation. This routine analyzes conditionals using AND logic (the default behavior).
209 {
210 if(preg_match('/^(\!?)(.+?)(\()(.*?)(\))$/', $attr_value, $m) && ($exclamation = $m[1]) !== 'nill' && ($conditional = $m[2]) && ($attr_args = preg_replace('/['."\r\n\t".'\s]/', '', $m[4])) !== 'nill')
211 {
212 if(!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site() || !(preg_match('/[\$\(\)]/', $attr_args) || preg_match('/new['."\r\n\t".'\s]/i', $attr_args)))
213 {
214 if(is_array($args = preg_split('/[;,]+/', $attr_args, 0, PREG_SPLIT_NO_EMPTY))) // Convert all arguments into an array. And take note; possibly into an empty array.
215 {
216 if((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) && in_array(strtolower($conditional), $blog_farm_safe))
217 {
218 $test = ($exclamation) ? FALSE : TRUE; // If !exclamation (false) otherwise this defaults to true.
219
220 if(preg_match('/^\{(.*?)\}$/', $attr_args)) // Single argument passed as an array.
221 {
222 if($test === TRUE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
223 {
224 $condition_failed = TRUE;
225 break;
226 }
227 else if($test === FALSE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
228 {
229 $condition_failed = TRUE;
230 break;
231 }
232 }
233 else if(empty($args)) // No arguments at all.
234 {
235 if($test === TRUE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional))
236 {
237 $condition_failed = TRUE;
238 break;
239 }
240 else if($test === FALSE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional))
241 {
242 $condition_failed = TRUE;
243 break;
244 }
245 }
246 else if($test === TRUE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
247 {
248 $condition_failed = TRUE;
249 break;
250 }
251 else if($test === FALSE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
252 {
253 $condition_failed = TRUE;
254 break;
255 }
256 }
257 else
258 {
259 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, unsafe conditional function [ '.$attr_value.' ]');
260 return ''; // Return now; empty string in this case.
261 }
262 }
263 else
264 {
265 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, conditional args are NOT an array [ '.$attr_value.' ]');
266 return ''; // Return now; empty string in this case.
267 }
268 }
269 else
270 {
271 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, unsafe conditional args [ '.$attr_value.' ]');
272 return ''; // Return now; empty string in this case.
273 }
274 }
275 else
276 {
277 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, malformed conditional [ '.$attr_value.' ]');
278 return ''; // Return now; empty string in this case.
279 }
280 }
281 if(!empty($condition_failed))
282 $condition_content = isset($content_else) ? $content_else : '';
283 else $condition_content = isset($content_if) ? $content_if : $content;
284
285 if($condition_content) $condition_content = c_ws_plugin__s2member_utils_strings::trim_html($condition_content);
286
287 return do_shortcode(apply_filters('ws_plugin__s2member_sc_if_conditionals', $condition_content, get_defined_vars()));
288 }
289 else if($conditional_logic === 'OR') // This is the OR variation. This routine analyzes conditionals using OR logic, instead of AND logic.
290 {
291 foreach($attr as $attr_value) // This is the OR variation. This routine analyzes conditionals using OR logic, instead of AND logic.
292 {
293 if(preg_match('/^(\!?)(.+?)(\()(.*?)(\))$/', $attr_value, $m) && ($exclamation = $m[1]) !== 'nill' && ($conditional = $m[2]) && ($attr_args = preg_replace('/['."\r\n\t".'\s]/', '', $m[4])) !== 'nill')
294 {
295 if(!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site() || !(preg_match('/[\$\(\)]/', $attr_args) || preg_match('/new['."\r\n\t".'\s]/i', $attr_args)))
296 {
297 if(is_array($args = preg_split('/[;,]+/', $attr_args, 0, PREG_SPLIT_NO_EMPTY))) // Convert all arguments into an array. And take note; possibly into an empty array.
298 {
299 if((!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) && in_array(strtolower($conditional), $blog_farm_safe))
300 {
301 $test = ($exclamation) ? FALSE : TRUE; // If !exclamation (false) otherwise this defaults to true.
302
303 if(preg_match('/^\{(.*?)\}$/', $attr_args)) // Single argument passed as an array.
304 {
305 if($test === TRUE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
306 {
307 $condition_succeeded = TRUE;
308 break;
309 }
310 else if($test === FALSE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
311 {
312 $condition_succeeded = TRUE;
313 break;
314 }
315 }
316 else if(empty($args)) // No arguments at all.
317 {
318 if($test === TRUE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional))
319 {
320 $condition_succeeded = TRUE;
321 break;
322 }
323 else if($test === FALSE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional))
324 {
325 $condition_succeeded = TRUE;
326 break;
327 }
328 }
329 else if($test === TRUE && c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
330 {
331 $condition_succeeded = TRUE;
332 break;
333 }
334 else if($test === FALSE && !c_ws_plugin__s2member_sc_if_conds_in::safer_call_func($conditional, $args))
335 {
336 $condition_succeeded = TRUE;
337 break;
338 }
339 }
340 else
341 {
342 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, unsafe conditional function [ '.$attr_value.' ]');
343 return ''; // Return now; empty string in this case.
344 }
345 }
346 else
347 {
348 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, conditional args are NOT an array [ '.$attr_value.' ]');
349 return ''; // Return now; empty string in this case.
350 }
351 }
352 else
353 {
354 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, unsafe conditional args [ '.$attr_value.' ]');
355 return ''; // Return now; empty string in this case.
356 }
357 }
358 else
359 {
360 c_ws_plugin__s2member_sc_if_conds_in::warning('s2If, malformed conditional [ '.$attr_value.' ]');
361 return ''; // Return now; empty string in this case.
362 }
363 }
364 if(!empty($condition_succeeded))
365 $condition_content = isset($content_if) ? $content_if : $content;
366 else $condition_content = isset($content_else) ? $content_else : '';
367
368 if($condition_content) $condition_content = c_ws_plugin__s2member_utils_strings::trim_html($condition_content);
369
370 return do_shortcode(apply_filters('ws_plugin__s2member_sc_if_conditionals', $condition_content, get_defined_vars()));
371 }
372 return ''; // Default return value.
373 }
374
375 /**
376 * Sandbox for arbitrary PHP code evaluation in `[s2If/]` shortcodes.
377 *
378 * @package s2Member\s2If
379 * @since 140326
380 *
381 * @param string $expression PHP expression.
382 *
383 * @return bool TRUE if condition succeed; else FALSE.
384 */
385 public static function evl($expression)
386 {
387 // Buffer the output.
388 ob_start();
389 $result = eval('return (' . (string)$expression . ');');
390 $output = ob_get_clean();
391
392 // Return bool true if result true or there's output.
393 return ((bool)!empty($output) || (bool)$result);
394 }
395
396 /**
397 * Warning handler for s2If problems.
398 *
399 * Instead of trigger_error, which prevents the page from loading,
400 * this will simply not show the s2If block's content, letting the rest load,
401 * and log the error, with the URI where it happened.
402 *
403 * @package s2Member\s2If
404 * @since 230814
405 *
406 * @param string Warning message.
407 *
408 * @return
409 * @todo Asynch admin notice, enqueued for the admin to see later
410 */
411 public static function warning($message)
412 {
413 $log_message = $message . ' - URI: ' . esc_url($_SERVER['REQUEST_URI']);
414 error_log($log_message);
415 }
416
417 /**
418 * Do a safer call_user_func and call_user_func_array,
419 * with sanitation and output buffering.
420 *
421 * @package s2Member\s2If
422 * @since 230814
423 *
424 * @param string $conditional The callable function or method to be invoked.
425 * @param array $args Optional array of arguments to pass to the function.
426 *
427 * @return bool The boolean result of the condition.
428 */
429 public static function safer_call_func($conditional, $args = array())
430 {
431 // Sanitize
432 $chars = '\'`"\=:;*<>()[]/\\|?!&%#';
433 $trans = ' ';
434 $conditional = strtr($conditional, $chars, $trans);
435 if (!empty($args)) {
436 foreach ($args as $k => $arg) {
437 $args[$k] = strtr($arg, $chars, $trans);
438 }
439 }
440
441 // Buffer output
442 ob_start();
443 $result = call_user_func_array($conditional, $args);
444 $output = ob_get_clean();
445
446 // Return bool true if result true or there's output.
447 return ((bool)!empty($output) || (bool)$result);
448 }
449 }
450 }
451