PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.05.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.05.02
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 4.05.02, at classes/models/FrmEntryValidate.php

423 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class FrmEntryValidate {
4 public static function validate( $values, $exclude = false ) {
5 FrmEntry::sanitize_entry_post( $values );
6 $errors = array();
7
8 if ( ! isset( $values['form_id'] ) || ! isset( $values['item_meta'] ) ) {
9 $errors['form'] = __( 'There was a problem with your submission. Please try again.', 'formidable' );
10
11 return $errors;
12 }
13
14 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' ) ) ) {
15 $errors['form'] = __( 'You do not have permission to do that', 'formidable' );
16 }
17
18 self::set_item_key( $values );
19
20 $posted_fields = self::get_fields_to_validate( $values, $exclude );
21
22 // Pass exclude value to validate_field function so it can be used for repeating sections
23 $args = array( 'exclude' => $exclude );
24
25 foreach ( $posted_fields as $posted_field ) {
26 self::validate_field( $posted_field, $errors, $values, $args );
27 unset( $posted_field );
28 }
29
30 if ( empty( $errors ) ) {
31 self::spam_check( $exclude, $values, $errors );
32 }
33
34 $errors = apply_filters( 'frm_validate_entry', $errors, $values, compact( 'exclude' ) );
35
36 return $errors;
37 }
38
39 private static function set_item_key( &$values ) {
40 if ( ! isset( $values['item_key'] ) || $values['item_key'] == '' ) {
41 global $wpdb;
42 $values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
43 $_POST['item_key'] = $values['item_key'];
44 }
45 }
46
47 private static function get_fields_to_validate( $values, $exclude ) {
48 $where = apply_filters( 'frm_posted_field_ids', array( 'fi.form_id' => $values['form_id'] ) );
49
50 // Don't get subfields
51 $where['fr.parent_form_id'] = array( null, 0 );
52
53 // Don't get excluded fields (like file upload fields in the ajax validation)
54 if ( ! empty( $exclude ) ) {
55 $where['fi.type not'] = $exclude;
56 }
57
58 return FrmField::getAll( $where, 'field_order' );
59 }
60
61 public static function validate_field( $posted_field, &$errors, $values, $args = array() ) {
62 $defaults = array(
63 'id' => $posted_field->id,
64 'parent_field_id' => '', // the id of the repeat or embed form
65 'key_pointer' => '', // the pointer in the posted array
66 'exclude' => array(), // exclude these field types from validation
67 );
68 $args = wp_parse_args( $args, $defaults );
69
70 if ( empty( $args['parent_field_id'] ) ) {
71 $value = isset( $values['item_meta'][ $args['id'] ] ) ? $values['item_meta'][ $args['id'] ] : '';
72 } else {
73 // value is from a nested form
74 $value = $values;
75 }
76
77 // Check for values in "Other" fields
78 FrmEntriesHelper::maybe_set_other_validation( $posted_field, $value, $args );
79
80 self::maybe_clear_value_for_default_blank_setting( $posted_field, $value );
81
82 $should_trim = is_array( $value ) && count( $value ) == 1 && isset( $value[0] ) && $posted_field->type !== 'checkbox';
83 if ( $should_trim ) {
84 $value = reset( $value );
85 }
86
87 if ( ! is_array( $value ) ) {
88 $value = trim( $value );
89 }
90
91 if ( $posted_field->required == '1' && FrmAppHelper::is_empty_value( $value ) ) {
92 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $posted_field, 'blank' );
93 } elseif ( $posted_field->type == 'text' && ! isset( $_POST['item_name'] ) ) { // WPCS: CSRF ok.
94 $_POST['item_name'] = $value;
95 }
96
97 FrmEntriesHelper::set_posted_value( $posted_field, $value, $args );
98
99 self::validate_field_types( $errors, $posted_field, $value, $args );
100
101 // Field might want to modify value before other parts of the system
102 // e.g. trim off excess values like in the case of fields with limit.
103 $value = apply_filters( 'frm_modify_posted_field_value', $value, $errors, $posted_field, $args );
104
105 if ( $value != '' ) {
106 self::validate_phone_field( $errors, $posted_field, $value, $args );
107 }
108
109 $errors = apply_filters( 'frm_validate_' . $posted_field->type . '_field_entry', $errors, $posted_field, $value, $args );
110 $errors = apply_filters( 'frm_validate_field_entry', $errors, $posted_field, $value, $args );
111 }
112
113 private static function maybe_clear_value_for_default_blank_setting( $field, &$value ) {
114 $placeholder = FrmField::get_option( $field, 'placeholder' );
115 $is_default = ( ! empty( $placeholder ) && $value == $placeholder );
116 $is_label = false;
117
118 if ( ! $is_default ) {
119 $position = FrmField::get_option( $field, 'label' );
120 if ( empty( $position ) ) {
121 $position = FrmStylesController::get_style_val( 'position', $field->form_id );
122 }
123
124 $is_label = ( $position == 'inside' && FrmFieldsHelper::is_placeholder_field_type( $field->type ) && $value == $field->name );
125 }
126
127 if ( $is_label || $is_default ) {
128 $value = '';
129 }
130 }
131
132 public static function validate_field_types( &$errors, $posted_field, $value, $args ) {
133 $field_obj = FrmFieldFactory::get_field_object( $posted_field );
134 $args['value'] = $value;
135 $args['errors'] = $errors;
136
137 $new_errors = $field_obj->validate( $args );
138 if ( ! empty( $new_errors ) ) {
139 $errors = array_merge( $errors, $new_errors );
140 }
141 }
142
143 public static function validate_phone_field( &$errors, $field, $value, $args ) {
144 if ( $field->type == 'phone' || ( $field->type == 'text' && FrmField::is_option_true_in_object( $field, 'format' ) ) ) {
145
146 $pattern = self::phone_format( $field );
147
148 if ( ! preg_match( $pattern, $value ) ) {
149 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
150 }
151 }
152 }
153
154 public static function phone_format( $field ) {
155 if ( FrmField::is_option_empty( $field, 'format' ) ) {
156 $pattern = self::default_phone_format();
157 } else {
158 $pattern = FrmField::get_option( $field, 'format' );
159 }
160
161 $pattern = apply_filters( 'frm_phone_pattern', $pattern, $field );
162
163 // Create a regexp if format is not already a regexp
164 if ( strpos( $pattern, '^' ) !== 0 ) {
165 $pattern = self::create_regular_expression_from_format( $pattern );
166 }
167
168 $pattern = '/' . $pattern . '/';
169
170 return $pattern;
171 }
172
173 /**
174 * @since 3.01
175 */
176 private static function default_phone_format() {
177 return '^((\+\d{1,3}(-|.| )?\(?\d\)?(-| |.)?\d{1,5})|(\(?\d{2,6}\)?))(-|.| )?(\d{3,4})(-|.| )?(\d{4})(( x| ext)\d{1,5}){0,1}$';
178 }
179
180 /**
181 * Create a regular expression from a phone number format
182 *
183 * @since 2.02.02
184 *
185 * @param string $pattern
186 *
187 * @return string
188 */
189 private static function create_regular_expression_from_format( $pattern ) {
190 $pattern = preg_quote( $pattern );
191
192 // Firefox doesn't like escaped dashes or colons
193 $pattern = str_replace( array( '\-', '\:' ), array( '-', ':' ), $pattern );
194
195 // Switch generic values out for their regular expression
196 $pattern = preg_replace( '/\d/', '\d', $pattern );
197 $pattern = str_replace( 'A', '[A-Z]', $pattern );
198 $pattern = str_replace( 'a', '[a-zA-Z]', $pattern );
199 $pattern = str_replace( '*', 'w', $pattern );
200 $pattern = str_replace( '/', '\/', $pattern );
201
202 if ( strpos( $pattern, '\?' ) !== false ) {
203 $parts = explode( '\?', $pattern );
204 $pattern = '';
205 foreach ( $parts as $part ) {
206 if ( empty( $pattern ) ) {
207 $pattern .= $part;
208 } else {
209 $pattern .= '(' . $part . ')?';
210 }
211 }
212 }
213 $pattern = '^' . $pattern . '$';
214
215 return $pattern;
216 }
217
218 /**
219 * Check for spam
220 *
221 * @param boolean $exclude
222 * @param array $values
223 * @param array $errors by reference
224 */
225 public static function spam_check( $exclude, $values, &$errors ) {
226 if ( ! empty( $exclude ) || ! isset( $values['item_meta'] ) || empty( $values['item_meta'] ) || ! empty( $errors ) ) {
227 // only check spam if there are no other errors
228 return;
229 }
230
231 if ( self::is_honeypot_spam() || self::is_spam_bot() ) {
232 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
233 }
234
235 if ( self::blacklist_check( $values ) ) {
236 $errors['spam'] = __( 'Your entry appears to be blacklist spam!', 'formidable' );
237 }
238
239 if ( self::is_akismet_spam( $values ) ) {
240 if ( self::is_akismet_enabled_for_user( $values['form_id'] ) ) {
241 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
242 }
243 }
244 }
245
246 private static function is_honeypot_spam() {
247 $honeypot_value = FrmAppHelper::get_param( 'frm_verify', '', 'get', 'sanitize_text_field' );
248
249 return ( $honeypot_value !== '' );
250 }
251
252 private static function is_spam_bot() {
253 $ip = FrmAppHelper::get_ip_address();
254
255 return empty( $ip );
256 }
257
258 private static function is_akismet_spam( $values ) {
259 global $wpcom_api_key;
260
261 return ( is_callable( 'Akismet::http_post' ) && ( get_option( 'wordpress_api_key' ) || $wpcom_api_key ) && self::akismet( $values ) );
262 }
263
264 private static function is_akismet_enabled_for_user( $form_id ) {
265 $form = FrmForm::getOne( $form_id );
266
267 return ( isset( $form->options['akismet'] ) && ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] != 'logged' || ! is_user_logged_in() ) );
268 }
269
270 public static function blacklist_check( $values ) {
271 if ( ! apply_filters( 'frm_check_blacklist', true, $values ) ) {
272 return false;
273 }
274
275 $mod_keys = trim( get_option( 'blacklist_keys' ) );
276 if ( empty( $mod_keys ) ) {
277 return false;
278 }
279
280 $content = FrmEntriesHelper::entry_array_to_string( $values );
281 if ( empty( $content ) ) {
282 return false;
283 }
284
285 $ip = FrmAppHelper::get_ip_address();
286 $user_agent = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
287 $user_info = self::get_spam_check_user_info( $values );
288
289 return wp_blacklist_check( $user_info['comment_author'], $user_info['comment_author_email'], $user_info['comment_author_url'], $content, $ip, $user_agent );
290 }
291
292 /**
293 * Check entries for Akismet spam
294 *
295 * @return boolean true if is spam
296 */
297 public static function akismet( $values ) {
298 $content = FrmEntriesHelper::entry_array_to_string( $values );
299 if ( empty( $content ) ) {
300 return false;
301 }
302
303 $datas = array(
304 'comment_type' => 'formidable',
305 'comment_content' => $content,
306 );
307 self::parse_akismet_array( $datas, $values );
308
309 $query_string = _http_build_query( $datas, '', '&' );
310 $response = Akismet::http_post( $query_string, 'comment-check' );
311
312 return ( is_array( $response ) && $response[1] == 'true' );
313 }
314
315 /**
316 * @since 2.0
317 */
318 private static function parse_akismet_array( &$datas, $values ) {
319 self::add_site_info_to_akismet( $datas );
320 self::add_user_info_to_akismet( $datas, $values );
321 self::add_server_values_to_akismet( $datas );
322 }
323
324 private static function add_site_info_to_akismet( &$datas ) {
325 $datas['blog'] = FrmAppHelper::site_url();
326 $datas['user_ip'] = preg_replace( '/[^0-9., ]/', '', FrmAppHelper::get_ip_address() );
327 $datas['user_agent'] = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
328 $datas['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? FrmAppHelper::get_server_value( 'HTTP_REFERER' ) : false;
329 $datas['blog_lang'] = get_locale();
330 $datas['blog_charset'] = get_option( 'blog_charset' );
331
332 if ( akismet_test_mode() ) {
333 $datas['is_test'] = 'true';
334 }
335 }
336
337 private static function add_user_info_to_akismet( &$datas, $values ) {
338 $user_info = self::get_spam_check_user_info( $values );
339 $datas = $datas + $user_info;
340
341 if ( isset( $user_info['user_ID'] ) ) {
342 $datas['user_role'] = Akismet::get_user_roles( $user_info['user_ID'] );
343 }
344 }
345
346 private static function get_spam_check_user_info( $values ) {
347 $datas = array();
348
349 if ( is_user_logged_in() ) {
350 $user = wp_get_current_user();
351
352 $datas['user_ID'] = $user->ID;
353 $datas['user_id'] = $user->ID;
354 $datas['comment_author'] = $user->display_name;
355 $datas['comment_author_email'] = $user->user_email;
356 $datas['comment_author_url'] = $user->user_url;
357 } else {
358 $datas['comment_author'] = '';
359 $datas['comment_author_email'] = '';
360 $datas['comment_author_url'] = '';
361
362 $values = array_filter( $values );
363 foreach ( $values as $value ) {
364 if ( ! is_array( $value ) ) {
365 if ( $datas['comment_author_email'] == '' && strpos( $value, '@' ) && is_email( $value ) ) {
366 $datas['comment_author_email'] = $value;
367 } elseif ( $datas['comment_author_url'] == '' && strpos( $value, 'http' ) === 0 ) {
368 $datas['comment_author_url'] = $value;
369 } elseif ( $datas['comment_author'] == '' && ! is_numeric( $value ) && strlen( $value ) < 200 ) {
370 $datas['comment_author'] = $value;
371 }
372 }
373 }
374 }
375
376 return $datas;
377 }
378
379 private static function add_server_values_to_akismet( &$datas ) {
380 foreach ( $_SERVER as $key => $value ) {
381 $include_value = is_string( $value ) && ! preg_match( '/^HTTP_COOKIE/', $key ) && preg_match( '/^(HTTP_|REMOTE_ADDR|REQUEST_URI|DOCUMENT_URI)/', $key );
382
383 // Send any potentially useful $_SERVER vars, but avoid sending junk we don't need.
384 if ( $include_value ) {
385 $datas[ $key ] = $value;
386 }
387 unset( $key, $value );
388 }
389 }
390
391 /**
392 * @deprecated 3.0
393 * @codeCoverageIgnore
394 */
395 public static function validate_url_field( &$errors, $field, $value, $args ) {
396 FrmDeprecated::validate_url_field( $errors, $field, $value, $args );
397 }
398
399 /**
400 * @deprecated 3.0
401 * @codeCoverageIgnore
402 */
403 public static function validate_email_field( &$errors, $field, $value, $args ) {
404 FrmDeprecated::validate_email_field( $errors, $field, $value, $args );
405 }
406
407 /**
408 * @deprecated 3.0
409 * @codeCoverageIgnore
410 */
411 public static function validate_number_field( &$errors, $field, $value, $args ) {
412 FrmDeprecated::validate_number_field( $errors, $field, $value, $args );
413 }
414
415 /**
416 * @deprecated 3.0
417 * @codeCoverageIgnore
418 */
419 public static function validate_recaptcha( &$errors, $field, $args ) {
420 FrmDeprecated::validate_recaptcha( $errors, $field, $args );
421 }
422 }
423