PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 5.3.1
Contact Form 7 v5.3.1
6.1.6 5.0.2 5.0.3 5.0.4 5.0.5 5.1 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2 5.2.1 5.2.2 5.3 5.3.1 5.3.2 5.4 5.4.1 5.4.2 5.5 5.5.1 5.5.2 5.5.3 5.5.4 5.5.5 5.5.6 5.5.6.1 5.6 5.6.1 5.6.2 5.6.3 5.6.4 5.7 5.7.1 5.7.2 5.7.3 5.7.4 5.7.5 5.7.5.1 5.7.6 5.7.7 5.8 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.9 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 6.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 trunk 1.1 1.10 1.10.0.1 1.10.1 1.2 1.3 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.6 1.6.1 1.7 1.7.1 1.7.2 1.7.4 1.7.5 1.7.6 1.7.6.1 1.7.7 1.7.7.1 1.7.8 1.8 1.8.0.1 1.8.0.2 1.8.0.3 1.8.0.4 1.8.1 1.8.1.1 1.9 1.9.1 1.9.2 1.9.2.1 1.9.2.2 1.9.3 1.9.4 1.9.5 1.9.5.1 2.0 2.0-beta 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1 2.1.1 2.1.2 2.2 2.2.1 2.3 2.3.1 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 3.0 3.0-beta 3.0.1 3.0.2 3.0.2.1 3.1 3.1.1 3.1.2 3.2 3.2.1 3.3 3.3.1 3.3.2 3.3.3 3.4 3.4.1 3.4.2 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.6 3.7 3.7.1 3.7.2 3.8 3.8.1 3.9 3.9-beta 3.9.1 3.9.2 3.9.3 4.0 4.0.1 4.0.2 4.0.3 4.1 4.1-beta 4.1.1 4.1.2 4.2 4.2-beta 4.2.1 4.2.2 4.3 4.3.1 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6 4.6.1 4.7 4.8 4.8.1 4.9 4.9.1 4.9.2 5.0 5.0.1
contact-form-7 / includes / submission.php
contact-form-7 / includes Last commit date
block-editor 5 years ago css 5 years ago js 5 years ago capabilities.php 7 years ago config-validator.php 5 years ago contact-form-functions.php 5 years ago contact-form-template.php 5 years ago contact-form.php 5 years ago controller.php 7 years ago form-tag.php 5 years ago form-tags-manager.php 6 years ago formatting.php 5 years ago functions.php 5 years ago integration.php 7 years ago l10n.php 5 years ago mail.php 5 years ago pipe.php 5 years ago rest-api.php 5 years ago shortcodes.php 9 years ago special-mail-tags.php 5 years ago submission.php 5 years ago upgrade.php 7 years ago validation.php 7 years ago
submission.php
525 lines
1 <?php
2
3 class WPCF7_Submission {
4
5 private static $instance;
6
7 private $contact_form;
8 private $status = 'init';
9 private $posted_data = array();
10 private $posted_data_hash = null;
11 private $skip_spam_check = false;
12 private $uploaded_files = array();
13 private $skip_mail = false;
14 private $response = '';
15 private $invalid_fields = array();
16 private $meta = array();
17 private $consent = array();
18 private $spam_log = array();
19
20 public static function get_instance( $contact_form = null, $args = '' ) {
21 if ( $contact_form instanceof WPCF7_ContactForm ) {
22 if ( empty( self::$instance ) ) {
23 self::$instance = new self( $contact_form, $args );
24 self::$instance->proceed();
25 return self::$instance;
26 } else {
27 return null;
28 }
29 } else {
30 if ( empty( self::$instance ) ) {
31 return null;
32 } else {
33 return self::$instance;
34 }
35 }
36 }
37
38 public static function is_restful() {
39 return defined( 'REST_REQUEST' ) && REST_REQUEST;
40 }
41
42 private function __construct( WPCF7_ContactForm $contact_form, $args = '' ) {
43 $args = wp_parse_args( $args, array(
44 'skip_mail' => false,
45 ) );
46
47 $this->contact_form = $contact_form;
48 $this->skip_mail = (bool) $args['skip_mail'];
49 }
50
51 private function proceed() {
52 $contact_form = $this->contact_form;
53
54 switch_to_locale( $contact_form->locale() );
55
56 $this->setup_meta_data();
57 $this->setup_posted_data();
58
59 if ( $this->is( 'init' ) and ! $this->validate() ) {
60 $this->set_status( 'validation_failed' );
61 $this->set_response( $contact_form->message( 'validation_error' ) );
62 }
63
64 if ( $this->is( 'init' ) and ! $this->accepted() ) {
65 $this->set_status( 'acceptance_missing' );
66 $this->set_response( $contact_form->message( 'accept_terms' ) );
67 }
68
69 if ( $this->is( 'init' ) and $this->spam() ) {
70 $this->set_status( 'spam' );
71 $this->set_response( $contact_form->message( 'spam' ) );
72 }
73
74 if ( $this->is( 'init' ) ) {
75 $abort = ! $this->before_send_mail();
76
77 if ( $abort ) {
78 if ( $this->is( 'init' ) ) {
79 $this->set_status( 'aborted' );
80 }
81
82 if ( '' === $this->get_response() ) {
83 $this->set_response( $contact_form->filter_message(
84 __( "Sending mail has been aborted.", 'contact-form-7' ) )
85 );
86 }
87 } elseif ( $this->mail() ) {
88 $this->set_status( 'mail_sent' );
89 $this->set_response( $contact_form->message( 'mail_sent_ok' ) );
90
91 do_action( 'wpcf7_mail_sent', $contact_form );
92 } else {
93 $this->set_status( 'mail_failed' );
94 $this->set_response( $contact_form->message( 'mail_sent_ng' ) );
95
96 do_action( 'wpcf7_mail_failed', $contact_form );
97 }
98 }
99
100 restore_previous_locale();
101
102 $this->remove_uploaded_files();
103 }
104
105 public function get_status() {
106 return $this->status;
107 }
108
109 public function set_status( $status ) {
110 if ( preg_match( '/^[a-z][0-9a-z_]+$/', $status ) ) {
111 $this->status = $status;
112 return true;
113 }
114
115 return false;
116 }
117
118 public function is( $status ) {
119 return $this->status == $status;
120 }
121
122 public function get_response() {
123 return $this->response;
124 }
125
126 public function set_response( $response ) {
127 $this->response = $response;
128 return true;
129 }
130
131 public function get_contact_form() {
132 return $this->contact_form;
133 }
134
135 public function get_invalid_field( $name ) {
136 if ( isset( $this->invalid_fields[$name] ) ) {
137 return $this->invalid_fields[$name];
138 } else {
139 return false;
140 }
141 }
142
143 public function get_invalid_fields() {
144 return $this->invalid_fields;
145 }
146
147 public function get_meta( $name ) {
148 if ( isset( $this->meta[$name] ) ) {
149 return $this->meta[$name];
150 }
151 }
152
153 private function setup_meta_data() {
154 $timestamp = time();
155
156 $remote_ip = $this->get_remote_ip_addr();
157
158 $remote_port = isset( $_SERVER['REMOTE_PORT'] )
159 ? (int) $_SERVER['REMOTE_PORT'] : '';
160
161 $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] )
162 ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '';
163
164 $url = $this->get_request_url();
165
166 $unit_tag = isset( $_POST['_wpcf7_unit_tag'] )
167 ? $_POST['_wpcf7_unit_tag'] : '';
168
169 $container_post_id = isset( $_POST['_wpcf7_container_post'] )
170 ? (int) $_POST['_wpcf7_container_post'] : 0;
171
172 $current_user_id = get_current_user_id();
173
174 $do_not_store = $this->contact_form->is_true( 'do_not_store' );
175
176 $this->meta = array(
177 'timestamp' => $timestamp,
178 'remote_ip' => $remote_ip,
179 'remote_port' => $remote_port,
180 'user_agent' => $user_agent,
181 'url' => $url,
182 'unit_tag' => $unit_tag,
183 'container_post_id' => $container_post_id,
184 'current_user_id' => $current_user_id,
185 'do_not_store' => $do_not_store,
186 );
187
188 return $this->meta;
189 }
190
191 public function get_posted_data( $name = '' ) {
192 if ( ! empty( $name ) ) {
193 if ( isset( $this->posted_data[$name] ) ) {
194 return $this->posted_data[$name];
195 } else {
196 return null;
197 }
198 }
199
200 return $this->posted_data;
201 }
202
203 private function setup_posted_data() {
204 $posted_data = array_filter( (array) $_POST, function( $key ) {
205 return '_' !== substr( $key, 0, 1 );
206 }, ARRAY_FILTER_USE_KEY );
207
208 $posted_data = wp_unslash( $posted_data );
209 $posted_data = $this->sanitize_posted_data( $posted_data );
210
211 $tags = $this->contact_form->scan_form_tags();
212
213 foreach ( (array) $tags as $tag ) {
214 if ( empty( $tag->name ) ) {
215 continue;
216 }
217
218 $type = $tag->type;
219 $name = $tag->name;
220 $pipes = $tag->pipes;
221
222 if ( wpcf7_form_tag_supports( $type, 'do-not-store' ) ) {
223 unset( $posted_data[$name] );
224 continue;
225 }
226
227 $value_orig = $value = '';
228
229 if ( isset( $posted_data[$name] ) ) {
230 $value_orig = $value = $posted_data[$name];
231 }
232
233 if ( WPCF7_USE_PIPE
234 and $pipes instanceof WPCF7_Pipes
235 and ! $pipes->zero() ) {
236 if ( is_array( $value_orig ) ) {
237 $value = array();
238
239 foreach ( $value_orig as $v ) {
240 $value[] = $pipes->do_pipe( $v );
241 }
242 } else {
243 $value = $pipes->do_pipe( $value_orig );
244 }
245 }
246
247 if ( wpcf7_form_tag_supports( $type, 'selectable-values' ) ) {
248 $value = (array) $value;
249
250 if ( $tag->has_option( 'free_text' )
251 and isset( $posted_data[$name . '_free_text'] ) ) {
252 $last_val = array_pop( $value );
253
254 list( $tied_item ) = array_slice(
255 WPCF7_USE_PIPE ? $tag->pipes->collect_afters() : $tag->values,
256 -1, 1
257 );
258
259 $tied_item = html_entity_decode( $tied_item, ENT_QUOTES, 'UTF-8' );
260
261 if ( $last_val === $tied_item ) {
262 $value[] = sprintf( '%s %s',
263 $last_val,
264 $posted_data[$name . '_free_text']
265 );
266 } else {
267 $value[] = $last_val;
268 }
269
270 unset( $posted_data[$name . '_free_text'] );
271 }
272 }
273
274 $value = apply_filters( "wpcf7_posted_data_{$type}", $value,
275 $value_orig, $tag );
276
277 $posted_data[$name] = $value;
278
279 if ( $tag->has_option( 'consent_for:storage' )
280 and empty( $posted_data[$name] ) ) {
281 $this->meta['do_not_store'] = true;
282 }
283 }
284
285 $this->posted_data = apply_filters( 'wpcf7_posted_data', $posted_data );
286
287 $this->posted_data_hash = wp_hash(
288 wpcf7_flat_join( array_merge(
289 array(
290 $this->get_meta( 'remote_ip' ),
291 $this->get_meta( 'remote_port' ),
292 $this->get_meta( 'unit_tag' ),
293 ),
294 $this->posted_data
295 ) ),
296 'wpcf7_submission'
297 );
298
299 return $this->posted_data;
300 }
301
302 private function sanitize_posted_data( $value ) {
303 if ( is_array( $value ) ) {
304 $value = array_map( array( $this, 'sanitize_posted_data' ), $value );
305 } elseif ( is_string( $value ) ) {
306 $value = wp_check_invalid_utf8( $value );
307 $value = wp_kses_no_null( $value );
308 }
309
310 return $value;
311 }
312
313 public function get_posted_data_hash() {
314 return $this->posted_data_hash;
315 }
316
317 private function get_remote_ip_addr() {
318 $ip_addr = '';
319
320 if ( isset( $_SERVER['REMOTE_ADDR'] )
321 and WP_Http::is_ip_address( $_SERVER['REMOTE_ADDR'] ) ) {
322 $ip_addr = $_SERVER['REMOTE_ADDR'];
323 }
324
325 return apply_filters( 'wpcf7_remote_ip_addr', $ip_addr );
326 }
327
328 private function get_request_url() {
329 $home_url = untrailingslashit( home_url() );
330
331 if ( self::is_restful() ) {
332 $referer = isset( $_SERVER['HTTP_REFERER'] )
333 ? trim( $_SERVER['HTTP_REFERER'] ) : '';
334
335 if ( $referer
336 and 0 === strpos( $referer, $home_url ) ) {
337 return esc_url_raw( $referer );
338 }
339 }
340
341 $url = preg_replace( '%(?<!:|/)/.*$%', '', $home_url )
342 . wpcf7_get_request_uri();
343
344 return $url;
345 }
346
347 private function validate() {
348 if ( $this->invalid_fields ) {
349 return false;
350 }
351
352 require_once WPCF7_PLUGIN_DIR . '/includes/validation.php';
353 $result = new WPCF7_Validation();
354
355 $tags = $this->contact_form->scan_form_tags();
356
357 foreach ( $tags as $tag ) {
358 $type = $tag->type;
359 $result = apply_filters( "wpcf7_validate_{$type}", $result, $tag );
360 }
361
362 $result = apply_filters( 'wpcf7_validate', $result, $tags );
363
364 $this->invalid_fields = $result->get_invalid_fields();
365
366 return $result->is_valid();
367 }
368
369 private function accepted() {
370 return apply_filters( 'wpcf7_acceptance', true, $this );
371 }
372
373 public function add_consent( $name, $conditions ) {
374 $this->consent[$name] = $conditions;
375 return true;
376 }
377
378 public function collect_consent() {
379 return (array) $this->consent;
380 }
381
382 private function spam() {
383 $spam = false;
384
385 $skip_spam_check = apply_filters( 'wpcf7_skip_spam_check',
386 $this->skip_spam_check,
387 $this
388 );
389
390 if ( $skip_spam_check ) {
391 return $spam;
392 }
393
394 if ( $this->contact_form->is_true( 'subscribers_only' )
395 and current_user_can( 'wpcf7_submit', $this->contact_form->id() ) ) {
396 return $spam;
397 }
398
399 $user_agent = (string) $this->get_meta( 'user_agent' );
400
401 if ( strlen( $user_agent ) < 2 ) {
402 $spam = true;
403
404 $this->add_spam_log( array(
405 'agent' => 'wpcf7',
406 'reason' => __( "User-Agent string is unnaturally short.", 'contact-form-7' ),
407 ) );
408 }
409
410 if ( ! $this->verify_nonce() ) {
411 $spam = true;
412
413 $this->add_spam_log( array(
414 'agent' => 'wpcf7',
415 'reason' => __( "Submitted nonce is invalid.", 'contact-form-7' ),
416 ) );
417 }
418
419 return apply_filters( 'wpcf7_spam', $spam, $this );
420 }
421
422 public function add_spam_log( $args = '' ) {
423 $args = wp_parse_args( $args, array(
424 'agent' => '',
425 'reason' => '',
426 ) );
427
428 $this->spam_log[] = $args;
429 }
430
431 public function get_spam_log() {
432 return $this->spam_log;
433 }
434
435 private function verify_nonce() {
436 if ( ! $this->contact_form->nonce_is_active() ) {
437 return true;
438 }
439
440 return wpcf7_verify_nonce( $_POST['_wpnonce'] );
441 }
442
443 /* Mail */
444
445 private function before_send_mail() {
446 $abort = false;
447
448 do_action_ref_array( 'wpcf7_before_send_mail', array(
449 $this->contact_form,
450 &$abort,
451 $this,
452 ) );
453
454 return ! $abort;
455 }
456
457 private function mail() {
458 $contact_form = $this->contact_form;
459
460 $skip_mail = apply_filters( 'wpcf7_skip_mail',
461 $this->skip_mail, $contact_form
462 );
463
464 if ( $skip_mail ) {
465 return true;
466 }
467
468 $result = WPCF7_Mail::send( $contact_form->prop( 'mail' ), 'mail' );
469
470 if ( $result ) {
471 $additional_mail = array();
472
473 if ( $mail_2 = $contact_form->prop( 'mail_2' )
474 and $mail_2['active'] ) {
475 $additional_mail['mail_2'] = $mail_2;
476 }
477
478 $additional_mail = apply_filters( 'wpcf7_additional_mail',
479 $additional_mail, $contact_form
480 );
481
482 foreach ( $additional_mail as $name => $template ) {
483 WPCF7_Mail::send( $template, $name );
484 }
485
486 return true;
487 }
488
489 return false;
490 }
491
492 public function uploaded_files() {
493 return $this->uploaded_files;
494 }
495
496 public function add_uploaded_file( $name, $file_path ) {
497 if ( ! wpcf7_is_name( $name ) ) {
498 return false;
499 }
500
501 if ( ! @is_file( $file_path ) or ! @is_readable( $file_path ) ) {
502 return false;
503 }
504
505 $this->uploaded_files[$name] = $file_path;
506
507 if ( empty( $this->posted_data[$name] ) ) {
508 $this->posted_data[$name] = md5_file( $file_path );
509 }
510 }
511
512 public function remove_uploaded_files() {
513 foreach ( (array) $this->uploaded_files as $name => $path ) {
514 wpcf7_rmdir_p( $path );
515
516 if ( $dir = dirname( $path )
517 and false !== ( $files = scandir( $dir ) )
518 and ! array_diff( $files, array( '.', '..' ) ) ) {
519 // remove parent dir if it's empty.
520 rmdir( $dir );
521 }
522 }
523 }
524 }
525