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 +552 -105 3.6.406.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,45 +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);
171 286
172 - $confirmation['messageToShow'] = apply_filters('fluentform_submission_message_parse', $confirmation['messageToShow'], $insertId, $formData, $form);
173 -
174 -
175 287 $message = ShortCodeParser::parse(
176 288 $confirmation['messageToShow'],
177 289 $insertId,
178 290 $formData,
179 - $form
291 + $form,
292 + false,
293 + true
180 294 );
181 295
182 -
183 296 $message = $message ? $message : 'The form has been successfully submitted.';
184 297
185 298 $returnData = [
186 - 'message' => do_shortcode($message),
187 - 'action' => $confirmation['samePageFormBehavior'],
299 + 'message' => $message,
300 + 'action' => $confirmation['samePageFormBehavior'],
188 301 ];
189 -
190 302 } else {
191 303 $redirectUrl = Arr::get($confirmation, 'customUrl');
192 304
193 - if ($confirmation['redirectTo'] == 'customPage') {
305 + if ('customPage' == $confirmation['redirectTo']) {
194 306 $redirectUrl = get_permalink($confirmation['customPage']);
195 307 }
196 308
197 309 if (
198 - (Arr::get($confirmation, 'enable_query_string') == 'yes') &&
310 + ('yes' == Arr::get($confirmation, 'enable_query_string')) &&
199 311 Arr::get($confirmation, 'query_strings')
200 312 ) {
201 313 if (strpos($redirectUrl, '?')) {
202 314 $redirectUrl .= '&' . Arr::get($confirmation, 'query_strings');
@@ -203,10 +315,21 @@
203 315 } else {
204 316 $redirectUrl .= '?' . Arr::get($confirmation, 'query_strings');
205 317 }
206 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 + );
207 330
208 - $isUrlParser = apply_filters('fluentform_will_parse_url_value', true, $form);
331 + $isUrlParser = apply_filters('fluentform/will_parse_url_value', $parseUrl, $form);
209 332
210 333 $redirectUrl = ShortCodeParser::parse(
211 334 $redirectUrl,
212 335 $insertId,
@@ -213,16 +336,14 @@
213 336 $formData,
214 337 $form,
215 338 $isUrlParser
216 339 );
217 -
218 - if($isUrlParser) {
219 - $redirectUrl = esc_url_raw($redirectUrl);
220 -
340 +
341 + if ($isUrlParser) {
221 342 /*
222 343 * For Empty Redirect Value
223 344 */
224 - if(strpos($redirectUrl, '=&') || substr($redirectUrl, -1) == '=') {
345 + if (strpos($redirectUrl, '=&') || '=' == substr($redirectUrl, -1)) {
225 346 $urlArray = explode('?', $redirectUrl);
226 347 $baseUrl = array_shift($urlArray);
227 348
228 349 $query = wp_parse_url($redirectUrl)['query'];
@@ -231,9 +352,9 @@
231 352
232 353 $params = [];
233 354 foreach ($queryParams as $queryParam) {
234 355 $paramArray = explode('=', $queryParam);
235 - if(!empty($paramArray[1])) {
356 + if (!empty($paramArray[1])) {
236 357 $params[$paramArray[0]] = $paramArray[1];
237 358 }
238 359 }
239 360
@@ -244,19 +365,34 @@
244 365 $message = ShortCodeParser::parse(
245 366 ArrayHelper::get($confirmation, 'redirectMessage', ''),
246 367 $insertId,
247 368 $formData,
248 - $form
369 + $form,
370 + false,
371 + true
249 372 );
250 -
373 +
374 + $redirectUrl = wp_sanitize_redirect(urldecode($redirectUrl));
251 375 $returnData = [
252 - 'redirectUrl' => $redirectUrl,
253 - 'message' => $message
376 + 'redirectUrl' => esc_url_raw($redirectUrl),
377 + 'message' => $message,
254 378 ];
255 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 + );
256 392
257 393 return $this->app->applyFilters(
258 - 'fluentform_submission_confirmation',
394 + 'fluentform/submission_confirmation',
259 395 $returnData,
260 396 $form,
261 397 $confirmation
262 398 );
@@ -265,22 +401,60 @@
265 401 /**
266 402 * Validate form data.
267 403 *
268 404 * @param $fields
405 + *
269 406 * @return bool
270 407 */
271 408 private function validate(&$fields)
272 409 {
410 + $this->preventMaliciousAttacks();
411 +
273 412 $this->validateRestrictions($fields);
274 413
275 414 $this->validateNonce();
276 415
277 416 $this->validateReCaptcha();
417 + $this->validateHCaptcha();
418 + $this->validateTurnstile();
278 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 +
279 442 $originalValidations = FormFieldsParser::getValidations($this->form, $this->formData, $fields);
280 -
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 + );
281 455 // Fire an event so that one can hook into it to work with the rules & messages.
282 - $validations = apply_filters('fluentform_validations', $originalValidations, $this->form, $this->formData);
456 + $validations = apply_filters('fluentform/validations', $originalValidations, $this->form, $this->formData);
283 457
284 458 /*
285 459 * Clean talk fix for now
286 460 * They should not hook fluentform_validations and return nothing!
@@ -289,9 +463,9 @@
289 463 if ($originalValidations && (!$validations || !array_filter($validations))) {
290 464 $validations = $originalValidations;
291 465 }
292 466
293 - $validator = \FluentValidator\Validator::make($this->formData, $validations[0], $validations[1]);
467 + $validator = wpFluentForm('validator')->make($this->formData, $validations[0], $validations[1]);
294 468
295 469 $errors = [];
296 470 if ($validator->validate()->fails()) {
297 471 foreach ($validator->errors() as $attribute => $rules) {
@@ -302,10 +476,24 @@
302 476 }
303 477
304 478 $errors[$attribute] = $rules;
305 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 + );
306 493 // Fire an event so that one can hook into it to work with the errors.
307 - $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);
308 496 }
309 497
310 498 foreach ($fields as $fieldKey => $field) {
311 499 $field['data_key'] = $fieldKey;
@@ -310,15 +498,31 @@
310 498 foreach ($fields as $fieldKey => $field) {
311 499 $field['data_key'] = $fieldKey;
312 500 $inputName = \FluentForm\Framework\Helpers\ArrayHelper::get($field, 'raw.attributes.name');
313 501 $field['name'] = $inputName;
314 - $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);
315 519 if ($error) {
316 520 if (empty($errors[$inputName])) {
317 521 $errors[$inputName] = [];
318 522 }
319 523
320 - if(is_string($error)) {
524 + if (is_string($error)) {
321 525 $error = [$error];
322 526 }
323 527
324 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
@@ -323,13 +527,61 @@
323 527
324 528 $errors[$inputName] = array_merge($error, $errors[$inputName]);
325 529 }
326 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 + );
327 544
328 - $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);
329 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 +
330 582 if ($errors) {
331 - wp_send_json(['errors' => $errors], 422);
583 + wp_send_json(['errors' => $errors], 423);
332 584 }
333 585
334 586 return true;
335 587 }
@@ -339,19 +591,30 @@
339 591 */
340 592 protected function validateNonce()
341 593 {
342 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);
343 598
344 - $shouldVerifyNonce = $this->app->applyFilters('fluentform_nonce_verify', false, $formId);
599 + $shouldVerifyNonce = $this->app->applyFilters('fluentform/nonce_verify', $nonceVerify, $formId);
345 600
346 601 if ($shouldVerifyNonce) {
347 602 $nonce = Arr::get($this->formData, '_fluentform_' . $formId . '_fluentformnonce');
348 603 if (!wp_verify_nonce($nonce, 'fluentform-submit-form')) {
349 - $errors = $this->app->applyFilters('fluentForm_nonce_error', [
350 - '_fluentformnonce' => [
351 - __('Nonce verification failed, please try again.', 'fluentform')
352 - ]
353 - ]);
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);
354 617 wp_send_json(['errors' => $errors], 422);
355 618 }
356 619 }
357 620 }
@@ -358,33 +621,61 @@
358 621
359 622 protected function handleSpamError()
360 623 {
361 624 $settings = get_option('_fluentform_global_form_settings');
362 - if (!$settings || ArrayHelper::get($settings, 'misc.akismet_validation') != 'validation_failed') {
625 + if (!$settings || 'validation_failed' != ArrayHelper::get($settings, 'misc.akismet_validation')) {
363 626 return;
364 627 }
365 628
366 - $errors = [
367 - '_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 + ),
368 635 ];
369 636
370 637 wp_send_json(['errors' => $errors], 422);
371 638 }
372 639
373 - protected function isSpam($formData, $form)
640 + protected function isAkismetSpam($formData, $form)
374 641 {
375 642 if (!AkismetHandler::isEnabled()) {
376 643 return false;
377 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 + );
378 657
379 - $isSpamCheck = apply_filters('fluentform_akismet_check_spam', true, $form->id, $formData);
658 + $isSpamCheck = apply_filters('fluentform/akismet_check_spam', $isSpamCheck, $form->id, $formData);
380 659 if (!$isSpamCheck) {
381 660 return false;
382 661 }
383 662 // Let's validate now
384 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 + );
385 676
386 - return apply_filters('fluentform_akismet_spam_result', $isSpam, $form->id, $formData);
677 + return $this->app->applyFilters('fluentform/akismet_spam_result', $isSpam, $form->id, $formData);
387 678 }
388 679
389 680 /**
390 681 * Validate reCaptcha.
@@ -390,24 +681,107 @@
390 681 * Validate reCaptcha.
391 682 */
392 683 private function validateReCaptcha()
393 684 {
394 - if (FormFieldsParser::hasElement($this->form, 'recaptcha')) {
395 - $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);
396 704
397 705 if (!$isValid) {
398 - wp_send_json([
399 - 'errors' => [
400 - 'g-recaptcha-response' => [
401 - __('reCaptcha verification failed, please try again.', 'fluentform')
402 - ]
403 - ]
404 - ], 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);
405 712 }
406 713 }
407 714 }
408 715
409 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 + /**
410 784 * Validate form data based on the form restrictions settings.
411 785 *
412 786 * @param $fields
413 787 */
@@ -420,10 +794,10 @@
420 794
421 795 $this->form->settings = $formSettings ? json_decode($formSettings->value, true) : [];
422 796
423 797 $isAllowed = [
424 - 'status' => true,
425 - 'message' => ''
798 + 'status' => true,
799 + 'message' => '',
426 800 ];
427 801
428 802 // This will check the following restriction settings.
429 803 // 1. limitNumberOfEntries
@@ -428,17 +802,21 @@
428 802 // This will check the following restriction settings.
429 803 // 1. limitNumberOfEntries
430 804 // 2. scheduleForm
431 805 // 3. requireLogin
806 +
807 + /* This filter is deprecated and will be removed soon */
432 808 $isAllowed = apply_filters('fluentform_is_form_renderable', $isAllowed, $this->form);
809 +
810 + $isAllowed = apply_filters('fluentform/is_form_renderable', $isAllowed, $this->form);
433 811
434 812 if (!$isAllowed['status']) {
435 813 wp_send_json([
436 814 'errors' => [
437 815 'restricted' => [
438 - __($isAllowed['message'], 'fluentform')
439 - ]
440 - ]
816 + $isAllowed['message'],
817 + ],
818 + ],
441 819 ], 422);
442 820 }
443 821
444 822 // Since we are here, we should now handle if the form should be allowed to submit empty.
@@ -452,9 +830,9 @@
452 830 *
453 831 * @param array $settings
454 832 * @param $fields
455 833 */
456 - private function handleDenyEmptySubmission($settings = [], &$fields)
834 + private function handleDenyEmptySubmission($settings, &$fields)
457 835 {
458 836 // Determine whether empty form submission is allowed or not.
459 837 if (Arr::get($settings, 'enabled')) {
460 838 // confirm this form has no required fields.
@@ -460,9 +838,9 @@
460 838 // confirm this form has no required fields.
461 839 if (!FormFieldsParser::hasRequiredFields($this->form, $fields)) {
462 840 // Filter out the form data which doesn't have values.
463 841 $filteredFormData = array_filter(
464 - // Filter out the other meta fields that aren't actual inputs.
842 + // Filter out the other meta fields that aren't actual inputs.
465 843 array_intersect_key($this->formData, $fields)
466 844 );
467 845
468 846 // TODO: Extract this function into global functions file...
@@ -476,19 +854,18 @@
476 854 return $array;
477 855 };
478 856
479 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 + }
480 862 wp_send_json([
481 863 'errors' => [
482 864 'restricted' => [
483 - __(
484 - !($m = Arr::get($settings, 'message'))
485 - ? 'Sorry! You can\'t submit an empty form.'
486 - : $m,
487 - 'fluentform'
488 - )
489 - ]
490 - ]
865 + $message,
866 + ],
867 + ],
491 868 ], 422);
492 869 }
493 870 }
494 871 }
@@ -497,13 +874,13 @@
497 874 /**
498 875 * Prepare the data to be inserted to the database.
499 876 *
500 877 * @param boolean $formData
878 + *
501 879 * @return array
502 880 */
503 881 public function prepareInsertData($formData = false)
504 882 {
505 -
506 883 $formId = $this->form->id;
507 884
508 885 if (!$formData) {
509 886 $formData = $this->formData;
@@ -519,34 +896,67 @@
519 896 if ($previousItem) {
520 897 $serialNumber = $previousItem->serial_number + 1;
521 898 }
522 899
523 - $browser = new Browser;
900 + $browser = new Browser();
524 901
525 - $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);
526 916
527 - $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 + );
528 929
529 - $ipAddress = $this->app->request->getIp();
530 -
531 - 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)) {
532 932 $ipAddress = false;
533 933 }
534 934
535 935 $response = [
536 - 'form_id' => $formId,
936 + 'form_id' => $formId,
537 937 'serial_number' => $serialNumber,
538 - 'response' => json_encode($this->formData),
539 - 'source_url' => site_url(Arr::get($this->formData, '_wp_http_referer')),
540 - 'user_id' => get_current_user_id(),
541 - 'browser' => $browser->getBrowser(),
542 - 'device' => $browser->getPlatform(),
543 - 'ip' => $ipAddress,
544 - 'created_at' => current_time('mysql'),
545 - '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'),
546 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 + );
547 957
548 - return apply_filters('fluentform_filter_insert_data', $response);
958 + return apply_filters('fluentform/filter_insert_data', $response);
549 959 }
550 960
551 961 /**
552 962 * Delegate the validation rules & messages to the
@@ -551,10 +961,11 @@
551 961 /**
552 962 * Delegate the validation rules & messages to the
553 963 * ones that the validation library recognizes.
554 964 *
555 - * @param $rules
556 - * @param $messages
965 + * @param $rules
966 + * @param $messages
967 + *
557 968 * @return array
558 969 */
559 970 protected function delegateValidations($rules, $messages, $search = [], $replace = [])
560 971 {
@@ -573,5 +984,41 @@
573 984
574 985 return [$rules, $messages];
575 986 }
576 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 + }
577 1024 }