PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0.14
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0.14
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
formidable / classes / models / FrmEntryValidate.php

FrmEntryValidate.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.0.14, at classes/models/FrmEntryValidate.php

761 lines 22.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmEntryValidate {
7 public static function validate( $values, $exclude = false ) {
8 FrmEntry::sanitize_entry_post( $values );
9 $errors = array();
10
11 if ( ! isset( $values['form_id'] ) || ! isset( $values['item_meta'] ) ) {
12 $errors['form'] = __( 'There was a problem with your submission. Please try again.', 'formidable' );
13
14 return $errors;
15 }
16
17 if ( FrmAppHelper::is_admin() && is_user_logged_in() && ( ! isset( $values[ 'frm_submit_entry_' . $values['form_id'] ] ) || ! wp_verify_nonce( $values[ 'frm_submit_entry_' . $values['form_id'] ], 'frm_submit_entry_nonce' ) ) ) {
18 $errors['form'] = __( 'You do not have permission to do that', 'formidable' );
19 }
20
21 self::set_item_key( $values );
22
23 $posted_fields = self::get_fields_to_validate( $values, $exclude );
24
25 // Pass exclude value to validate_field function so it can be used for repeating sections
26 $args = array( 'exclude' => $exclude );
27
28 foreach ( $posted_fields as $posted_field ) {
29 self::validate_field( $posted_field, $errors, $values, $args );
30 unset( $posted_field );
31 }
32
33 if ( empty( $errors ) ) {
34 self::spam_check( $exclude, $values, $errors );
35 }
36
37 /**
38 * Allows modifying the validation errors after validating all fields.
39 *
40 * @since 5.0.04 Added `posted_fields` to the third param.
41 *
42 * @param array $errors Errors data.
43 * @param array $values Value data of the form.
44 * @param array $args Custom arguments. Contains `exclude` and `posted_fields`.
45 */
46 $errors = apply_filters( 'frm_validate_entry', $errors, $values, compact( 'exclude', 'posted_fields' ) );
47
48 return $errors;
49 }
50
51 private static function set_item_key( &$values ) {
52 if ( ! isset( $values['item_key'] ) || $values['item_key'] == '' ) {
53 global $wpdb;
54 $values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
55 $_POST['item_key'] = $values['item_key'];
56 }
57 }
58
59 private static function get_fields_to_validate( $values, $exclude ) {
60 $where = apply_filters( 'frm_posted_field_ids', array( 'fi.form_id' => $values['form_id'] ) );
61
62 // Don't get subfields
63 $where['fr.parent_form_id'] = array( null, 0 );
64
65 // Don't get excluded fields (like file upload fields in the ajax validation)
66 if ( ! empty( $exclude ) ) {
67 $where['fi.type not'] = $exclude;
68 }
69
70 $fields = FrmField::getAll( $where, 'field_order' );
71
72 /**
73 * Allows modifying fields to validate.
74 *
75 * @since 5.0.06
76 *
77 * @param array $fields List of fields.
78 * @param array $args Includes `values`, `exclude`, `where`.
79 */
80 return apply_filters( 'frm_fields_to_validate', $fields, compact( 'values', 'exclude', 'where' ) );
81 }
82
83 public static function validate_field( $posted_field, &$errors, $values, $args = array() ) {
84 $defaults = array(
85 'id' => $posted_field->id,
86 'parent_field_id' => '', // the id of the repeat or embed form
87 'key_pointer' => '', // the pointer in the posted array
88 'exclude' => array(), // exclude these field types from validation
89 );
90 $args = wp_parse_args( $args, $defaults );
91
92 if ( empty( $args['parent_field_id'] ) ) {
93 $value = isset( $values['item_meta'][ $args['id'] ] ) ? $values['item_meta'][ $args['id'] ] : '';
94 } else {
95 // value is from a nested form
96 $value = $values;
97 }
98
99 // Check for values in "Other" fields
100 FrmEntriesHelper::maybe_set_other_validation( $posted_field, $value, $args );
101
102 self::maybe_clear_value_for_default_blank_setting( $posted_field, $value );
103
104 $should_trim = is_array( $value ) && count( $value ) == 1 && isset( $value[0] ) && $posted_field->type !== 'checkbox';
105 if ( $should_trim ) {
106 $value = reset( $value );
107 }
108
109 if ( ! is_array( $value ) ) {
110 $value = trim( $value );
111 }
112
113 if ( $posted_field->required == '1' && FrmAppHelper::is_empty_value( $value ) ) {
114 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $posted_field, 'blank' );
115 } elseif ( $posted_field->type === 'text' && ! isset( $_POST['item_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
116 $_POST['item_name'] = $value;
117 }
118
119 FrmEntriesHelper::set_posted_value( $posted_field, $value, $args );
120
121 self::validate_field_types( $errors, $posted_field, $value, $args );
122
123 // Field might want to modify value before other parts of the system
124 // e.g. trim off excess values like in the case of fields with limit.
125 $value = apply_filters( 'frm_modify_posted_field_value', $value, $errors, $posted_field, $args );
126
127 if ( $value != '' ) {
128 self::validate_phone_field( $errors, $posted_field, $value, $args );
129 }
130
131 $errors = apply_filters( 'frm_validate_' . $posted_field->type . '_field_entry', $errors, $posted_field, $value, $args );
132 $errors = apply_filters( 'frm_validate_field_entry', $errors, $posted_field, $value, $args );
133 }
134
135 /**
136 * Set $value to an empty string if it matches its label
137 *
138 * @param object $field
139 * @param string $value
140 */
141 private static function maybe_clear_value_for_default_blank_setting( $field, &$value ) {
142 $position = FrmField::get_option( $field, 'label' );
143 if ( ! $position ) {
144 $position = FrmStylesController::get_style_val( 'position', $field->form_id );
145 }
146
147 if ( $position === 'inside' && FrmFieldsHelper::is_placeholder_field_type( $field->type ) && $value === $field->name ) {
148 $value = '';
149 }
150 }
151
152 public static function validate_field_types( &$errors, $posted_field, $value, $args ) {
153 $field_obj = FrmFieldFactory::get_field_object( $posted_field );
154 $args['value'] = $value;
155 $args['errors'] = $errors;
156
157 $new_errors = $field_obj->validate( $args );
158 if ( ! empty( $new_errors ) ) {
159 $errors = array_merge( $errors, $new_errors );
160 }
161 }
162
163 public static function validate_phone_field( &$errors, $field, $value, $args ) {
164 if ( $field->type == 'phone' || ( $field->type == 'text' && FrmField::is_option_true_in_object( $field, 'format' ) ) ) {
165
166 $pattern = self::phone_format( $field );
167
168 if ( ! preg_match( $pattern, $value ) ) {
169 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
170 }
171 }
172 }
173
174 public static function phone_format( $field ) {
175 if ( FrmField::is_option_empty( $field, 'format' ) ) {
176 $pattern = self::default_phone_format();
177 } else {
178 $pattern = FrmField::get_option( $field, 'format' );
179 }
180
181 $pattern = apply_filters( 'frm_phone_pattern', $pattern, $field );
182
183 // Create a regexp if format is not already a regexp
184 if ( strpos( $pattern, '^' ) !== 0 ) {
185 $pattern = self::create_regular_expression_from_format( $pattern );
186 }
187
188 $pattern = '/' . $pattern . '/';
189
190 return $pattern;
191 }
192
193 /**
194 * @since 3.01
195 */
196 private static function default_phone_format() {
197 return '^((\+\d{1,3}(-|.| )?\(?\d\)?(-| |.)?\d{1,5})|(\(?\d{2,6}\)?))(-|.| )?(\d{3,4})(-|.| )?(\d{4})(( x| ext)\d{1,5}){0,1}$';
198 }
199
200 /**
201 * Create a regular expression from a phone number format
202 *
203 * @since 2.02.02
204 *
205 * @param string $pattern
206 *
207 * @return string
208 */
209 private static function create_regular_expression_from_format( $pattern ) {
210 $pattern = preg_quote( $pattern );
211
212 // Firefox doesn't like escaped dashes or colons
213 $pattern = str_replace( array( '\-', '\:' ), array( '-', ':' ), $pattern );
214
215 // Switch generic values out for their regular expression
216 $pattern = preg_replace( '/\d/', '\d', $pattern );
217 $pattern = str_replace( 'A', '[A-Z]', $pattern );
218 $pattern = str_replace( 'a', '[a-zA-Z]', $pattern );
219 $pattern = str_replace( '*', 'w', $pattern );
220 $pattern = str_replace( '/', '\/', $pattern );
221
222 if ( strpos( $pattern, '\?' ) !== false ) {
223 $parts = explode( '\?', $pattern );
224 $pattern = '';
225 foreach ( $parts as $part ) {
226 if ( empty( $pattern ) ) {
227 $pattern .= $part;
228 } else {
229 $pattern .= '(' . $part . ')?';
230 }
231 }
232 }
233 $pattern = '^' . $pattern . '$';
234
235 return $pattern;
236 }
237
238 /**
239 * Check for spam
240 *
241 * @param boolean $exclude
242 * @param array $values
243 * @param array $errors by reference
244 */
245 public static function spam_check( $exclude, $values, &$errors ) {
246 if ( ! empty( $exclude ) || ! isset( $values['item_meta'] ) || empty( $values['item_meta'] ) || ! empty( $errors ) ) {
247 // only check spam if there are no other errors
248 return;
249 }
250
251 $antispam_check = self::is_antispam_check( $values['form_id'] );
252 if ( is_string( $antispam_check ) ) {
253 $errors['spam'] = $antispam_check;
254 } elseif ( self::is_honeypot_spam( $values ) || self::is_spam_bot() ) {
255 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
256 } elseif ( self::blacklist_check( $values ) ) {
257 $errors['spam'] = __( 'Your entry appears to be blocked spam!', 'formidable' );
258 }
259
260 if ( isset( $errors['spam'] ) || self::form_is_in_progress( $values ) ) {
261 return;
262 }
263
264 if ( self::is_akismet_enabled_for_user( $values['form_id'] ) && self::is_akismet_spam( $values ) ) {
265 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
266 }
267 }
268
269 /**
270 * Checks if form is in progress.
271 *
272 * @since 5.0.13
273 *
274 * @param array $values The values.
275 * @return bool
276 */
277 private static function form_is_in_progress( $values ) {
278 return FrmAppHelper::pro_is_installed() &&
279 ( isset( $values[ 'frm_page_order_' . $values['form_id'] ] ) || FrmAppHelper::get_post_param( 'frm_next_page' ) ) &&
280 FrmField::get_all_types_in_form( $values['form_id'], 'break' );
281 }
282
283 /**
284 * @param int $form_id
285 * @return boolean
286 */
287 private static function is_antispam_check( $form_id ) {
288 $aspm = new FrmAntiSpam( $form_id );
289 return $aspm->validate();
290 }
291
292 /**
293 * @param array $values
294 * @return boolean
295 */
296 private static function is_honeypot_spam( $values ) {
297 $honeypot = new FrmHoneypot( $values['form_id'] );
298 return ! $honeypot->validate();
299 }
300
301 /**
302 * @return boolean
303 */
304 private static function is_spam_bot() {
305 $ip = FrmAppHelper::get_ip_address();
306
307 return empty( $ip );
308 }
309
310 /**
311 * @param array $values
312 * @return boolean
313 */
314 private static function is_akismet_spam( $values ) {
315 global $wpcom_api_key;
316
317 return ( is_callable( 'Akismet::http_post' ) && ( get_option( 'wordpress_api_key' ) || $wpcom_api_key ) && self::akismet( $values ) );
318 }
319
320 /**
321 * @param int $form_id
322 * @return bool
323 */
324 private static function is_akismet_enabled_for_user( $form_id ) {
325 $form = FrmForm::getOne( $form_id );
326
327 return ( ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] !== 'logged' || ! is_user_logged_in() ) );
328 }
329
330 public static function blacklist_check( $values ) {
331 if ( ! apply_filters( 'frm_check_blacklist', true, $values ) ) {
332 return false;
333 }
334
335 $mod_keys = trim( self::get_disallowed_words() );
336 if ( empty( $mod_keys ) ) {
337 return false;
338 }
339
340 $content = FrmEntriesHelper::entry_array_to_string( $values );
341 if ( empty( $content ) ) {
342 return false;
343 }
344
345 self::prepare_values_for_spam_check( $values );
346 $ip = FrmAppHelper::get_ip_address();
347 $user_agent = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
348 $user_info = self::get_spam_check_user_info( $values );
349
350 return self::check_disallowed_words( $user_info['comment_author'], $user_info['comment_author_email'], $user_info['comment_author_url'], $content, $ip, $user_agent );
351 }
352
353 /**
354 * For WP 5.5 compatibility.
355 *
356 * @since 4.06.02
357 */
358 private static function check_disallowed_words( $author, $email, $url, $content, $ip, $user_agent ) {
359 if ( function_exists( 'wp_check_comment_disallowed_list' ) ) {
360 return wp_check_comment_disallowed_list( $author, $email, $url, $content, $ip, $user_agent );
361 } else {
362 return wp_blacklist_check( $author, $email, $url, $content, $ip, $user_agent );
363 }
364 }
365
366 /**
367 * For WP 5.5 compatibility.
368 *
369 * @since 4.06.02
370 */
371 private static function get_disallowed_words() {
372 $keys = get_option( 'disallowed_keys' );
373 if ( false === $keys ) {
374 // Fallback for WP < 5.5.
375 $keys = get_option( 'blacklist_keys' );
376 }
377 return $keys;
378 }
379
380 /**
381 * Check entries for Akismet spam
382 *
383 * @return boolean true if is spam
384 */
385 public static function akismet( $values ) {
386 if ( empty( $values['item_meta'] ) ) {
387 return false;
388 }
389
390 $datas = array(
391 'comment_type' => 'formidable',
392 );
393 self::parse_akismet_array( $datas, $values );
394
395 /**
396 * Allows modifying the values sent to Akismet.
397 *
398 * @since 5.0.07
399 *
400 * @param array $datas The array of values being sent to Akismet.
401 */
402 $datas = apply_filters( 'frm_akismet_values', $datas );
403
404 $query_string = _http_build_query( $datas, '', '&' );
405 $response = Akismet::http_post( $query_string, 'comment-check' );
406
407 return ( is_array( $response ) && $response[1] == 'true' );
408 }
409
410 /**
411 * @since 2.0
412 */
413 private static function parse_akismet_array( &$datas, $values ) {
414 self::add_site_info_to_akismet( $datas );
415 self::add_server_values_to_akismet( $datas );
416
417 self::prepare_values_for_spam_check( $values );
418
419 self::add_user_info_to_akismet( $datas, $values );
420 self::add_comment_content_to_akismet( $datas, $values );
421 }
422
423 private static function add_site_info_to_akismet( &$datas ) {
424 $datas['blog'] = FrmAppHelper::site_url();
425 $datas['user_ip'] = preg_replace( '/[^0-9., ]/', '', FrmAppHelper::get_ip_address() );
426 $datas['user_agent'] = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
427 $datas['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? FrmAppHelper::get_server_value( 'HTTP_REFERER' ) : false;
428 $datas['blog_lang'] = get_locale();
429 $datas['blog_charset'] = get_option( 'blog_charset' );
430
431 if ( akismet_test_mode() ) {
432 $datas['is_test'] = 'true';
433 }
434 }
435
436 private static function add_user_info_to_akismet( &$datas, $values ) {
437 $user_info = self::get_spam_check_user_info( $values );
438 $datas = $datas + $user_info;
439
440 if ( isset( $user_info['user_ID'] ) ) {
441 $datas['user_role'] = Akismet::get_user_roles( $user_info['user_ID'] );
442 }
443 }
444
445 /**
446 * Gets user info for Akismet spam check.
447 *
448 * @since 5.0.13 Separate code for guest. Handle value of embedded|repeater.
449 *
450 * @param array $values Entry values after running through {@see FrmEntryValidate::prepare_values_for_spam_check()}.
451 * @return array
452 */
453 private static function get_spam_check_user_info( $values ) {
454 if ( ! is_user_logged_in() ) {
455 return self::get_spam_check_user_info_for_guest( $values );
456 }
457
458 $user = wp_get_current_user();
459
460 return array(
461 'user_ID' => $user->ID,
462 'user_id' => $user->ID,
463 'comment_author' => $user->display_name,
464 'comment_author_email' => $user->user_email,
465 'comment_author_url' => $user->user_url,
466 );
467 }
468
469 /**
470 * Gets user info for Akismet spam check for guest.
471 *
472 * @since 5.0.13
473 *
474 * @param array $values Entry values after flattened.
475 * @return array
476 */
477 private static function get_spam_check_user_info_for_guest( $values ) {
478 $datas = array(
479 'comment_author' => '',
480 'comment_author_email' => '',
481 'comment_author_url' => '',
482 'name_field_ids' => $values['name_field_ids'],
483 'missing_keys' => array( 'comment_author_email', 'comment_author_url', 'comment_author' ),
484 'frm_duplicated' => array(),
485 );
486
487 if ( isset( $values['item_meta'] ) ) {
488 $values = $values['item_meta'];
489 }
490
491 $values = array_filter( $values );
492
493 self::recursive_add_akismet_guest_info( $datas, $values );
494 unset( $datas['name_field_ids'] );
495 unset( $datas['missing_keys'] );
496
497 return $datas;
498 }
499
500 /**
501 * Recursive adds akismet guest info.
502 *
503 * @since 5.0.13
504 *
505 * @param array $datas Guest data.
506 * @param array $values The values.
507 * @param int|null $custom_index Custom index (or field ID).
508 */
509 private static function recursive_add_akismet_guest_info( &$datas, $values, $custom_index = null ) {
510 foreach ( $values as $index => $value ) {
511 if ( ! $datas['missing_keys'] ) {
512 return; // Found all info.
513 }
514
515 if ( is_array( $value ) ) {
516 self::recursive_add_akismet_guest_info( $datas, $value, $index );
517 continue;
518 }
519
520 $field_id = ! is_null( $custom_index ) ? $custom_index : $index;
521 foreach ( $datas['missing_keys'] as $key_index => $key ) {
522 $found = self::is_akismet_guest_info_value( $key, $value, $field_id, $datas['name_field_ids'] );
523 if ( $found ) {
524 $datas[ $key ] = $value;
525 $datas['frm_duplicated'][] = $field_id;
526 unset( $datas['missing_keys'][ $key_index ] );
527 }
528 }
529 }
530 }
531
532 /**
533 * Checks if given value is an akismet guest info.
534 *
535 * @since 5.0.13
536 *
537 * @param string $key Guest info key.
538 * @param string $value Value to check.
539 * @param int $field_id Field ID.
540 * @param array $name_field_ids Name field IDs.
541 * @return bool
542 */
543 private static function is_akismet_guest_info_value( $key, $value, $field_id, $name_field_ids ) {
544 if ( ! $value || is_numeric( $value ) ) {
545 return false;
546 }
547
548 switch ( $key ) {
549 case 'comment_author_email':
550 return strpos( $value, '@' ) && is_email( $value );
551
552 case 'comment_author_url':
553 return 0 === strpos( $value, 'http' );
554
555 case 'comment_author':
556 if ( $name_field_ids ) {
557 // If there is name field in the form, we should always use it as author name.
558 return in_array( $field_id, $name_field_ids, true );
559 }
560 return strlen( $value ) < 200;
561 }
562
563 return false;
564 }
565
566 private static function add_server_values_to_akismet( &$datas ) {
567 foreach ( $_SERVER as $key => $value ) {
568 $include_value = is_string( $value ) && ! preg_match( '/^HTTP_COOKIE/', $key ) && preg_match( '/^(HTTP_|REMOTE_ADDR|REQUEST_URI|DOCUMENT_URI)/', $key );
569
570 // Send any potentially useful $_SERVER vars, but avoid sending junk we don't need.
571 if ( $include_value ) {
572 $datas[ $key ] = $value;
573 }
574 unset( $key, $value );
575 }
576 }
577
578 /**
579 * Adds comment content to Akismet data.
580 *
581 * @since 5.0.09
582 *
583 * @param array $datas The array of values being sent to Akismet.
584 * @param array $values Entry values.
585 */
586 private static function add_comment_content_to_akismet( &$datas, $values ) {
587 if ( isset( $datas['frm_duplicated'] ) ) {
588 foreach ( $datas['frm_duplicated'] as $index ) {
589 if ( isset( $values['item_meta'][ $index ] ) ) {
590 unset( $values['item_meta'][ $index ] );
591 } else {
592 unset( $values[ $index ] );
593 }
594 }
595 unset( $datas['frm_duplicated'] );
596 }
597
598 self::skip_adding_values_to_akismet( $values );
599
600 $datas['comment_content'] = FrmEntriesHelper::entry_array_to_string( $values );
601 }
602
603 /**
604 * Skips adding field values to Akismet.
605 *
606 * @since 5.0.09
607 *
608 * @param array $values Entry values.
609 */
610 private static function skip_adding_values_to_akismet( &$values ) {
611 $skipped_field_ids = self::get_akismet_skipped_field_ids( $values );
612 foreach ( $skipped_field_ids as $field_id ) {
613 if ( isset( $values['item_meta'][ $field_id ] ) ) {
614 unset( $values['item_meta'][ $field_id ] );
615 }
616 }
617 }
618
619 /**
620 * Gets field IDs that are skipped from sending to Akismet spam check.
621 *
622 * @since 5.0.09
623 * @since 5.0.13 Move out get_all_form_ids_and_flatten_meta() call and get `form_ids` from `$values`.
624 *
625 * @param array $values Entry values after running through {@see FrmEntryValidate::prepare_values_for_spam_check()}.
626 * @return array
627 */
628 private static function get_akismet_skipped_field_ids( $values ) {
629 if ( empty( $values['form_ids'] ) ) {
630 return array();
631 }
632
633 $skipped_types = array( 'divider', 'form', 'hidden', 'user_id', 'file', 'date', 'time', 'scale', 'star', 'range', 'toggle', 'data', 'lookup', 'likert', 'nps' );
634 $has_other_types = array( 'radio', 'checkbox', 'select' );
635
636 $where = array(
637 array(
638 'form_id' => $values['form_ids'],
639 array(
640 array(
641 'field_options not like' => ';s:5:"other";s:1:"1"',
642 'type' => $has_other_types,
643 ),
644 'or' => 1,
645 'type' => $skipped_types,
646 ),
647 ),
648 );
649
650 return FrmDb::get_col( 'frm_fields', $where );
651 }
652
653 /**
654 * Prepares values array for spam check.
655 *
656 * @since 5.0.13
657 *
658 * @param array $values Entry values.
659 */
660 private static function prepare_values_for_spam_check( &$values ) {
661 $form_ids = self::get_all_form_ids_and_flatten_meta( $values );
662 $values['form_ids'] = $form_ids;
663 }
664
665 /**
666 * Gets all form IDs (include child form IDs) and flatten item_meta array. Used for skipping values sent to Akismet.
667 * This also removes some unused data from the item_meta.
668 *
669 * @since 5.0.09
670 * @since 5.0.13 Convert name field value to string.
671 *
672 * @param array $values Entry values.
673 * @return array Form IDs.
674 */
675 private static function get_all_form_ids_and_flatten_meta( &$values ) {
676 $values['name_field_ids'] = array();
677
678 // Blacklist check for File field in the old version doesn't contain `form_id`.
679 $form_ids = isset( $values['form_id'] ) ? array( absint( $values['form_id'] ) ) : array();
680 foreach ( $values['item_meta'] as $field_id => $value ) {
681 if ( ! is_numeric( $field_id ) ) { // Maybe `other`.
682 continue;
683 }
684
685 // Convert name array to string.
686 if ( isset( $value['first'] ) && isset( $value['last'] ) ) {
687 $values['item_meta'][ $field_id ] = trim( implode( ' ', $value ) );
688 $values['name_field_ids'][] = $field_id;
689 continue;
690 }
691
692 if ( ! is_array( $value ) || empty( $value['form'] ) ) {
693 continue;
694 }
695
696 $form_ids[] = absint( $value['form'] );
697
698 foreach ( $value as $subindex => $subvalue ) {
699 if ( ! is_numeric( $subindex ) || ! is_array( $subvalue ) ) {
700 continue;
701 }
702
703 foreach ( $subvalue as $subsubindex => $subsubvalue ) {
704 if ( ! $subsubvalue ) {
705 continue;
706 }
707
708 if ( ! isset( $values['item_meta'][ $subsubindex ] ) ) {
709 $values['item_meta'][ $subsubindex ] = array();
710 }
711
712 // Convert name array to string.
713 if ( isset( $subsubvalue['first'] ) && isset( $subsubvalue['last'] ) ) {
714 $subsubvalue = trim( implode( ' ', $subsubvalue ) );
715
716 $values['name_field_ids'][] = $subsubindex;
717 }
718
719 $values['item_meta'][ $subsubindex ][] = $subsubvalue;
720 }
721 }
722
723 unset( $values['item_meta'][ $field_id ] );
724 }
725
726 return $form_ids;
727 }
728
729 /**
730 * @deprecated 3.0
731 * @codeCoverageIgnore
732 */
733 public static function validate_url_field( &$errors, $field, $value, $args ) {
734 FrmDeprecated::validate_url_field( $errors, $field, $value, $args );
735 }
736
737 /**
738 * @deprecated 3.0
739 * @codeCoverageIgnore
740 */
741 public static function validate_email_field( &$errors, $field, $value, $args ) {
742 FrmDeprecated::validate_email_field( $errors, $field, $value, $args );
743 }
744
745 /**
746 * @deprecated 3.0
747 * @codeCoverageIgnore
748 */
749 public static function validate_number_field( &$errors, $field, $value, $args ) {
750 FrmDeprecated::validate_number_field( $errors, $field, $value, $args );
751 }
752
753 /**
754 * @deprecated 3.0
755 * @codeCoverageIgnore
756 */
757 public static function validate_recaptcha( &$errors, $field, $args ) {
758 FrmDeprecated::validate_recaptcha( $errors, $field, $args );
759 }
760 }
761