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