PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 5.7.2
Contact Form 7 v5.7.2
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 / mail.php
contact-form-7 / includes Last commit date
block-editor 3 years ago css 3 years ago js 3 years ago swv 3 years ago capabilities.php 7 years ago config-validator.php 3 years ago contact-form-functions.php 3 years ago contact-form-template.php 3 years ago contact-form.php 3 years ago controller.php 3 years ago file.php 3 years ago form-tag.php 3 years ago form-tags-manager.php 3 years ago formatting.php 3 years ago functions.php 3 years ago html-formatter.php 3 years ago integration.php 3 years ago l10n.php 3 years ago mail.php 3 years ago pipe.php 4 years ago pocket-holder.php 3 years ago rest-api.php 4 years ago shortcodes.php 3 years ago special-mail-tags.php 3 years ago submission.php 3 years ago upgrade.php 7 years ago validation-functions.php 3 years ago validation.php 3 years ago
mail.php
518 lines
1 <?php
2
3 class WPCF7_Mail {
4
5 private static $current = null;
6
7 private $name = '';
8 private $locale = '';
9 private $template = array();
10 private $use_html = false;
11 private $exclude_blank = false;
12
13 public static function get_current() {
14 return self::$current;
15 }
16
17 public static function send( $template, $name = '' ) {
18 self::$current = new self( $name, $template );
19 return self::$current->compose();
20 }
21
22 private function __construct( $name, $template ) {
23 $this->name = trim( $name );
24 $this->use_html = ! empty( $template['use_html'] );
25 $this->exclude_blank = ! empty( $template['exclude_blank'] );
26
27 $this->template = wp_parse_args( $template, array(
28 'subject' => '',
29 'sender' => '',
30 'body' => '',
31 'recipient' => '',
32 'additional_headers' => '',
33 'attachments' => '',
34 ) );
35
36 if ( $submission = WPCF7_Submission::get_instance() ) {
37 $contact_form = $submission->get_contact_form();
38 $this->locale = $contact_form->locale();
39 }
40 }
41
42 public function name() {
43 return $this->name;
44 }
45
46 public function get( $component, $replace_tags = false ) {
47 $use_html = ( $this->use_html && 'body' == $component );
48 $exclude_blank = ( $this->exclude_blank && 'body' == $component );
49
50 $template = $this->template;
51 $component = isset( $template[$component] ) ? $template[$component] : '';
52
53 if ( $replace_tags ) {
54 $component = $this->replace_tags( $component, array(
55 'html' => $use_html,
56 'exclude_blank' => $exclude_blank,
57 ) );
58
59 if ( $use_html
60 and ! preg_match( '%<html[>\s].*</html>%is', $component ) ) {
61 $component = $this->htmlize( $component );
62 }
63 }
64
65 return $component;
66 }
67
68 private function htmlize( $body ) {
69 if ( $this->locale ) {
70 $lang_atts = sprintf( ' %s',
71 wpcf7_format_atts( array(
72 'dir' => wpcf7_is_rtl( $this->locale ) ? 'rtl' : 'ltr',
73 'lang' => str_replace( '_', '-', $this->locale ),
74 ) )
75 );
76 } else {
77 $lang_atts = '';
78 }
79
80 $header = apply_filters( 'wpcf7_mail_html_header',
81 '<!doctype html>
82 <html xmlns="http://www.w3.org/1999/xhtml"' . $lang_atts . '>
83 <head>
84 <title>' . esc_html( $this->get( 'subject', true ) ) . '</title>
85 </head>
86 <body>
87 ', $this );
88
89 $footer = apply_filters( 'wpcf7_mail_html_footer',
90 '</body>
91 </html>', $this );
92
93 $html = $header . wpcf7_autop( $body ) . $footer;
94 return $html;
95 }
96
97 private function compose( $send = true ) {
98 $components = array(
99 'subject' => $this->get( 'subject', true ),
100 'sender' => $this->get( 'sender', true ),
101 'body' => $this->get( 'body', true ),
102 'recipient' => $this->get( 'recipient', true ),
103 'additional_headers' => $this->get( 'additional_headers', true ),
104 'attachments' => $this->attachments(),
105 );
106
107 $components = apply_filters( 'wpcf7_mail_components',
108 $components, wpcf7_get_current_contact_form(), $this
109 );
110
111 if ( ! $send ) {
112 return $components;
113 }
114
115 $subject = wpcf7_strip_newline( $components['subject'] );
116 $sender = wpcf7_strip_newline( $components['sender'] );
117 $recipient = wpcf7_strip_newline( $components['recipient'] );
118 $body = $components['body'];
119 $additional_headers = trim( $components['additional_headers'] );
120
121 $headers = "From: $sender\n";
122
123 if ( $this->use_html ) {
124 $headers .= "Content-Type: text/html\n";
125 $headers .= "X-WPCF7-Content-Type: text/html\n";
126 } else {
127 $headers .= "X-WPCF7-Content-Type: text/plain\n";
128 }
129
130 if ( $additional_headers ) {
131 $headers .= $additional_headers . "\n";
132 }
133
134 $attachments = array_filter(
135 (array) $components['attachments'],
136 function ( $attachment ) {
137 $path = path_join( WP_CONTENT_DIR, $attachment );
138
139 if ( ! wpcf7_is_file_path_in_content_dir( $path ) ) {
140 if ( WP_DEBUG ) {
141 trigger_error(
142 sprintf(
143 /* translators: %s: Attachment file path. */
144 __( 'Failed to attach a file. %s is not in the allowed directory.', 'contact-form-7' ),
145 $path
146 ),
147 E_USER_NOTICE
148 );
149 }
150
151 return false;
152 }
153
154 if ( ! is_readable( $path ) or ! is_file( $path ) ) {
155 if ( WP_DEBUG ) {
156 trigger_error(
157 sprintf(
158 /* translators: %s: Attachment file path. */
159 __( 'Failed to attach a file. %s is not a readable file.', 'contact-form-7' ),
160 $path
161 ),
162 E_USER_NOTICE
163 );
164 }
165
166 return false;
167 }
168
169 static $total_size = array();
170
171 if ( ! isset( $total_size[$this->name] ) ) {
172 $total_size[$this->name] = 0;
173 }
174
175 $file_size = (int) @filesize( $path );
176
177 if ( 25 * MB_IN_BYTES < $total_size[$this->name] + $file_size ) {
178 if ( WP_DEBUG ) {
179 trigger_error(
180 __( 'Failed to attach a file. The total file size exceeds the limit of 25 megabytes.', 'contact-form-7' ),
181 E_USER_NOTICE
182 );
183 }
184
185 return false;
186 }
187
188 $total_size[$this->name] += $file_size;
189
190 return true;
191 }
192 );
193
194 return wp_mail( $recipient, $subject, $body, $headers, $attachments );
195 }
196
197 public function replace_tags( $content, $args = '' ) {
198 if ( true === $args ) {
199 $args = array( 'html' => true );
200 }
201
202 $args = wp_parse_args( $args, array(
203 'html' => false,
204 'exclude_blank' => false,
205 ) );
206
207 return wpcf7_mail_replace_tags( $content, $args );
208 }
209
210 private function attachments( $template = null ) {
211 if ( ! $template ) {
212 $template = $this->get( 'attachments' );
213 }
214
215 $attachments = array();
216
217 if ( $submission = WPCF7_Submission::get_instance() ) {
218 $uploaded_files = $submission->uploaded_files();
219
220 foreach ( (array) $uploaded_files as $name => $paths ) {
221 if ( false !== strpos( $template, "[{$name}]" ) ) {
222 $attachments = array_merge( $attachments, (array) $paths );
223 }
224 }
225 }
226
227 foreach ( explode( "\n", $template ) as $line ) {
228 $line = trim( $line );
229
230 if ( '' === $line or '[' == substr( $line, 0, 1 ) ) {
231 continue;
232 }
233
234 $attachments[] = path_join( WP_CONTENT_DIR, $line );
235 }
236
237 if ( $submission = WPCF7_Submission::get_instance() ) {
238 $attachments = array_merge(
239 $attachments,
240 (array) $submission->extra_attachments( $this->name )
241 );
242 }
243
244 return $attachments;
245 }
246 }
247
248 function wpcf7_mail_replace_tags( $content, $args = '' ) {
249 $args = wp_parse_args( $args, array(
250 'html' => false,
251 'exclude_blank' => false,
252 ) );
253
254 if ( is_array( $content ) ) {
255 foreach ( $content as $key => $value ) {
256 $content[$key] = wpcf7_mail_replace_tags( $value, $args );
257 }
258
259 return $content;
260 }
261
262 $content = explode( "\n", $content );
263
264 foreach ( $content as $num => $line ) {
265 $line = new WPCF7_MailTaggedText( $line, $args );
266 $replaced = $line->replace_tags();
267
268 if ( $args['exclude_blank'] ) {
269 $replaced_tags = $line->get_replaced_tags();
270
271 if ( empty( $replaced_tags )
272 or array_filter( $replaced_tags, 'strlen' ) ) {
273 $content[$num] = $replaced;
274 } else {
275 unset( $content[$num] ); // Remove a line.
276 }
277 } else {
278 $content[$num] = $replaced;
279 }
280 }
281
282 $content = implode( "\n", $content );
283
284 return $content;
285 }
286
287 add_action( 'phpmailer_init', 'wpcf7_phpmailer_init', 10, 1 );
288
289 function wpcf7_phpmailer_init( $phpmailer ) {
290 $custom_headers = $phpmailer->getCustomHeaders();
291 $phpmailer->clearCustomHeaders();
292 $wpcf7_content_type = false;
293
294 foreach ( (array) $custom_headers as $custom_header ) {
295 $name = $custom_header[0];
296 $value = $custom_header[1];
297
298 if ( 'X-WPCF7-Content-Type' === $name ) {
299 $wpcf7_content_type = trim( $value );
300 } else {
301 $phpmailer->addCustomHeader( $name, $value );
302 }
303 }
304
305 if ( 'text/html' === $wpcf7_content_type ) {
306 $phpmailer->msgHTML( $phpmailer->Body );
307 } elseif ( 'text/plain' === $wpcf7_content_type ) {
308 $phpmailer->AltBody = '';
309 }
310 }
311
312 class WPCF7_MailTaggedText {
313
314 private $html = false;
315 private $callback = null;
316 private $content = '';
317 private $replaced_tags = array();
318
319 public function __construct( $content, $args = '' ) {
320 $args = wp_parse_args( $args, array(
321 'html' => false,
322 'callback' => null,
323 ) );
324
325 $this->html = (bool) $args['html'];
326
327 if ( null !== $args['callback']
328 and is_callable( $args['callback'] ) ) {
329 $this->callback = $args['callback'];
330 } elseif ( $this->html ) {
331 $this->callback = array( $this, 'replace_tags_callback_html' );
332 } else {
333 $this->callback = array( $this, 'replace_tags_callback' );
334 }
335
336 $this->content = $content;
337 }
338
339 public function get_replaced_tags() {
340 return $this->replaced_tags;
341 }
342
343 public function replace_tags() {
344 $regex = '/(\[?)\[[\t ]*'
345 . '([a-zA-Z_][0-9a-zA-Z:._-]*)' // [2] = name
346 . '((?:[\t ]+"[^"]*"|[\t ]+\'[^\']*\')*)' // [3] = values
347 . '[\t ]*\](\]?)/';
348
349 return preg_replace_callback( $regex, $this->callback, $this->content );
350 }
351
352 private function replace_tags_callback_html( $matches ) {
353 return $this->replace_tags_callback( $matches, true );
354 }
355
356 private function replace_tags_callback( $matches, $html = false ) {
357 // allow [[foo]] syntax for escaping a tag
358 if ( $matches[1] == '['
359 and $matches[4] == ']' ) {
360 return substr( $matches[0], 1, -1 );
361 }
362
363 $tag = $matches[0];
364 $tagname = $matches[2];
365 $values = $matches[3];
366
367 $mail_tag = new WPCF7_MailTag( $tag, $tagname, $values );
368 $field_name = $mail_tag->field_name();
369
370 $submission = WPCF7_Submission::get_instance();
371 $submitted = $submission
372 ? $submission->get_posted_data( $field_name )
373 : null;
374
375 if ( $mail_tag->get_option( 'do_not_heat' ) ) {
376 $submitted = isset( $_POST[$field_name] )
377 ? wp_unslash( $_POST[$field_name] )
378 : '';
379 }
380
381 $replaced = $submitted;
382
383 if ( null !== $replaced ) {
384 if ( $format = $mail_tag->get_option( 'format' ) ) {
385 $replaced = $this->format( $replaced, $format );
386 }
387
388 $replaced = wpcf7_flat_join( $replaced, array(
389 'separator' => wp_get_list_item_separator(),
390 ) );
391
392 if ( $html ) {
393 $replaced = esc_html( $replaced );
394 $replaced = wptexturize( $replaced );
395 }
396 }
397
398 if ( $form_tag = $mail_tag->corresponding_form_tag() ) {
399 $type = $form_tag->type;
400
401 $replaced = apply_filters(
402 "wpcf7_mail_tag_replaced_{$type}", $replaced,
403 $submitted, $html, $mail_tag
404 );
405 }
406
407 $replaced = apply_filters(
408 'wpcf7_mail_tag_replaced', $replaced,
409 $submitted, $html, $mail_tag
410 );
411
412 if ( null !== $replaced ) {
413 $replaced = trim( $replaced );
414
415 $this->replaced_tags[$tag] = $replaced;
416 return $replaced;
417 }
418
419 $special = apply_filters( 'wpcf7_special_mail_tags', null,
420 $mail_tag->tag_name(), $html, $mail_tag
421 );
422
423 if ( null !== $special ) {
424 $this->replaced_tags[$tag] = $special;
425 return $special;
426 }
427
428 return $tag;
429 }
430
431 public function format( $original, $format ) {
432 $original = (array) $original;
433
434 foreach ( $original as $key => $value ) {
435 if ( preg_match( '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $value ) ) {
436 $datetime = date_create( $value, wp_timezone() );
437
438 if ( false !== $datetime ) {
439 $original[$key] = wp_date( $format, $datetime->getTimestamp() );
440 }
441 }
442 }
443
444 return $original;
445 }
446 }
447
448 class WPCF7_MailTag {
449
450 private $tag;
451 private $tagname = '';
452 private $name = '';
453 private $options = array();
454 private $values = array();
455 private $form_tag = null;
456
457 public function __construct( $tag, $tagname, $values ) {
458 $this->tag = $tag;
459 $this->name = $this->tagname = $tagname;
460
461 $this->options = array(
462 'do_not_heat' => false,
463 'format' => '',
464 );
465
466 if ( ! empty( $values ) ) {
467 preg_match_all( '/"[^"]*"|\'[^\']*\'/', $values, $matches );
468 $this->values = wpcf7_strip_quote_deep( $matches[0] );
469 }
470
471 if ( preg_match( '/^_raw_(.+)$/', $tagname, $matches ) ) {
472 $this->name = trim( $matches[1] );
473 $this->options['do_not_heat'] = true;
474 }
475
476 if ( preg_match( '/^_format_(.+)$/', $tagname, $matches ) ) {
477 $this->name = trim( $matches[1] );
478 $this->options['format'] = $this->values[0];
479 }
480 }
481
482 public function tag_name() {
483 return $this->tagname;
484 }
485
486 public function field_name() {
487 return strtr( $this->name, '.', '_' );
488 }
489
490 public function get_option( $option ) {
491 return $this->options[$option];
492 }
493
494 public function values() {
495 return $this->values;
496 }
497
498 public function corresponding_form_tag() {
499 if ( $this->form_tag instanceof WPCF7_FormTag ) {
500 return $this->form_tag;
501 }
502
503 if ( $submission = WPCF7_Submission::get_instance() ) {
504 $contact_form = $submission->get_contact_form();
505 $tags = $contact_form->scan_form_tags( array(
506 'name' => $this->field_name(),
507 'feature' => '! zero-controls-container',
508 ) );
509
510 if ( $tags ) {
511 $this->form_tag = $tags[0];
512 }
513 }
514
515 return $this->form_tag;
516 }
517 }
518