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

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