PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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/FrmEntry.php +142 -58 6.27 → trunk View file →
@@ -16,9 +16,9 @@
16 16 * Create a new entry
17 17 *
18 18 * @param array $values
19 19 *
20 - * @return bool|int $entry_id
20 + * @return bool|int Entry ID.
21 21 */
22 22 public static function create( $values ) {
23 23 return self::create_entry( $values, 'standard' );
24 24 }
@@ -28,9 +28,9 @@
28 28 *
29 29 * @param array $values
30 30 * @param string $type
31 31 *
32 - * @return bool|int $entry_id
32 + * @return bool|int Entry ID.
33 33 */
34 34 private static function create_entry( $values, $type ) {
35 35 $new_values = self::before_insert_entry_in_database( $values, $type );
36 36
@@ -88,12 +88,15 @@
88 88 }
89 89
90 90 $check_val = apply_filters( 'frm_duplicate_check_val', $check_val );
91 91
92 - global $wpdb;
93 - $entry_exists = FrmDb::get_col( $wpdb->prefix . 'frm_items', $check_val, 'id', array( 'order_by' => 'created_at DESC' ) );
92 + if ( ! isset( $values['item_meta'] ) ) {
93 + return false;
94 + }
94 95
95 - if ( ! $entry_exists || ! isset( $values['item_meta'] ) ) {
96 + $entry_exists = FrmDb::get_col( 'frm_items', $check_val, 'id', array( 'order_by' => 'created_at DESC' ) );
97 +
98 + if ( ! $entry_exists ) {
96 99 return false;
97 100 }
98 101
99 102 global $frm_vars;
@@ -102,9 +105,9 @@
102 105
103 106 foreach ( $entry_exists as $entry_exist ) {
104 107 $is_duplicate = true;
105 108
106 - // make sure it's a duplicate
109 + // Make sure it's a duplicate
107 110 $metas = FrmEntryMeta::get_entry_meta_info( $entry_exist );
108 111 $field_metas = array();
109 112
110 113 foreach ( $metas as $meta ) {
@@ -123,9 +126,9 @@
123 126 if ( ! $field_metas && $filtered_vals ) {
124 127 return false;
125 128 }
126 129
127 - // compare serialized values and not arrays
130 + // Compare serialized values and not arrays
128 131 $new_meta = array_map( 'maybe_serialize', $filtered_vals );
129 132
130 133 if ( $field_metas === $new_meta ) {
131 134 $is_duplicate = true;
@@ -140,9 +143,9 @@
140 143
141 144 $diff = array_diff_assoc( $field_metas, $new_meta );
142 145
143 146 foreach ( $diff as $meta_value ) {
144 - if ( ! empty( $meta_value ) ) {
147 + if ( $meta_value ) {
145 148 $is_duplicate = false;
146 149 }
147 150 }
148 151
@@ -238,9 +241,9 @@
238 241 $field = FrmFieldFactory::get_field_object( $field_id );
239 242 $reduced[ $field_id ] = $field->get_value_to_save( $value, array( 'entry_id' => $entry_id ) );
240 243 $reduced[ $field_id ] = $field->set_value_before_save( $reduced[ $field_id ] );
241 244
242 - if ( '' === $reduced[ $field_id ] || ( is_array( $reduced[ $field_id ] ) && 0 === count( $reduced[ $field_id ] ) ) ) {
245 + if ( '' === $reduced[ $field_id ] || array() === $reduced[ $field_id ] ) {
243 246 unset( $reduced[ $field_id ] );
244 247 }
245 248 }
246 249
@@ -319,9 +322,9 @@
319 322 *
320 323 * @param int $id
321 324 * @param array $values
322 325 *
323 - * @return bool|int $update_results
326 + * @return bool|int Update results.
324 327 */
325 328 public static function update( $id, $values ) {
326 329 return self::update_entry( $id, $values, 'standard' );
327 330 }
@@ -334,9 +337,9 @@
334 337 * @param int $id
335 338 * @param array $values
336 339 * @param string $update_type
337 340 *
338 - * @return bool|int $query_results
341 + * @return bool|int Query results.
339 342 */
340 343 private static function update_entry( $id, $values, $update_type ) {
341 344 global $wpdb;
342 345
@@ -345,9 +348,9 @@
345 348 if ( ! $update ) {
346 349 return false;
347 350 }
348 351
349 - $new_values = self::package_entry_to_update( $id, $values );
352 + $new_values = self::package_entry_to_update( $id, $values, $update_type );
350 353 $query_results = $wpdb->update( $wpdb->prefix . 'frm_items', $new_values, compact( 'id' ) );
351 354
352 355 self::after_update_entry( $query_results, $id, $values, $new_values );
353 356
@@ -445,14 +448,9 @@
445 448 * @return string
446 449 */
447 450 public static function get_new_entry_name( $values, $default = '' ) {
448 451 $name = $values['item_name'] ?? $values['name'] ?? $default;
449 -
450 - if ( is_array( $name ) ) {
451 - $name = reset( $name );
452 - }
453 -
454 - return $name;
452 + return is_array( $name ) ? reset( $name ) : $name;
455 453 }
456 454
457 455 /**
458 456 * If $entry is numeric, get the entry object
@@ -458,9 +456,9 @@
458 456 * If $entry is numeric, get the entry object
459 457 *
460 458 * @since 2.0.9
461 459 *
462 - * @param int|object $entry By reference.
460 + * @param int|object|string $entry By reference.
463 461 *
464 462 * @return void
465 463 */
466 464 public static function maybe_get_entry( &$entry ) {
@@ -573,9 +571,9 @@
573 571 }
574 572 continue;
575 573 }
576 574
577 - // include sub entries in an array
575 + // Include sub entries in an array
578 576 if ( ! isset( $entry->metas[ $meta_val->field_id ] ) ) {
579 577 $entry->metas[ $meta_val->field_id ] = array();
580 578 }
581 579
@@ -595,16 +593,14 @@
595 593 *
596 594 * @return bool
597 595 */
598 596 public static function exists( $id ) {
599 - global $wpdb;
600 -
601 597 if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
602 598 return true;
603 599 }
604 600
605 601 $where = is_numeric( $id ) ? array( 'id' => $id ) : array( 'item_key' => $id );
606 - $id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
602 + $id = FrmDb::get_var( 'frm_items', $where );
607 603
608 604 return $id && $id > 0;
609 605 }
610 606
@@ -637,9 +633,9 @@
637 633 $fields .= self::sort_by_field( $order_matches[1] );
638 634 unset( $order_matches );
639 635 }
640 636
641 - // prepare the query
637 + // Prepare the query
642 638 $query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
643 639
644 640 $entries = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
645 641 unset( $query );
@@ -756,9 +752,8 @@
756 752 * @return int
757 753 */
758 754 public static function getPageCount( $p_size, $where = '' ) {
759 755 $p_size = (int) $p_size;
760 - $count = 1;
761 756
762 757 if ( $p_size ) {
763 758 if ( ! is_numeric( $where ) ) {
764 759 $where = self::getRecordCount( $where );
@@ -763,12 +758,12 @@
763 758 if ( ! is_numeric( $where ) ) {
764 759 $where = self::getRecordCount( $where );
765 760 }
766 761
767 - $count = ceil( (int) $where / $p_size );
762 + return ceil( (int) $where / $p_size );
768 763 }
769 764
770 - return $count;
765 + return 1;
771 766 }
772 767
773 768 /**
774 769 * Prepare the data before inserting it into the database
@@ -777,9 +772,9 @@
777 772 *
778 773 * @param array $values
779 774 * @param string $type
780 775 *
781 - * @return array $new_values
776 + * @return array New values.
782 777 */
783 778 private static function before_insert_entry_in_database( &$values, $type ) {
784 779 self::sanitize_entry_post( $values );
785 780
@@ -786,9 +781,9 @@
786 781 if ( $type !== 'xml' ) {
787 782 $values = apply_filters( 'frm_pre_create_entry', $values );
788 783 }
789 784
790 - return self::package_entry_data( $values );
785 + return self::package_entry_data( $values, $type );
791 786 }
792 787
793 788 /**
794 789 * Create an entry and perform after create actions
@@ -797,9 +792,9 @@
797 792 *
798 793 * @param array $values
799 794 * @param array $new_values
800 795 *
801 - * @return bool|int $entry_id
796 + * @return bool|int Entry ID.
802 797 */
803 798 private static function continue_to_create_entry( $values, $new_values ) {
804 799 $entry_id = self::insert_entry_into_database( $new_values );
805 800
@@ -843,13 +838,14 @@
843 838 * Prepare the new values for inserting into the database
844 839 *
845 840 * @since 2.0.16
846 841 *
847 - * @param array $values
842 + * @param array $values
843 + * @param string $type The create type. 'xml' for an import.
848 844 *
849 - * @return array $new_values
845 + * @return array New values.
850 846 */
851 - private static function package_entry_data( &$values ) {
847 + private static function package_entry_data( &$values, $type = 'standard' ) {
852 848 global $wpdb;
853 849
854 850 if ( ! isset( $values['item_key'] ) ) {
855 851 $values['item_key'] = '';
@@ -857,9 +853,9 @@
857 853
858 854 $item_name = self::get_new_entry_name( $values, $values['item_key'] );
859 855 $new_values = array(
860 856 'item_key' => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
861 - 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
857 + 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '', true ),
862 858 'ip' => self::get_ip( $values ),
863 859 'is_draft' => self::get_is_draft_value( $values ),
864 860 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
865 861 'post_id' => (int) self::get_entry_value( $values, 'post_id', 0 ),
@@ -866,12 +862,12 @@
866 862 'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
867 863 'created_at' => self::get_created_at( $values ),
868 864 'updated_at' => self::get_updated_at( $values ),
869 865 'description' => self::get_entry_description( $values ),
870 - 'user_id' => self::get_entry_user_id( $values ),
866 + 'user_id' => self::get_entry_user_id( $values, $type ),
871 867 );
872 868
873 - $new_values['updated_by'] = $values['updated_by'] ?? $new_values['user_id'];
869 + $new_values['updated_by'] = self::get_updated_by( $values, $type, $new_values['user_id'] );
874 870
875 871 return $new_values;
876 872 }
877 873
@@ -886,8 +882,33 @@
886 882 return $values[ $name ] ?? $default;
887 883 }
888 884
889 885 /**
886 + * Get the updated_by value for an entry.
887 + *
888 + * The submitted value is only used during a trusted import, which restores the user who last
889 + * edited each entry. Every other save is being made by the current user, so a submitted
890 + * updated_by is ignored and cannot be pointed at another account. This matters because
891 + * updated_by is treated as a privilege signal when deciding how much HTML to strip from entry
892 + * values in FrmFieldType::should_strip_most_html().
893 + *
894 + * @since 6.35
895 + *
896 + * @param array $values
897 + * @param string $type The create/update type. 'xml' for an import.
898 + * @param int|string $default The value to use when an import doesn't include updated_by.
899 + *
900 + * @return int
901 + */
902 + private static function get_updated_by( $values, $type, $default ) {
903 + if ( self::is_trusted_import( $type ) ) {
904 + return absint( self::get_entry_value( $values, 'updated_by', $default ) );
905 + }
906 +
907 + return get_current_user_id();
908 + }
909 +
910 + /**
890 911 * Get the ip for a new entry.
891 912 * Allow the import to override the value.
892 913 *
893 914 * @since 2.03.10
@@ -903,9 +924,9 @@
903 924
904 925 $ip = FrmAppHelper::get_ip_address();
905 926
906 927 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
907 - $ip = self::get_entry_value( $values, 'ip', $ip );
928 + return self::get_entry_value( $values, 'ip', $ip );
908 929 }
909 930
910 931 return $ip;
911 932 }
@@ -979,14 +1000,15 @@
979 1000 * Get the user_id value for a new entry
980 1001 *
981 1002 * @since 2.0.16
982 1003 *
983 - * @param array $values
1004 + * @param array $values
1005 + * @param string $type The create type. 'xml' for an import.
984 1006 *
985 1007 * @return int
986 1008 */
987 - private static function get_entry_user_id( $values ) {
988 - if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
1009 + private static function get_entry_user_id( $values, $type = 'standard' ) {
1010 + if ( isset( $values['frm_user_id'] ) && self::can_set_entry_user_id_from_values( $type ) ) {
989 1011 return $values['frm_user_id'];
990 1012 }
991 1013
992 1014 $current_user_id = get_current_user_id();
@@ -993,8 +1015,46 @@
993 1015 return $current_user_id ? $current_user_id : 0;
994 1016 }
995 1017
996 1018 /**
1019 + * Whether a submitted frm_user_id is allowed to set the entry owner.
1020 + *
1021 + * The owner is only taken from the submitted value when the current user is allowed to manage
1022 + * entries, or during a trusted import that restores each entry's original owner. On a public
1023 + * submission neither is true, so the owner falls back to the current user and cannot be set to
1024 + * another account.
1025 + *
1026 + * @since 6.34
1027 + *
1028 + * @param string $type The create/update type. 'xml' for an import.
1029 + *
1030 + * @return bool
1031 + */
1032 + private static function can_set_entry_user_id_from_values( $type = 'standard' ) {
1033 + if ( self::is_trusted_import( $type ) ) {
1034 + return true;
1035 + }
1036 +
1037 + return current_user_can( 'frm_edit_entries' ) || current_user_can( 'administrator' );
1038 + }
1039 +
1040 + /**
1041 + * Whether an entry is being saved by an import rather than by a normal request.
1042 + *
1043 + * An import is trusted to restore the values stored on each entry, including the columns that
1044 + * are otherwise taken from the current request.
1045 + *
1046 + * @since 6.35
1047 + *
1048 + * @param string $type The create/update type. 'xml' for an import.
1049 + *
1050 + * @return bool
1051 + */
1052 + private static function is_trusted_import( $type = 'standard' ) {
1053 + return 'xml' === $type || ( defined( 'WP_IMPORTING' ) && WP_IMPORTING );
1054 + }
1055 +
1056 + /**
997 1057 * Insert new entry into the database
998 1058 *
999 1059 * @since 2.0.16
1000 1060 *
@@ -999,9 +1059,9 @@
999 1059 * @since 2.0.16
1000 1060 *
1001 1061 * @param array $new_values
1002 1062 *
1003 - * @return bool|int $entry_id
1063 + * @return bool|int Entry ID.
1004 1064 */
1005 1065 private static function insert_entry_into_database( $new_values ) {
1006 1066 global $wpdb;
1007 1067
@@ -1006,9 +1066,9 @@
1006 1066 global $wpdb;
1007 1067
1008 1068 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
1009 1069
1010 - return ! $query_results ? false : $wpdb->insert_id;
1070 + return $query_results ? $wpdb->insert_id : false;
1011 1071 }
1012 1072
1013 1073 /**
1014 1074 * Add the new entry to global $frm_vars
@@ -1063,12 +1123,14 @@
1063 1123 // This unique ID is inserted with JS on form submit.
1064 1124 // It is used to check for duplicate entries.
1065 1125 $unique_id = sanitize_key( $values['unique_id'] );
1066 1126
1067 - if ( $unique_id ) {
1068 - FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1069 - self::flag_new_unique_key( $unique_id );
1127 + if ( ! $unique_id ) {
1128 + return;
1070 1129 }
1130 +
1131 + FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1132 + self::flag_new_unique_key( $unique_id );
1071 1133 }
1072 1134
1073 1135 /**
1074 1136 * @since 5.0.15
@@ -1080,12 +1142,14 @@
1080 1142 */
1081 1143 private static function maybe_add_captcha_meta( $form_id, $entry_id ) {
1082 1144 global $frm_vars;
1083 1145
1084 - if ( array_key_exists( 'captcha_scores', $frm_vars ) && array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
1085 - $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
1086 - FrmEntryMeta::add_entry_meta( $entry_id, 0, '', maybe_serialize( $captcha_score_meta ) );
1146 + if ( ! array_key_exists( 'captcha_scores', $frm_vars ) || ! array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
1147 + return;
1087 1148 }
1149 +
1150 + $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
1151 + FrmEntryMeta::add_entry_meta( $entry_id, 0, '', maybe_serialize( $captcha_score_meta ) );
1088 1152 }
1089 1153
1090 1154 /**
1091 1155 * Trigger frm_after_create_entry hooks
@@ -1103,8 +1167,18 @@
1103 1167 $is_child = isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
1104 1168
1105 1169 do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
1106 1170 do_action( 'frm_after_create_entry_' . $new_values['form_id'], $entry_id, compact( 'is_child' ) );
1171 +
1172 + if ( ! empty( $values['form_key'] ) ) {
1173 + /**
1174 + * @since 6.30
1175 + *
1176 + * @param int $entry_id
1177 + * @param array $is_child
1178 + */
1179 + do_action( 'frm_after_create_entry_' . $values['form_key'], $entry_id, compact( 'is_child' ) );
1180 + }
1107 1181 }
1108 1182
1109 1183 /**
1110 1184 * Actions to perform immediately after an entry is inserted in the frm_items database
@@ -1135,9 +1209,9 @@
1135 1209 * @param int|string $id
1136 1210 * @param array $values
1137 1211 * @param string $update_type
1138 1212 *
1139 - * @return bool $update
1213 + * @return bool Update.
1140 1214 */
1141 1215 private static function before_update_entry( $id, &$values, $update_type ) {
1142 1216 $update = true;
1143 1217
@@ -1159,22 +1233,23 @@
1159 1233 * Package the entry data for updating
1160 1234 *
1161 1235 * @since 2.0.16
1162 1236 *
1163 - * @param int $id
1164 - * @param array $values
1237 + * @param int $id
1238 + * @param array $values
1239 + * @param string $update_type The update type. 'xml' for an import.
1165 1240 *
1166 - * @return array $new_values
1241 + * @return array New values.
1167 1242 */
1168 - private static function package_entry_to_update( $id, $values ) {
1243 + private static function package_entry_to_update( $id, $values, $update_type = 'standard' ) {
1169 1244 global $wpdb;
1170 1245
1171 1246 $new_values = array(
1172 - 'name' => self::get_new_entry_name( $values ),
1247 + 'name' => FrmAppHelper::truncate( self::get_new_entry_name( $values ), 255, 1, '', true ),
1173 1248 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
1174 1249 'is_draft' => self::get_is_draft_value( $values ),
1175 1250 'updated_at' => current_time( 'mysql', 1 ),
1176 - 'updated_by' => $values['updated_by'] ?? get_current_user_id(),
1251 + 'updated_by' => self::get_updated_by( $values, $update_type, get_current_user_id() ),
1177 1252 );
1178 1253
1179 1254 if ( isset( $values['post_id'] ) ) {
1180 1255 $new_values['post_id'] = (int) $values['post_id'];
@@ -1187,9 +1262,9 @@
1187 1262 if ( isset( $values['parent_item_id'] ) ) {
1188 1263 $new_values['parent_item_id'] = (int) $values['parent_item_id'];
1189 1264 }
1190 1265
1191 - if ( isset( $values['frm_user_id'] ) && is_numeric( $values['frm_user_id'] ) ) {
1266 + if ( isset( $values['frm_user_id'] ) && is_numeric( $values['frm_user_id'] ) && self::can_set_entry_user_id_from_values( $update_type ) ) {
1192 1267 $new_values['user_id'] = $values['frm_user_id'];
1193 1268 }
1194 1269
1195 1270 return apply_filters( 'frm_update_entry', $new_values, $id );
@@ -1225,8 +1300,17 @@
1225 1300 }
1226 1301
1227 1302 do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
1228 1303 do_action( 'frm_after_update_entry_' . $new_values['form_id'], $id );
1304 +
1305 + if ( ! empty( $values['form_key'] ) ) {
1306 + /**
1307 + * @since 6.30
1308 + *
1309 + * @param int $entry_id
1310 + */
1311 + do_action( 'frm_after_update_entry_' . $values['form_key'], $id );
1312 + }
1229 1313 }
1230 1314
1231 1315 /**
1232 1316 * Create entry from an XML import
@@ -1235,9 +1319,9 @@
1235 1319 * @since 2.0.16
1236 1320 *
1237 1321 * @param array $values
1238 1322 *
1239 - * @return bool|int $entry_id
1323 + * @return bool|int Entry ID.
1240 1324 */
1241 1325 public static function create_entry_from_xml( $values ) {
1242 1326 return self::create_entry( $values, 'xml' );
1243 1327 }
@@ -1250,9 +1334,9 @@
1250 1334 *
1251 1335 * @param int $id
1252 1336 * @param array $values
1253 1337 *
1254 - * @return bool|int $updated
1338 + * @return bool|int Updated.
1255 1339 */
1256 1340 public static function update_entry_from_xml( $id, $values ) {
1257 1341 return self::update_entry( $id, $values, 'xml' );
1258 1342 }