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

419 lines 13.2 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 // Reset arrays with only one value if it's not a field where array keys need to be preserved
83 if ( is_array( $value ) && count( $value ) == 1 && isset( $value[0] ) ) {
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 if ( $value != '' ) {
102 self::validate_phone_field( $errors, $posted_field, $value, $args );
103 }
104
105 $errors = apply_filters( 'frm_validate_' . $posted_field->type . '_field_entry', $errors, $posted_field, $value, $args );
106 $errors = apply_filters( 'frm_validate_field_entry', $errors, $posted_field, $value, $args );
107 }
108
109 private static function maybe_clear_value_for_default_blank_setting( $field, &$value ) {
110 $placeholder = FrmField::get_option( $field, 'placeholder' );
111 $is_default = ( ! empty( $placeholder ) && $value == $placeholder );
112 $is_label = false;
113
114 if ( ! $is_default ) {
115 $position = FrmField::get_option( $field, 'label' );
116 if ( empty( $position ) ) {
117 $position = FrmStylesController::get_style_val( 'position', $field->form_id );
118 }
119
120 $is_label = ( $position == 'inside' && FrmFieldsHelper::is_placeholder_field_type( $field->type ) && $value == $field->name );
121 }
122
123 if ( $is_label || $is_default ) {
124 $value = '';
125 }
126 }
127
128 public static function validate_field_types( &$errors, $posted_field, $value, $args ) {
129 $field_obj = FrmFieldFactory::get_field_object( $posted_field );
130 $args['value'] = $value;
131 $args['errors'] = $errors;
132
133 $new_errors = $field_obj->validate( $args );
134 if ( ! empty( $new_errors ) ) {
135 $errors = array_merge( $errors, $new_errors );
136 }
137 }
138
139 public static function validate_phone_field( &$errors, $field, $value, $args ) {
140 if ( $field->type == 'phone' || ( $field->type == 'text' && FrmField::is_option_true_in_object( $field, 'format' ) ) ) {
141
142 $pattern = self::phone_format( $field );
143
144 if ( ! preg_match( $pattern, $value ) ) {
145 $errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
146 }
147 }
148 }
149
150 public static function phone_format( $field ) {
151 if ( FrmField::is_option_empty( $field, 'format' ) ) {
152 $pattern = self::default_phone_format();
153 } else {
154 $pattern = FrmField::get_option( $field, 'format' );
155 }
156
157 $pattern = apply_filters( 'frm_phone_pattern', $pattern, $field );
158
159 // Create a regexp if format is not already a regexp
160 if ( strpos( $pattern, '^' ) !== 0 ) {
161 $pattern = self::create_regular_expression_from_format( $pattern );
162 }
163
164 $pattern = '/' . $pattern . '/';
165
166 return $pattern;
167 }
168
169 /**
170 * @since 3.01
171 */
172 private static function default_phone_format() {
173 return '^((\+\d{1,3}(-|.| )?\(?\d\)?(-| |.)?\d{1,5})|(\(?\d{2,6}\)?))(-|.| )?(\d{3,4})(-|.| )?(\d{4})(( x| ext)\d{1,5}){0,1}$';
174 }
175
176 /**
177 * Create a regular expression from a phone number format
178 *
179 * @since 2.02.02
180 *
181 * @param string $pattern
182 *
183 * @return string
184 */
185 private static function create_regular_expression_from_format( $pattern ) {
186 $pattern = preg_quote( $pattern );
187
188 // Firefox doesn't like escaped dashes or colons
189 $pattern = str_replace( array( '\-', '\:' ), array( '-', ':' ), $pattern );
190
191 // Switch generic values out for their regular expression
192 $pattern = preg_replace( '/\d/', '\d', $pattern );
193 $pattern = str_replace( 'a', '[a-z]', $pattern );
194 $pattern = str_replace( 'A', '[A-Z]', $pattern );
195 $pattern = str_replace( '*', 'w', $pattern );
196 $pattern = str_replace( '/', '\/', $pattern );
197
198 if ( strpos( $pattern, '\?' ) !== false ) {
199 $parts = explode( '\?', $pattern );
200 $pattern = '';
201 foreach ( $parts as $part ) {
202 if ( empty( $pattern ) ) {
203 $pattern .= $part;
204 } else {
205 $pattern .= '(' . $part . ')?';
206 }
207 }
208 }
209 $pattern = '^' . $pattern . '$';
210
211 return $pattern;
212 }
213
214 /**
215 * Check for spam
216 *
217 * @param boolean $exclude
218 * @param array $values
219 * @param array $errors by reference
220 */
221 public static function spam_check( $exclude, $values, &$errors ) {
222 if ( ! empty( $exclude ) || ! isset( $values['item_meta'] ) || empty( $values['item_meta'] ) || ! empty( $errors ) ) {
223 // only check spam if there are no other errors
224 return;
225 }
226
227 if ( self::is_honeypot_spam() || self::is_spam_bot() ) {
228 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
229 }
230
231 if ( self::blacklist_check( $values ) ) {
232 $errors['spam'] = __( 'Your entry appears to be blacklist spam!', 'formidable' );
233 }
234
235 if ( self::is_akismet_spam( $values ) ) {
236 if ( self::is_akismet_enabled_for_user( $values['form_id'] ) ) {
237 $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
238 }
239 }
240 }
241
242 private static function is_honeypot_spam() {
243 $honeypot_value = FrmAppHelper::get_param( 'frm_verify', '', 'get', 'sanitize_text_field' );
244
245 return ( $honeypot_value !== '' );
246 }
247
248 private static function is_spam_bot() {
249 $ip = FrmAppHelper::get_ip_address();
250
251 return empty( $ip );
252 }
253
254 private static function is_akismet_spam( $values ) {
255 global $wpcom_api_key;
256
257 return ( is_callable( 'Akismet::http_post' ) && ( get_option( 'wordpress_api_key' ) || $wpcom_api_key ) && self::akismet( $values ) );
258 }
259
260 private static function is_akismet_enabled_for_user( $form_id ) {
261 $form = FrmForm::getOne( $form_id );
262
263 return ( isset( $form->options['akismet'] ) && ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] != 'logged' || ! is_user_logged_in() ) );
264 }
265
266 public static function blacklist_check( $values ) {
267 if ( ! apply_filters( 'frm_check_blacklist', true, $values ) ) {
268 return false;
269 }
270
271 $mod_keys = trim( get_option( 'blacklist_keys' ) );
272 if ( empty( $mod_keys ) ) {
273 return false;
274 }
275
276 $content = FrmEntriesHelper::entry_array_to_string( $values );
277 if ( empty( $content ) ) {
278 return false;
279 }
280
281 $ip = FrmAppHelper::get_ip_address();
282 $user_agent = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
283 $user_info = self::get_spam_check_user_info( $values );
284
285 return wp_blacklist_check( $user_info['comment_author'], $user_info['comment_author_email'], $user_info['comment_author_url'], $content, $ip, $user_agent );
286 }
287
288 /**
289 * Check entries for Akismet spam
290 *
291 * @return boolean true if is spam
292 */
293 public static function akismet( $values ) {
294 $content = FrmEntriesHelper::entry_array_to_string( $values );
295 if ( empty( $content ) ) {
296 return false;
297 }
298
299 $datas = array(
300 'comment_type' => 'formidable',
301 'comment_content' => $content,
302 );
303 self::parse_akismet_array( $datas, $values );
304
305 $query_string = _http_build_query( $datas, '', '&' );
306 $response = Akismet::http_post( $query_string, 'comment-check' );
307
308 return ( is_array( $response ) && $response[1] == 'true' );
309 }
310
311 /**
312 * @since 2.0
313 */
314 private static function parse_akismet_array( &$datas, $values ) {
315 self::add_site_info_to_akismet( $datas );
316 self::add_user_info_to_akismet( $datas, $values );
317 self::add_server_values_to_akismet( $datas );
318 }
319
320 private static function add_site_info_to_akismet( &$datas ) {
321 $datas['blog'] = FrmAppHelper::site_url();
322 $datas['user_ip'] = preg_replace( '/[^0-9., ]/', '', FrmAppHelper::get_ip_address() );
323 $datas['user_agent'] = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
324 $datas['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? FrmAppHelper::get_server_value( 'HTTP_REFERER' ) : false;
325 $datas['blog_lang'] = get_locale();
326 $datas['blog_charset'] = get_option( 'blog_charset' );
327
328 if ( akismet_test_mode() ) {
329 $datas['is_test'] = 'true';
330 }
331 }
332
333 private static function add_user_info_to_akismet( &$datas, $values ) {
334 $user_info = self::get_spam_check_user_info( $values );
335 $datas = $datas + $user_info;
336
337 if ( isset( $user_info['user_ID'] ) ) {
338 $datas['user_role'] = Akismet::get_user_roles( $user_info['user_ID'] );
339 }
340 }
341
342 private static function get_spam_check_user_info( $values ) {
343 $datas = array();
344
345 if ( is_user_logged_in() ) {
346 $user = wp_get_current_user();
347
348 $datas['user_ID'] = $user->ID;
349 $datas['user_id'] = $user->ID;
350 $datas['comment_author'] = $user->display_name;
351 $datas['comment_author_email'] = $user->user_email;
352 $datas['comment_author_url'] = $user->user_url;
353 } else {
354 $datas['comment_author'] = '';
355 $datas['comment_author_email'] = '';
356 $datas['comment_author_url'] = '';
357
358 $values = array_filter( $values );
359 foreach ( $values as $value ) {
360 if ( ! is_array( $value ) ) {
361 if ( $datas['comment_author_email'] == '' && strpos( $value, '@' ) && is_email( $value ) ) {
362 $datas['comment_author_email'] = $value;
363 } elseif ( $datas['comment_author_url'] == '' && strpos( $value, 'http' ) === 0 ) {
364 $datas['comment_author_url'] = $value;
365 } elseif ( $datas['comment_author'] == '' && ! is_numeric( $value ) && strlen( $value ) < 200 ) {
366 $datas['comment_author'] = $value;
367 }
368 }
369 }
370 }
371
372 return $datas;
373 }
374
375 private static function add_server_values_to_akismet( &$datas ) {
376 foreach ( $_SERVER as $key => $value ) {
377 $include_value = is_string( $value ) && ! preg_match( '/^HTTP_COOKIE/', $key ) && preg_match( '/^(HTTP_|REMOTE_ADDR|REQUEST_URI|DOCUMENT_URI)/', $key );
378
379 // Send any potentially useful $_SERVER vars, but avoid sending junk we don't need.
380 if ( $include_value ) {
381 $datas[ $key ] = $value;
382 }
383 unset( $key, $value );
384 }
385 }
386
387 /**
388 * @deprecated 3.0
389 * @codeCoverageIgnore
390 */
391 public static function validate_url_field( &$errors, $field, $value, $args ) {
392 FrmDeprecated::validate_url_field( $errors, $field, $value, $args );
393 }
394
395 /**
396 * @deprecated 3.0
397 * @codeCoverageIgnore
398 */
399 public static function validate_email_field( &$errors, $field, $value, $args ) {
400 FrmDeprecated::validate_email_field( $errors, $field, $value, $args );
401 }
402
403 /**
404 * @deprecated 3.0
405 * @codeCoverageIgnore
406 */
407 public static function validate_number_field( &$errors, $field, $value, $args ) {
408 FrmDeprecated::validate_number_field( $errors, $field, $value, $args );
409 }
410
411 /**
412 * @deprecated 3.0
413 * @codeCoverageIgnore
414 */
415 public static function validate_recaptcha( &$errors, $field, $args ) {
416 FrmDeprecated::validate_recaptcha( $errors, $field, $args );
417 }
418 }
419