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
fluentform / app / Services / FormBuilder / EditorShortcodeParser.php

EditorShortcodeParser.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.15, at app/Services/FormBuilder/EditorShortcodeParser.php

440 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\FormBuilder;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\App\Services\Browser\Browser;
7
8 class EditorShortcodeParser
9 {
10 /**
11 * Available dynamic short codes
12 *
13 * @var null
14 */
15 private static $dynamicShortcodes = null;
16
17 /**
18 * mappings of methods to parse the shortcode
19 *
20 * @var array
21 */
22 private static $handlers = [
23 'ip' => 'parseIp',
24 'date.m/d/Y' => 'parseDate',
25 'date.d/m/Y' => 'parseDate',
26
27 'embed_post.ID' => 'parsePostProperties',
28 'embed_post.post_title' => 'parsePostProperties',
29 'embed_post.permalink' => 'parsePostProperties',
30 'http_referer' => 'parseWPProperties',
31
32 'wp.admin_email' => 'parseWPProperties',
33 'wp.site_url' => 'parseWPProperties',
34 'wp.site_title' => 'parseWPProperties',
35
36 'user.ID' => 'parseUserProperties',
37 'user.display_name' => 'parseUserProperties',
38 'user.first_name' => 'parseUserProperties',
39 'user.last_name' => 'parseUserProperties',
40 'user.user_email' => 'parseUserProperties',
41 'user.user_login' => 'parseUserProperties',
42
43 'browser.name' => 'parseBrowserProperties',
44 'browser.platform' => 'parseBrowserProperties',
45
46 'get.param_name' => 'parseRequestParam',
47 'random_string.param_name' => 'parseRandomString',
48 ];
49
50 /**
51 * Filter dynamic shortcodes in input value
52 *
53 * @param string $value
54 *
55 * @return string
56 */
57 public static function filter($value, $form)
58 {
59 if (0 === strpos($value, '{ ')) {
60 // it's the css
61 return $value;
62 }
63
64 if (is_null(static::$dynamicShortcodes)) {
65 static::$dynamicShortcodes = fluentFormEditorShortCodes();
66 }
67
68 $filteredValue = '';
69
70 foreach (static::parseValue($value) as $handler) {
71 if (isset(static::$handlers[$handler])) {
72 return call_user_func_array(
73 [__CLASS__, static::$handlers[$handler]],
74 ['{' . $handler . '}', $form]
75 );
76 }
77
78 if (false !== strpos($handler, 'get.')) {
79 return static::parseRequestParam($handler);
80 }
81 if (false !== strpos($handler, 'random_string.')) {
82 return static::parseRandomString($handler);
83 }
84
85 if (false !== strpos($handler, 'user.')) {
86 $parsedValue = self::parseUserProperties($handler);
87 if (is_array($parsedValue) || is_object($parsedValue)) {
88 return '';
89 }
90 return esc_html($parsedValue);
91 }
92
93 if (false !== strpos($handler, 'date.')) {
94 return esc_html(self::parseDate($handler));
95 }
96
97 if (false !== strpos($handler, 'embed_post.meta.')) {
98 $key = substr(str_replace(['{', '}'], '', $value), 16);
99 global $post;
100 if ($post) {
101 $metaValue = get_post_meta($post->ID, $key, true);
102 if (!is_array($metaValue) && !is_object($metaValue)) {
103 return esc_html($metaValue);
104 }
105 }
106 return '';
107 }
108
109 if (false !== strpos($handler, 'embed_post.')) {
110 return self::parsePostProperties($handler, $form);
111 }
112
113 if (false !== strpos($handler, 'cookie.')) {
114 $scookieProperty = substr($handler, strlen('cookie.'));
115 $cookieValue = array_key_exists($scookieProperty, $_COOKIE) ? sanitize_text_field(wp_unslash($_COOKIE[$scookieProperty])) : '';
116
117 return static::escapeReflectedValue($cookieValue);
118 }
119
120 if (false !== strpos($handler, 'dynamic.')) {
121 $dynamicKey = substr($handler, strlen('dynamic.'));
122 // maybe has fallback value
123 $dynamicKey = explode('|', $dynamicKey);
124 $fallBack = '';
125 $ref = '';
126 if (count($dynamicKey) > 1) {
127 $fallBack = $dynamicKey[1];
128 }
129 if (isset($dynamicKey[0])) {
130 $ref = $dynamicKey[0];
131 }
132
133 if ('payment_summary' == $ref) {
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>');
135 }
136
137 return fluentform_sanitize_html('<span class="ff_dynamic_value" data-ref="' . $ref . '" data-fallback="' . $fallBack . '">' . $fallBack . '</span>');
138 }
139
140 // if it's multi line then just return
141 if (false !== strpos($handler, PHP_EOL)) { // most probably it's a css
142 return '{' . $handler . '}';
143 }
144
145 $handlerArray = explode('.', $handler);
146
147 if (count($handlerArray) > 1) {
148 // it's a grouped handler
149 $group = array_shift($handlerArray);
150 $parsedValue = apply_filters('fluentform_editor_shortcode_callback_group_' . $group, '{' . $handler . '}', $form, $handlerArray);
151 return apply_filters('fluentform/editor_shortcode_callback_group_' . $group, $parsedValue, $form, $handlerArray);
152 }
153
154 $parsedValue = apply_filters('fluentform_editor_shortcode_callback_' . $handler, '{' . $handler . '}', $form);
155 return apply_filters('fluentform/editor_shortcode_callback_' . $handler, $parsedValue, $form);
156 }
157
158 return $filteredValue;
159 }
160
161 /**
162 * Parse request query param.
163 *
164 * @param string $value
165 * @param \stdClass $form
166 *
167 * @return string
168 */
169 public static function parseRequestParam($value)
170 {
171 $exploded = explode('.', $value);
172 $param = array_pop($exploded);
173 $value = wpFluentForm('request')->get($param);
174
175 if (null === $value || '' === $value) {
176 return '';
177 }
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 '';
203 }
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));
207 }
208
209 /**
210 * Parse the curly braced shortcode into array
211 *
212 * @param string $value
213 *
214 * @return mixed
215 */
216 public static function parseValue($value)
217 {
218 if (!is_array($value)) {
219 return preg_split(
220 '/{(.*?)}/',
221 $value,
222 -1,
223 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
224 );
225 }
226
227 return $value;
228 }
229
230 /**
231 * Declare all parsers and must be [private] static methods
232 */
233
234 /**
235 * Parse loggedin user properties
236 *
237 * @param string $value
238 *
239 * @return string
240 */
241 private static function parseUserProperties($value, $form = null)
242 {
243 if ($user = wp_get_current_user()) {
244 $prop = substr(str_replace(['{', '}'], '', $value), 5);
245
246 if (false !== strpos($prop, 'meta.')) {
247 $metaKey = substr($prop, strlen('meta.'));
248 $metaKey = sanitize_text_field($metaKey);
249 if (empty($metaKey) || ShortCodeParser::isDeniedUserProperty($metaKey)) {
250 return '';
251 }
252 $userId = $user->ID;
253 $data = get_user_meta($userId, $metaKey, true);
254 $data = Helper::safeUnserialize($data);
255 if (!is_array($data)) {
256 return esc_html($data);
257 }
258 return esc_html(implode(',', $data));
259 }
260
261 if (ShortCodeParser::isDeniedUserProperty($prop)) {
262 return '';
263 }
264
265 return esc_html($user->{$prop});
266 }
267
268 return '';
269 }
270
271 /**
272 * Parse embedded post properties
273 *
274 * @param string $value
275 *
276 * @return string
277 */
278 private static function parsePostProperties($value, $form = null)
279 {
280 global $post;
281 if (!$post) {
282 return '';
283 }
284
285 $key = $prop = substr(str_replace(['{', '}'], '', $value), 11);
286
287 if (false !== strpos($key, 'author.')) {
288 $authorProperty = substr($key, strlen('author.'));
289 $authorId = $post->post_author;
290 if ($authorId && !ShortCodeParser::isDeniedUserProperty($authorProperty)) {
291 $data = get_the_author_meta($authorProperty, $authorId);
292 if (!is_array($data)) {
293 return esc_html($data);
294 }
295 }
296 return '';
297 } elseif (false !== strpos($key, 'meta.')) {
298 $metaKey = substr($key, strlen('meta.'));
299 $postId = $post->ID;
300 $data = get_post_meta($postId, $metaKey, true);
301 if (!is_array($data)) {
302 return esc_html($data);
303 }
304 return '';
305 } elseif (false !== strpos($key, 'acf.')) {
306 $metaKey = substr($key, strlen('acf.'));
307 $postId = $post->ID;
308 if (function_exists('get_field')) {
309 $data = get_field($metaKey, $postId, true);
310 if (!is_array($data)) {
311 return esc_html($data);
312 }
313 return '';
314 }
315 }
316
317 if ('permalink' == $prop) {
318 return site_url(esc_attr(urldecode(wpFluentForm('request')->server('REQUEST_URI'))));
319 }
320
321 if ('post_password' !== $prop && property_exists($post, $prop)) {
322 return esc_html($post->{$prop});
323 }
324 return '';
325 }
326
327 /**
328 * Parse WP Properties
329 *
330 * @param string $value
331 *
332 * @return string
333 */
334 private static function parseWPProperties($value, $form = null)
335 {
336 if ('{wp.admin_email}' == $value) {
337 return esc_html(get_option('admin_email'));
338 }
339 if ('{wp.site_url}' == $value) {
340 return esc_url(site_url());
341 }
342 if ('{wp.site_title}' == $value) {
343 return esc_html(get_option('blogname'));
344 }
345 if ('{http_referer}' == $value) {
346 return esc_url(wp_get_referer());
347 }
348
349 return '';
350 }
351
352 /**
353 * Parse browser/user-agent properties
354 *
355 * @param string $value
356 *
357 * @return string
358 */
359 private static function parseBrowserProperties($value, $form = null)
360 {
361 $browser = new Browser();
362 if ('{browser.name}' == $value) {
363 return esc_html($browser->getBrowser());
364 } elseif ('{browser.platform}' == $value) {
365 return esc_html($browser->getPlatform());
366 }
367
368 return '';
369 }
370
371 /**
372 * Parse ip shortcode
373 *
374 * @param string $value
375 *
376 * @return string
377 */
378 private static function parseIp($value, $form = null)
379 {
380 $rawIp = wpFluentForm('request')->getIp();
381 $ip = sanitize_text_field($rawIp);
382 return $ip ? esc_html($ip) : $value;
383 }
384
385 /**
386 * Parse date shortcode
387 *
388 * @param string $value
389 *
390 * @return string
391 */
392 private static function parseDate($value, $form = null)
393 {
394 $format = substr(str_replace(['}', '{'], '', $value), 5);
395 $date = date($format, strtotime(current_time('mysql')));
396 return $date ? esc_html($date) : '';
397 }
398
399 /**
400 * Parse request query param.
401 *
402 * @param string $value
403 * @param \stdClass $form
404 *
405 * @return string
406 */
407 public static function parseQueryParam($value)
408 {
409 $exploded = explode('.', $value);
410 $param = array_pop($exploded);
411 $value = wpFluentForm('request')->get($param);
412
413 if (!$value) {
414 return '';
415 }
416
417 if (is_array($value)) {
418 return sanitize_textarea_field(implode(', ', $value));
419 }
420
421 return sanitize_textarea_field($value);
422 }
423
424 /**
425 * Generate random a string with prefix
426 *
427 * @param $value
428 *
429 * @return string
430 */
431 public static function parseRandomString($value)
432 {
433 $exploded = explode('.', $value);
434 $prefix = array_pop($exploded);
435 $value = $prefix . uniqid();
436
437 return esc_html(apply_filters('fluentform/shortcode_parser_callback_random_string', $value, $prefix, new static()));
438 }
439 }
440