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 +187 -147 6.26 → trunk View file →
@@ -16,14 +16,12 @@
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 - $entry_id = self::create_entry( $values, 'standard' );
24 -
25 - return $entry_id;
23 + return self::create_entry( $values, 'standard' );
26 24 }
27 25
28 26 /**
29 27 * Create a new entry with some differences depending on type
@@ -30,9 +28,9 @@
30 28 *
31 29 * @param array $values
32 30 * @param string $type
33 31 *
34 - * @return bool|int $entry_id
32 + * @return bool|int Entry ID.
35 33 */
36 34 private static function create_entry( $values, $type ) {
37 35 $new_values = self::before_insert_entry_in_database( $values, $type );
38 36
@@ -40,11 +38,9 @@
40 38 if ( $type !== 'xml' && self::is_duplicate( $new_values, $values ) ) {
41 39 return false;
42 40 }
43 41
44 - $entry_id = self::continue_to_create_entry( $values, $new_values );
45 -
46 - return $entry_id;
42 + return self::continue_to_create_entry( $values, $new_values );
47 43 }
48 44
49 45 /**
50 46 * Flag the memoized unique id check after a new entry is created.
@@ -85,8 +81,9 @@
85 81 $check_val['created_at >'] = gmdate( 'Y-m-d H:i:s', strtotime( $new_values['created_at'] ) - absint( $duplicate_entry_time ) );
86 82
87 83 unset( $check_val['created_at'], $check_val['updated_at'], $check_val['is_draft'], $check_val['id'], $check_val['item_key'] );
88 84
85 + // phpcs:ignore Universal.Operators.StrictComparisons
89 86 if ( $new_values['item_key'] == $new_values['name'] ) {
90 87 unset( $check_val['name'] );
91 88 }
92 89
@@ -91,24 +88,26 @@
91 88 }
92 89
93 90 $check_val = apply_filters( 'frm_duplicate_check_val', $check_val );
94 91
95 - global $wpdb;
96 - $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 + }
97 95
98 - 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 ) {
99 99 return false;
100 100 }
101 101
102 102 global $frm_vars;
103 103 $frm_vars['checking_duplicates'] = true;
104 + $is_duplicate = false;
104 105
105 - $is_duplicate = false;
106 -
107 106 foreach ( $entry_exists as $entry_exist ) {
108 107 $is_duplicate = true;
109 108
110 - // make sure it's a duplicate
109 + // Make sure it's a duplicate
111 110 $metas = FrmEntryMeta::get_entry_meta_info( $entry_exist );
112 111 $field_metas = array();
113 112
114 113 foreach ( $metas as $meta ) {
@@ -114,8 +113,9 @@
114 113 foreach ( $metas as $meta ) {
115 114 if ( 0 === (int) $meta->field_id ) {
116 115 continue;
117 116 }
117 +
118 118 $field_metas[ $meta->field_id ] = $meta->meta_value;
119 119 }
120 120
121 121 $filtered_vals = array_filter( $values['item_meta'] );
@@ -122,13 +122,13 @@
122 122 $filtered_vals = self::convert_values_to_their_saved_value( $filtered_vals, $entry_exist );
123 123 $field_metas = array_filter( $field_metas );
124 124
125 125 // If prev entry is empty and current entry is not, they are not duplicates
126 - if ( empty( $field_metas ) && ! empty( $filtered_vals ) ) {
126 + if ( ! $field_metas && $filtered_vals ) {
127 127 return false;
128 128 }
129 129
130 - // compare serialized values and not arrays
130 + // Compare serialized values and not arrays
131 131 $new_meta = array_map( 'maybe_serialize', $filtered_vals );
132 132
133 133 if ( $field_metas === $new_meta ) {
134 134 $is_duplicate = true;
@@ -143,9 +143,9 @@
143 143
144 144 $diff = array_diff_assoc( $field_metas, $new_meta );
145 145
146 146 foreach ( $diff as $meta_value ) {
147 - if ( ! empty( $meta_value ) ) {
147 + if ( $meta_value ) {
148 148 $is_duplicate = false;
149 149 }
150 150 }
151 151
@@ -224,10 +224,12 @@
224 224 }
225 225
226 226 /**
227 227 * Convert form data to the actual value that would be saved into the database.
228 - * This is important for the duplicate check as something like 'a:2:{s:5:"typed";s:0:"";s:6:"output";s:0:"";}' (a signature value) is actually an empty string and does not get saved.
229 228 *
229 + * This is important for the duplicate check as something like 'a:2:{s:5:"typed";s:0:"";s:6:"output";s:0:"";}'
230 + * (a signature value) is actually an empty string and does not get saved.
231 + *
230 232 * @param array $filter_vals
231 233 * @param int $entry_id
232 234 *
233 235 * @return array
@@ -239,12 +241,13 @@
239 241 $field = FrmFieldFactory::get_field_object( $field_id );
240 242 $reduced[ $field_id ] = $field->get_value_to_save( $value, array( 'entry_id' => $entry_id ) );
241 243 $reduced[ $field_id ] = $field->set_value_before_save( $reduced[ $field_id ] );
242 244
243 - if ( '' === $reduced[ $field_id ] || ( is_array( $reduced[ $field_id ] ) && 0 === count( $reduced[ $field_id ] ) ) ) {
245 + if ( '' === $reduced[ $field_id ] || array() === $reduced[ $field_id ] ) {
244 246 unset( $reduced[ $field_id ] );
245 247 }
246 248 }
249 +
247 250 return $reduced;
248 251 }
249 252
250 253 /**
@@ -258,9 +261,9 @@
258 261 * @return bool
259 262 */
260 263 private static function is_duplicate_check_needed( $values, $duplicate_entry_time ) {
261 264 // If time for checking duplicates is set to an empty value, don't check for duplicates
262 - if ( empty( $duplicate_entry_time ) ) {
265 + if ( ! $duplicate_entry_time ) {
263 266 return false;
264 267 }
265 268
266 269 // If CSV is importing, don't check for duplicates
@@ -268,13 +271,9 @@
268 271 return false;
269 272 }
270 273
271 274 // If repeating field entries are getting created, don't check for duplicates
272 - if ( isset( $values['parent_form_id'] ) && $values['parent_form_id'] ) {
273 - return false;
274 - }
275 -
276 - return true;
275 + return empty( $values['parent_form_id'] );
277 276 }
278 277
279 278 /**
280 279 * @param int|string $id
@@ -283,10 +282,9 @@
283 282 */
284 283 public static function duplicate( $id ) {
285 284 global $wpdb;
286 285
287 - $values = self::getOne( $id );
288 -
286 + $values = self::getOne( $id );
289 287 $new_values = array();
290 288 $new_values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
291 289 $new_values['name'] = $values->name;
292 290 $new_values['is_draft'] = $values->is_draft;
@@ -324,14 +322,12 @@
324 322 *
325 323 * @param int $id
326 324 * @param array $values
327 325 *
328 - * @return bool|int $update_results
326 + * @return bool|int Update results.
329 327 */
330 328 public static function update( $id, $values ) {
331 - $update_results = self::update_entry( $id, $values, 'standard' );
332 -
333 - return $update_results;
329 + return self::update_entry( $id, $values, 'standard' );
334 330 }
335 331
336 332 /**
337 333 * Update an entry with some differences depending on the update type
@@ -341,9 +337,9 @@
341 337 * @param int $id
342 338 * @param array $values
343 339 * @param string $update_type
344 340 *
345 - * @return bool|int $query_results
341 + * @return bool|int Query results.
346 342 */
347 343 private static function update_entry( $id, $values, $update_type ) {
348 344 global $wpdb;
349 345
@@ -352,10 +348,9 @@
352 348 if ( ! $update ) {
353 349 return false;
354 350 }
355 351
356 - $new_values = self::package_entry_to_update( $id, $values );
357 -
352 + $new_values = self::package_entry_to_update( $id, $values, $update_type );
358 353 $query_results = $wpdb->update( $wpdb->prefix . 'frm_items', $new_values, compact( 'id' ) );
359 354
360 355 self::after_update_entry( $query_results, $id, $values, $new_values );
361 356
@@ -376,10 +371,9 @@
376 371 // Item meta is required for conditional logic in actions with 'delete' events.
377 372 $entry = self::getOne( $id, true );
378 373
379 374 if ( ! $entry ) {
380 - $result = false;
381 - return $result;
375 + return false;
382 376 }
383 377
384 378 /**
385 379 * Trigger an action to run custom logic before the entry is deleted.
@@ -454,14 +448,9 @@
454 448 * @return string
455 449 */
456 450 public static function get_new_entry_name( $values, $default = '' ) {
457 451 $name = $values['item_name'] ?? $values['name'] ?? $default;
458 -
459 - if ( is_array( $name ) ) {
460 - $name = reset( $name );
461 - }
462 -
463 - return $name;
452 + return is_array( $name ) ? reset( $name ) : $name;
464 453 }
465 454
466 455 /**
467 456 * If $entry is numeric, get the entry object
@@ -467,9 +456,9 @@
467 456 * If $entry is numeric, get the entry object
468 457 *
469 458 * @since 2.0.9
470 459 *
471 - * @param int|object $entry By reference.
460 + * @param int|object|string $entry By reference.
472 461 *
473 462 * @return void
474 463 */
475 464 public static function maybe_get_entry( &$entry ) {
@@ -474,9 +463,9 @@
474 463 */
475 464 public static function maybe_get_entry( &$entry ) {
476 465 if ( $entry && is_numeric( $entry ) ) {
477 466 $entry = self::getOne( $entry );
478 - } elseif ( empty( $entry ) || 'false' === $entry ) {
467 + } elseif ( ! $entry || 'false' === $entry ) {
479 468 $entry = false;
480 469 }
481 470 }
482 471
@@ -523,9 +512,9 @@
523 512 *
524 513 * @return void
525 514 */
526 515 private static function prepare_entry( &$entry ) {
527 - if ( empty( $entry ) ) {
516 + if ( ! $entry ) {
528 517 return;
529 518 }
530 519
531 520 FrmAppHelper::unserialize_or_decode( $entry->description );
@@ -573,9 +562,9 @@
573 562
574 563 foreach ( $metas as $meta_val ) {
575 564 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
576 565
577 - if ( $meta_val->item_id == $entry->id ) {
566 + if ( (int) $meta_val->item_id === (int) $entry->id ) {
578 567 $entry->metas[ $meta_val->field_id ] = $meta_val->meta_value;
579 568
580 569 if ( $include_key ) {
581 570 $entry->metas[ $meta_val->field_key ] = $entry->metas[ $meta_val->field_id ];
@@ -582,9 +571,9 @@
582 571 }
583 572 continue;
584 573 }
585 574
586 - // include sub entries in an array
575 + // Include sub entries in an array
587 576 if ( ! isset( $entry->metas[ $meta_val->field_id ] ) ) {
588 577 $entry->metas[ $meta_val->field_id ] = array();
589 578 }
590 579
@@ -604,24 +593,15 @@
604 593 *
605 594 * @return bool
606 595 */
607 596 public static function exists( $id ) {
608 - global $wpdb;
609 -
610 597 if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
611 - $exists = true;
612 -
613 - return $exists;
598 + return true;
614 599 }
615 600
616 - if ( is_numeric( $id ) ) {
617 - $where = array( 'id' => $id );
618 - } else {
619 - $where = array( 'item_key' => $id );
620 - }
601 + $where = is_numeric( $id ) ? array( 'id' => $id ) : array( 'item_key' => $id );
602 + $id = FrmDb::get_var( 'frm_items', $where );
621 603
622 - $id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
623 -
624 604 return $id && $id > 0;
625 605 }
626 606
627 607 /**
@@ -635,15 +615,14 @@
635 615 */
636 616 public static function getAll( $where, $order_by = '', $limit = '', $meta = false, $inc_form = true ) {
637 617 global $wpdb;
638 618
639 - $limit = FrmDb::esc_limit( $limit );
640 -
619 + $limit = FrmDb::esc_limit( $limit );
641 620 $cache_key = FrmAppHelper::maybe_json_encode( $where ) . $order_by . $limit . $inc_form;
642 621 $entries = wp_cache_get( $cache_key, 'frm_entry' );
643 622
644 623 if ( false === $entries ) {
645 - $fields = 'it.id, it.item_key, it.name, it.ip, it.form_id, it.post_id, it.user_id, it.parent_item_id, it.updated_by, it.created_at, it.updated_at, it.is_draft, it.description';
624 + $fields = 'it.id, it.item_key, it.name, it.ip, it.form_id, it.post_id, it.user_id, it.parent_item_id, it.updated_by, it.created_at, it.updated_at, it.is_draft, it.description'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
646 625 $table = $wpdb->prefix . 'frm_items it ';
647 626
648 627 if ( $inc_form ) {
649 628 $fields = 'it.*, fr.name as form_name,fr.form_key as form_key';
@@ -654,9 +633,9 @@
654 633 $fields .= self::sort_by_field( $order_matches[1] );
655 634 unset( $order_matches );
656 635 }
657 636
658 - // prepare the query
637 + // Prepare the query
659 638 $query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
660 639
661 640 $entries = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
662 641 unset( $query );
@@ -675,9 +654,10 @@
675 654 }
676 655
677 656 $meta_where = array( 'field_id !' => 0 );
678 657
679 - if ( $limit == '' && is_array( $where ) && count( $where ) == 1 && isset( $where['it.form_id'] ) ) {
658 + // phpcs:ignore Universal.Operators.StrictComparisons
659 + if ( $limit == '' && is_array( $where ) && count( $where ) === 1 && isset( $where['it.form_id'] ) ) {
680 660 $meta_where['fi.form_id'] = $where['it.form_id'];
681 661 } else {
682 662 $meta_where['item_id'] = array_keys( $entries );
683 663 }
@@ -726,10 +706,9 @@
726 706 * @return string
727 707 */
728 708 private static function sort_by_field( $field_id ) {
729 709 global $wpdb;
730 - $field_id = (int) $field_id;
731 -
710 + $field_id = (int) $field_id;
732 711 $field_options = FrmDb::get_var( 'frm_fields', array( 'id' => $field_id ), 'field_options' );
733 712 FrmAppHelper::unserialize_or_decode( $field_options );
734 713
735 714 if ( empty( $field_options['post_field'] ) ) {
@@ -756,16 +735,15 @@
756 735 $where = array( 'form_id' => $where );
757 736 }
758 737
759 738 if ( is_array( $where ) ) {
760 - $count = FrmDb::get_count( $table_join, $where );
761 - } else {
762 - $cache_key = 'count_' . FrmAppHelper::maybe_json_encode( $where );
763 - $query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
764 - $count = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
739 + return FrmDb::get_count( $table_join, $where );
765 740 }
766 741
767 - return $count;
742 + $cache_key = 'count_' . FrmAppHelper::maybe_json_encode( $where );
743 + $query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
744 +
745 + return FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
768 746 }
769 747
770 748 /**
771 749 * @param int|string $p_size
@@ -774,9 +752,8 @@
774 752 * @return int
775 753 */
776 754 public static function getPageCount( $p_size, $where = '' ) {
777 755 $p_size = (int) $p_size;
778 - $count = 1;
779 756
780 757 if ( $p_size ) {
781 758 if ( ! is_numeric( $where ) ) {
782 759 $where = self::getRecordCount( $where );
@@ -781,12 +758,12 @@
781 758 if ( ! is_numeric( $where ) ) {
782 759 $where = self::getRecordCount( $where );
783 760 }
784 761
785 - $count = ceil( (int) $where / $p_size );
762 + return ceil( (int) $where / $p_size );
786 763 }
787 764
788 - return $count;
765 + return 1;
789 766 }
790 767
791 768 /**
792 769 * Prepare the data before inserting it into the database
@@ -795,12 +772,11 @@
795 772 *
796 773 * @param array $values
797 774 * @param string $type
798 775 *
799 - * @return array $new_values
776 + * @return array New values.
800 777 */
801 778 private static function before_insert_entry_in_database( &$values, $type ) {
802 -
803 779 self::sanitize_entry_post( $values );
804 780
805 781 if ( $type !== 'xml' ) {
806 782 $values = apply_filters( 'frm_pre_create_entry', $values );
@@ -805,11 +781,9 @@
805 781 if ( $type !== 'xml' ) {
806 782 $values = apply_filters( 'frm_pre_create_entry', $values );
807 783 }
808 784
809 - $new_values = self::package_entry_data( $values );
810 -
811 - return $new_values;
785 + return self::package_entry_data( $values, $type );
812 786 }
813 787
814 788 /**
815 789 * Create an entry and perform after create actions
@@ -818,9 +792,9 @@
818 792 *
819 793 * @param array $values
820 794 * @param array $new_values
821 795 *
822 - * @return bool|int $entry_id
796 + * @return bool|int Entry ID.
823 797 */
824 798 private static function continue_to_create_entry( $values, $new_values ) {
825 799 $entry_id = self::insert_entry_into_database( $new_values );
826 800
@@ -864,13 +838,14 @@
864 838 * Prepare the new values for inserting into the database
865 839 *
866 840 * @since 2.0.16
867 841 *
868 - * @param array $values
842 + * @param array $values
843 + * @param string $type The create type. 'xml' for an import.
869 844 *
870 - * @return array $new_values
845 + * @return array New values.
871 846 */
872 - private static function package_entry_data( &$values ) {
847 + private static function package_entry_data( &$values, $type = 'standard' ) {
873 848 global $wpdb;
874 849
875 850 if ( ! isset( $values['item_key'] ) ) {
876 851 $values['item_key'] = '';
@@ -878,9 +853,9 @@
878 853
879 854 $item_name = self::get_new_entry_name( $values, $values['item_key'] );
880 855 $new_values = array(
881 856 'item_key' => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
882 - 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
857 + 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '', true ),
883 858 'ip' => self::get_ip( $values ),
884 859 'is_draft' => self::get_is_draft_value( $values ),
885 860 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
886 861 'post_id' => (int) self::get_entry_value( $values, 'post_id', 0 ),
@@ -887,12 +862,12 @@
887 862 'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
888 863 'created_at' => self::get_created_at( $values ),
889 864 'updated_at' => self::get_updated_at( $values ),
890 865 'description' => self::get_entry_description( $values ),
891 - 'user_id' => self::get_entry_user_id( $values ),
866 + 'user_id' => self::get_entry_user_id( $values, $type ),
892 867 );
893 868
894 - $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'] );
895 870
896 871 return $new_values;
897 872 }
898 873
@@ -907,8 +882,33 @@
907 882 return $values[ $name ] ?? $default;
908 883 }
909 884
910 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 + /**
911 911 * Get the ip for a new entry.
912 912 * Allow the import to override the value.
913 913 *
914 914 * @since 2.03.10
@@ -924,9 +924,9 @@
924 924
925 925 $ip = FrmAppHelper::get_ip_address();
926 926
927 927 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
928 - $ip = self::get_entry_value( $values, 'ip', $ip );
928 + return self::get_entry_value( $values, 'ip', $ip );
929 929 }
930 930
931 931 return $ip;
932 932 }
@@ -970,15 +970,9 @@
970 970 *
971 971 * @return string
972 972 */
973 973 private static function get_updated_at( $values ) {
974 - if ( isset( $values['updated_at'] ) ) {
975 - $updated_at = $values['updated_at'];
976 - } else {
977 - $updated_at = self::get_created_at( $values );
978 - }
979 -
980 - return $updated_at;
974 + return $values['updated_at'] ?? self::get_created_at( $values );
981 975 }
982 976
983 977 /**
984 978 * Get the description value for a new entry
@@ -990,19 +984,17 @@
990 984 * @return string
991 985 */
992 986 private static function get_entry_description( $values ) {
993 987 if ( ! empty( $values['description'] ) ) {
994 - $description = FrmAppHelper::maybe_json_encode( $values['description'] );
995 - } else {
996 - $description = json_encode(
997 - array(
998 - 'browser' => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
999 - 'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
1000 - )
1001 - );
988 + return FrmAppHelper::maybe_json_encode( $values['description'] );
1002 989 }
1003 990
1004 - return $description;
991 + return json_encode(
992 + array(
993 + 'browser' => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
994 + 'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
995 + )
996 + );
1005 997 }
1006 998
1007 999 /**
1008 1000 * Get the user_id value for a new entry
@@ -1008,24 +1000,61 @@
1008 1000 * Get the user_id value for a new entry
1009 1001 *
1010 1002 * @since 2.0.16
1011 1003 *
1012 - * @param array $values
1004 + * @param array $values
1005 + * @param string $type The create type. 'xml' for an import.
1013 1006 *
1014 1007 * @return int
1015 1008 */
1016 - private static function get_entry_user_id( $values ) {
1017 - if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
1018 - $user_id = $values['frm_user_id'];
1019 - } else {
1020 - $current_user_id = get_current_user_id();
1021 - $user_id = $current_user_id ? $current_user_id : 0;
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 ) ) {
1011 + return $values['frm_user_id'];
1022 1012 }
1023 1013
1024 - return $user_id;
1014 + $current_user_id = get_current_user_id();
1015 + return $current_user_id ? $current_user_id : 0;
1025 1016 }
1026 1017
1027 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 + /**
1028 1057 * Insert new entry into the database
1029 1058 *
1030 1059 * @since 2.0.16
1031 1060 *
@@ -1030,9 +1059,9 @@
1030 1059 * @since 2.0.16
1031 1060 *
1032 1061 * @param array $new_values
1033 1062 *
1034 - * @return bool|int $entry_id
1063 + * @return bool|int Entry ID.
1035 1064 */
1036 1065 private static function insert_entry_into_database( $new_values ) {
1037 1066 global $wpdb;
1038 1067
@@ -1037,15 +1066,9 @@
1037 1066 global $wpdb;
1038 1067
1039 1068 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
1040 1069
1041 - if ( ! $query_results ) {
1042 - $entry_id = false;
1043 - } else {
1044 - $entry_id = $wpdb->insert_id;
1045 - }
1046 -
1047 - return $entry_id;
1070 + return $query_results ? $wpdb->insert_id : false;
1048 1071 }
1049 1072
1050 1073 /**
1051 1074 * Add the new entry to global $frm_vars
@@ -1100,12 +1123,14 @@
1100 1123 // This unique ID is inserted with JS on form submit.
1101 1124 // It is used to check for duplicate entries.
1102 1125 $unique_id = sanitize_key( $values['unique_id'] );
1103 1126
1104 - if ( $unique_id ) {
1105 - FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1106 - self::flag_new_unique_key( $unique_id );
1127 + if ( ! $unique_id ) {
1128 + return;
1107 1129 }
1130 +
1131 + FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1132 + self::flag_new_unique_key( $unique_id );
1108 1133 }
1109 1134
1110 1135 /**
1111 1136 * @since 5.0.15
@@ -1117,12 +1142,14 @@
1117 1142 */
1118 1143 private static function maybe_add_captcha_meta( $form_id, $entry_id ) {
1119 1144 global $frm_vars;
1120 1145
1121 - if ( array_key_exists( 'captcha_scores', $frm_vars ) && array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
1122 - $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
1123 - 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;
1124 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 ) );
1125 1152 }
1126 1153
1127 1154 /**
1128 1155 * Trigger frm_after_create_entry hooks
@@ -1140,8 +1167,18 @@
1140 1167 $is_child = isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
1141 1168
1142 1169 do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
1143 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 + }
1144 1181 }
1145 1182
1146 1183 /**
1147 1184 * Actions to perform immediately after an entry is inserted in the frm_items database
@@ -1154,9 +1191,8 @@
1154 1191 *
1155 1192 * @return void
1156 1193 */
1157 1194 private static function after_insert_entry_in_database( $values, $new_values, $entry_id ) {
1158 -
1159 1195 self::add_new_entry_to_frm_vars( $entry_id );
1160 1196
1161 1197 self::maybe_add_entry_metas( $values, $entry_id );
1162 1198
@@ -1173,9 +1209,9 @@
1173 1209 * @param int|string $id
1174 1210 * @param array $values
1175 1211 * @param string $update_type
1176 1212 *
1177 - * @return bool $update
1213 + * @return bool Update.
1178 1214 */
1179 1215 private static function before_update_entry( $id, &$values, $update_type ) {
1180 1216 $update = true;
1181 1217
@@ -1180,8 +1216,9 @@
1180 1216 $update = true;
1181 1217
1182 1218 global $frm_vars;
1183 1219
1220 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
1184 1221 if ( isset( $frm_vars['saved_entries'] ) && is_array( $frm_vars['saved_entries'] ) && in_array( (int) $id, $frm_vars['saved_entries'] ) ) {
1185 1222 $update = false;
1186 1223 }
1187 1224
@@ -1196,22 +1233,23 @@
1196 1233 * Package the entry data for updating
1197 1234 *
1198 1235 * @since 2.0.16
1199 1236 *
1200 - * @param int $id
1201 - * @param array $values
1237 + * @param int $id
1238 + * @param array $values
1239 + * @param string $update_type The update type. 'xml' for an import.
1202 1240 *
1203 - * @return array $new_values
1241 + * @return array New values.
1204 1242 */
1205 - private static function package_entry_to_update( $id, $values ) {
1243 + private static function package_entry_to_update( $id, $values, $update_type = 'standard' ) {
1206 1244 global $wpdb;
1207 1245
1208 1246 $new_values = array(
1209 - 'name' => self::get_new_entry_name( $values ),
1247 + 'name' => FrmAppHelper::truncate( self::get_new_entry_name( $values ), 255, 1, '', true ),
1210 1248 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
1211 1249 'is_draft' => self::get_is_draft_value( $values ),
1212 1250 'updated_at' => current_time( 'mysql', 1 ),
1213 - 'updated_by' => $values['updated_by'] ?? get_current_user_id(),
1251 + 'updated_by' => self::get_updated_by( $values, $update_type, get_current_user_id() ),
1214 1252 );
1215 1253
1216 1254 if ( isset( $values['post_id'] ) ) {
1217 1255 $new_values['post_id'] = (int) $values['post_id'];
@@ -1224,15 +1262,13 @@
1224 1262 if ( isset( $values['parent_item_id'] ) ) {
1225 1263 $new_values['parent_item_id'] = (int) $values['parent_item_id'];
1226 1264 }
1227 1265
1228 - 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 ) ) {
1229 1267 $new_values['user_id'] = $values['frm_user_id'];
1230 1268 }
1231 1269
1232 - $new_values = apply_filters( 'frm_update_entry', $new_values, $id );
1233 -
1234 - return $new_values;
1270 + return apply_filters( 'frm_update_entry', $new_values, $id );
1235 1271 }
1236 1272
1237 1273 /**
1238 1274 * Perform some actions right after updating an entry
@@ -1264,8 +1300,17 @@
1264 1300 }
1265 1301
1266 1302 do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
1267 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 + }
1268 1313 }
1269 1314
1270 1315 /**
1271 1316 * Create entry from an XML import
@@ -1274,14 +1319,12 @@
1274 1319 * @since 2.0.16
1275 1320 *
1276 1321 * @param array $values
1277 1322 *
1278 - * @return bool|int $entry_id
1323 + * @return bool|int Entry ID.
1279 1324 */
1280 1325 public static function create_entry_from_xml( $values ) {
1281 - $entry_id = self::create_entry( $values, 'xml' );
1282 -
1283 - return $entry_id;
1326 + return self::create_entry( $values, 'xml' );
1284 1327 }
1285 1328
1286 1329 /**
1287 1330 * Update entry from an XML import
@@ -1291,14 +1334,12 @@
1291 1334 *
1292 1335 * @param int $id
1293 1336 * @param array $values
1294 1337 *
1295 - * @return bool|int $updated
1338 + * @return bool|int Updated.
1296 1339 */
1297 1340 public static function update_entry_from_xml( $id, $values ) {
1298 - $updated = self::update_entry( $id, $values, 'xml' );
1299 -
1300 - return $updated;
1341 + return self::update_entry( $id, $values, 'xml' );
1301 1342 }
1302 1343
1303 1344 /**
1304 1345 * @param string $key
@@ -1306,9 +1347,8 @@
1306 1347 * @return int entry_id
1307 1348 */
1308 1349 public static function get_id_by_key( $key ) {
1309 1350 $entry_id = FrmDb::get_var( 'frm_items', array( 'item_key' => sanitize_title( $key ) ) );
1310 -
1311 1351 return (int) $entry_id;
1312 1352 }
1313 1353
1314 1354 /**