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 +304 -159 6.25 → 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.
@@ -52,8 +48,9 @@
52 48 *
53 49 * @since 6.16.3
54 50 *
55 51 * @param string $unique_id
52 + *
56 53 * @return void
57 54 */
58 55 private static function flag_new_unique_key( $unique_id ) {
59 56 if ( ! isset( self::$unique_id_match_checks[ $unique_id ] ) ) {
@@ -63,8 +60,11 @@
63 60
64 61 /**
65 62 * Check for duplicate entries created in the last minute
66 63 *
64 + * @param array $new_values New values.
65 + * @param array $values Values.
66 + *
67 67 * @return bool
68 68 */
69 69 public static function is_duplicate( $new_values, $values ) {
70 70 $duplicate_entry_time = apply_filters( 'frm_time_to_check_duplicates', 60, $new_values );
@@ -81,8 +81,9 @@
81 81 $check_val['created_at >'] = gmdate( 'Y-m-d H:i:s', strtotime( $new_values['created_at'] ) - absint( $duplicate_entry_time ) );
82 82
83 83 unset( $check_val['created_at'], $check_val['updated_at'], $check_val['is_draft'], $check_val['id'], $check_val['item_key'] );
84 84
85 + // phpcs:ignore Universal.Operators.StrictComparisons
85 86 if ( $new_values['item_key'] == $new_values['name'] ) {
86 87 unset( $check_val['name'] );
87 88 }
88 89
@@ -87,29 +88,34 @@
87 88 }
88 89
89 90 $check_val = apply_filters( 'frm_duplicate_check_val', $check_val );
90 91
91 - global $wpdb;
92 - $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 + }
93 95
94 - 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 ) {
95 99 return false;
96 100 }
97 101
98 102 global $frm_vars;
99 103 $frm_vars['checking_duplicates'] = true;
104 + $is_duplicate = false;
100 105
101 - $is_duplicate = false;
102 106 foreach ( $entry_exists as $entry_exist ) {
103 107 $is_duplicate = true;
104 108
105 - // make sure it's a duplicate
109 + // Make sure it's a duplicate
106 110 $metas = FrmEntryMeta::get_entry_meta_info( $entry_exist );
107 111 $field_metas = array();
112 +
108 113 foreach ( $metas as $meta ) {
109 114 if ( 0 === (int) $meta->field_id ) {
110 115 continue;
111 116 }
117 +
112 118 $field_metas[ $meta->field_id ] = $meta->meta_value;
113 119 }
114 120
115 121 $filtered_vals = array_filter( $values['item_meta'] );
@@ -116,13 +122,13 @@
116 122 $filtered_vals = self::convert_values_to_their_saved_value( $filtered_vals, $entry_exist );
117 123 $field_metas = array_filter( $field_metas );
118 124
119 125 // If prev entry is empty and current entry is not, they are not duplicates
120 - if ( empty( $field_metas ) && ! empty( $filtered_vals ) ) {
126 + if ( ! $field_metas && $filtered_vals ) {
121 127 return false;
122 128 }
123 129
124 - // compare serialized values and not arrays
130 + // Compare serialized values and not arrays
125 131 $new_meta = array_map( 'maybe_serialize', $filtered_vals );
126 132
127 133 if ( $field_metas === $new_meta ) {
128 134 $is_duplicate = true;
@@ -135,10 +141,11 @@
135 141 continue;
136 142 }
137 143
138 144 $diff = array_diff_assoc( $field_metas, $new_meta );
145 +
139 146 foreach ( $diff as $meta_value ) {
140 - if ( ! empty( $meta_value ) ) {
147 + if ( $meta_value ) {
141 148 $is_duplicate = false;
142 149 }
143 150 }
144 151
@@ -156,8 +163,9 @@
156 163 * @since 6.16.3
157 164 *
158 165 * @param array $values POST request data.
159 166 * @param string $created_at The timestamp of the entry we are checking for.
167 + *
160 168 * @return bool
161 169 */
162 170 private static function maybe_check_for_unique_id_match( $values, $created_at ) {
163 171 if ( ! self::should_check_for_unique_id_match() ) {
@@ -168,8 +176,9 @@
168 176 return false;
169 177 }
170 178
171 179 $unique_id = sanitize_key( $values['unique_id'] );
180 +
172 181 if ( ! $unique_id ) {
173 182 // Only continue if a unique ID was generated on form submit.
174 183 return false;
175 184 }
@@ -178,8 +187,9 @@
178 187 return self::$unique_id_match_checks[ $unique_id ];
179 188 }
180 189
181 190 $timestamp = strtotime( $created_at );
191 +
182 192 if ( false === $timestamp ) {
183 193 $timestamp = time();
184 194 }
185 195
@@ -197,8 +207,10 @@
197 207 }
198 208
199 209 /**
200 210 * @since 6.16.3
211 + *
212 + * @return bool
201 213 */
202 214 private static function should_check_for_unique_id_match() {
203 215 /**
204 216 * Allow users to opt out of the DB query, in case it causes performance issues.
@@ -212,24 +224,30 @@
212 224 }
213 225
214 226 /**
215 227 * Convert form data to the actual value that would be saved into the database.
216 - * 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.
217 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 + *
218 232 * @param array $filter_vals
219 233 * @param int $entry_id
234 + *
220 235 * @return array
221 236 */
222 237 private static function convert_values_to_their_saved_value( $filter_vals, $entry_id ) {
223 238 $reduced = array();
239 +
224 240 foreach ( $filter_vals as $field_id => $value ) {
225 241 $field = FrmFieldFactory::get_field_object( $field_id );
226 242 $reduced[ $field_id ] = $field->get_value_to_save( $value, array( 'entry_id' => $entry_id ) );
227 243 $reduced[ $field_id ] = $field->set_value_before_save( $reduced[ $field_id ] );
228 - if ( '' === $reduced[ $field_id ] || ( is_array( $reduced[ $field_id ] ) && 0 === count( $reduced[ $field_id ] ) ) ) {
244 +
245 + if ( '' === $reduced[ $field_id ] || array() === $reduced[ $field_id ] ) {
229 246 unset( $reduced[ $field_id ] );
230 247 }
231 248 }
249 +
232 250 return $reduced;
233 251 }
234 252
235 253 /**
@@ -243,9 +261,9 @@
243 261 * @return bool
244 262 */
245 263 private static function is_duplicate_check_needed( $values, $duplicate_entry_time ) {
246 264 // If time for checking duplicates is set to an empty value, don't check for duplicates
247 - if ( empty( $duplicate_entry_time ) ) {
265 + if ( ! $duplicate_entry_time ) {
248 266 return false;
249 267 }
250 268
251 269 // If CSV is importing, don't check for duplicates
@@ -253,20 +271,20 @@
253 271 return false;
254 272 }
255 273
256 274 // If repeating field entries are getting created, don't check for duplicates
257 - if ( isset( $values['parent_form_id'] ) && $values['parent_form_id'] ) {
258 - return false;
259 - }
260 -
261 - return true;
275 + return empty( $values['parent_form_id'] );
262 276 }
263 277
278 + /**
279 + * @param int|string $id
280 + *
281 + * @return false|int
282 + */
264 283 public static function duplicate( $id ) {
265 284 global $wpdb;
266 285
267 - $values = self::getOne( $id );
268 -
286 + $values = self::getOne( $id );
269 287 $new_values = array();
270 288 $new_values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
271 289 $new_values['name'] = $values->name;
272 290 $new_values['is_draft'] = $values->is_draft;
@@ -276,8 +294,9 @@
276 294 $new_values['created_at'] = current_time( 'mysql', 1 );
277 295 $new_values['updated_at'] = $new_values['created_at'];
278 296
279 297 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
298 +
280 299 if ( ! $query_results ) {
281 300 return false;
282 301 }
283 302
@@ -283,8 +302,9 @@
283 302
284 303 $entry_id = $wpdb->insert_id;
285 304
286 305 global $frm_vars;
306 +
287 307 if ( ! isset( $frm_vars['saved_entries'] ) ) {
288 308 $frm_vars['saved_entries'] = array();
289 309 }
290 310 $frm_vars['saved_entries'][] = (int) $entry_id;
@@ -302,14 +322,12 @@
302 322 *
303 323 * @param int $id
304 324 * @param array $values
305 325 *
306 - * @return bool|int $update_results
326 + * @return bool|int Update results.
307 327 */
308 328 public static function update( $id, $values ) {
309 - $update_results = self::update_entry( $id, $values, 'standard' );
310 -
311 - return $update_results;
329 + return self::update_entry( $id, $values, 'standard' );
312 330 }
313 331
314 332 /**
315 333 * Update an entry with some differences depending on the update type
@@ -315,23 +333,24 @@
315 333 * Update an entry with some differences depending on the update type
316 334 *
317 335 * @since 2.0.16
318 336 *
319 - * @param int $id
320 - * @param array $values
337 + * @param int $id
338 + * @param array $values
339 + * @param string $update_type
321 340 *
322 - * @return bool|int $query_results
341 + * @return bool|int Query results.
323 342 */
324 343 private static function update_entry( $id, $values, $update_type ) {
325 344 global $wpdb;
326 345
327 346 $update = self::before_update_entry( $id, $values, $update_type );
347 +
328 348 if ( ! $update ) {
329 349 return false;
330 350 }
331 351
332 - $new_values = self::package_entry_to_update( $id, $values );
333 -
352 + $new_values = self::package_entry_to_update( $id, $values, $update_type );
334 353 $query_results = $wpdb->update( $wpdb->prefix . 'frm_items', $new_values, compact( 'id' ) );
335 354
336 355 self::after_update_entry( $query_results, $id, $values, $new_values );
337 356
@@ -341,8 +360,9 @@
341 360 /**
342 361 * Delete an entry.
343 362 *
344 363 * @param int|string $id
364 + *
345 365 * @return bool True on success, false if nothing was deleted.
346 366 */
347 367 public static function destroy( $id ) {
348 368 global $wpdb;
@@ -349,11 +369,11 @@
349 369 $id = (int) $id;
350 370
351 371 // Item meta is required for conditional logic in actions with 'delete' events.
352 372 $entry = self::getOne( $id, true );
373 +
353 374 if ( ! $entry ) {
354 - $result = false;
355 - return $result;
375 + return false;
356 376 }
357 377
358 378 /**
359 379 * Trigger an action to run custom logic before the entry is deleted.
@@ -381,12 +401,20 @@
381 401
382 402 return $result;
383 403 }
384 404
405 + /**
406 + * @param int $id
407 + * @param mixed $value
408 + * @param int|string $form_id
409 + *
410 + * @return false|int
411 + */
385 412 public static function update_form( $id, $value, $form_id ) {
386 413 global $wpdb;
387 414 $form_id = isset( $value ) ? $form_id : null;
388 415 $result = $wpdb->update( $wpdb->prefix . 'frm_items', array( 'form_id' => $form_id ), array( 'id' => $id ) );
416 +
389 417 if ( $result ) {
390 418 self::clear_cache();
391 419 }
392 420
@@ -397,8 +425,10 @@
397 425 * Clear entry caching
398 426 * Called when an entry is changed
399 427 *
400 428 * @since 2.0.5
429 + *
430 + * @return void
401 431 */
402 432 public static function clear_cache() {
403 433 FrmDb::cache_delete_group( 'frm_entry' );
404 434 FrmDb::cache_delete_group( 'frm_item' );
@@ -410,16 +440,17 @@
410 440 * After switching to the wp_loaded hook for processing entries,
411 441 * we can no longer use 'name', but check it as a fallback
412 442 *
413 443 * @since 2.0.11
444 + *
445 + * @param array $values
446 + * @param array|string $default
447 + *
448 + * @return string
414 449 */
415 450 public static function get_new_entry_name( $values, $default = '' ) {
416 451 $name = $values['item_name'] ?? $values['name'] ?? $default;
417 - if ( is_array( $name ) ) {
418 - $name = reset( $name );
419 - }
420 -
421 - return $name;
452 + return is_array( $name ) ? reset( $name ) : $name;
422 453 }
423 454
424 455 /**
425 456 * If $entry is numeric, get the entry object
@@ -425,19 +456,26 @@
425 456 * If $entry is numeric, get the entry object
426 457 *
427 458 * @since 2.0.9
428 459 *
429 - * @param int|object $entry By reference.
460 + * @param int|object|string $entry By reference.
461 + *
430 462 * @return void
431 463 */
432 464 public static function maybe_get_entry( &$entry ) {
433 465 if ( $entry && is_numeric( $entry ) ) {
434 466 $entry = self::getOne( $entry );
435 - } elseif ( empty( $entry ) || 'false' === $entry ) {
467 + } elseif ( ! $entry || 'false' === $entry ) {
436 468 $entry = false;
437 469 }
438 470 }
439 471
472 + /**
473 + * @param int|string $id
474 + * @param bool $meta
475 + *
476 + * @return object|null
477 + */
440 478 public static function getOne( $id, $meta = false ) {
441 479 global $wpdb;
442 480
443 481 $query = "SELECT it.*, fr.name as form_name, fr.form_key as form_key FROM {$wpdb->prefix}frm_items it
@@ -453,8 +491,9 @@
453 491 return $entry;
454 492 }
455 493
456 494 $entry = FrmDb::check_cache( $id, 'frm_entry' );
495 +
457 496 if ( $entry !== false ) {
458 497 self::prepare_entry( $entry );
459 498 return $entry;
460 499 }
@@ -469,11 +508,13 @@
469 508 /**
470 509 * @since 4.02.03
471 510 *
472 511 * @param object $entry
512 + *
513 + * @return void
473 514 */
474 515 private static function prepare_entry( &$entry ) {
475 - if ( empty( $entry ) ) {
516 + if ( ! $entry ) {
476 517 return;
477 518 }
478 519
479 520 FrmAppHelper::unserialize_or_decode( $entry->description );
@@ -484,8 +525,10 @@
484 525 /**
485 526 * @since 4.02.03
486 527 *
487 528 * @param array $entries
529 + *
530 + * @return void
488 531 */
489 532 private static function prepare_entries( &$entries ) {
490 533 foreach ( $entries as $k => $entry ) {
491 534 self::prepare_entry( $entry );
@@ -492,8 +535,13 @@
492 535 $entries[ $k ] = $entry;
493 536 }
494 537 }
495 538
539 + /**
540 + * @param object|null $entry
541 + *
542 + * @return object|null
543 + */
496 544 public static function get_meta( $entry ) {
497 545 if ( ! $entry ) {
498 546 return $entry;
499 547 }
@@ -510,13 +558,15 @@
510 558
511 559 $entry->metas = array();
512 560
513 561 $include_key = apply_filters( 'frm_include_meta_keys', false, array( 'form_id' => $entry->form_id ) );
562 +
514 563 foreach ( $metas as $meta_val ) {
515 564 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
516 565
517 - if ( $meta_val->item_id == $entry->id ) {
566 + if ( (int) $meta_val->item_id === (int) $entry->id ) {
518 567 $entry->metas[ $meta_val->field_id ] = $meta_val->meta_value;
568 +
519 569 if ( $include_key ) {
520 570 $entry->metas[ $meta_val->field_key ] = $entry->metas[ $meta_val->field_id ];
521 571 }
522 572 continue;
@@ -521,9 +571,9 @@
521 571 }
522 572 continue;
523 573 }
524 574
525 - // include sub entries in an array
575 + // Include sub entries in an array
526 576 if ( ! isset( $entry->metas[ $meta_val->field_id ] ) ) {
527 577 $entry->metas[ $meta_val->field_id ] = array();
528 578 }
529 579
@@ -529,9 +579,9 @@
529 579
530 580 $entry->metas[ $meta_val->field_id ][] = $meta_val->meta_value;
531 581
532 582 unset( $meta_val );
533 - }
583 + }//end foreach
534 584 unset( $metas );
535 585
536 586 FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
537 587
@@ -539,38 +589,40 @@
539 589 }
540 590
541 591 /**
542 592 * @param string $id
593 + *
594 + * @return bool
543 595 */
544 596 public static function exists( $id ) {
545 - global $wpdb;
546 -
547 597 if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
548 - $exists = true;
549 -
550 - return $exists;
598 + return true;
551 599 }
552 600
553 - if ( is_numeric( $id ) ) {
554 - $where = array( 'id' => $id );
555 - } else {
556 - $where = array( 'item_key' => $id );
557 - }
558 - $id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
601 + $where = is_numeric( $id ) ? array( 'id' => $id ) : array( 'item_key' => $id );
602 + $id = FrmDb::get_var( 'frm_items', $where );
559 603
560 604 return $id && $id > 0;
561 605 }
562 606
607 + /**
608 + * @param array|string $where
609 + * @param string $order_by
610 + * @param string $limit
611 + * @param bool $meta
612 + * @param bool $inc_form
613 + *
614 + * @return array
615 + */
563 616 public static function getAll( $where, $order_by = '', $limit = '', $meta = false, $inc_form = true ) {
564 617 global $wpdb;
565 618
566 - $limit = FrmDb::esc_limit( $limit );
567 -
619 + $limit = FrmDb::esc_limit( $limit );
568 620 $cache_key = FrmAppHelper::maybe_json_encode( $where ) . $order_by . $limit . $inc_form;
569 621 $entries = wp_cache_get( $cache_key, 'frm_entry' );
570 622
571 623 if ( false === $entries ) {
572 - $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
573 625 $table = $wpdb->prefix . 'frm_items it ';
574 626
575 627 if ( $inc_form ) {
576 628 $fields = 'it.*, fr.name as form_name,fr.form_key as form_key';
@@ -581,9 +633,9 @@
581 633 $fields .= self::sort_by_field( $order_matches[1] );
582 634 unset( $order_matches );
583 635 }
584 636
585 - // prepare the query
637 + // Prepare the query
586 638 $query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
587 639
588 640 $entries = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
589 641 unset( $query );
@@ -601,9 +653,11 @@
601 653 $where = array( 'it.form_id' => substr( $where, 11 ) );
602 654 }
603 655
604 656 $meta_where = array( 'field_id !' => 0 );
605 - if ( $limit == '' && is_array( $where ) && count( $where ) == 1 && isset( $where['it.form_id'] ) ) {
657 +
658 + // phpcs:ignore Universal.Operators.StrictComparisons
659 + if ( $limit == '' && is_array( $where ) && count( $where ) === 1 && isset( $where['it.form_id'] ) ) {
606 660 $meta_where['fi.form_id'] = $where['it.form_id'];
607 661 } else {
608 662 $meta_where['item_id'] = array_keys( $entries );
609 663 }
@@ -646,15 +700,15 @@
646 700 return $entries;
647 701 }
648 702
649 703 /**
650 - * @param int $field_id
704 + * @param int|string $field_id
705 + *
651 706 * @return string
652 707 */
653 708 private static function sort_by_field( $field_id ) {
654 709 global $wpdb;
655 - $field_id = (int) $field_id;
656 -
710 + $field_id = (int) $field_id;
657 711 $field_options = FrmDb::get_var( 'frm_fields', array( 'id' => $field_id ), 'field_options' );
658 712 FrmAppHelper::unserialize_or_decode( $field_options );
659 713
660 714 if ( empty( $field_options['post_field'] ) ) {
@@ -668,8 +722,9 @@
668 722
669 723 // Pagination Methods
670 724 /**
671 725 * @param array|int|string $where If int, use the form id.
726 + *
672 727 * @return int|string
673 728 */
674 729 public static function getRecordCount( $where = '' ) {
675 730 global $wpdb;
@@ -680,33 +735,35 @@
680 735 $where = array( 'form_id' => $where );
681 736 }
682 737
683 738 if ( is_array( $where ) ) {
684 - $count = FrmDb::get_count( $table_join, $where );
685 - } else {
686 - $cache_key = 'count_' . FrmAppHelper::maybe_json_encode( $where );
687 - $query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
688 - $count = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
739 + return FrmDb::get_count( $table_join, $where );
689 740 }
690 741
691 - 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' );
692 746 }
693 747
694 748 /**
695 - * @param int|string $p_size
749 + * @param int|string $p_size
750 + * @param array|int|string $where
751 + *
696 752 * @return int
697 753 */
698 754 public static function getPageCount( $p_size, $where = '' ) {
699 755 $p_size = (int) $p_size;
700 - $count = 1;
756 +
701 757 if ( $p_size ) {
702 758 if ( ! is_numeric( $where ) ) {
703 759 $where = self::getRecordCount( $where );
704 760 }
705 - $count = ceil( (int) $where / $p_size );
761 +
762 + return ceil( (int) $where / $p_size );
706 763 }
707 764
708 - return $count;
765 + return 1;
709 766 }
710 767
711 768 /**
712 769 * Prepare the data before inserting it into the database
@@ -715,12 +772,11 @@
715 772 *
716 773 * @param array $values
717 774 * @param string $type
718 775 *
719 - * @return array $new_values
776 + * @return array New values.
720 777 */
721 778 private static function before_insert_entry_in_database( &$values, $type ) {
722 -
723 779 self::sanitize_entry_post( $values );
724 780
725 781 if ( $type !== 'xml' ) {
726 782 $values = apply_filters( 'frm_pre_create_entry', $values );
@@ -725,11 +781,9 @@
725 781 if ( $type !== 'xml' ) {
726 782 $values = apply_filters( 'frm_pre_create_entry', $values );
727 783 }
728 784
729 - $new_values = self::package_entry_data( $values );
730 -
731 - return $new_values;
785 + return self::package_entry_data( $values, $type );
732 786 }
733 787
734 788 /**
735 789 * Create an entry and perform after create actions
@@ -738,12 +792,13 @@
738 792 *
739 793 * @param array $values
740 794 * @param array $new_values
741 795 *
742 - * @return bool|int $entry_id
796 + * @return bool|int Entry ID.
743 797 */
744 798 private static function continue_to_create_entry( $values, $new_values ) {
745 799 $entry_id = self::insert_entry_into_database( $new_values );
800 +
746 801 if ( ! $entry_id ) {
747 802 return false;
748 803 }
749 804
@@ -757,8 +812,10 @@
757 812 *
758 813 * @since 2.0
759 814 *
760 815 * @param array $values The POST values by reference.
816 + *
817 + * @return void
761 818 */
762 819 public static function sanitize_entry_post( &$values ) {
763 820 $sanitize_method = array(
764 821 'form_id' => 'absint',
@@ -781,13 +838,14 @@
781 838 * Prepare the new values for inserting into the database
782 839 *
783 840 * @since 2.0.16
784 841 *
785 - * @param array $values
842 + * @param array $values
843 + * @param string $type The create type. 'xml' for an import.
786 844 *
787 - * @return array $new_values
845 + * @return array New values.
788 846 */
789 - private static function package_entry_data( &$values ) {
847 + private static function package_entry_data( &$values, $type = 'standard' ) {
790 848 global $wpdb;
791 849
792 850 if ( ! isset( $values['item_key'] ) ) {
793 851 $values['item_key'] = '';
@@ -795,9 +853,9 @@
795 853
796 854 $item_name = self::get_new_entry_name( $values, $values['item_key'] );
797 855 $new_values = array(
798 856 'item_key' => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
799 - 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
857 + 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '', true ),
800 858 'ip' => self::get_ip( $values ),
801 859 'is_draft' => self::get_is_draft_value( $values ),
802 860 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
803 861 'post_id' => (int) self::get_entry_value( $values, 'post_id', 0 ),
@@ -804,21 +862,53 @@
804 862 'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
805 863 'created_at' => self::get_created_at( $values ),
806 864 'updated_at' => self::get_updated_at( $values ),
807 865 'description' => self::get_entry_description( $values ),
808 - 'user_id' => self::get_entry_user_id( $values ),
866 + 'user_id' => self::get_entry_user_id( $values, $type ),
809 867 );
810 868
811 - $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'] );
812 870
813 871 return $new_values;
814 872 }
815 873
874 + /**
875 + * @param array $values
876 + * @param string $name
877 + * @param mixed $default
878 + *
879 + * @return mixed
880 + */
816 881 private static function get_entry_value( $values, $name, $default ) {
817 882 return $values[ $name ] ?? $default;
818 883 }
819 884
820 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 + /**
821 911 * Get the ip for a new entry.
822 912 * Allow the import to override the value.
823 913 *
824 914 * @since 2.03.10
@@ -832,10 +922,11 @@
832 922 return '';
833 923 }
834 924
835 925 $ip = FrmAppHelper::get_ip_address();
926 +
836 927 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
837 - $ip = self::get_entry_value( $values, 'ip', $ip );
928 + return self::get_entry_value( $values, 'ip', $ip );
838 929 }
839 930
840 931 return $ip;
841 932 }
@@ -879,15 +970,9 @@
879 970 *
880 971 * @return string
881 972 */
882 973 private static function get_updated_at( $values ) {
883 - if ( isset( $values['updated_at'] ) ) {
884 - $updated_at = $values['updated_at'];
885 - } else {
886 - $updated_at = self::get_created_at( $values );
887 - }
888 -
889 - return $updated_at;
974 + return $values['updated_at'] ?? self::get_created_at( $values );
890 975 }
891 976
892 977 /**
893 978 * Get the description value for a new entry
@@ -899,19 +984,17 @@
899 984 * @return string
900 985 */
901 986 private static function get_entry_description( $values ) {
902 987 if ( ! empty( $values['description'] ) ) {
903 - $description = FrmAppHelper::maybe_json_encode( $values['description'] );
904 - } else {
905 - $description = json_encode(
906 - array(
907 - 'browser' => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
908 - 'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
909 - )
910 - );
988 + return FrmAppHelper::maybe_json_encode( $values['description'] );
911 989 }
912 990
913 - 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 + );
914 997 }
915 998
916 999 /**
917 1000 * Get the user_id value for a new entry
@@ -917,24 +1000,61 @@
917 1000 * Get the user_id value for a new entry
918 1001 *
919 1002 * @since 2.0.16
920 1003 *
921 - * @param array $values
1004 + * @param array $values
1005 + * @param string $type The create type. 'xml' for an import.
922 1006 *
923 1007 * @return int
924 1008 */
925 - private static function get_entry_user_id( $values ) {
926 - if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
927 - $user_id = $values['frm_user_id'];
928 - } else {
929 - $current_user_id = get_current_user_id();
930 - $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'];
931 1012 }
932 1013
933 - return $user_id;
1014 + $current_user_id = get_current_user_id();
1015 + return $current_user_id ? $current_user_id : 0;
934 1016 }
935 1017
936 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 + /**
937 1057 * Insert new entry into the database
938 1058 *
939 1059 * @since 2.0.16
940 1060 *
@@ -939,9 +1059,9 @@
939 1059 * @since 2.0.16
940 1060 *
941 1061 * @param array $new_values
942 1062 *
943 - * @return bool|int $entry_id
1063 + * @return bool|int Entry ID.
944 1064 */
945 1065 private static function insert_entry_into_database( $new_values ) {
946 1066 global $wpdb;
947 1067
@@ -946,15 +1066,9 @@
946 1066 global $wpdb;
947 1067
948 1068 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
949 1069
950 - if ( ! $query_results ) {
951 - $entry_id = false;
952 - } else {
953 - $entry_id = $wpdb->insert_id;
954 - }
955 -
956 - return $entry_id;
1070 + return $query_results ? $wpdb->insert_id : false;
957 1071 }
958 1072
959 1073 /**
960 1074 * Add the new entry to global $frm_vars
@@ -960,9 +1074,11 @@
960 1074 * Add the new entry to global $frm_vars
961 1075 *
962 1076 * @since 2.0.16
963 1077 *
964 - * @param int $entry_id
1078 + * @param int|string $entry_id
1079 + *
1080 + * @return void
965 1081 */
966 1082 private static function add_new_entry_to_frm_vars( $entry_id ) {
967 1083 global $frm_vars;
968 1084
@@ -977,10 +1093,11 @@
977 1093 * Add entry metas, if there are any
978 1094 *
979 1095 * @since 2.0.16
980 1096 *
981 - * @param array $values
982 - * @param int $entry_id
1097 + * @param array $values
1098 + * @param int|string $entry_id
1099 + *
983 1100 * @return void
984 1101 */
985 1102 private static function maybe_add_entry_metas( $values, $entry_id ) {
986 1103 if ( isset( $values['item_meta'] ) ) {
@@ -994,8 +1111,9 @@
994 1111 * @since 6.16.3
995 1112 *
996 1113 * @param array $values
997 1114 * @param int $entry_id
1115 + *
998 1116 * @return void
999 1117 */
1000 1118 private static function maybe_add_unique_id_meta( $values, $entry_id ) {
1001 1119 if ( ! empty( $values['parent_form_id'] ) || empty( $values['unique_id'] ) || ! self::should_check_for_unique_id_match() ) {
@@ -1004,12 +1122,15 @@
1004 1122
1005 1123 // This unique ID is inserted with JS on form submit.
1006 1124 // It is used to check for duplicate entries.
1007 1125 $unique_id = sanitize_key( $values['unique_id'] );
1008 - if ( $unique_id ) {
1009 - FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1010 - self::flag_new_unique_key( $unique_id );
1126 +
1127 + if ( ! $unique_id ) {
1128 + return;
1011 1129 }
1130 +
1131 + FrmEntryMeta::add_entry_meta( $entry_id, 0, '', compact( 'unique_id' ) );
1132 + self::flag_new_unique_key( $unique_id );
1012 1133 }
1013 1134
1014 1135 /**
1015 1136 * @since 5.0.15
@@ -1015,16 +1136,20 @@
1015 1136 * @since 5.0.15
1016 1137 *
1017 1138 * @param int $form_id
1018 1139 * @param int $entry_id
1140 + *
1019 1141 * @return void
1020 1142 */
1021 1143 private static function maybe_add_captcha_meta( $form_id, $entry_id ) {
1022 1144 global $frm_vars;
1023 - if ( array_key_exists( 'captcha_scores', $frm_vars ) && array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
1024 - $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
1025 - FrmEntryMeta::add_entry_meta( $entry_id, 0, '', maybe_serialize( $captcha_score_meta ) );
1145 +
1146 + if ( ! array_key_exists( 'captcha_scores', $frm_vars ) || ! array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
1147 + return;
1026 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 ) );
1027 1152 }
1028 1153
1029 1154 /**
1030 1155 * Trigger frm_after_create_entry hooks
@@ -1033,8 +1158,10 @@
1033 1158 *
1034 1159 * @param int $entry_id
1035 1160 * @param array $values
1036 1161 * @param array $new_values
1162 + *
1163 + * @return void
1037 1164 */
1038 1165 private static function after_entry_created_actions( $entry_id, $values, $new_values ) {
1039 1166 // This is a child entry.
1040 1167 $is_child = isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
@@ -1040,8 +1167,18 @@
1040 1167 $is_child = isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
1041 1168
1042 1169 do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
1043 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 + }
1044 1181 }
1045 1182
1046 1183 /**
1047 1184 * Actions to perform immediately after an entry is inserted in the frm_items database
@@ -1050,11 +1187,12 @@
1050 1187 *
1051 1188 * @param array $values
1052 1189 * @param array $new_values
1053 1190 * @param int $entry_id
1191 + *
1192 + * @return void
1054 1193 */
1055 1194 private static function after_insert_entry_in_database( $values, $new_values, $entry_id ) {
1056 -
1057 1195 self::add_new_entry_to_frm_vars( $entry_id );
1058 1196
1059 1197 self::maybe_add_entry_metas( $values, $entry_id );
1060 1198
@@ -1067,13 +1205,13 @@
1067 1205 * Perform some actions right before updating an entry
1068 1206 *
1069 1207 * @since 2.0.16
1070 1208 *
1071 - * @param int $id
1072 - * @param array $values
1073 - * @param string $update_type
1209 + * @param int|string $id
1210 + * @param array $values
1211 + * @param string $update_type
1074 1212 *
1075 - * @return bool $update
1213 + * @return bool Update.
1076 1214 */
1077 1215 private static function before_update_entry( $id, &$values, $update_type ) {
1078 1216 $update = true;
1079 1217
@@ -1078,8 +1216,9 @@
1078 1216 $update = true;
1079 1217
1080 1218 global $frm_vars;
1081 1219
1220 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
1082 1221 if ( isset( $frm_vars['saved_entries'] ) && is_array( $frm_vars['saved_entries'] ) && in_array( (int) $id, $frm_vars['saved_entries'] ) ) {
1083 1222 $update = false;
1084 1223 }
1085 1224
@@ -1094,22 +1233,23 @@
1094 1233 * Package the entry data for updating
1095 1234 *
1096 1235 * @since 2.0.16
1097 1236 *
1098 - * @param int $id
1099 - * @param array $values
1237 + * @param int $id
1238 + * @param array $values
1239 + * @param string $update_type The update type. 'xml' for an import.
1100 1240 *
1101 - * @return array $new_values
1241 + * @return array New values.
1102 1242 */
1103 - private static function package_entry_to_update( $id, $values ) {
1243 + private static function package_entry_to_update( $id, $values, $update_type = 'standard' ) {
1104 1244 global $wpdb;
1105 1245
1106 1246 $new_values = array(
1107 - 'name' => self::get_new_entry_name( $values ),
1247 + 'name' => FrmAppHelper::truncate( self::get_new_entry_name( $values ), 255, 1, '', true ),
1108 1248 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
1109 1249 'is_draft' => self::get_is_draft_value( $values ),
1110 1250 'updated_at' => current_time( 'mysql', 1 ),
1111 - 'updated_by' => $values['updated_by'] ?? get_current_user_id(),
1251 + 'updated_by' => self::get_updated_by( $values, $update_type, get_current_user_id() ),
1112 1252 );
1113 1253
1114 1254 if ( isset( $values['post_id'] ) ) {
1115 1255 $new_values['post_id'] = (int) $values['post_id'];
@@ -1122,15 +1262,13 @@
1122 1262 if ( isset( $values['parent_item_id'] ) ) {
1123 1263 $new_values['parent_item_id'] = (int) $values['parent_item_id'];
1124 1264 }
1125 1265
1126 - 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 ) ) {
1127 1267 $new_values['user_id'] = $values['frm_user_id'];
1128 1268 }
1129 1269
1130 - $new_values = apply_filters( 'frm_update_entry', $new_values, $id );
1131 -
1132 - return $new_values;
1270 + return apply_filters( 'frm_update_entry', $new_values, $id );
1133 1271 }
1134 1272
1135 1273 /**
1136 1274 * Perform some actions right after updating an entry
@@ -1136,12 +1274,14 @@
1136 1274 * Perform some actions right after updating an entry
1137 1275 *
1138 1276 * @since 2.0.16
1139 1277 *
1140 - * @param bool|int $query_results
1141 - * @param int $id
1142 - * @param array $values
1143 - * @param array $new_values
1278 + * @param bool|int $query_results
1279 + * @param int|string $id
1280 + * @param array $values
1281 + * @param array $new_values
1282 + *
1283 + * @return void
1144 1284 */
1145 1285 private static function after_update_entry( $query_results, $id, $values, $new_values ) {
1146 1286 if ( $query_results ) {
1147 1287 self::clear_cache();
@@ -1147,8 +1287,9 @@
1147 1287 self::clear_cache();
1148 1288 }
1149 1289
1150 1290 global $frm_vars;
1291 +
1151 1292 if ( ! isset( $frm_vars['saved_entries'] ) ) {
1152 1293 $frm_vars['saved_entries'] = array();
1153 1294 }
1154 1295
@@ -1159,8 +1300,17 @@
1159 1300 }
1160 1301
1161 1302 do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
1162 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 + }
1163 1313 }
1164 1314
1165 1315 /**
1166 1316 * Create entry from an XML import
@@ -1169,14 +1319,12 @@
1169 1319 * @since 2.0.16
1170 1320 *
1171 1321 * @param array $values
1172 1322 *
1173 - * @return bool|int $entry_id
1323 + * @return bool|int Entry ID.
1174 1324 */
1175 1325 public static function create_entry_from_xml( $values ) {
1176 - $entry_id = self::create_entry( $values, 'xml' );
1177 -
1178 - return $entry_id;
1326 + return self::create_entry( $values, 'xml' );
1179 1327 }
1180 1328
1181 1329 /**
1182 1330 * Update entry from an XML import
@@ -1186,14 +1334,12 @@
1186 1334 *
1187 1335 * @param int $id
1188 1336 * @param array $values
1189 1337 *
1190 - * @return bool|int $updated
1338 + * @return bool|int Updated.
1191 1339 */
1192 1340 public static function update_entry_from_xml( $id, $values ) {
1193 - $updated = self::update_entry( $id, $values, 'xml' );
1194 -
1195 - return $updated;
1341 + return self::update_entry( $id, $values, 'xml' );
1196 1342 }
1197 1343
1198 1344 /**
1199 1345 * @param string $key
@@ -1201,9 +1347,8 @@
1201 1347 * @return int entry_id
1202 1348 */
1203 1349 public static function get_id_by_key( $key ) {
1204 1350 $entry_id = FrmDb::get_var( 'frm_items', array( 'item_key' => sanitize_title( $key ) ) );
1205 -
1206 1351 return (int) $entry_id;
1207 1352 }
1208 1353
1209 1354 /**