Completed
Push — master ( a0de24...442934 )
by Stephanie
04:02
created

FrmEntryValidate::validate_number_field()   C

Complexity

Conditions 9
Paths 11

Size

Total Lines 24
Code Lines 12

Duplication

Lines 3
Ratio 12.5 %
Metric Value
dl 3
loc 24
rs 5.3563
cc 9
eloc 12
nc 11
nop 3
1
<?php
2
3
class FrmEntryValidate {
4
    public static function validate( $values, $exclude = false ) {
5
        global $wpdb;
6
7
        FrmEntry::sanitize_entry_post( $values );
8
        $errors = array();
9
10
        if ( ! isset($values['form_id']) || ! isset($values['item_meta']) ) {
11
            $errors['form'] = __( 'There was a problem with your submission. Please try again.', 'formidable' );
12
            return $errors;
13
        }
14
15
		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' ) ) ) {
16
            $errors['form'] = __( 'You do not have permission to do that', 'formidable' );
17
        }
18
19 View Code Duplication
        if ( ! isset($values['item_key']) || $values['item_key'] == '' ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
20
            $_POST['item_key'] = $values['item_key'] = FrmAppHelper::get_unique_key('', $wpdb->prefix .'frm_items', 'item_key');
21
        }
22
23
        $where = apply_filters('frm_posted_field_ids', array( 'fi.form_id' => $values['form_id'] ) );
24
		// Don't get subfields
25
		$where['fr.parent_form_id'] = array( null, 0 );
26
		// Don't get excluded fields (like file upload fields in the ajax validation)
27
		if ( ! empty( $exclude ) ) {
28
			$where['fi.type not'] = $exclude;
29
		}
30
31
        $posted_fields = FrmField::getAll($where, 'field_order');
32
33
        // Pass exclude value to validate_field function so it can be used for repeating sections
34
        $args = array( 'exclude' => $exclude );
35
36
        foreach ( $posted_fields as $posted_field ) {
37
            self::validate_field($posted_field, $errors, $values, $args);
38
            unset($posted_field);
39
        }
40
41
        // check for spam
42
        self::spam_check( $exclude, $values, $errors );
43
44
        $errors = apply_filters( 'frm_validate_entry', $errors, $values, compact('exclude') );
45
46
        return $errors;
47
    }
48
49
    public static function validate_field( $posted_field, &$errors, $values, $args = array() ) {
50
        $defaults = array(
51
            'id'              => $posted_field->id,
52
            'parent_field_id' => '', // the id of the repeat or embed form
53
            'key_pointer'     => '', // the pointer in the posted array
54
            'exclude'         => array(), // exclude these field types from validation
55
        );
56
        $args = wp_parse_args( $args, $defaults );
57
58
        if ( empty($args['parent_field_id']) ) {
59
			$value = isset( $values['item_meta'][ $args['id'] ] ) ? $values['item_meta'][ $args['id'] ] : '';
60
        } else {
61
            // value is from a nested form
62
            $value = $values;
63
        }
64
65
        // Check for values in "Other" fields
66
        FrmEntriesHelper::maybe_set_other_validation( $posted_field, $value, $args );
67
68
        if ( isset($posted_field->field_options['default_blank']) && $posted_field->field_options['default_blank'] && $value == $posted_field->default_value ) {
69
            $value = '';
70
        }
71
72
		// Check for an array with only one value
73
		// Don't reset values in "Other" fields because array keys need to be preserved
74
		if ( is_array($value) && count( $value ) == 1 && $args['other'] !== true ) {
75
			$value = reset($value);
76
		}
77
78
        if ( $posted_field->required == '1' && ! is_array( $value ) && trim( $value ) == '' ) {
79
			$errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $posted_field, 'blank' );
80
        } else if ( $posted_field->type == 'text' && ! isset( $_POST['item_name'] ) ) {
81
            $_POST['item_name'] = $value;
82
        }
83
84
        self::validate_url_field($errors, $posted_field, $value, $args);
85
        self::validate_email_field($errors, $posted_field, $value, $args);
86
		self::validate_number_field( $errors, $posted_field, $value );
87
		self::validate_phone_field( $errors, $posted_field, $value );
88
89
        FrmEntriesHelper::set_posted_value($posted_field, $value, $args);
90
91
        self::validate_recaptcha($errors, $posted_field, $args);
92
93
        $errors = apply_filters('frm_validate_field_entry', $errors, $posted_field, $value, $args);
94
    }
95
96
	public static function validate_url_field( &$errors, $field, &$value, $args ) {
97
		if ( $value == '' || ! in_array( $field->type, array( 'website', 'url', 'image' ) ) ) {
98
            return;
99
        }
100
101
        if ( trim($value) == 'http://' ) {
102
            $value = '';
103
        } else {
104
            $value = esc_url_raw( $value );
105
            $value = preg_match('/^(https?|ftps?|mailto|news|feed|telnet):/is', $value) ? $value : 'http://'. $value;
106
        }
107
108
        //validate the url format
109 View Code Duplication
        if ( ! preg_match('/^http(s)?:\/\/([\da-z\.-]+)\.([\da-z\.-]+)/i', $value) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
			$errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
111
        }
112
    }
113
114
	public static function validate_email_field( &$errors, $field, $value, $args ) {
115
        if ( $value == '' || $field->type != 'email' ) {
116
            return;
117
        }
118
119
        //validate the email format
120 View Code Duplication
        if ( ! is_email($value) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
			$errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
122
        }
123
    }
124
125
	public static function validate_number_field( &$errors, $field, $value ) {
126
		//validate the number format
127
		if ( $field->type != 'number' ) {
128
			return;
129
		}
130
131 View Code Duplication
		if ( ! is_numeric( $value) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
			$errors[ 'field' . $field->temp_id ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
133
		}
134
135
		// validate number settings
136
		if ( $value != '' ) {
137
			$frm_settings = FrmAppHelper::get_settings();
138
			// only check if options are available in settings
139
			if ( $frm_settings->use_html && isset( $field->field_options['minnum'] ) && isset( $field->field_options['maxnum'] ) ) {
140
				//minnum maxnum
141
				if ( (float) $value < $field->field_options['minnum'] ) {
142
					$errors[ 'field' . $field->temp_id ] = __( 'Please select a higher number', 'formidable' );
143
				} else if ( (float) $value > $field->field_options['maxnum'] ) {
144
					$errors[ 'field' . $field->temp_id ] = __( 'Please select a lower number', 'formidable' );
145
				}
146
			}
147
		}
148
	}
149
150
	public static function validate_phone_field( &$errors, $field, $value ) {
151
		if ( $field->type != 'phone' ) {
152
			return;
153
		}
154
155
		$pattern = self::phone_format( $field );
156
157 View Code Duplication
		if ( ! preg_match( $pattern, $value ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158
			$errors[ 'field' . $field->temp_id ] = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
159
		}
160
	}
161
162
	public static function phone_format( $field ) {
163
		$default_format = '^((\+\d{1,3}(-|.| )?\(?\d\)?(-| |.)?\d{1,5})|(\(?\d{2,6}\)?))(-|.| )?(\d{3,4})(-|.| )?(\d{4})(( x| ext)\d{1,5}){0,1}$';
164
		if ( FrmField::is_option_empty( $field, 'format' ) ) {
165
			$pattern = $default_format;
166
		} else {
167
			$pattern = FrmField::get_option( $field, 'format' );
168
		}
169
170
		$pattern = apply_filters( 'frm_phone_pattern', $pattern, $field );
171
172
		//check if format is already a regular expression
173
		if ( strpos( $pattern, '^' ) !== 0 ) {
174
			//if not, create a regular expression
175
			$pattern = preg_replace( '/\d/', '\d', preg_quote( $pattern ) );
176
			$pattern = str_replace( 'a', '[a-z]', $pattern );
177
			$pattern = str_replace( 'A', '[A-Z]', $pattern );
178
			$pattern = str_replace( '*', 'w', $pattern );
179
			$pattern = str_replace( '/', '\/', $pattern );
180
181
			if ( strpos( $pattern, '\?' ) !== false ) {
182
				$parts = explode( '\?', $pattern );
183
				$pattern = '';
184
				foreach ( $parts as $part ) {
185
					if ( empty( $pattern ) ) {
186
						$pattern .= $part;
187
					} else {
188
						$pattern .= '(' . $part . ')?';
189
					}
190
				}
191
			}
192
			$pattern = '^' . $pattern . '$';
193
		}
194
195
		$pattern = '/' . $pattern . '/';
196
		return $pattern;
197
	}
198
199
	public static function validate_recaptcha( &$errors, $field, $args ) {
200
        if ( $field->type != 'captcha' || FrmAppHelper::is_admin() || apply_filters( 'frm_is_field_hidden', false, $field, stripslashes_deep( $_POST ) ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
201
            return;
202
        }
203
204
		$frm_settings = FrmAppHelper::get_settings();
205
		if ( empty( $frm_settings->pubkey ) ) {
206
			// don't require the captcha if it shouldn't be shown
207
			return;
208
		}
209
210
        if ( ! isset($_POST['g-recaptcha-response']) ) {
211
            // If captcha is missing, check if it was already verified
212
			if ( ! isset( $_POST['recaptcha_checked'] ) || ! wp_verify_nonce( $_POST['recaptcha_checked'], 'frm_ajax' ) ) {
213
                // There was no captcha submitted
214
				$errors[ 'field' . $args['id'] ] = __( 'The captcha is missing from this form', 'formidable' );
215
            }
216
            return;
217
        }
218
219
        $arg_array = array(
220
            'body'      => array(
221
				'secret'   => $frm_settings->privkey,
222
				'response' => $_POST['g-recaptcha-response'],
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
223
				'remoteip' => FrmAppHelper::get_ip_address(),
224
			),
225
		);
226
        $resp = wp_remote_post( 'https://www.google.com/recaptcha/api/siteverify', $arg_array );
227
        $response = json_decode(wp_remote_retrieve_body( $resp ), true);
228
229
        if ( isset( $response['success'] ) && ! $response['success'] ) {
230
            // What happens when the CAPTCHA was entered incorrectly
231
			$errors[ 'field' . $args['id'] ] = ( ! isset( $field->field_options['invalid'] ) || $field->field_options['invalid'] == '' ) ? $frm_settings->re_msg : $field->field_options['invalid'];
232
        }
233
    }
234
235
    /**
236
     * check for spam
237
     * @param boolean $exclude
238
     * @param array $values
239
     * @param array $errors by reference
240
     */
241
    public static function spam_check( $exclude, $values, &$errors ) {
242
        if ( ! empty( $exclude ) || ! isset( $values['item_meta'] ) || empty( $values['item_meta'] ) || ! empty( $errors ) ) {
243
            // only check spam if there are no other errors
244
            return;
245
        }
246
247
        if ( self::is_akismet_spam( $values ) ) {
248
			if ( self::is_akismet_enabled_for_user( $values['form_id'] ) ) {
249
				$errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
250
			}
251
	    }
252
253
    	if ( self::blacklist_check( $values ) ) {
254
            $errors['spam'] = __( 'Your entry appears to be spam!', 'formidable' );
255
    	}
256
    }
257
258
	private static function is_akismet_spam( $values ) {
259
		global $wpcom_api_key;
260
		return ( is_callable('Akismet::http_post') && ( get_option('wordpress_api_key') || $wpcom_api_key ) && self::akismet( $values ) );
261
	}
262
263
	private static function is_akismet_enabled_for_user( $form_id ) {
264
		$form = FrmForm::getOne( $form_id );
265
		return ( isset( $form->options['akismet'] ) && ! empty( $form->options['akismet'] ) && ( $form->options['akismet'] != 'logged' || ! is_user_logged_in() ) );
266
	}
267
268
    public static function blacklist_check( $values ) {
269
        if ( ! apply_filters('frm_check_blacklist', true, $values) ) {
270
            return false;
271
        }
272
273
    	$mod_keys = trim( get_option( 'blacklist_keys' ) );
274
275
    	if ( empty( $mod_keys ) ) {
276
    		return false;
277
    	}
278
279
    	$content = FrmEntriesHelper::entry_array_to_string($values);
280
281
		if ( empty($content) ) {
282
		    return false;
283
		}
284
285
    	$words = explode( "\n", $mod_keys );
286
287
    	foreach ( (array) $words as $word ) {
288
    		$word = trim( $word );
289
290
    		if ( empty($word) ) {
291
    			continue;
292
    		}
293
294
    		if ( preg_match('#' . preg_quote( $word, '#' ) . '#', $content) ) {
295
    			return true;
296
    		}
297
    	}
298
299
    	return false;
300
    }
301
302
    /**
303
     * Check entries for spam
304
     *
305
     * @return boolean true if is spam
306
     */
307
    public static function akismet( $values ) {
308
	    $content = FrmEntriesHelper::entry_array_to_string( $values );
309
310
		if ( empty( $content ) ) {
311
		    return false;
312
		}
313
314
        $datas = array();
315
        self::parse_akismet_array( $datas, $content );
316
317
		$query_string = '';
318
		foreach ( $datas as $key => $data ) {
319
			$query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
320
			unset( $key, $data );
321
		}
322
323
        $response = Akismet::http_post($query_string, 'comment-check');
324
325
		return ( is_array( $response ) && $response[1] == 'true' );
326
    }
327
328
    /**
329
     * @since 2.0
330
     * @param string $content
331
     */
332
    private  static function parse_akismet_array( &$datas, $content ) {
333
        $datas['blog'] = FrmAppHelper::site_url();
334
        $datas['user_ip'] = preg_replace( '/[^0-9., ]/', '', FrmAppHelper::get_ip_address() );
335
		$datas['user_agent'] = FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' );
336
		$datas['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? FrmAppHelper::get_server_value( 'HTTP_REFERER' ) : false;
337
        $datas['comment_type'] = 'formidable';
338
        $datas['comment_content'] = $content;
339
340
        if ( $permalink = get_permalink() ) {
341
            $datas['permalink'] = $permalink;
342
        }
343
344
        foreach ( $_SERVER as $key => $value ) {
345
			if ( ! in_array( $key, array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' ) ) && is_string( $value ) ) {
346
				$datas[ $key ] = wp_strip_all_tags( $value );
347
            } else {
348
				$datas[ $key ] = '';
349
            }
350
351
            unset($key, $value);
352
        }
353
    }
354
}
355