PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/models/FrmEntryValidate.php +41 -404 6.45.0 View file →
@@ -3,14 +3,8 @@
3 3 die( 'You are not allowed to call this page directly.' );
4 4 }
5 5
6 6 class FrmEntryValidate {
7 -
8 - /**
9 - * @param array $values
10 - * @param string[]|bool $exclude
11 - * @return array
12 - */
13 7 public static function validate( $values, $exclude = false ) {
14 8 FrmEntry::sanitize_entry_post( $values );
15 9 $errors = array();
16 10
@@ -20,10 +14,9 @@
20 14 return $errors;
21 15 }
22 16
23 17 if ( FrmAppHelper::is_admin() && is_user_logged_in() && ( ! isset( $values[ 'frm_submit_entry_' . $values['form_id'] ] ) || ! wp_verify_nonce( $values[ 'frm_submit_entry_' . $values['form_id'] ], 'frm_submit_entry_nonce' ) ) ) {
24 - $frm_settings = FrmAppHelper::get_settings();
25 - $errors['form'] = $frm_settings->admin_permission;
18 + $errors['form'] = __( 'You do not have permission to do that', 'formidable' );
26 19 }
27 20
28 21 self::set_item_key( $values );
29 22
@@ -40,25 +33,10 @@
40 33 if ( empty( $errors ) ) {
41 34 self::spam_check( $exclude, $values, $errors );
42 35 }
43 36
44 - /**
45 - * Allows modifying the validation errors after validating all fields.
46 - *
47 - * @since 5.0.04 Added `posted_fields` to the third param.
48 - *
49 - * @param array $errors Errors data.
50 - * @param array $values Value data of the form.
51 - * @param array $args Custom arguments. Contains `exclude` and `posted_fields`.
52 - */
53 - $filtered_errors = apply_filters( 'frm_validate_entry', $errors, $values, compact( 'exclude', 'posted_fields' ) );
37 + $errors = apply_filters( 'frm_validate_entry', $errors, $values, compact( 'exclude' ) );
54 38
55 - if ( is_array( $filtered_errors ) ) {
56 - $errors = $filtered_errors;
57 - } else {
58 - _doing_it_wrong( __FUNCTION__, 'Only arrays should be returned when using the frm_validate_entry filter.', '6.3' );
59 - }
60 -
61 39 return $errors;
62 40 }
63 41
64 42 private static function set_item_key( &$values ) {
@@ -79,19 +57,9 @@
79 57 if ( ! empty( $exclude ) ) {
80 58 $where['fi.type not'] = $exclude;
81 59 }
82 60
83 - $fields = FrmField::getAll( $where, 'field_order' );
84 -
85 - /**
86 - * Allows modifying fields to validate.
87 - *
88 - * @since 5.0.06
89 - *
90 - * @param array $fields List of fields.
91 - * @param array $args Includes `values`, `exclude`, `where`.
92 - */
93 - return apply_filters( 'frm_fields_to_validate', $fields, compact( 'values', 'exclude', 'where' ) );
61 + return FrmField::getAll( $where, 'field_order' );
94 62 }
95 63
96 64 public static function validate_field( $posted_field, &$errors, $values, $args = array() ) {
97 65 $defaults = array(
@@ -124,10 +92,10 @@
124 92 }
125 93
126 94 if ( $posted_field->required == '1' && FrmAppHelper::is_empty_value( $value ) ) {
127 95 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $posted_field, 'blank' );
128 - } elseif ( ! isset( $_POST['item_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
129 - self::maybe_add_item_name( $value, $posted_field );
96 + } elseif ( $posted_field->type == 'text' && ! isset( $_POST['item_name'] ) ) { // WPCS: CSRF ok.
97 + $_POST['item_name'] = $value;
130 98 }
131 99
132 100 FrmEntriesHelper::set_posted_value( $posted_field, $value, $args );
133 101
@@ -145,30 +113,8 @@
145 113 $errors = apply_filters( 'frm_validate_field_entry', $errors, $posted_field, $value, $args );
146 114 }
147 115
148 116 /**
149 - * Maybe add item_name to $_POST to save it in items table.
150 - *
151 - * @since 5.2.02
152 - *
153 - * @param object $field Field object.
154 - */
155 - private static function maybe_add_item_name( $value, $field ) {
156 - $item_name = false;
157 - if ( 'name' === $field->type ) {
158 - $field_obj = FrmFieldFactory::get_field_object( $field );
159 - $item_name = $field_obj->get_display_value( $value );
160 - } elseif ( 'text' === $field->type ) {
161 - $item_name = $value;
162 - }
163 -
164 - if ( false !== $item_name ) {
165 - // Item name has a max length of 255 characters so truncate it so it doesn't fail to save in the database.
166 - $_POST['item_name'] = substr( $item_name, 0, 255 );
167 - }
168 - }
169 -
170 - /**
171 117 * Set $value to an empty string if it matches its label
172 118 *
173 119 * @param object $field
174 120 * @param string $value
@@ -289,37 +235,16 @@
289 235 } elseif ( self::is_honeypot_spam( $values ) || self::is_spam_bot() ) {
290 236 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
291 237 } elseif ( self::blacklist_check( $values ) ) {
292 238 $errors['spam'] = __( 'Your entry appears to be blocked spam!', 'formidable' );
293 - }
294 -
295 - if ( isset( $errors['spam'] ) || self::form_is_in_progress( $values ) ) {
296 - return;
297 - }
298 -
299 - if ( self::is_akismet_enabled_for_user( $values['form_id'] ) && self::is_akismet_spam( $values ) ) {
239 + } elseif ( self::is_akismet_spam( $values ) && self::is_akismet_enabled_for_user( $values['form_id'] ) ) {
300 240 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
301 241 }
302 242 }
303 243
304 244 /**
305 - * Checks if form is in progress.
306 - *
307 - * @since 5.0.13
308 - *
309 - * @param array $values The values.
310 - * @return bool
311 - */
312 - private static function form_is_in_progress( $values ) {
313 - return FrmAppHelper::pro_is_installed() &&
314 - ( isset( $values[ 'frm_page_order_' . $values['form_id'] ] ) || FrmAppHelper::get_post_param( 'frm_next_page' ) ) &&
315 - FrmField::get_all_types_in_form( $values['form_id'], 'break' );
316 - }
317 -
318 - /**
319 245 * @param int $form_id
320 - *
321 - * @return bool|string
246 + * @return boolean
322 247 */
323 248 private static function is_antispam_check( $form_id ) {
324 249 $aspm = new FrmAntiSpam( $form_id );
325 250 return $aspm->validate();
@@ -359,9 +284,9 @@
359 284 */
360 285 private static function is_akismet_enabled_for_user( $form_id ) {
361 286 $form = FrmForm::getOne( $form_id );
362 287
363 - return ( ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] !== 'logged' || ! is_user_logged_in() ) );
288 + return ( isset( $form->options['akismet'] ) && ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] !== 'logged' || ! is_user_logged_in() ) );
364 289 }
365 290
366 291 public static function blacklist_check( $values ) {
367 292 if ( ! apply_filters( 'frm_check_blacklist', true, $values ) ) {
@@ -373,10 +298,12 @@
373 298 return false;
374 299 }
375 300
376 301 $content = FrmEntriesHelper::entry_array_to_string( $values );
302 + if ( empty( $content ) ) {
303 + return false;
304 + }
377 305
378 - self::prepare_values_for_spam_check( $values );
379 306 $ip = FrmAppHelper::get_ip_address();
380 307 $user_agent = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
381 308 $user_info = self::get_spam_check_user_info( $values );
382 309
@@ -415,26 +342,19 @@
415 342 *
416 343 * @return boolean true if is spam
417 344 */
418 345 public static function akismet( $values ) {
419 - if ( empty( $values['item_meta'] ) ) {
346 + $content = FrmEntriesHelper::entry_array_to_string( $values );
347 + if ( empty( $content ) ) {
420 348 return false;
421 349 }
422 350
423 351 $datas = array(
424 - 'comment_type' => 'formidable',
352 + 'comment_type' => 'formidable',
353 + 'comment_content' => $content,
425 354 );
426 355 self::parse_akismet_array( $datas, $values );
427 356
428 - /**
429 - * Allows modifying the values sent to Akismet.
430 - *
431 - * @since 5.0.07
432 - *
433 - * @param array $datas The array of values being sent to Akismet.
434 - */
435 - $datas = apply_filters( 'frm_akismet_values', $datas );
436 -
437 357 $query_string = _http_build_query( $datas, '', '&' );
438 358 $response = Akismet::http_post( $query_string, 'comment-check' );
439 359
440 360 return ( is_array( $response ) && $response[1] == 'true' );
@@ -444,14 +364,10 @@
444 364 * @since 2.0
445 365 */
446 366 private static function parse_akismet_array( &$datas, $values ) {
447 367 self::add_site_info_to_akismet( $datas );
368 + self::add_user_info_to_akismet( $datas, $values );
448 369 self::add_server_values_to_akismet( $datas );
449 -
450 - self::prepare_values_for_spam_check( $values );
451 -
452 - self::add_user_info_to_akismet( $datas, $values );
453 - self::add_comment_content_to_akismet( $datas, $values );
454 370 }
455 371
456 372 private static function add_site_info_to_akismet( &$datas ) {
457 373 $datas['blog'] = FrmAppHelper::site_url();
@@ -474,127 +390,43 @@
474 390 $datas['user_role'] = Akismet::get_user_roles( $user_info['user_ID'] );
475 391 }
476 392 }
477 393
478 - /**
479 - * Gets user info for Akismet spam check.
480 - *
481 - * @since 5.0.13 Separate code for guest. Handle value of embedded|repeater.
482 - *
483 - * @param array $values Entry values after running through {@see FrmEntryValidate::prepare_values_for_spam_check()}.
484 - * @return array
485 - */
486 394 private static function get_spam_check_user_info( $values ) {
487 - if ( ! is_user_logged_in() ) {
488 - return self::get_spam_check_user_info_for_guest( $values );
489 - }
395 + $datas = array();
490 396
491 - $user = wp_get_current_user();
397 + if ( is_user_logged_in() ) {
398 + $user = wp_get_current_user();
492 399
493 - return array(
494 - 'user_ID' => $user->ID,
495 - 'user_id' => $user->ID,
496 - 'comment_author' => $user->display_name,
497 - 'comment_author_email' => $user->user_email,
498 - 'comment_author_url' => $user->user_url,
499 - );
500 - }
400 + $datas['user_ID'] = $user->ID;
401 + $datas['user_id'] = $user->ID;
402 + $datas['comment_author'] = $user->display_name;
403 + $datas['comment_author_email'] = $user->user_email;
404 + $datas['comment_author_url'] = $user->user_url;
405 + } else {
406 + $datas['comment_author'] = '';
407 + $datas['comment_author_email'] = '';
408 + $datas['comment_author_url'] = '';
501 409
502 - /**
503 - * Gets user info for Akismet spam check for guest.
504 - *
505 - * @since 5.0.13
506 - *
507 - * @param array $values Entry values after flattened.
508 - * @return array
509 - */
510 - private static function get_spam_check_user_info_for_guest( $values ) {
511 - $datas = array(
512 - 'comment_author' => '',
513 - 'comment_author_email' => '',
514 - 'comment_author_url' => '',
515 - 'name_field_ids' => $values['name_field_ids'],
516 - 'missing_keys' => array( 'comment_author_email', 'comment_author_url', 'comment_author' ),
517 - 'frm_duplicated' => array(),
518 - );
519 -
520 - if ( isset( $values['item_meta'] ) ) {
521 - $values = $values['item_meta'];
522 - }
523 -
524 - $values = array_filter( $values );
525 -
526 - self::recursive_add_akismet_guest_info( $datas, $values );
527 - unset( $datas['name_field_ids'] );
528 - unset( $datas['missing_keys'] );
529 -
530 - return $datas;
531 - }
532 -
533 - /**
534 - * Recursive adds akismet guest info.
535 - *
536 - * @since 5.0.13
537 - *
538 - * @param array $datas Guest data.
539 - * @param array $values The values.
540 - * @param int|null $custom_index Custom index (or field ID).
541 - */
542 - private static function recursive_add_akismet_guest_info( &$datas, $values, $custom_index = null ) {
543 - foreach ( $values as $index => $value ) {
544 - if ( ! $datas['missing_keys'] ) {
545 - return; // Found all info.
410 + if ( isset( $values['item_meta'] ) ) {
411 + $values = $values['item_meta'];
546 412 }
547 413
548 - if ( is_array( $value ) ) {
549 - self::recursive_add_akismet_guest_info( $datas, $value, $index );
550 - continue;
551 - }
552 -
553 - $field_id = ! is_null( $custom_index ) ? $custom_index : $index;
554 - foreach ( $datas['missing_keys'] as $key_index => $key ) {
555 - $found = self::is_akismet_guest_info_value( $key, $value, $field_id, $datas['name_field_ids'] );
556 - if ( $found ) {
557 - $datas[ $key ] = $value;
558 - $datas['frm_duplicated'][] = $field_id;
559 - unset( $datas['missing_keys'][ $key_index ] );
414 + $values = array_filter( $values );
415 + foreach ( $values as $value ) {
416 + if ( ! is_array( $value ) ) {
417 + if ( $datas['comment_author_email'] == '' && strpos( $value, '@' ) && is_email( $value ) ) {
418 + $datas['comment_author_email'] = $value;
419 + } elseif ( $datas['comment_author_url'] == '' && strpos( $value, 'http' ) === 0 ) {
420 + $datas['comment_author_url'] = $value;
421 + } elseif ( $datas['comment_author'] == '' && ! is_numeric( $value ) && strlen( $value ) < 200 ) {
422 + $datas['comment_author'] = $value;
423 + }
560 424 }
561 425 }
562 426 }
563 - }
564 427
565 - /**
566 - * Checks if given value is an akismet guest info.
567 - *
568 - * @since 5.0.13
569 - *
570 - * @param string $key Guest info key.
571 - * @param string $value Value to check.
572 - * @param int $field_id Field ID.
573 - * @param array $name_field_ids Name field IDs.
574 - * @return bool
575 - */
576 - private static function is_akismet_guest_info_value( $key, $value, $field_id, $name_field_ids ) {
577 - if ( ! $value || is_numeric( $value ) ) {
578 - return false;
579 - }
580 -
581 - switch ( $key ) {
582 - case 'comment_author_email':
583 - return strpos( $value, '@' ) && is_email( $value );
584 -
585 - case 'comment_author_url':
586 - return 0 === strpos( $value, 'http' );
587 -
588 - case 'comment_author':
589 - if ( $name_field_ids ) {
590 - // If there is name field in the form, we should always use it as author name.
591 - return in_array( $field_id, $name_field_ids, true );
592 - }
593 - return strlen( $value ) < 200;
594 - }
595 -
596 - return false;
428 + return $datas;
597 429 }
598 430
599 431 private static function add_server_values_to_akismet( &$datas ) {
600 432 foreach ( $_SERVER as $key => $value ) {
@@ -605,203 +437,8 @@
605 437 $datas[ $key ] = $value;
606 438 }
607 439 unset( $key, $value );
608 440 }
609 - }
610 -
611 - /**
612 - * Adds comment content to Akismet data.
613 - *
614 - * @since 5.0.09
615 - *
616 - * @param array $datas The array of values being sent to Akismet.
617 - * @param array $values Entry values.
618 - */
619 - private static function add_comment_content_to_akismet( &$datas, $values ) {
620 - if ( isset( $datas['frm_duplicated'] ) ) {
621 - foreach ( $datas['frm_duplicated'] as $index ) {
622 - if ( isset( $values['item_meta'][ $index ] ) ) {
623 - unset( $values['item_meta'][ $index ] );
624 - } else {
625 - unset( $values[ $index ] );
626 - }
627 - }
628 - unset( $datas['frm_duplicated'] );
629 - }
630 -
631 - self::skip_adding_values_to_akismet( $values );
632 -
633 - $datas['comment_content'] = FrmEntriesHelper::entry_array_to_string( $values );
634 - }
635 -
636 - /**
637 - * Skips adding field values to Akismet.
638 - *
639 - * @since 5.0.09
640 - *
641 - * @param array $values Entry values.
642 - */
643 - private static function skip_adding_values_to_akismet( &$values ) {
644 - $skipped_fields = self::get_akismet_skipped_field_ids( $values );
645 - foreach ( $skipped_fields as $skipped_field ) {
646 - if ( ! isset( $values['item_meta'][ $skipped_field->id ] ) ) {
647 - continue;
648 - }
649 -
650 - if ( self::should_really_skip_field( $skipped_field, $values ) ) {
651 - unset( $values['item_meta'][ $skipped_field->id ] );
652 - if ( isset( $values['item_meta']['other'][ $skipped_field->id ] ) ) {
653 - unset( $values['item_meta']['other'][ $skipped_field->id ] );
654 - }
655 - }
656 - }
657 - }
658 -
659 - /**
660 - * Checks if a skip field should be really skipped.
661 - *
662 - * @since 5.02.04
663 - *
664 - * @param object $field_data Object contains `id` and `options`.
665 - * @param array $values Entry values.
666 - * @return bool
667 - */
668 - private static function should_really_skip_field( $field_data, $values ) {
669 - if ( empty( $field_data->options ) ) { // This is skipped field types.
670 - return true;
671 - }
672 -
673 - FrmAppHelper::unserialize_or_decode( $field_data->options );
674 - if ( ! $field_data->options ) { // Check if an error happens when unserializing, or empty options.
675 - return true;
676 - }
677 -
678 - end( $field_data->options );
679 - $last_key = key( $field_data->options );
680 -
681 - // If a choice field has no Other option.
682 - if ( is_numeric( $last_key ) || 0 !== strpos( $last_key, 'other_' ) ) {
683 - return true;
684 - }
685 -
686 - // If a choice field has Other option, but Other is not selected.
687 - if ( empty( $values['item_meta']['other'][ $field_data->id ] ) ) {
688 - return true;
689 - }
690 -
691 - // Check if submitted value is same as one of field option.
692 - foreach ( $field_data->options as $option ) {
693 - $option_value = ! is_array( $option ) ? $option : ( isset( $option['value'] ) ? $option['value'] : '' );
694 - if ( $values['item_meta']['other'][ $field_data->id ] === $option_value ) {
695 - return true;
696 - }
697 - }
698 -
699 - return false;
700 - }
701 -
702 - /**
703 - * Gets field IDs that are skipped from sending to Akismet spam check.
704 - *
705 - * @since 5.0.09
706 - * @since 5.0.13 Move out get_all_form_ids_and_flatten_meta() call and get `form_ids` from `$values`.
707 - * @since 5.2.04 This method returns array of object contains `id` and `options` instead of array of `id` only.
708 - *
709 - * @param array $values Entry values after running through {@see FrmEntryValidate::prepare_values_for_spam_check()}.
710 - * @return array
711 - */
712 - private static function get_akismet_skipped_field_ids( $values ) {
713 - if ( empty( $values['form_ids'] ) ) {
714 - return array();
715 - }
716 -
717 - $skipped_types = array( 'divider', 'form', 'hidden', 'user_id', 'file', 'date', 'time', 'scale', 'star', 'range', 'toggle', 'data', 'lookup', 'likert', 'nps' );
718 - $has_other_types = array( 'radio', 'checkbox', 'select' );
719 -
720 - $where = array(
721 - array(
722 - 'form_id' => $values['form_ids'],
723 - 'type' => array_merge( $skipped_types, $has_other_types ),
724 - ),
725 - );
726 -
727 - return FrmDb::get_results( 'frm_fields', $where, 'id,options' );
728 - }
729 -
730 - /**
731 - * Prepares values array for spam check.
732 - *
733 - * @since 5.0.13
734 - *
735 - * @param array $values Entry values.
736 - */
737 - private static function prepare_values_for_spam_check( &$values ) {
738 - $form_ids = self::get_all_form_ids_and_flatten_meta( $values );
739 - $values['form_ids'] = $form_ids;
740 - }
741 -
742 - /**
743 - * Gets all form IDs (include child form IDs) and flatten item_meta array. Used for skipping values sent to Akismet.
744 - * This also removes some unused data from the item_meta.
745 - *
746 - * @since 5.0.09
747 - * @since 5.0.13 Convert name field value to string.
748 - *
749 - * @param array $values Entry values.
750 - * @return array Form IDs.
751 - */
752 - private static function get_all_form_ids_and_flatten_meta( &$values ) {
753 - $values['name_field_ids'] = array();
754 -
755 - // Blacklist check for File field in the old version doesn't contain `form_id`.
756 - $form_ids = isset( $values['form_id'] ) ? array( absint( $values['form_id'] ) ) : array();
757 - foreach ( $values['item_meta'] as $field_id => $value ) {
758 - if ( ! is_numeric( $field_id ) ) { // Maybe `other`.
759 - continue;
760 - }
761 -
762 - // Convert name array to string.
763 - if ( isset( $value['first'] ) && isset( $value['last'] ) ) {
764 - $values['item_meta'][ $field_id ] = trim( implode( ' ', $value ) );
765 - $values['name_field_ids'][] = $field_id;
766 - continue;
767 - }
768 -
769 - if ( ! is_array( $value ) || empty( $value['form'] ) ) {
770 - continue;
771 - }
772 -
773 - $form_ids[] = absint( $value['form'] );
774 -
775 - foreach ( $value as $subindex => $subvalue ) {
776 - if ( ! is_numeric( $subindex ) || ! is_array( $subvalue ) ) {
777 - continue;
778 - }
779 -
780 - foreach ( $subvalue as $subsubindex => $subsubvalue ) {
781 - if ( ! $subsubvalue ) {
782 - continue;
783 - }
784 -
785 - if ( ! isset( $values['item_meta'][ $subsubindex ] ) ) {
786 - $values['item_meta'][ $subsubindex ] = array();
787 - }
788 -
789 - // Convert name array to string.
790 - if ( isset( $subsubvalue['first'] ) && isset( $subsubvalue['last'] ) ) {
791 - $subsubvalue = trim( implode( ' ', $subsubvalue ) );
792 -
793 - $values['name_field_ids'][] = $subsubindex;
794 - }
795 -
796 - $values['item_meta'][ $subsubindex ][] = $subsubvalue;
797 - }
798 - }
799 -
800 - unset( $values['item_meta'][ $field_id ] );
801 - }
802 -
803 - return $form_ids;
804 441 }
805 442
806 443 /**
807 444 * @deprecated 3.0