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 +538 -111 3.6.606.2.14 View file →
@@ -1,38 +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 6 use FluentForm\App\Helpers\Helper;
7 7 use FluentForm\App\Modules\Activator;
8 -use FluentForm\App\Modules\Entries\Entries;
9 8 use FluentForm\App\Modules\ReCaptcha\ReCaptcha;
9 +use FluentForm\App\Modules\HCaptcha\HCaptcha;
10 +use FluentForm\App\Modules\Turnstile\Turnstile;
10 11 use FluentForm\App\Services\Browser\Browser;
11 12 use FluentForm\App\Services\FormBuilder\ShortCodeParser;
13 +use FluentForm\App\Services\Submission\SubmissionService;
12 14 use FluentForm\Framework\Foundation\Application;
13 15 use FluentForm\Framework\Helpers\ArrayHelper as Arr;
14 16 use FluentForm\Framework\Helpers\ArrayHelper;
15 17
18 +/* @deprecated Use class \FluentForm\App\Http\Controllers\SubmissionHandlerController */
19 +
16 20 class FormHandler
17 21 {
18 22 /**
23 + * App instance
24 + *
19 25 * @var \FluentForm\Framework\Foundation\Application
20 26 */
21 27 protected $app;
22 28
23 29 /**
30 + * Request object
31 + *
24 32 * @var \FluentForm\Framework\Request\Request
25 33 */
26 34 protected $request;
27 35
28 36 /**
37 + * Form Data
38 + *
29 39 * @var array $formData
30 40 */
31 41 protected $formData;
32 42
33 43 /**
34 - * The fluent form object.
44 + * The Fluent Forms object.
35 45 *
36 46 * @var \stdClass
37 47 */
38 48 protected $form;
@@ -51,8 +61,9 @@
51 61 /**
52 62 * Set the form using it's ID.
53 63 *
54 64 * @param $formId
65 + *
55 66 * @return $this
56 67 */
57 68 public function setForm($formId)
58 69 {
@@ -67,9 +78,9 @@
67 78 {
68 79 // Parse the url encoded data from the request object.
69 80 parse_str($this->app->request->get('data'), $data);
70 81
71 - $data['_wp_http_referer'] = urldecode( $data['_wp_http_referer']);
82 + $data['_wp_http_referer'] = urldecode($data['_wp_http_referer']);
72 83
73 84 // Merge it back again to the request object.
74 85 $this->app->request->merge(['data' => $data]);
75 86
@@ -76,8 +87,15 @@
76 87 $formId = intval($this->app->request->get('form_id'));
77 88
78 89 $this->setForm($formId);
79 90
91 + if (!$this->form) {
92 + wp_send_json([
93 + 'errors' => [],
94 + 'message' => 'Sorry, No corresponding form found',
95 + ], 423);
96 + }
97 +
80 98 // Parse the form and get the flat inputs with validations.
81 99 $fields = FormFieldsParser::getInputs($this->form, ['rules', 'raw']);
82 100
83 101 // Sanitize the data properly.
@@ -88,26 +106,64 @@
88 106
89 107 // Prepare the data to be inserted to the DB.
90 108 $insertData = $this->prepareInsertData();
91 109
92 - if ($this->isSpam($this->formData, $this->form)) {
110 + if ($this->isAkismetSpam($this->formData, $this->form)) {
93 111 $insertData['status'] = 'spam';
94 112 $this->handleSpamError();
95 113 }
96 114
97 - 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 + );
98 126
127 + do_action('fluentform/before_insert_submission', $insertData, $data, $this->form);
128 +
99 129 if ($this->form->has_payment) {
100 - 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);
101 143 }
102 144
103 - $insertId = wpFluent()->table('fluentform_submissions')->insert($insertData);
145 + $insertId = wpFluent()->table('fluentform_submissions')->insertGetId($insertData);
104 146
147 + do_action('fluentform/notify_on_form_submit', $insertId, $this->formData, $this->form);
148 +
105 149 $uidHash = md5(wp_generate_uuid4() . $insertId);
106 150 Helper::setSubmissionMeta($insertId, '_entry_uid_hash', $uidHash, $formId);
107 151
108 - do_action('fluentform_before_form_actions_processing', $insertId, $this->formData, $this->form);
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 + );
109 163
164 + do_action('fluentform/before_form_actions_processing', $insertId, $this->formData, $this->form);
165 +
110 166 $result = $this->processFormSubmissionData($insertId, $this->formData, $this->form);
111 167
112 168 wp_send_json_success($result, 200);
113 169 }
@@ -115,13 +171,13 @@
115 171 public function processFormSubmissionData($insertId, $formData, $form)
116 172 {
117 173 if ($insertId) {
118 174 ob_start();
119 - $entries = new Entries();
120 - $entries->recordEntryDetails($insertId, $form->id, $formData);
175 + $submissionService = new SubmissionService();
176 + $submissionService->recordEntryDetails($insertId, $form->id, $formData);
121 177 $isError = ob_get_clean();
122 178 if ($isError) {
123 - FormSubmissionDetails::migrate();
179 + SubmissionDetails::migrate();
124 180 }
125 181 }
126 182
127 183 $returnData = $this->getReturnData($insertId, $form, $formData);
@@ -127,10 +183,16 @@
127 183 $returnData = $this->getReturnData($insertId, $form, $formData);
128 184
129 185 $error = '';
130 186 try {
131 - $this->app->doAction(
132 - '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',
133 195 $insertId,
134 196 $formData,
135 197 $form
136 198 );
@@ -136,14 +198,27 @@
136 198 );
137 199
138 200 Helper::setSubmissionMeta($insertId, 'is_form_action_fired', 'yes');
139 201
140 - $this->app->doAction(
202 + do_action_deprecated(
141 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',
142 216 $insertId,
143 217 $formData,
144 218 $form
145 219 );
220 +
146 221 } catch (\Exception $e) {
147 222 if (defined('WP_DEBUG') && WP_DEBUG) {
148 223 $error = $e->getMessage();
149 224 }
@@ -148,14 +223,26 @@
148 223 $error = $e->getMessage();
149 224 }
150 225 }
151 226
152 - 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 + );
153 238
239 + do_action('fluentform/before_submission_confirmation', $insertId, $formData, $form);
240 +
154 241 return [
155 242 'insert_id' => $insertId,
156 - 'result' => $returnData,
157 - 'error' => $error
243 + 'result' => $returnData,
244 + 'error' => $error,
158 245 ];
159 246 }
160 247
161 248 public function getReturnData($insertId, $form, $formData)
@@ -167,45 +254,61 @@
167 254 ->first();
168 255
169 256 $form->settings = $formSettings ? json_decode($formSettings->value, true) : [];
170 257 }
171 -
172 - $confirmation = apply_filters(
258 + $confirmation = $form->settings['confirmation'];
259 + $confirmation = apply_filters_deprecated(
173 260 'fluentform_form_submission_confirmation',
174 - $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,
175 274 $formData,
176 275 $form
177 276 );
178 277
179 - 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);
180 286
181 - $confirmation['messageToShow'] = apply_filters('fluentform_submission_message_parse', $confirmation['messageToShow'], $insertId, $formData, $form);
182 -
183 -
184 287 $message = ShortCodeParser::parse(
185 288 $confirmation['messageToShow'],
186 289 $insertId,
187 290 $formData,
188 - $form
291 + $form,
292 + false,
293 + true
189 294 );
190 295
191 -
192 296 $message = $message ? $message : 'The form has been successfully submitted.';
193 297
194 298 $returnData = [
195 - 'message' => do_shortcode($message),
196 - 'action' => $confirmation['samePageFormBehavior'],
299 + 'message' => $message,
300 + 'action' => $confirmation['samePageFormBehavior'],
197 301 ];
198 -
199 302 } else {
200 303 $redirectUrl = Arr::get($confirmation, 'customUrl');
201 304
202 - if ($confirmation['redirectTo'] == 'customPage') {
305 + if ('customPage' == $confirmation['redirectTo']) {
203 306 $redirectUrl = get_permalink($confirmation['customPage']);
204 307 }
205 308
206 309 if (
207 - (Arr::get($confirmation, 'enable_query_string') == 'yes') &&
310 + ('yes' == Arr::get($confirmation, 'enable_query_string')) &&
208 311 Arr::get($confirmation, 'query_strings')
209 312 ) {
210 313 if (strpos($redirectUrl, '?')) {
211 314 $redirectUrl .= '&' . Arr::get($confirmation, 'query_strings');
@@ -212,10 +315,21 @@
212 315 } else {
213 316 $redirectUrl .= '?' . Arr::get($confirmation, 'query_strings');
214 317 }
215 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 + );
216 330
217 - $isUrlParser = apply_filters('fluentform_will_parse_url_value', true, $form);
331 + $isUrlParser = apply_filters('fluentform/will_parse_url_value', $parseUrl, $form);
218 332
219 333 $redirectUrl = ShortCodeParser::parse(
220 334 $redirectUrl,
221 335 $insertId,
@@ -222,16 +336,14 @@
222 336 $formData,
223 337 $form,
224 338 $isUrlParser
225 339 );
226 -
227 - if($isUrlParser) {
228 - $redirectUrl = esc_url_raw($redirectUrl);
229 -
340 +
341 + if ($isUrlParser) {
230 342 /*
231 343 * For Empty Redirect Value
232 344 */
233 - if(strpos($redirectUrl, '=&') || substr($redirectUrl, -1) == '=') {
345 + if (strpos($redirectUrl, '=&') || '=' == substr($redirectUrl, -1)) {
234 346 $urlArray = explode('?', $redirectUrl);
235 347 $baseUrl = array_shift($urlArray);
236 348
237 349 $query = wp_parse_url($redirectUrl)['query'];
@@ -240,9 +352,9 @@
240 352
241 353 $params = [];
242 354 foreach ($queryParams as $queryParam) {
243 355 $paramArray = explode('=', $queryParam);
244 - if(!empty($paramArray[1])) {
356 + if (!empty($paramArray[1])) {
245 357 $params[$paramArray[0]] = $paramArray[1];
246 358 }
247 359 }
248 360
@@ -253,19 +365,34 @@
253 365 $message = ShortCodeParser::parse(
254 366 ArrayHelper::get($confirmation, 'redirectMessage', ''),
255 367 $insertId,
256 368 $formData,
257 - $form
369 + $form,
370 + false,
371 + true
258 372 );
259 -
373 +
374 + $redirectUrl = wp_sanitize_redirect(urldecode($redirectUrl));
260 375 $returnData = [
261 - 'redirectUrl' => $redirectUrl,
262 - 'message' => $message
376 + 'redirectUrl' => esc_url_raw($redirectUrl),
377 + 'message' => $message,
263 378 ];
264 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 + );
265 392
266 393 return $this->app->applyFilters(
267 - 'fluentform_submission_confirmation',
394 + 'fluentform/submission_confirmation',
268 395 $returnData,
269 396 $form,
270 397 $confirmation
271 398 );
@@ -274,29 +401,60 @@
274 401 /**
275 402 * Validate form data.
276 403 *
277 404 * @param $fields
405 + *
278 406 * @return bool
279 407 */
280 408 private function validate(&$fields)
281 409 {
410 + $this->preventMaliciousAttacks();
411 +
282 412 $this->validateRestrictions($fields);
283 413
284 414 $this->validateNonce();
285 415
286 416 $this->validateReCaptcha();
417 + $this->validateHCaptcha();
418 + $this->validateTurnstile();
287 419
288 420 foreach ($fields as $fieldName => $field) {
289 - if(isset($this->formData[$fieldName])) {
421 + if (isset($this->formData[$fieldName])) {
290 422 $element = $field['element'];
291 - $this->formData[$fieldName] = apply_filters('fluentform_input_data_'.$element, $this->formData[$fieldName], $field, $this->formData);
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);
292 439 }
293 440 }
294 441
295 442 $originalValidations = FormFieldsParser::getValidations($this->form, $this->formData, $fields);
296 -
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 + );
297 455 // Fire an event so that one can hook into it to work with the rules & messages.
298 - $validations = apply_filters('fluentform_validations', $originalValidations, $this->form, $this->formData);
456 + $validations = apply_filters('fluentform/validations', $originalValidations, $this->form, $this->formData);
299 457
300 458 /*
301 459 * Clean talk fix for now
302 460 * They should not hook fluentform_validations and return nothing!
@@ -305,9 +463,9 @@
305 463 if ($originalValidations && (!$validations || !array_filter($validations))) {
306 464 $validations = $originalValidations;
307 465 }
308 466
309 - $validator = \FluentValidator\Validator::make($this->formData, $validations[0], $validations[1]);
467 + $validator = wpFluentForm('validator')->make($this->formData, $validations[0], $validations[1]);
310 468
311 469 $errors = [];
312 470 if ($validator->validate()->fails()) {
313 471 foreach ($validator->errors() as $attribute => $rules) {
@@ -318,10 +476,24 @@
318 476 }
319 477
320 478 $errors[$attribute] = $rules;
321 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 + );
322 493 // Fire an event so that one can hook into it to work with the errors.
323 - $errors = $this->app->applyFilters('fluentform_validation_error', $errors, $this->form, $fields, $this->formData);
494 + $errors = $this->app->applyFilters('fluentform/validation_error', $errors, $this->form, $fields,
495 + $this->formData);
324 496 }
325 497
326 498 foreach ($fields as $fieldKey => $field) {
327 499 $field['data_key'] = $fieldKey;
@@ -326,15 +498,31 @@
326 498 foreach ($fields as $fieldKey => $field) {
327 499 $field['data_key'] = $fieldKey;
328 500 $inputName = \FluentForm\Framework\Helpers\ArrayHelper::get($field, 'raw.attributes.name');
329 501 $field['name'] = $inputName;
330 - $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);
331 519 if ($error) {
332 520 if (empty($errors[$inputName])) {
333 521 $errors[$inputName] = [];
334 522 }
335 523
336 - if(is_string($error)) {
524 + if (is_string($error)) {
337 525 $error = [$error];
338 526 }
339 527
340 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
@@ -339,17 +527,61 @@
339 527
340 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
341 529 }
342 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 + );
343 544
344 - $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);
345 546
346 - if(Helper::getFormMeta($this->form->id, '_has_user_registration') == 'yes') {
347 - $errors = apply_filters('fluentform_validation_user_registration_errors', $errors, $this->formData, $this->form, $fields);
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);
348 563 }
349 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 +
350 582 if ($errors) {
351 - wp_send_json(['errors' => $errors], 422);
583 + wp_send_json(['errors' => $errors], 423);
352 584 }
353 585
354 586 return true;
355 587 }
@@ -359,19 +591,30 @@
359 591 */
360 592 protected function validateNonce()
361 593 {
362 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);
363 598
364 - $shouldVerifyNonce = $this->app->applyFilters('fluentform_nonce_verify', false, $formId);
599 + $shouldVerifyNonce = $this->app->applyFilters('fluentform/nonce_verify', $nonceVerify, $formId);
365 600
366 601 if ($shouldVerifyNonce) {
367 602 $nonce = Arr::get($this->formData, '_fluentform_' . $formId . '_fluentformnonce');
368 603 if (!wp_verify_nonce($nonce, 'fluentform-submit-form')) {
369 - $errors = $this->app->applyFilters('fluentForm_nonce_error', [
370 - '_fluentformnonce' => [
371 - __('Nonce verification failed, please try again.', 'fluentform')
372 - ]
373 - ]);
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);
374 617 wp_send_json(['errors' => $errors], 422);
375 618 }
376 619 }
377 620 }
@@ -378,33 +621,61 @@
378 621
379 622 protected function handleSpamError()
380 623 {
381 624 $settings = get_option('_fluentform_global_form_settings');
382 - if (!$settings || ArrayHelper::get($settings, 'misc.akismet_validation') != 'validation_failed') {
625 + if (!$settings || 'validation_failed' != ArrayHelper::get($settings, 'misc.akismet_validation')) {
383 626 return;
384 627 }
385 628
386 - $errors = [
387 - '_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 + ),
388 635 ];
389 636
390 637 wp_send_json(['errors' => $errors], 422);
391 638 }
392 639
393 - protected function isSpam($formData, $form)
640 + protected function isAkismetSpam($formData, $form)
394 641 {
395 642 if (!AkismetHandler::isEnabled()) {
396 643 return false;
397 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 + );
398 657
399 - $isSpamCheck = apply_filters('fluentform_akismet_check_spam', true, $form->id, $formData);
658 + $isSpamCheck = apply_filters('fluentform/akismet_check_spam', $isSpamCheck, $form->id, $formData);
400 659 if (!$isSpamCheck) {
401 660 return false;
402 661 }
403 662 // Let's validate now
404 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 + );
405 676
406 - return apply_filters('fluentform_akismet_spam_result', $isSpam, $form->id, $formData);
677 + return $this->app->applyFilters('fluentform/akismet_spam_result', $isSpam, $form->id, $formData);
407 678 }
408 679
409 680 /**
410 681 * Validate reCaptcha.
@@ -410,24 +681,107 @@
410 681 * Validate reCaptcha.
411 682 */
412 683 private function validateReCaptcha()
413 684 {
414 - if (FormFieldsParser::hasElement($this->form, 'recaptcha')) {
415 - $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);
416 704
417 705 if (!$isValid) {
418 - wp_send_json([
419 - 'errors' => [
420 - 'g-recaptcha-response' => [
421 - __('reCaptcha verification failed, please try again.', 'fluentform')
422 - ]
423 - ]
424 - ], 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);
425 712 }
426 713 }
427 714 }
428 715
429 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 + /**
430 784 * Validate form data based on the form restrictions settings.
431 785 *
432 786 * @param $fields
433 787 */
@@ -440,10 +794,10 @@
440 794
441 795 $this->form->settings = $formSettings ? json_decode($formSettings->value, true) : [];
442 796
443 797 $isAllowed = [
444 - 'status' => true,
445 - 'message' => ''
798 + 'status' => true,
799 + 'message' => '',
446 800 ];
447 801
448 802 // This will check the following restriction settings.
449 803 // 1. limitNumberOfEntries
@@ -448,17 +802,21 @@
448 802 // This will check the following restriction settings.
449 803 // 1. limitNumberOfEntries
450 804 // 2. scheduleForm
451 805 // 3. requireLogin
806 +
807 + /* This filter is deprecated and will be removed soon */
452 808 $isAllowed = apply_filters('fluentform_is_form_renderable', $isAllowed, $this->form);
809 +
810 + $isAllowed = apply_filters('fluentform/is_form_renderable', $isAllowed, $this->form);
453 811
454 812 if (!$isAllowed['status']) {
455 813 wp_send_json([
456 814 'errors' => [
457 815 'restricted' => [
458 - $isAllowed['message']
459 - ]
460 - ]
816 + $isAllowed['message'],
817 + ],
818 + ],
461 819 ], 422);
462 820 }
463 821
464 822 // Since we are here, we should now handle if the form should be allowed to submit empty.
@@ -472,9 +830,9 @@
472 830 *
473 831 * @param array $settings
474 832 * @param $fields
475 833 */
476 - private function handleDenyEmptySubmission($settings = [], &$fields)
834 + private function handleDenyEmptySubmission($settings, &$fields)
477 835 {
478 836 // Determine whether empty form submission is allowed or not.
479 837 if (Arr::get($settings, 'enabled')) {
480 838 // confirm this form has no required fields.
@@ -480,9 +838,9 @@
480 838 // confirm this form has no required fields.
481 839 if (!FormFieldsParser::hasRequiredFields($this->form, $fields)) {
482 840 // Filter out the form data which doesn't have values.
483 841 $filteredFormData = array_filter(
484 - // Filter out the other meta fields that aren't actual inputs.
842 + // Filter out the other meta fields that aren't actual inputs.
485 843 array_intersect_key($this->formData, $fields)
486 844 );
487 845
488 846 // TODO: Extract this function into global functions file...
@@ -496,19 +854,18 @@
496 854 return $array;
497 855 };
498 856
499 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 + }
500 862 wp_send_json([
501 863 'errors' => [
502 864 'restricted' => [
503 - __(
504 - !($m = Arr::get($settings, 'message'))
505 - ? 'Sorry! You can\'t submit an empty form.'
506 - : $m,
507 - 'fluentform'
508 - )
509 - ]
510 - ]
865 + $message,
866 + ],
867 + ],
511 868 ], 422);
512 869 }
513 870 }
514 871 }
@@ -517,8 +874,9 @@
517 874 /**
518 875 * Prepare the data to be inserted to the database.
519 876 *
520 877 * @param boolean $formData
878 + *
521 879 * @return array
522 880 */
523 881 public function prepareInsertData($formData = false)
524 882 {
@@ -538,35 +896,67 @@
538 896 if ($previousItem) {
539 897 $serialNumber = $previousItem->serial_number + 1;
540 898 }
541 899
542 - $browser = new Browser;
900 + $browser = new Browser();
543 901
544 - $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);
545 916
546 - $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 + );
547 929
548 - $ipAddress = $this->app->request->getIp();
549 -
550 - 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)) {
551 932 $ipAddress = false;
552 933 }
553 934
554 935 $response = [
555 - 'form_id' => $formId,
936 + 'form_id' => $formId,
556 937 'serial_number' => $serialNumber,
557 - 'response' => json_encode($this->formData),
558 - 'source_url' => site_url(Arr::get($formData, '_wp_http_referer')),
559 - 'user_id' => get_current_user_id(),
560 - 'browser' => $browser->getBrowser(),
561 - 'device' => $browser->getPlatform(),
562 - 'ip' => $ipAddress,
563 - 'created_at' => current_time('mysql'),
564 - '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'),
565 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 + );
566 957
567 -
568 - return apply_filters('fluentform_filter_insert_data', $response);
958 + return apply_filters('fluentform/filter_insert_data', $response);
569 959 }
570 960
571 961 /**
572 962 * Delegate the validation rules & messages to the
@@ -571,10 +961,11 @@
571 961 /**
572 962 * Delegate the validation rules & messages to the
573 963 * ones that the validation library recognizes.
574 964 *
575 - * @param $rules
576 - * @param $messages
965 + * @param $rules
966 + * @param $messages
967 + *
577 968 * @return array
578 969 */
579 970 protected function delegateValidations($rules, $messages, $search = [], $replace = [])
580 971 {
@@ -593,5 +984,41 @@
593 984
594 985 return [$rules, $messages];
595 986 }
596 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 + }
597 1024 }