PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Services/FormBuilder/EditorShortcodeParser.php +91 -61 6.2.8 → 6.2.15 View file →
@@ -8,14 +8,16 @@
8 8 class EditorShortcodeParser
9 9 {
10 10 /**
11 11 * Available dynamic short codes
12 + *
12 13 * @var null
13 14 */
14 15 private static $dynamicShortcodes = null;
15 -
16 +
16 17 /**
17 18 * mappings of methods to parse the shortcode
19 + *
18 20 * @var array
19 21 */
20 22 private static $handlers = [
21 23 'ip' => 'parseIp',
@@ -20,18 +22,18 @@
20 22 private static $handlers = [
21 23 'ip' => 'parseIp',
22 24 'date.m/d/Y' => 'parseDate',
23 25 'date.d/m/Y' => 'parseDate',
24 -
26 +
25 27 'embed_post.ID' => 'parsePostProperties',
26 28 'embed_post.post_title' => 'parsePostProperties',
27 29 'embed_post.permalink' => 'parsePostProperties',
28 30 'http_referer' => 'parseWPProperties',
29 -
31 +
30 32 'wp.admin_email' => 'parseWPProperties',
31 33 'wp.site_url' => 'parseWPProperties',
32 34 'wp.site_title' => 'parseWPProperties',
33 -
35 +
34 36 'user.ID' => 'parseUserProperties',
35 37 'user.display_name' => 'parseUserProperties',
36 38 'user.first_name' => 'parseUserProperties',
37 39 'user.last_name' => 'parseUserProperties',
@@ -36,16 +38,16 @@
36 38 'user.first_name' => 'parseUserProperties',
37 39 'user.last_name' => 'parseUserProperties',
38 40 'user.user_email' => 'parseUserProperties',
39 41 'user.user_login' => 'parseUserProperties',
40 -
42 +
41 43 'browser.name' => 'parseBrowserProperties',
42 44 'browser.platform' => 'parseBrowserProperties',
43 -
45 +
44 46 'get.param_name' => 'parseRequestParam',
45 47 'random_string.param_name' => 'parseRandomString',
46 48 ];
47 -
49 +
48 50 /**
49 51 * Filter dynamic shortcodes in input value
50 52 *
51 53 * @param string $value
@@ -57,15 +59,15 @@
57 59 if (0 === strpos($value, '{ ')) {
58 60 // it's the css
59 61 return $value;
60 62 }
61 -
63 +
62 64 if (is_null(static::$dynamicShortcodes)) {
63 65 static::$dynamicShortcodes = fluentFormEditorShortCodes();
64 66 }
65 -
67 +
66 68 $filteredValue = '';
67 -
69 +
68 70 foreach (static::parseValue($value) as $handler) {
69 71 if (isset(static::$handlers[$handler])) {
70 72 return call_user_func_array(
71 73 [__CLASS__, static::$handlers[$handler]],
@@ -71,9 +73,9 @@
71 73 [__CLASS__, static::$handlers[$handler]],
72 74 ['{' . $handler . '}', $form]
73 75 );
74 76 }
75 -
77 +
76 78 if (false !== strpos($handler, 'get.')) {
77 79 return static::parseRequestParam($handler);
78 80 }
79 81 if (false !== strpos($handler, 'random_string.')) {
@@ -78,9 +80,9 @@
78 80 }
79 81 if (false !== strpos($handler, 'random_string.')) {
80 82 return static::parseRandomString($handler);
81 83 }
82 -
84 +
83 85 if (false !== strpos($handler, 'user.')) {
84 86 $parsedValue = self::parseUserProperties($handler);
85 87 if (is_array($parsedValue) || is_object($parsedValue)) {
86 88 return '';
@@ -86,13 +88,13 @@
86 88 return '';
87 89 }
88 90 return esc_html($parsedValue);
89 91 }
90 -
92 +
91 93 if (false !== strpos($handler, 'date.')) {
92 94 return esc_html(self::parseDate($handler));
93 95 }
94 -
96 +
95 97 if (false !== strpos($handler, 'embed_post.meta.')) {
96 98 $key = substr(str_replace(['{', '}'], '', $value), 16);
97 99 global $post;
98 100 if ($post) {
@@ -102,19 +104,20 @@
102 104 }
103 105 }
104 106 return '';
105 107 }
106 -
108 +
107 109 if (false !== strpos($handler, 'embed_post.')) {
108 110 return self::parsePostProperties($handler, $form);
109 111 }
110 -
112 +
111 113 if (false !== strpos($handler, 'cookie.')) {
112 114 $scookieProperty = substr($handler, strlen('cookie.'));
113 -
114 - return array_key_exists($scookieProperty, $_COOKIE) ? wp_unslash($_COOKIE[$scookieProperty]) : '';
115 + $cookieValue = array_key_exists($scookieProperty, $_COOKIE) ? sanitize_text_field(wp_unslash($_COOKIE[$scookieProperty])) : '';
116 +
117 + return static::escapeReflectedValue($cookieValue);
115 118 }
116 -
119 +
117 120 if (false !== strpos($handler, 'dynamic.')) {
118 121 $dynamicKey = substr($handler, strlen('dynamic.'));
119 122 // maybe has fallback value
120 123 $dynamicKey = explode('|', $dynamicKey);
@@ -125,23 +128,23 @@
125 128 }
126 129 if (isset($dynamicKey[0])) {
127 130 $ref = $dynamicKey[0];
128 131 }
129 -
132 +
130 133 if ('payment_summary' == $ref) {
131 134 return fluentform_sanitize_html('<div class="ff_dynamic_value ff_dynamic_payment_summary" data-ref="payment_summary"><div class="ff_payment_summary"></div><div class="ff_payment_summary_fallback">' . $fallBack . '</div></div>');
132 135 }
133 -
136 +
134 137 return fluentform_sanitize_html('<span class="ff_dynamic_value" data-ref="' . $ref . '" data-fallback="' . $fallBack . '">' . $fallBack . '</span>');
135 138 }
136 -
139 +
137 140 // if it's multi line then just return
138 141 if (false !== strpos($handler, PHP_EOL)) { // most probably it's a css
139 142 return '{' . $handler . '}';
140 143 }
141 -
144 +
142 145 $handlerArray = explode('.', $handler);
143 -
146 +
144 147 if (count($handlerArray) > 1) {
145 148 // it's a grouped handler
146 149 $group = array_shift($handlerArray);
147 150 $parsedValue = apply_filters('fluentform_editor_shortcode_callback_group_' . $group, '{' . $handler . '}', $form, $handlerArray);
@@ -146,16 +149,16 @@
146 149 $group = array_shift($handlerArray);
147 150 $parsedValue = apply_filters('fluentform_editor_shortcode_callback_group_' . $group, '{' . $handler . '}', $form, $handlerArray);
148 151 return apply_filters('fluentform/editor_shortcode_callback_group_' . $group, $parsedValue, $form, $handlerArray);
149 152 }
150 -
153 +
151 154 $parsedValue = apply_filters('fluentform_editor_shortcode_callback_' . $handler, '{' . $handler . '}', $form);
152 155 return apply_filters('fluentform/editor_shortcode_callback_' . $handler, $parsedValue, $form);
153 156 }
154 -
157 +
155 158 return $filteredValue;
156 159 }
157 -
160 +
158 161 /**
159 162 * Parse request query param.
160 163 *
161 164 * @param string $value
@@ -167,20 +170,43 @@
167 170 {
168 171 $exploded = explode('.', $value);
169 172 $param = array_pop($exploded);
170 173 $value = wpFluentForm('request')->get($param);
171 -
172 - if (!$value) {
174 +
175 + if (null === $value || '' === $value) {
173 176 return '';
174 177 }
175 -
176 - if (is_array($value)) {
177 - return esc_attr(implode(', ', $value));
178 +
179 + return static::escapeReflectedValue(Helper::flattenRequestValue($value));
180 + }
181 +
182 + /**
183 + * Escape a visitor-supplied value ({get.x}, {cookie.x}) for the assembled form HTML.
184 + *
185 + * Smartcodes are substituted after Custom HTML was sanitized, so the value can land in
186 + * any attribute, including an iframe src or anchor href. esc_attr() leaves a javascript:
187 + * scheme intact and keeps existing entities (?p=java&#9;script:...), so encode every
188 + * ampersand and drop values that would resolve to a script-capable URL.
189 + *
190 + * @param string $value
191 + *
192 + * @return string
193 + */
194 + public static function escapeReflectedValue($value)
195 + {
196 + $value = wp_check_invalid_utf8((string) $value);
197 +
198 + // Browsers strip control chars and whitespace from URLs before reading the scheme.
199 + $scheme = strtolower(preg_replace('/[\x00-\x20]+/', '', $value));
200 +
201 + if (preg_match('/^(javascript|vbscript|data):/', $scheme)) {
202 + return '';
178 203 }
179 -
180 - return esc_attr($value);
204 +
205 + // Encode braces too, so the value cannot plant a smartcode for a later replacement pass.
206 + return str_replace(['{', '}'], ['&#123;', '&#125;'], htmlspecialchars($value, ENT_QUOTES, 'UTF-8', true));
181 207 }
182 -
208 +
183 209 /**
184 210 * Parse the curly braced shortcode into array
185 211 *
186 212 * @param string $value
@@ -196,16 +222,16 @@
196 222 -1,
197 223 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
198 224 );
199 225 }
200 -
226 +
201 227 return $value;
202 228 }
203 -
229 +
204 230 /**
205 231 * Declare all parsers and must be [private] static methods
206 232 */
207 -
233 +
208 234 /**
209 235 * Parse loggedin user properties
210 236 *
211 237 * @param string $value
@@ -215,13 +241,13 @@
215 241 private static function parseUserProperties($value, $form = null)
216 242 {
217 243 if ($user = wp_get_current_user()) {
218 244 $prop = substr(str_replace(['{', '}'], '', $value), 5);
219 -
245 +
220 246 if (false !== strpos($prop, 'meta.')) {
221 247 $metaKey = substr($prop, strlen('meta.'));
222 248 $metaKey = sanitize_text_field($metaKey);
223 - if (empty($metaKey)) {
249 + if (empty($metaKey) || ShortCodeParser::isDeniedUserProperty($metaKey)) {
224 250 return '';
225 251 }
226 252 $userId = $user->ID;
227 253 $data = get_user_meta($userId, $metaKey, true);
@@ -230,15 +256,19 @@
230 256 return esc_html($data);
231 257 }
232 258 return esc_html(implode(',', $data));
233 259 }
234 -
260 +
261 + if (ShortCodeParser::isDeniedUserProperty($prop)) {
262 + return '';
263 + }
264 +
235 265 return esc_html($user->{$prop});
236 266 }
237 -
267 +
238 268 return '';
239 269 }
240 -
270 +
241 271 /**
242 272 * Parse embedded post properties
243 273 *
244 274 * @param string $value
@@ -250,15 +280,15 @@
250 280 global $post;
251 281 if (!$post) {
252 282 return '';
253 283 }
254 -
284 +
255 285 $key = $prop = substr(str_replace(['{', '}'], '', $value), 11);
256 -
286 +
257 287 if (false !== strpos($key, 'author.')) {
258 288 $authorProperty = substr($key, strlen('author.'));
259 289 $authorId = $post->post_author;
260 - if ($authorId) {
290 + if ($authorId && !ShortCodeParser::isDeniedUserProperty($authorProperty)) {
261 291 $data = get_the_author_meta($authorProperty, $authorId);
262 292 if (!is_array($data)) {
263 293 return esc_html($data);
264 294 }
@@ -282,19 +312,19 @@
282 312 }
283 313 return '';
284 314 }
285 315 }
286 -
316 +
287 317 if ('permalink' == $prop) {
288 318 return site_url(esc_attr(urldecode(wpFluentForm('request')->server('REQUEST_URI'))));
289 319 }
290 -
291 - if (property_exists($post, $prop)) {
320 +
321 + if ('post_password' !== $prop && property_exists($post, $prop)) {
292 322 return esc_html($post->{$prop});
293 323 }
294 324 return '';
295 325 }
296 -
326 +
297 327 /**
298 328 * Parse WP Properties
299 329 *
300 330 * @param string $value
@@ -314,12 +344,12 @@
314 344 }
315 345 if ('{http_referer}' == $value) {
316 346 return esc_url(wp_get_referer());
317 347 }
318 -
348 +
319 349 return '';
320 350 }
321 -
351 +
322 352 /**
323 353 * Parse browser/user-agent properties
324 354 *
325 355 * @param string $value
@@ -333,12 +363,12 @@
333 363 return esc_html($browser->getBrowser());
334 364 } elseif ('{browser.platform}' == $value) {
335 365 return esc_html($browser->getPlatform());
336 366 }
337 -
367 +
338 368 return '';
339 369 }
340 -
370 +
341 371 /**
342 372 * Parse ip shortcode
343 373 *
344 374 * @param string $value
@@ -350,9 +380,9 @@
350 380 $rawIp = wpFluentForm('request')->getIp();
351 381 $ip = sanitize_text_field($rawIp);
352 382 return $ip ? esc_html($ip) : $value;
353 383 }
354 -
384 +
355 385 /**
356 386 * Parse date shortcode
357 387 *
358 388 * @param string $value
@@ -364,9 +394,9 @@
364 394 $format = substr(str_replace(['}', '{'], '', $value), 5);
365 395 $date = date($format, strtotime(current_time('mysql')));
366 396 return $date ? esc_html($date) : '';
367 397 }
368 -
398 +
369 399 /**
370 400 * Parse request query param.
371 401 *
372 402 * @param string $value
@@ -378,20 +408,20 @@
378 408 {
379 409 $exploded = explode('.', $value);
380 410 $param = array_pop($exploded);
381 411 $value = wpFluentForm('request')->get($param);
382 -
412 +
383 413 if (!$value) {
384 414 return '';
385 415 }
386 -
416 +
387 417 if (is_array($value)) {
388 418 return sanitize_textarea_field(implode(', ', $value));
389 419 }
390 -
420 +
391 421 return sanitize_textarea_field($value);
392 422 }
393 -
423 +
394 424 /**
395 425 * Generate random a string with prefix
396 426 *
397 427 * @param $value
@@ -402,8 +432,8 @@
402 432 {
403 433 $exploded = explode('.', $value);
404 434 $prefix = array_pop($exploded);
405 435 $value = $prefix . uniqid();
406 -
436 +
407 437 return esc_html(apply_filters('fluentform/shortcode_parser_callback_random_string', $value, $prefix, new static()));
408 438 }
409 439 }