PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.6
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.6
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 3.6.65 All 196 releases
fluentform / boot / globals.php

globals.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.6, at boot/globals.php

577 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') or die;
4
5 use FluentForm\Framework\Helpers\ArrayHelper;
6 use FluentForm\App\Modules\Component\BaseComponent;
7 use FluentForm\App\Services\FormBuilder\EditorShortCode;
8
9 /**
10 ***** DO NOT CALL ANY FUNCTIONS DIRECTLY FROM THIS FILE ******
11 *
12 * This file will be loaded even before the framework is loaded
13 * so the $app is not available here, only declare functions here.
14 */
15
16 //if ('dev' == $app->config->get('app.env')) {
17 // $globalsDevFile = __DIR__ . '/globals_dev.php';
18 //
19 // is_readable($globalsDevFile) && include $globalsDevFile;
20 //}
21
22 if (!function_exists('dd')) {
23 // function dd()
24 // {
25 // foreach (func_get_args() as $arg) {
26 // echo '<pre>';
27 // print_r($arg); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $value is only used for debugging in development.
28 // echo '</pre>';
29 // }
30 // exit();
31 // }
32 }
33
34 /**
35 * Get fluentform instance or other core modules
36 *
37 * @param string $key
38 *
39 * @return mixed
40 */
41 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
42 function wpFluentForm($key = null)
43 {
44 return \FluentForm\App\App::make($key);
45 }
46
47 /**
48 * Generate URL for static assets
49 *
50 * @param string $path
51 *
52 * @return string
53 */
54 function fluentFormMix($path = '')
55 {
56 return wpFluentForm('url.assets') . ltrim($path, '/');
57 }
58
59 if (! function_exists('wpFluent')) {
60 /**
61 * @return \FluentForm\Framework\Database\Query\Builder|\FluentForm\Framework\Database\Query\WPDBConnection
62 */
63 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
64 function wpFluent()
65 {
66 return wpFluentForm('db');
67 }
68 }
69
70
71 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
72 function wpFluentFormAddComponent(BaseComponent $component)
73 {
74 return $component->_init();
75 }
76
77 /**
78 * Sanitize form inputs recursively.
79 *
80 * @param $input
81 *
82 * @return mixed $input
83 */
84 function fluentFormSanitizer($input, $attribute = null, $fields = [])
85 {
86 if (is_string($input)) {
87 $element = ArrayHelper::get($fields, $attribute . '.element');
88
89 if (in_array($element, ['post_content', 'rich_text_input'])) {
90 return wp_kses_post($input);
91 } elseif ('textarea' === $element) {
92 $input = sanitize_textarea_field($input);
93 } elseif ('input_email' === $element) {
94 $input = strtolower(sanitize_text_field($input));
95 } elseif ('input_url' === $element) {
96 $input = sanitize_url($input);
97 } elseif ('input_password' === $element) {
98 $input = trim($input);
99 } else {
100 $input = sanitize_text_field($input);
101 }
102 } elseif (is_array($input)) {
103 $sanitizedInput = [];
104
105 foreach ($input as $key => &$value) {
106 $key = fluentFormSanitizer($key);
107 $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;
108
109 $value = fluentFormSanitizer($value, $attribute, $fields);
110 $attribute = null;
111 $sanitizedInput[$key] = $value;
112 }
113
114 $input = $sanitizedInput;
115 }
116
117 return $input;
118 }
119
120 function fluentFormEditorShortCodes()
121 {
122 $generalShortCodes = [EditorShortCode::getGeneralShortCodes()];
123 /* This filter is deprecated, will be removed soon. */
124 $generalShortCodes = apply_filters('fluentform_editor_shortcodes', $generalShortCodes);
125
126 return apply_filters('fluentform/editor_shortcodes', $generalShortCodes);
127 }
128
129 function fluentFormGetAllEditorShortCodes($form)
130 {
131 $editorShortCodes = EditorShortCode::getShortCodes($form);
132 /* This filter is deprecated and will be removed soon */
133 $editorShortCodes = apply_filters(
134 'fluentform_all_editor_shortcodes',
135 $editorShortCodes,
136 $form
137 );
138 return apply_filters(
139 'fluentform/all_editor_shortcodes',
140 $editorShortCodes,
141 $form
142 );
143 }
144
145 /**
146 * Recursively implode a multi-dimentional array
147 *
148 * @param string $glue
149 * @param array $array
150 *
151 * @return string
152 */
153 function fluentImplodeRecursive($glue, array $array)
154 {
155 $fn = function ($glue, array $array) use (&$fn) {
156 $result = '';
157 foreach ($array as $item) {
158 if (is_array($item)) {
159 $result .= $fn($glue, $item);
160 } else {
161 $result .= $glue . $item;
162 }
163 }
164
165 return $result;
166 };
167
168 return ltrim($fn($glue, $array), $glue);
169 }
170
171 function fluentform_get_active_theme_slug()
172 {
173 $ins = get_option('_ff_ins_by');
174
175 if ($ins) {
176 return sanitize_text_field($ins);
177 }
178
179 if (defined('TEMPLATELY_FILE')) {
180 return 'templately';
181 }
182
183 return get_option('template');
184 }
185
186 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
187 function getFluentFormCountryList()
188 {
189 static $countries = null;
190
191 if (is_null($countries)) {
192 $countries = fluentformLoadFile('/Services/FormBuilder/CountryNames.php');
193 }
194
195 return $countries;
196 }
197
198 function fluentFormWasSubmitted($action = 'fluentform_submit')
199 {
200 return wpFluentForm('request')->get('action') == $action;
201 }
202
203 if (!function_exists('isWpAsyncRequest')) {
204 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Global helper function, part of plugin API
205 function isWpAsyncRequest($action)
206 {
207 return false !== strpos(wpFluentForm('request')->get('action'), $action);
208 }
209 }
210
211 function fluentFormIsHandlingSubmission()
212 {
213 $status = fluentFormWasSubmitted() || isWpAsyncRequest('fluentform_async_request');
214
215 $status = apply_filters_deprecated(
216 'fluentform_is_handling_submission',
217 [
218 $status
219 ],
220 FLUENTFORM_FRAMEWORK_UPGRADE,
221 'fluentform/is_handling_submission',
222 'Use fluentform/is_handling_submission instead of fluentform_is_handling_submission'
223 );
224 return apply_filters('fluentform/is_handling_submission', $status);
225 }
226
227 function fluentform_mb_strpos($haystack, $needle)
228 {
229 if (function_exists('mb_strpos')) {
230 return mb_strpos($haystack, $needle);
231 }
232
233 return strpos($haystack, $needle);
234 }
235
236 function fluentFormHandleScheduledTasks()
237 {
238 $failedActions = wpFluent()->table('ff_scheduled_actions')->where('status', 'failed')->where('retry_count', '<', 4)->get();
239
240 if (count($failedActions)) {
241 $scheduler = wpFluentForm('fluentFormAsyncRequest');
242
243 foreach ($failedActions as $action) {
244 $scheduler->process($action);
245 }
246 }
247
248 $rand = wp_rand(1, 10);
249 if ($rand >= 5) {
250 do_action('fluentform/maybe_scheduled_jobs');
251 }
252 }
253
254 function fluentFormHandleScheduledEmailReport()
255 {
256 \FluentForm\App\Services\Scheduler\Scheduler::processEmailReport();
257 }
258
259 function fluentform_upgrade_url()
260 {
261 return 'https://fluentforms.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=ff_upgrade&theme_style=' . fluentform_get_active_theme_slug();
262 }
263
264 function fluentform_integrations_url()
265 {
266 return 'https://fluentforms.com/integration/?utm_source=plugin&utm_medium=wp_install&utm_campaign=ff_upgrade&theme_style=' . fluentform_get_active_theme_slug();
267 }
268
269 function fluentFormApi($module = 'forms')
270 {
271 if ('forms' == $module) {
272 return new \FluentForm\App\Api\Form();
273 } elseif ('submissions' == $module) {
274 return new \FluentForm\App\Api\Submission();
275 }
276
277 throw new \Exception(esc_html('No Module found with name ' . $module));
278 }
279
280 function fluentFormGetRandomPhoto()
281 {
282 $photos = [
283 'demo_1.jpg',
284 'demo_2.jpg',
285 'demo_3.jpg',
286 'demo_4.jpg',
287 'demo_5.jpg',
288 ];
289
290 $selected = array_rand($photos, 1);
291
292 $photoName = $photos[$selected];
293
294 return fluentformMix('img/conversational/' . $photoName);
295 }
296
297 function fluentFormRender($atts)
298 {
299 $shortcodeDefaults = [
300 'id' => null,
301 'title' => null,
302 'css_classes' => '',
303 'permission' => '',
304 'type' => 'classic',
305 'permission_message' => __('Sorry, You do not have permission to view this form', 'fluentform'),
306 ];
307 $atts = shortcode_atts($shortcodeDefaults, $atts);
308
309 return (new \FluentForm\App\Modules\Component\Component(wpFluentForm()))->renderForm($atts);
310 }
311
312 /**
313 * Print internal content (not user input) without escaping.
314 */
315 function fluentFormPrintUnescapedInternalString($string)
316 {
317 echo $string; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- deprecated function, should remove it later.
318 }
319
320 function fluentform_options_sanitize($options)
321 {
322 return \FluentForm\App\Helpers\Helper::sanitizeAdvancedOptions($options);
323 }
324
325 function fluentform_iframe_srcdoc_sanitize($value)
326 {
327 $tags = wp_kses_allowed_html('post');
328 $tags['style'] = [
329 'types' => [],
330 ];
331 // Check if decoding is necessary
332 if (strpos($value, '&') !== false) {
333 // Decode HTML entities
334 $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
335 $value = stripslashes($value);
336 }
337 return wp_kses($value, $tags);
338 }
339
340
341 function fluentform_sanitize_html($html)
342 {
343 if (!$html) {
344 return $html;
345 }
346
347 // Remove event handlers (e.g., onerror, onclick, onmouseover)
348 $html = preg_replace('/\s+on[a-z]+\s*=\s*([\'"])[^\'"]*\1/i', '', $html);
349
350 // Remove JavaScript protocol (e.g., `href="javascript:alert(1)"`)
351 $html = preg_replace('/\bjavascript\s*:/i', '', $html);
352
353 $tags = wp_kses_allowed_html('post');
354 $tags['style'] = [
355 'types' => [],
356 ];
357 // iframe
358 $tags['iframe'] = [
359 'width' => [],
360 'height' => [],
361 'src' => [],
362 'srcdoc' => [
363 'value_callback' => 'fluentform_iframe_srcdoc_sanitize'
364 ],
365 'title' => [],
366 'frameborder' => [],
367 'allow' => [],
368 'class' => [],
369 'id' => [],
370 'allowfullscreen' => [],
371 'style' => [],
372 ];
373
374 //svg
375 if (empty($tags['svg'])) {
376 $svg_args = [
377 'svg' => [
378 'class' => true,
379 'aria-hidden' => true,
380 'aria-labelledby' => true,
381 'role' => true,
382 'xmlns' => true,
383 'width' => true,
384 'height' => true,
385 'viewbox' => true,
386 'fill' => true,
387 'stroke' => true,
388 'stroke-width' => true,
389 'stroke-linecap' => true,
390 'stroke-linejoin' => true
391 ],
392 'g' => ['fill' => true],
393 'title' => ['title' => true],
394 'path' => [
395 'd' => true,
396 'fill' => true,
397 'transform' => true,
398 ],
399 'polyline' => [
400 'points' => true
401 ]
402 ];
403 $tags = array_merge($tags, $svg_args);
404 }
405
406 $tags = apply_filters_deprecated(
407 'fluentform_allowed_html_tags',
408 [
409 $tags
410 ],
411 FLUENTFORM_FRAMEWORK_UPGRADE,
412 'fluentform/allowed_html_tags',
413 'Use fluentform/allowed_html_tags instead of fluentform_allowed_html_tags'
414 );
415
416 $tags = apply_filters('fluentform/allowed_html_tags', $tags);
417
418 // Event-handler attributes are executable JavaScript and must not be re-enabled by filters.
419 foreach ($tags as $tagName => $attributes) {
420 if (!is_array($attributes)) {
421 continue;
422 }
423
424 foreach (array_keys($attributes) as $attribute) {
425 if (preg_match('/^on[a-z]+/i', $attribute)) {
426 unset($tags[$tagName][$attribute]);
427 }
428 }
429 }
430
431 return wp_kses($html, $tags);
432 }
433
434 function fluentform_kses_js($content)
435 {
436 if (!$content) {
437 return '';
438 }
439
440 return preg_replace('/<\/?script[^>]*>/is', '', $content);
441 }
442
443 function fluentform_sanitize_json_object($value)
444 {
445 if (!is_string($value) || '' === trim($value)) {
446 return '';
447 }
448
449 $value = trim($value);
450
451 $decoded = json_decode($value, true);
452
453 // Best-effort recovery of a pure-data JS-object literal (unquoted keys,
454 // single quotes, trailing commas) — the documented "JS object" format for
455 // the Date/Time field's advanced config. json_decode below is the security
456 // gate: any function or expression that survives normalisation is still not
457 // valid JSON, so it is rejected. Normalisation can only recover data, never
458 // execute or emit code.
459 if (JSON_ERROR_NONE !== json_last_error() || !is_array($decoded)) {
460 $decoded = json_decode(fluentform_js_object_to_json($value), true);
461 }
462
463 if (JSON_ERROR_NONE !== json_last_error() || !is_array($decoded)) {
464 return '';
465 }
466
467 if ([] === $decoded) {
468 return '{}';
469 }
470
471 // date_config must be an object; reject a top-level JSON array. Nested
472 // arrays (e.g. flatpickr `disable: [...]`) are preserved by not forcing
473 // JSON_FORCE_OBJECT recursively.
474 if (array_keys($decoded) === range(0, count($decoded) - 1)) {
475 return '';
476 }
477
478 return wp_json_encode($decoded);
479 }
480
481 function fluentform_js_object_to_json($value)
482 {
483 // Single-quoted strings -> double-quoted (respecting escapes).
484 $value = preg_replace_callback(
485 "/'((?:\\\\.|[^'\\\\])*)'/s",
486 function ($m) {
487 return '"' . str_replace(['\\\'', '"'], ['\'', '\\"'], $m[1]) . '"';
488 },
489 $value
490 );
491
492 // Quote unquoted object keys: `{ key:` / `, key:` -> `{ "key":`.
493 $value = preg_replace('/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)(\s*:)/', '$1"$2"$3', $value);
494
495 // Drop trailing commas before a closing brace/bracket.
496 $value = preg_replace('/,\s*([}\]])/', '$1', $value);
497
498 return $value;
499 }
500
501 /**
502 * Sanitize inputs recursively.
503 *
504 * @param array $input
505 * @param array $sanitizeMap
506 *
507 * @return array $input
508 */
509 function fluentform_backend_sanitizer($inputs, $sanitizeMap = [])
510 {
511 $originalValues = $inputs;
512 foreach ($inputs as $key => &$value) {
513 if (is_array($value)) {
514 $value = fluentform_backend_sanitizer($value, $sanitizeMap);
515 } else {
516 $method = ArrayHelper::get($sanitizeMap, $key);
517 if (is_callable($method)) {
518 $value = call_user_func($method, $value);
519 }
520 }
521 }
522
523 return apply_filters('fluentform/backend_sanitized_values', $inputs, $originalValues);
524 }
525
526 /**
527 * Sanitizes CSS.
528 *
529 * @return mixed $css
530 */
531 function fluentformSanitizeCSS($css)
532 {
533 if ($css === null || $css === '') {
534 return '';
535 }
536
537 // Convert to string if not already
538 if (!is_string($css)) {
539 $css = (string) $css;
540 }
541
542 return preg_match('#</?\w+#', $css) ? '' : $css;
543 }
544
545 function fluentformCanUnfilteredHTML()
546 {
547 return current_user_can('unfiltered_html') || apply_filters('fluentform/disable_fields_sanitize', false);
548 }
549
550 function fluentformLoadFile($path)
551 {
552 return require wpFluentForm('path.app') . '/' . ltrim($path, '/');
553 }
554
555 if (!function_exists('fluentValidator')) {
556 function fluentValidator($data = [], $rules = [], $messages = [])
557 {
558 return wpFluentForm('validator')->make($data, $rules, $messages);
559 }
560 }
561
562 function fluentformGetPages()
563 {
564 $pages = get_pages();
565 $formattedPages = [];
566
567 foreach ($pages as $page) {
568 $formattedPages[] = [
569 'ID' => $page->ID,
570 'post_title' => $page->post_title,
571 'guid' => $page->guid,
572 ];
573 }
574
575 return $formattedPages;
576 }
577