PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
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
← All changes | app/Modules/Form/FormHandler.php +569 -113 3.6.226.2.14 View file →
@@ -1,37 +1,48 @@
1 1 <?php
2 2
3 3 namespace FluentForm\App\Modules\Form;
4 4
5 -use FluentForm\App\Databases\Migrations\FormSubmissionDetails;
5 +use FluentForm\Database\Migrations\SubmissionDetails;
6 +use FluentForm\App\Helpers\Helper;
6 7 use FluentForm\App\Modules\Activator;
7 -use FluentForm\App\Modules\Entries\Entries;
8 8 use FluentForm\App\Modules\ReCaptcha\ReCaptcha;
9 +use FluentForm\App\Modules\HCaptcha\HCaptcha;
10 +use FluentForm\App\Modules\Turnstile\Turnstile;
9 11 use FluentForm\App\Services\Browser\Browser;
10 12 use FluentForm\App\Services\FormBuilder\ShortCodeParser;
13 +use FluentForm\App\Services\Submission\SubmissionService;
11 14 use FluentForm\Framework\Foundation\Application;
12 15 use FluentForm\Framework\Helpers\ArrayHelper as Arr;
13 16 use FluentForm\Framework\Helpers\ArrayHelper;
14 17
18 +/* @deprecated Use class \FluentForm\App\Http\Controllers\SubmissionHandlerController */
19 +
15 20 class FormHandler
16 21 {
17 22 /**
23 + * App instance
24 + *
18 25 * @var \FluentForm\Framework\Foundation\Application
19 26 */
20 27 protected $app;
21 28
22 29 /**
30 + * Request object
31 + *
23 32 * @var \FluentForm\Framework\Request\Request
24 33 */
25 34 protected $request;
26 35
27 36 /**
37 + * Form Data
38 + *
28 39 * @var array $formData
29 40 */
30 41 protected $formData;
31 42
32 43 /**
33 - * The fluent form object.
44 + * The Fluent Forms object.
34 45 *
35 46 * @var \stdClass
36 47 */
37 48 protected $form;
@@ -50,8 +61,9 @@
50 61 /**
51 62 * Set the form using it's ID.
52 63 *
53 64 * @param $formId
65 + *
54 66 * @return $this
55 67 */
56 68 public function setForm($formId)
57 69 {
@@ -66,8 +78,10 @@
66 78 {
67 79 // Parse the url encoded data from the request object.
68 80 parse_str($this->app->request->get('data'), $data);
69 81
82 + $data['_wp_http_referer'] = urldecode($data['_wp_http_referer']);
83 +
70 84 // Merge it back again to the request object.
71 85 $this->app->request->merge(['data' => $data]);
72 86
73 87 $formId = intval($this->app->request->get('form_id'));
@@ -73,8 +87,14 @@
73 87 $formId = intval($this->app->request->get('form_id'));
74 88
75 89 $this->setForm($formId);
76 90
91 + if (!$this->form) {
92 + wp_send_json([
93 + 'errors' => [],
94 + 'message' => 'Sorry, No corresponding form found',
95 + ], 423);
96 + }
77 97
78 98 // Parse the form and get the flat inputs with validations.
79 99 $fields = FormFieldsParser::getInputs($this->form, ['rules', 'raw']);
80 100
@@ -86,21 +106,64 @@
86 106
87 107 // Prepare the data to be inserted to the DB.
88 108 $insertData = $this->prepareInsertData();
89 109
90 - if ($this->isSpam($this->formData, $this->form)) {
110 + if ($this->isAkismetSpam($this->formData, $this->form)) {
91 111 $insertData['status'] = 'spam';
92 112 $this->handleSpamError();
93 113 }
94 114
95 - do_action('fluentform_before_insert_submission', $insertData, $data, $this->form);
115 + do_action_deprecated(
116 + 'fluentform_before_insert_submission',
117 + [
118 + $insertData,
119 + $data,
120 + $this->form
121 + ],
122 + FLUENTFORM_FRAMEWORK_UPGRADE,
123 + 'fluentform/before_insert_submission',
124 + 'Use fluentform/before_insert_submission instead of fluentform_before_insert_submission.'
125 + );
96 126
127 + do_action('fluentform/before_insert_submission', $insertData, $data, $this->form);
128 +
97 129 if ($this->form->has_payment) {
98 - do_action('fluentform_before_insert_payment_form', $insertData, $data, $this->form);
130 + do_action_deprecated(
131 + 'fluentform_before_insert_payment_form',
132 + [
133 + $insertData,
134 + $data,
135 + $this->form
136 + ],
137 + FLUENTFORM_FRAMEWORK_UPGRADE,
138 + 'fluentform/before_insert_payment_form',
139 + 'Use fluentform/before_insert_payment_form instead of fluentform_before_insert_payment_form.'
140 + );
141 +
142 + do_action('fluentform/before_insert_payment_form', $insertData, $data, $this->form);
99 143 }
100 144
101 - $insertId = wpFluent()->table('fluentform_submissions')->insert($insertData);
145 + $insertId = wpFluent()->table('fluentform_submissions')->insertGetId($insertData);
102 146
147 + do_action('fluentform/notify_on_form_submit', $insertId, $this->formData, $this->form);
148 +
149 + $uidHash = md5(wp_generate_uuid4() . $insertId);
150 + Helper::setSubmissionMeta($insertId, '_entry_uid_hash', $uidHash, $formId);
151 +
152 + do_action_deprecated(
153 + 'fluentform_before_form_actions_processing',
154 + [
155 + $insertId,
156 + $this->formData,
157 + $this->form
158 + ],
159 + FLUENTFORM_FRAMEWORK_UPGRADE,
160 + 'fluentform/before_form_actions_processing',
161 + 'Use fluentform/before_form_actions_processing instead of fluentform_before_form_actions_processing.'
162 + );
163 +
164 + do_action('fluentform/before_form_actions_processing', $insertId, $this->formData, $this->form);
165 +
103 166 $result = $this->processFormSubmissionData($insertId, $this->formData, $this->form);
104 167
105 168 wp_send_json_success($result, 200);
106 169 }
@@ -108,13 +171,13 @@
108 171 public function processFormSubmissionData($insertId, $formData, $form)
109 172 {
110 173 if ($insertId) {
111 174 ob_start();
112 - $entries = new Entries();
113 - $entries->recordEntryDetails($insertId, $form->id, $formData);
175 + $submissionService = new SubmissionService();
176 + $submissionService->recordEntryDetails($insertId, $form->id, $formData);
114 177 $isError = ob_get_clean();
115 178 if ($isError) {
116 - FormSubmissionDetails::migrate();
179 + SubmissionDetails::migrate();
117 180 }
118 181 }
119 182
120 183 $returnData = $this->getReturnData($insertId, $form, $formData);
@@ -120,21 +183,42 @@
120 183 $returnData = $this->getReturnData($insertId, $form, $formData);
121 184
122 185 $error = '';
123 186 try {
124 - $this->app->doAction(
125 - 'fluentform_submission_inserted',
187 +
188 + /*
189 + * We will keep this old hook for backward compatability.
190 + */
191 + do_action('fluentform_submission_inserted', $insertId, $formData, $form);
192 +
193 + do_action(
194 + 'fluentform/submission_inserted',
126 195 $insertId,
127 196 $formData,
128 197 $form
129 198 );
130 199
131 - $this->app->doAction(
200 + Helper::setSubmissionMeta($insertId, 'is_form_action_fired', 'yes');
201 +
202 + do_action_deprecated(
132 203 'fluentform_submission_inserted_' . $form->type . '_form',
204 + [
205 + $insertId,
206 + $formData,
207 + $form
208 + ],
209 + FLUENTFORM_FRAMEWORK_UPGRADE,
210 + 'fluentform/submission_inserted',
211 + 'Use fluentform/submission_inserted_' . $form->type . '_form' . ' instead of fluentform_submission_inserted_' . $form->type . '_form'
212 + );
213 +
214 + do_action(
215 + 'fluentform/submission_inserted_' . $form->type . '_form',
133 216 $insertId,
134 217 $formData,
135 218 $form
136 219 );
220 +
137 221 } catch (\Exception $e) {
138 222 if (defined('WP_DEBUG') && WP_DEBUG) {
139 223 $error = $e->getMessage();
140 224 }
@@ -139,14 +223,26 @@
139 223 $error = $e->getMessage();
140 224 }
141 225 }
142 226
143 - do_action('fluenform_before_submission_confirmation', $insertId, $formData, $form);
227 + do_action_deprecated(
228 + 'fluentform_before_submission_confirmation',
229 + [
230 + $insertId,
231 + $formData,
232 + $form
233 + ],
234 + FLUENTFORM_FRAMEWORK_UPGRADE,
235 + 'fluentform/before_submission_confirmation',
236 + 'Use fluentform/before_submission_confirmation instead of fluentform_before_submission_confirmation.'
237 + );
144 238
239 + do_action('fluentform/before_submission_confirmation', $insertId, $formData, $form);
240 +
145 241 return [
146 242 'insert_id' => $insertId,
147 - 'result' => $returnData,
148 - 'error' => $error
243 + 'result' => $returnData,
244 + 'error' => $error,
149 245 ];
150 246 }
151 247
152 248 public function getReturnData($insertId, $form, $formData)
@@ -158,40 +254,61 @@
158 254 ->first();
159 255
160 256 $form->settings = $formSettings ? json_decode($formSettings->value, true) : [];
161 257 }
162 -
163 - $confirmation = apply_filters(
258 + $confirmation = $form->settings['confirmation'];
259 + $confirmation = apply_filters_deprecated(
164 260 'fluentform_form_submission_confirmation',
165 - $form->settings['confirmation'],
261 + [
262 + $confirmation,
263 + $formData,
264 + $form
265 + ],
266 + FLUENTFORM_FRAMEWORK_UPGRADE,
267 + 'fluentform/form_submission_confirmation',
268 + 'Use fluentform/form_submission_confirmation instead of fluentform_form_submission_confirmation.'
269 + );
270 +
271 + $confirmation = $this->app->applyFilters(
272 + 'fluentform/form_submission_confirmation',
273 + $confirmation,
166 274 $formData,
167 275 $form
168 276 );
169 277
170 - if ($confirmation['redirectTo'] == 'samePage') {
278 + if ('samePage' == $confirmation['redirectTo']) {
279 +
280 + $confirmation['messageToShow'] = fluentform_sanitize_html($confirmation['messageToShow']);
281 +
282 + $confirmation['messageToShow'] = do_shortcode($confirmation['messageToShow']);
283 +
284 + $confirmation['messageToShow'] = apply_filters('fluentform/submission_message_parse',
285 + $confirmation['messageToShow'], $insertId, $formData, $form);
286 +
171 287 $message = ShortCodeParser::parse(
172 288 $confirmation['messageToShow'],
173 289 $insertId,
174 290 $formData,
175 - $form
291 + $form,
292 + false,
293 + true
176 294 );
177 295
178 296 $message = $message ? $message : 'The form has been successfully submitted.';
179 297
180 298 $returnData = [
181 - 'message' => do_shortcode($message),
182 - 'action' => $confirmation['samePageFormBehavior'],
299 + 'message' => $message,
300 + 'action' => $confirmation['samePageFormBehavior'],
183 301 ];
184 -
185 302 } else {
186 303 $redirectUrl = Arr::get($confirmation, 'customUrl');
187 304
188 - if ($confirmation['redirectTo'] == 'customPage') {
305 + if ('customPage' == $confirmation['redirectTo']) {
189 306 $redirectUrl = get_permalink($confirmation['customPage']);
190 307 }
191 308
192 309 if (
193 - (Arr::get($confirmation, 'enable_query_string') == 'yes') &&
310 + ('yes' == Arr::get($confirmation, 'enable_query_string')) &&
194 311 Arr::get($confirmation, 'query_strings')
195 312 ) {
196 313 if (strpos($redirectUrl, '?')) {
197 314 $redirectUrl .= '&' . Arr::get($confirmation, 'query_strings');
@@ -198,39 +315,52 @@
198 315 } else {
199 316 $redirectUrl .= '?' . Arr::get($confirmation, 'query_strings');
200 317 }
201 318 }
319 + $parseUrl = true;
320 + $parseUrl = apply_filters_deprecated(
321 + 'fluentform_will_parse_url_value',
322 + [
323 + $parseUrl,
324 + $form
325 + ],
326 + FLUENTFORM_FRAMEWORK_UPGRADE,
327 + 'fluentform/will_parse_url_value',
328 + 'Use fluentform/will_parse_url_value instead of fluentform_will_parse_url_value.'
329 + );
202 330
331 + $isUrlParser = apply_filters('fluentform/will_parse_url_value', $parseUrl, $form);
332 +
203 333 $redirectUrl = ShortCodeParser::parse(
204 334 $redirectUrl,
205 335 $insertId,
206 336 $formData,
207 337 $form,
208 - true
338 + $isUrlParser
209 339 );
340 +
341 + if ($isUrlParser) {
342 + /*
343 + * For Empty Redirect Value
344 + */
345 + if (strpos($redirectUrl, '=&') || '=' == substr($redirectUrl, -1)) {
346 + $urlArray = explode('?', $redirectUrl);
347 + $baseUrl = array_shift($urlArray);
210 348
211 - $redirectUrl = esc_url_raw($redirectUrl);
349 + $query = wp_parse_url($redirectUrl)['query'];
212 350
213 - /*
214 - * For Empty Redirect Value
215 - */
216 - if(strpos($redirectUrl, '=&') || substr($redirectUrl, -1) == '=') {
217 - $urlArray = explode('?', $redirectUrl);
218 - $baseUrl = array_shift($urlArray);
351 + $queryParams = explode('&', $query);
219 352
220 - $query = wp_parse_url($redirectUrl)['query'];
353 + $params = [];
354 + foreach ($queryParams as $queryParam) {
355 + $paramArray = explode('=', $queryParam);
356 + if (!empty($paramArray[1])) {
357 + $params[$paramArray[0]] = $paramArray[1];
358 + }
359 + }
221 360
222 - $queryParams = explode('&', $query);
223 -
224 - $params = [];
225 - foreach ($queryParams as $queryParam) {
226 - $paramArray = explode('=', $queryParam);
227 - if(!empty($paramArray[1])) {
228 - $params[$paramArray[0]] = $paramArray[1];
229 - }
361 + $redirectUrl = add_query_arg($params, $baseUrl);
230 362 }
231 -
232 - $redirectUrl = add_query_arg($params, $baseUrl);
233 363 }
234 364
235 365 $message = ShortCodeParser::parse(
236 366 ArrayHelper::get($confirmation, 'redirectMessage', ''),
@@ -235,19 +365,34 @@
235 365 $message = ShortCodeParser::parse(
236 366 ArrayHelper::get($confirmation, 'redirectMessage', ''),
237 367 $insertId,
238 368 $formData,
239 - $form
369 + $form,
370 + false,
371 + true
240 372 );
241 -
373 +
374 + $redirectUrl = wp_sanitize_redirect(urldecode($redirectUrl));
242 375 $returnData = [
243 - 'redirectUrl' => $redirectUrl,
244 - 'message' => $message
376 + 'redirectUrl' => esc_url_raw($redirectUrl),
377 + 'message' => $message,
245 378 ];
246 379 }
380 +
381 + $returnData = apply_filters_deprecated(
382 + 'fluentform_submission_confirmation',
383 + [
384 + $returnData,
385 + $form,
386 + $confirmation
387 + ],
388 + FLUENTFORM_FRAMEWORK_UPGRADE,
389 + 'fluentform/submission_confirmation',
390 + 'Use fluentform/submission_confirmation instead of fluentform_submission_confirmation.'
391 + );
247 392
248 393 return $this->app->applyFilters(
249 - 'fluentform_submission_confirmation',
394 + 'fluentform/submission_confirmation',
250 395 $returnData,
251 396 $form,
252 397 $confirmation
253 398 );
@@ -256,22 +401,60 @@
256 401 /**
257 402 * Validate form data.
258 403 *
259 404 * @param $fields
405 + *
260 406 * @return bool
261 407 */
262 408 private function validate(&$fields)
263 409 {
410 + $this->preventMaliciousAttacks();
411 +
264 412 $this->validateRestrictions($fields);
265 413
266 414 $this->validateNonce();
267 415
268 416 $this->validateReCaptcha();
417 + $this->validateHCaptcha();
418 + $this->validateTurnstile();
269 419
420 + foreach ($fields as $fieldName => $field) {
421 + if (isset($this->formData[$fieldName])) {
422 + $element = $field['element'];
423 +
424 + $this->formData[$fieldName] = apply_filters_deprecated(
425 + 'fluentform_input_data_' . $element,
426 + [
427 + $this->formData[$fieldName],
428 + $field,
429 + $this->formData,
430 + $this->form
431 + ],
432 + FLUENTFORM_FRAMEWORK_UPGRADE,
433 + 'fluentform/input_data_' . $element,
434 + 'Use fluentform/input_data_' . $element . ' instead of fluentform_input_data_' . $element
435 + );
436 +
437 + $this->formData[$fieldName] = $this->app->applyFilters('fluentform/input_data_' . $element,
438 + $this->formData[$fieldName], $field, $this->formData, $this->form);
439 + }
440 + }
441 +
270 442 $originalValidations = FormFieldsParser::getValidations($this->form, $this->formData, $fields);
271 -
443 +
444 + $originalValidations = apply_filters_deprecated(
445 + 'fluentform_validations',
446 + [
447 + $originalValidations,
448 + $this->form,
449 + $this->formData
450 + ],
451 + FLUENTFORM_FRAMEWORK_UPGRADE,
452 + 'fluentform/validations',
453 + 'Use fluentform/validations instead of fluentform_validations.'
454 + );
272 455 // Fire an event so that one can hook into it to work with the rules & messages.
273 - $validations = apply_filters('fluentform_validations', $originalValidations, $this->form);
456 + $validations = apply_filters('fluentform/validations', $originalValidations, $this->form, $this->formData);
274 457
275 458 /*
276 459 * Clean talk fix for now
277 460 * They should not hook fluentform_validations and return nothing!
@@ -280,9 +463,9 @@
280 463 if ($originalValidations && (!$validations || !array_filter($validations))) {
281 464 $validations = $originalValidations;
282 465 }
283 466
284 - $validator = \FluentValidator\Validator::make($this->formData, $validations[0], $validations[1]);
467 + $validator = wpFluentForm('validator')->make($this->formData, $validations[0], $validations[1]);
285 468
286 469 $errors = [];
287 470 if ($validator->validate()->fails()) {
288 471 foreach ($validator->errors() as $attribute => $rules) {
@@ -293,10 +476,24 @@
293 476 }
294 477
295 478 $errors[$attribute] = $rules;
296 479 }
480 +
481 + $errors = apply_filters_deprecated(
482 + 'fluentform_validation_error',
483 + [
484 + $errors,
485 + $this->form,
486 + $fields,
487 + $this->formData
488 + ],
489 + FLUENTFORM_FRAMEWORK_UPGRADE,
490 + 'fluentform/validation_error',
491 + 'Use fluentform/validation_error instead of fluentform_validation_error.'
492 + );
297 493 // Fire an event so that one can hook into it to work with the errors.
298 - $errors = $this->app->applyFilters('fluentform_validation_error', $errors, $this->form, $fields);
494 + $errors = $this->app->applyFilters('fluentform/validation_error', $errors, $this->form, $fields,
495 + $this->formData);
299 496 }
300 497
301 498 foreach ($fields as $fieldKey => $field) {
302 499 $field['data_key'] = $fieldKey;
@@ -301,15 +498,31 @@
301 498 foreach ($fields as $fieldKey => $field) {
302 499 $field['data_key'] = $fieldKey;
303 500 $inputName = \FluentForm\Framework\Helpers\ArrayHelper::get($field, 'raw.attributes.name');
304 501 $field['name'] = $inputName;
305 - $error = apply_filters('fluentform_validate_input_item_' . $field['element'], '', $field, $this->formData, $fields, $this->form, $errors);
502 +
503 + $error = apply_filters_deprecated(
504 + 'fluentform_validate_input_item_' . $field['element'],
505 + [
506 + '',
507 + $field,
508 + $this->formData,
509 + $fields,
510 + $this->form,
511 + $errors
512 + ],
513 + FLUENTFORM_FRAMEWORK_UPGRADE,
514 + 'fluentform_validate_input_item_' . $field['element'],
515 + 'Use fluentform/validate_input_item_' . $field['element'] . ' instead of fluentform_validate_input_item_' . $field['element']
516 + );
517 +
518 + $error = apply_filters('fluentform/validate_input_item_' . $field['element'], $error, $field, $this->formData, $fields, $this->form, $errors);
306 519 if ($error) {
307 520 if (empty($errors[$inputName])) {
308 521 $errors[$inputName] = [];
309 522 }
310 523
311 - if(is_string($error)) {
524 + if (is_string($error)) {
312 525 $error = [$error];
313 526 }
314 527
315 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
@@ -314,13 +527,61 @@
314 527
315 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
316 529 }
317 530 }
531 +
532 + $errors = apply_filters_deprecated(
533 + 'fluentform_validation_errors',
534 + [
535 + $errors,
536 + $this->formData,
537 + $this->form,
538 + $fields
539 + ],
540 + FLUENTFORM_FRAMEWORK_UPGRADE,
541 + 'fluentform/validation_errors',
542 + 'Use fluentform/validation_errors instead of fluentform_validation_errors.'
543 + );
318 544
319 - $errors = apply_filters('fluentform_validation_errors', $errors, $this->formData, $this->form, $fields);
545 + $errors = apply_filters('fluentform/validation_errors', $errors, $this->formData, $this->form, $fields);
320 546
547 + if ('yes' == Helper::getFormMeta($this->form->id, '_has_user_registration') && !get_current_user_id()) {
548 + $errors = apply_filters_deprecated(
549 + 'fluentform_validation_user_registration_errors',
550 + [
551 + $errors,
552 + $this->formData,
553 + $this->form,
554 + $fields
555 + ],
556 + FLUENTFORM_FRAMEWORK_UPGRADE,
557 + 'fluentform/validation_user_registration_errors',
558 + 'Use fluentform/validation_user_registration_errors instead of fluentform_validation_user_registration_errors.'
559 + );
560 +
561 + $errors = apply_filters('fluentform/validation_user_registration_errors', $errors, $this->formData,
562 + $this->form, $fields);
563 + }
564 +
565 + if ('yes' == Helper::getFormMeta($this->form->id, '_has_user_update') && get_current_user_id()) {
566 + $errors = apply_filters_deprecated(
567 + 'fluentform_validation_user_update_errors',
568 + [
569 + $errors,
570 + $this->formData,
571 + $this->form,
572 + $fields
573 + ],
574 + FLUENTFORM_FRAMEWORK_UPGRADE,
575 + 'fluentform/validation_user_update_errors',
576 + 'Use fluentform/validation_user_update_errors instead of fluentform_validation_user_update_errors.'
577 + );
578 +
579 + $errors = apply_filters('fluentform/validation_user_update_errors', $errors, $this->formData, $this->form, $fields);
580 + }
581 +
321 582 if ($errors) {
322 - wp_send_json(['errors' => $errors], 422);
583 + wp_send_json(['errors' => $errors], 423);
323 584 }
324 585
325 586 return true;
326 587 }
@@ -330,19 +591,30 @@
330 591 */
331 592 protected function validateNonce()
332 593 {
333 594 $formId = $this->form->id;
595 + $nonceVerify = false;
596 + /* This filter is deprecated and will be removed soon. */
597 + $nonceVerify = $this->app->applyFilters('fluentform_nonce_verify', $nonceVerify, $formId);
334 598
335 - $shouldVerifyNonce = $this->app->applyFilters('fluentform_nonce_verify', false, $formId);
599 + $shouldVerifyNonce = $this->app->applyFilters('fluentform/nonce_verify', $nonceVerify, $formId);
336 600
337 601 if ($shouldVerifyNonce) {
338 602 $nonce = Arr::get($this->formData, '_fluentform_' . $formId . '_fluentformnonce');
339 603 if (!wp_verify_nonce($nonce, 'fluentform-submit-form')) {
340 - $errors = $this->app->applyFilters('fluentForm_nonce_error', [
341 - '_fluentformnonce' => [
342 - __('Nonce verification failed, please try again.', 'fluentform')
343 - ]
344 - ]);
604 + $nonceMessage = apply_filters_deprecated(
605 + 'fluentForm_nonce_error',
606 + [
607 + '_fluentformnonce' => [
608 + __('Nonce verification failed, please try again.', 'fluentform'),
609 + ],
610 + ],
611 + FLUENTFORM_FRAMEWORK_UPGRADE,
612 + 'fluentform/nonce_error',
613 + 'Use fluentform/nonce_error instead of fluentForm_nonce_error.'
614 + );
615 +
616 + $errors = $this->app->applyFilters('fluentform/nonce_error', $nonceMessage);
345 617 wp_send_json(['errors' => $errors], 422);
346 618 }
347 619 }
348 620 }
@@ -349,33 +621,61 @@
349 621
350 622 protected function handleSpamError()
351 623 {
352 624 $settings = get_option('_fluentform_global_form_settings');
353 - if (!$settings || ArrayHelper::get($settings, 'misc.akismet_validation') != 'validation_failed') {
625 + if (!$settings || 'validation_failed' != ArrayHelper::get($settings, 'misc.akismet_validation')) {
354 626 return;
355 627 }
356 628
357 - $errors = [
358 - '_fluentformakismet' => __('Submission marked as spammed. Please try again', 'fluentform')
629 + $errors = [
630 + '_fluentformakismet' => apply_filters(
631 + 'fluentform/akismet_spam_message',
632 + __('Submission marked as spammed. Please try again', 'fluentform'),
633 + $this->form->id
634 + ),
359 635 ];
360 636
361 637 wp_send_json(['errors' => $errors], 422);
362 638 }
363 639
364 - protected function isSpam($formData, $form)
640 + protected function isAkismetSpam($formData, $form)
365 641 {
366 642 if (!AkismetHandler::isEnabled()) {
367 643 return false;
368 644 }
645 + $isSpamCheck = true;
646 + $isSpamCheck = apply_filters_deprecated(
647 + 'fluentform_akismet_check_spam',
648 + [
649 + true,
650 + $form->id,
651 + $formData
652 + ],
653 + FLUENTFORM_FRAMEWORK_UPGRADE,
654 + 'fluentform/akismet_check_spam',
655 + 'Use fluentform/akismet_check_spam instead of fluentform_akismet_check_spam.'
656 + );
369 657
370 - $isSpamCheck = apply_filters('fluentform_akismet_check_spam', true, $form->id, $formData);
658 + $isSpamCheck = apply_filters('fluentform/akismet_check_spam', $isSpamCheck, $form->id, $formData);
371 659 if (!$isSpamCheck) {
372 660 return false;
373 661 }
374 662 // Let's validate now
375 663 $isSpam = AkismetHandler::isSpamSubmission($formData, $form);
664 +
665 + $isSpam = apply_filters_deprecated(
666 + 'fluentform_akismet_spam_result',
667 + [
668 + $isSpam,
669 + $form->id,
670 + $formData
671 + ],
672 + FLUENTFORM_FRAMEWORK_UPGRADE,
673 + 'fluentform/akismet_spam_result',
674 + 'Use fluentform/akismet_spam_result instead of fluentform_akismet_spam_result.'
675 + );
376 676
377 - return apply_filters('fluentform_akismet_spam_result', $isSpam, $form->id, $formData);
677 + return $this->app->applyFilters('fluentform/akismet_spam_result', $isSpam, $form->id, $formData);
378 678 }
379 679
380 680 /**
381 681 * Validate reCaptcha.
@@ -381,24 +681,107 @@
381 681 * Validate reCaptcha.
382 682 */
383 683 private function validateReCaptcha()
384 684 {
385 - if (FormFieldsParser::hasElement($this->form, 'recaptcha')) {
386 - $isValid = ReCaptcha::validate(Arr::get($this->formData, 'g-recaptcha-response'));
685 + $hasAutoRecaptcha = false;
686 + $hasAutoRecaptcha = apply_filters_deprecated(
687 + 'ff_has_auto_recaptcha',
688 + [
689 + $hasAutoRecaptcha
690 + ],
691 + FLUENTFORM_FRAMEWORK_UPGRADE,
692 + 'fluentform/has_recaptcha',
693 + 'Use fluentform/has_recaptcha instead of ff_has_auto_recaptcha.'
694 + );
695 + $autoInclude = apply_filters('fluentform/has_recaptcha', $hasAutoRecaptcha);
696 + if (FormFieldsParser::hasElement($this->form, 'recaptcha') || $autoInclude) {
697 + $keys = get_option('_fluentform_reCaptcha_details');
698 + $token = Arr::get($this->formData, 'g-recaptcha-response');
699 + $version = 'v2_visible';
700 + if (!empty($keys['api_version'])) {
701 + $version = $keys['api_version'];
702 + }
703 + $isValid = ReCaptcha::validate($token, $keys['secretKey'], $version);
387 704
388 705 if (!$isValid) {
389 - wp_send_json([
390 - 'errors' => [
391 - 'g-recaptcha-response' => [
392 - __('reCaptcha verification failed, please try again.', 'fluentform')
393 - ]
394 - ]
395 - ], 422);
706 + $message = apply_filters(
707 + 'fluentform/recaptcha_failed_message',
708 + __('reCaptcha verification failed, please try again.', 'fluentform'),
709 + $this->form
710 + );
711 + wp_send_json(['errors' => ['g-recaptcha-response' => [$message]]], 422);
396 712 }
397 713 }
398 714 }
399 715
400 716 /**
717 + * Validate hCaptcha.
718 + */
719 + private function validateHCaptcha()
720 + {
721 + $hasAutoHcaptcha = false;
722 +
723 + $hasAutoHcaptcha = apply_filters_deprecated(
724 + 'ff_has_auto_hcaptcha',
725 + [
726 + $hasAutoHcaptcha
727 + ],
728 + FLUENTFORM_FRAMEWORK_UPGRADE,
729 + 'fluentform/has_hcaptcha',
730 + 'Use fluentform/has_hcaptcha instead of ff_has_auto_hcaptcha.'
731 + );
732 + $autoInclude = apply_filters('fluentform/has_hcaptcha', $hasAutoHcaptcha);
733 + FormFieldsParser::resetData();
734 + if (FormFieldsParser::hasElement($this->form, 'hcaptcha') || $autoInclude) {
735 + $keys = get_option('_fluentform_hCaptcha_details');
736 + $token = Arr::get($this->formData, 'h-captcha-response');
737 + $isValid = HCaptcha::validate($token, $keys['secretKey']);
738 +
739 + if (!$isValid) {
740 + $message = apply_filters(
741 + 'fluentform/hcaptcha_failed_message',
742 + __('hCaptcha verification failed, please try again.', 'fluentform'),
743 + $this->form
744 + );
745 + wp_send_json(['errors' => ['h-captcha-response' => [$message]]], 422);
746 + }
747 + }
748 + }
749 +
750 + /**
751 + * Validate turnstile.
752 + */
753 + private function validateTurnstile()
754 + {
755 + $hasAutoTurnsTile = false;
756 + $hasAutoTurnsTile = apply_filters_deprecated(
757 + 'ff_has_auto_turnstile',
758 + [
759 + $hasAutoTurnsTile
760 + ],
761 + FLUENTFORM_FRAMEWORK_UPGRADE,
762 + 'fluentform/has_turnstile',
763 + 'Use fluentform/has_turnstile instead of ff_has_auto_turnstile.'
764 + );
765 + $autoInclude = apply_filters('fluentform/has_turnstile', $hasAutoTurnsTile);
766 + if (FormFieldsParser::hasElement($this->form, 'turnstile') || $autoInclude) {
767 + $keys = get_option('_fluentform_turnstile_details');
768 + $token = Arr::get($this->formData, 'cf-turnstile-response');
769 +
770 + $isValid = Turnstile::validate($token, $keys['secretKey']);
771 +
772 + if (!$isValid) {
773 + $message = apply_filters(
774 + 'fluentform/turnstile_failed_message',
775 + __('Turnstile verification failed, please try again.', 'fluentform'),
776 + $this->form
777 + );
778 + wp_send_json(['errors' => ['cf-turnstile-response' => [$message]]], 422);
779 + }
780 + }
781 + }
782 +
783 + /**
401 784 * Validate form data based on the form restrictions settings.
402 785 *
403 786 * @param $fields
404 787 */
@@ -411,10 +794,10 @@
411 794
412 795 $this->form->settings = $formSettings ? json_decode($formSettings->value, true) : [];
413 796
414 797 $isAllowed = [
415 - 'status' => true,
416 - 'message' => ''
798 + 'status' => true,
799 + 'message' => '',
417 800 ];
418 801
419 802 // This will check the following restriction settings.
420 803 // 1. limitNumberOfEntries
@@ -419,17 +802,21 @@
419 802 // This will check the following restriction settings.
420 803 // 1. limitNumberOfEntries
421 804 // 2. scheduleForm
422 805 // 3. requireLogin
806 +
807 + /* This filter is deprecated and will be removed soon */
423 808 $isAllowed = apply_filters('fluentform_is_form_renderable', $isAllowed, $this->form);
809 +
810 + $isAllowed = apply_filters('fluentform/is_form_renderable', $isAllowed, $this->form);
424 811
425 812 if (!$isAllowed['status']) {
426 813 wp_send_json([
427 814 'errors' => [
428 815 'restricted' => [
429 - __($isAllowed['message'], 'fluentform')
430 - ]
431 - ]
816 + $isAllowed['message'],
817 + ],
818 + ],
432 819 ], 422);
433 820 }
434 821
435 822 // Since we are here, we should now handle if the form should be allowed to submit empty.
@@ -443,9 +830,9 @@
443 830 *
444 831 * @param array $settings
445 832 * @param $fields
446 833 */
447 - private function handleDenyEmptySubmission($settings = [], &$fields)
834 + private function handleDenyEmptySubmission($settings, &$fields)
448 835 {
449 836 // Determine whether empty form submission is allowed or not.
450 837 if (Arr::get($settings, 'enabled')) {
451 838 // confirm this form has no required fields.
@@ -451,9 +838,9 @@
451 838 // confirm this form has no required fields.
452 839 if (!FormFieldsParser::hasRequiredFields($this->form, $fields)) {
453 840 // Filter out the form data which doesn't have values.
454 841 $filteredFormData = array_filter(
455 - // Filter out the other meta fields that aren't actual inputs.
842 + // Filter out the other meta fields that aren't actual inputs.
456 843 array_intersect_key($this->formData, $fields)
457 844 );
458 845
459 846 // TODO: Extract this function into global functions file...
@@ -467,19 +854,18 @@
467 854 return $array;
468 855 };
469 856
470 857 if (!count($arrayFilterRecursive($filteredFormData))) {
858 + $message = Arr::get($settings, 'message');
859 + if (!$message) {
860 + $message = __('Sorry! You can\'t submit an empty form.', 'fluentform');
861 + }
471 862 wp_send_json([
472 863 'errors' => [
473 864 'restricted' => [
474 - __(
475 - !($m = Arr::get($settings, 'message'))
476 - ? 'Sorry! You can\'t submit an empty form.'
477 - : $m,
478 - 'fluentform'
479 - )
480 - ]
481 - ]
865 + $message,
866 + ],
867 + ],
482 868 ], 422);
483 869 }
484 870 }
485 871 }
@@ -488,13 +874,13 @@
488 874 /**
489 875 * Prepare the data to be inserted to the database.
490 876 *
491 877 * @param boolean $formData
878 + *
492 879 * @return array
493 880 */
494 881 public function prepareInsertData($formData = false)
495 882 {
496 -
497 883 $formId = $this->form->id;
498 884
499 885 if (!$formData) {
500 886 $formData = $this->formData;
@@ -510,34 +896,67 @@
510 896 if ($previousItem) {
511 897 $serialNumber = $previousItem->serial_number + 1;
512 898 }
513 899
514 - $browser = new Browser;
900 + $browser = new Browser();
515 901
516 - $inputConfigs = FormFieldsParser::getEntryInputs($this->form, array('admin_label', 'raw'));
902 + $inputConfigs = FormFieldsParser::getEntryInputs($this->form, ['admin_label', 'raw']);
903 +
904 + $formData = apply_filters_deprecated(
905 + 'fluentform_insert_response_data',
906 + [
907 + $formData,
908 + $formId,
909 + $inputConfigs
910 + ],
911 + FLUENTFORM_FRAMEWORK_UPGRADE,
912 + 'fluentform/insert_response_data',
913 + 'Use fluentform/insert_response_data instead of fluentform_insert_response_data.'
914 + );
915 + $this->formData = apply_filters('fluentform/insert_response_data', $formData, $formId, $inputConfigs);
517 916
518 - $this->formData = apply_filters('fluentform_insert_response_data', $formData, $formId, $inputConfigs);
917 + $ipAddress = sanitize_text_field($this->app->request->getIp());
918 + $disableIpLogging = false;
919 + $disableIpLogging = apply_filters_deprecated(
920 + 'fluentform_disable_ip_logging',
921 + [
922 + $disableIpLogging,
923 + $formId
924 + ],
925 + FLUENTFORM_FRAMEWORK_UPGRADE,
926 + 'fluentform/disable_ip_logging',
927 + 'Use fluentform/disable_ip_logging instead of fluentform_disable_ip_logging.'
928 + );
519 929
520 - $ipAddress = $this->app->request->getIp();
521 -
522 - if ((defined('FLUENTFROM_DISABLE_IP_LOGGING') && FLUENTFROM_DISABLE_IP_LOGGING) || apply_filters('fluentform_disable_ip_logging', false, $formId)) {
930 + if ((defined('FLUENTFROM_DISABLE_IP_LOGGING') && FLUENTFROM_DISABLE_IP_LOGGING) || apply_filters('fluentform/disable_ip_logging',
931 + $disableIpLogging, $formId)) {
523 932 $ipAddress = false;
524 933 }
525 934
526 935 $response = [
527 - 'form_id' => $formId,
936 + 'form_id' => $formId,
528 937 'serial_number' => $serialNumber,
529 - 'response' => json_encode($this->formData),
530 - 'source_url' => site_url(Arr::get($this->formData, '_wp_http_referer')),
531 - 'user_id' => get_current_user_id(),
532 - 'browser' => $browser->getBrowser(),
533 - 'device' => $browser->getPlatform(),
534 - 'ip' => $ipAddress,
535 - 'created_at' => current_time('mysql'),
536 - 'updated_at' => current_time('mysql')
938 + 'response' => json_encode($this->formData, JSON_UNESCAPED_UNICODE),
939 + 'source_url' => site_url(Arr::get($formData, '_wp_http_referer')),
940 + 'user_id' => get_current_user_id(),
941 + 'browser' => $browser->getBrowser(),
942 + 'device' => $browser->getPlatform(),
943 + 'ip' => $ipAddress,
944 + 'created_at' => current_time('mysql'),
945 + 'updated_at' => current_time('mysql'),
537 946 ];
947 +
948 + $response = apply_filters_deprecated(
949 + 'fluentform_filter_insert_data',
950 + [
951 + $response
952 + ],
953 + FLUENTFORM_FRAMEWORK_UPGRADE,
954 + 'fluentform/filter_insert_data',
955 + 'Use fluentform/filter_insert_data instead of fluentform_filter_insert_data.'
956 + );
538 957
539 - return apply_filters('fluentform_filter_insert_data', $response);
958 + return apply_filters('fluentform/filter_insert_data', $response);
540 959 }
541 960
542 961 /**
543 962 * Delegate the validation rules & messages to the
@@ -542,10 +961,11 @@
542 961 /**
543 962 * Delegate the validation rules & messages to the
544 963 * ones that the validation library recognizes.
545 964 *
546 - * @param $rules
547 - * @param $messages
965 + * @param $rules
966 + * @param $messages
967 + *
548 968 * @return array
549 969 */
550 970 protected function delegateValidations($rules, $messages, $search = [], $replace = [])
551 971 {
@@ -564,5 +984,41 @@
564 984
565 985 return [$rules, $messages];
566 986 }
567 987
988 + /**
989 + * Prevents malicious attacks when the submission
990 + * count exceeds in an allowed interval.
991 + */
992 + public function preventMaliciousAttacks()
993 + {
994 + $prevent = apply_filters('fluentform/prevent_malicious_attacks', true, $this->form->id);
995 +
996 + if ($prevent) {
997 + $maxSubmissionCount = apply_filters('fluentform/max_submission_count', 5, $this->form->id);
998 + $minSubmissionInterval = apply_filters('fluentform/min_submission_interval', 30, $this->form->id);
999 +
1000 + $interval = date('Y-m-d H:i:s', strtotime(current_time('mysql')) - $minSubmissionInterval);
1001 +
1002 + $clientIp = sanitize_text_field($this->app->request->getIp());
1003 + $submissionCount = wpFluent()->table('fluentform_submissions')
1004 + ->where('status', '!=', 'trashed')
1005 + ->where('ip', $clientIp ?: '0.0.0.0')
1006 + ->where('created_at', '>=', $interval)
1007 + ->count();
1008 +
1009 + if ($submissionCount >= $maxSubmissionCount) {
1010 + wp_send_json([
1011 + 'errors' => [
1012 + 'restricted' => [
1013 + apply_filters(
1014 + 'fluentform/too_many_requests',
1015 + __('Too Many Requests.', 'fluentform'),
1016 + $this->form->id
1017 + ),
1018 + ],
1019 + ],
1020 + ], 429);
1021 + }
1022 + }
1023 + }
568 1024 }