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 / FrmEmail.php

FrmEmail.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 3.06.06, at classes/models/FrmEmail.php

783 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @since 2.03.04
5 */
6 class FrmEmail {
7
8 private $email_key = '';
9 private $to = array();
10 private $cc = array();
11 private $bcc = array();
12 private $from = '';
13 private $reply_to = '';
14 private $subject = '';
15 private $message = '';
16 private $attachments = array();
17
18 private $is_plain_text = false;
19 private $is_single_recipient = false;
20 private $include_user_info = false;
21
22 private $charset = '';
23 private $content_type = 'text/html';
24
25 private $settings = array();
26 private $entry;
27 private $form;
28
29 /**
30 * FrmEmail constructor
31 *
32 * @param object $action
33 * @param object $entry
34 * @param object $form
35 */
36 public function __construct( $action, $entry, $form ) {
37 $this->set_email_key( $action );
38 $this->entry = $entry;
39 $this->form = $form;
40 $this->settings = $action->post_content;
41
42 $user_id_args = self::get_user_id_args( $form->id );
43 $this->set_to( $user_id_args );
44 $this->set_cc( $user_id_args );
45 $this->set_bcc( $user_id_args );
46
47 if ( ! $this->has_recipients() ) {
48 return;
49 }
50
51 $this->set_from( $user_id_args );
52 $this->set_reply_to( $user_id_args );
53
54 $this->set_include_user_info();
55 $this->set_is_plain_text();
56 $this->set_is_single_recipient( $action );
57
58 $this->set_charset();
59 $this->set_content_type();
60
61 $this->set_subject();
62 $this->set_message();
63 $this->set_attachments();
64 }
65
66 /**
67 * Set the email key property
68 *
69 * @since 2.03.04
70 *
71 * @param object $action
72 */
73 private function set_email_key( $action ) {
74 $this->email_key = $action->ID;
75 }
76
77 /**
78 * Set the to addresses
79 *
80 * @since 2.03.04
81 *
82 * @param array $user_id_args
83 */
84 private function set_to( $user_id_args ) {
85 $to = $this->prepare_email_setting( $this->settings['email_to'], $user_id_args );
86 $to = $this->explode_emails( $to );
87
88 $where = array(
89 'it.field_id !' => 0,
90 'it.item_id' => $this->entry->id,
91 );
92 $values = FrmEntryMeta::getAll( $where, ' ORDER BY fi.field_order' );
93 $args = array(
94 'email_key' => $this->email_key,
95 'entry' => $this->entry,
96 'form' => $this->form,
97 );
98 $to = apply_filters( 'frm_to_email', $to, $values, $this->form->id, $args );
99
100 $this->to = array_unique( (array) $to );
101
102 if ( empty( $this->to ) ) {
103 return;
104 }
105
106 $this->handle_phone_numbers();
107
108 $this->to = $this->format_recipients( $this->to );
109 }
110
111 /**
112 * Set the CC addresses
113 *
114 * @since 2.03.04
115 *
116 * @param array $user_id_args
117 */
118 private function set_cc( $user_id_args ) {
119 $this->cc = $this->prepare_additional_recipients( $this->settings['cc'], $user_id_args );
120 }
121
122 /**
123 * Set the BCC addresses
124 *
125 * @since 2.03.04
126 *
127 * @param array $user_id_args
128 */
129 private function set_bcc( $user_id_args ) {
130 $this->bcc = $this->prepare_additional_recipients( $this->settings['bcc'], $user_id_args );
131 }
132
133 /**
134 * Prepare CC and BCC recipients
135 *
136 * @since 2.03.04
137 *
138 * @param string $recipients
139 * @param array $user_id_args
140 *
141 * @return array
142 */
143 private function prepare_additional_recipients( $recipients, $user_id_args ) {
144 $recipients = $this->prepare_email_setting( $recipients, $user_id_args );
145 $recipients = $this->explode_emails( $recipients );
146
147 $recipients = array_unique( (array) $recipients );
148 $recipients = $this->format_recipients( $recipients );
149
150 return $recipients;
151 }
152
153 /**
154 * Set the From addresses
155 *
156 * @since 2.03.04
157 *
158 * @param array $user_id_args
159 */
160 private function set_from( $user_id_args ) {
161 if ( empty( $this->settings['from'] ) ) {
162 $from = get_option( 'admin_email' );
163 } else {
164 $from = $this->prepare_email_setting( $this->settings['from'], $user_id_args );
165 }
166
167 $this->from = $this->format_from( $from );
168 }
169
170 /**
171 * Set the Reply To addresses
172 *
173 * @since 2.03.04
174 *
175 * @param array $user_id_args
176 */
177 private function set_reply_to( $user_id_args ) {
178 $this->reply_to = trim( $this->settings['reply_to'] );
179
180 if ( empty( $this->reply_to ) ) {
181 $this->reply_to = $this->get_email_from_name( $this->from );
182 } else {
183 $this->reply_to = $this->prepare_email_setting( $this->settings['reply_to'], $user_id_args );
184 }
185 $this->reply_to = $this->format_reply_to( $this->reply_to );
186 }
187
188 /**
189 * Set the is_plain_text property
190 * This should be set before the message
191 *
192 * @since 2.03.04
193 */
194 private function set_is_plain_text() {
195 if ( $this->settings['plain_text'] ) {
196 $this->is_plain_text = true;
197 }
198 }
199
200 /**
201 * Set the include_user_info property
202 * This should be set before the message
203 *
204 * @since 2.03.04
205 */
206 private function set_include_user_info() {
207 if ( isset( $this->settings['inc_user_info'] ) ) {
208 $this->include_user_info = $this->settings['inc_user_info'];
209 }
210 }
211
212 /**
213 * Set the is_single_recipient property
214 *
215 * @since 2.03.04
216 *
217 * @param $action
218 */
219 private function set_is_single_recipient( $action ) {
220 $args = array(
221 'form' => $this->form,
222 'entry' => $this->entry,
223 'action' => $action,
224 );
225
226 /**
227 * Send a separate email for email address in the "to" section
228 *
229 * @since 2.2.13
230 */
231 $this->is_single_recipient = apply_filters( 'frm_send_separate_emails', false, $args );
232 }
233
234 /**
235 * Set the charset
236 *
237 * @since 2.03.04
238 */
239 private function set_charset() {
240 $this->charset = get_option( 'blog_charset' );
241 }
242
243 /**
244 * Set the content type
245 *
246 * @since 2.03.04
247 */
248 private function set_content_type() {
249 if ( $this->is_plain_text ) {
250 $this->content_type = 'text/plain';
251 }
252 }
253
254 /**
255 * Set the subject
256 *
257 * @since 2.03.04
258 */
259 private function set_subject() {
260 if ( empty( $this->settings['email_subject'] ) ) {
261 /* translators: %1$s: Form name, %2$s: Site name */
262 $this->subject = sprintf( __( '%1$s Form submitted on %2$s', 'formidable' ), $this->form->name, '[sitename]' );
263 } else {
264 $this->subject = $this->settings['email_subject'];
265 }
266
267 $this->subject = FrmFieldsHelper::basic_replace_shortcodes( $this->subject, $this->form, $this->entry );
268
269 $args = array(
270 'form' => $this->form,
271 'entry' => $this->entry,
272 'email_key' => $this->email_key,
273 );
274 $this->subject = apply_filters( 'frm_email_subject', $this->subject, $args );
275
276 $this->subject = wp_specialchars_decode( strip_tags( stripslashes( $this->subject ) ), ENT_QUOTES );
277 }
278
279 /**
280 * Set the email message
281 *
282 * @since 2.03.04
283 */
284 private function set_message() {
285 $this->message = FrmFieldsHelper::basic_replace_shortcodes( $this->settings['email_message'], $this->form, $this->entry );
286
287 $prev_mail_body = $this->message;
288 $pass_entry = clone $this->entry; // make a copy to prevent changes by reference
289 $mail_body = FrmEntriesHelper::replace_default_message(
290 $prev_mail_body,
291 array(
292 'id' => $this->entry->id,
293 'entry' => $pass_entry,
294 'plain_text' => $this->is_plain_text,
295 'user_info' => $this->include_user_info,
296 )
297 );
298
299 // Add the user info if it isn't already included
300 if ( $this->include_user_info && $prev_mail_body === $mail_body ) {
301 $data = maybe_unserialize( $this->entry->description );
302 $mail_body .= "\r\n\r\n" . __( 'User Information', 'formidable' ) . "\r\n";
303 $this->maybe_add_ip( $mail_body );
304 $mail_body .= __( 'User-Agent (Browser/OS)', 'formidable' ) . ': ' . FrmEntriesHelper::get_browser( $data['browser'] ) . "\r\n";
305 $mail_body .= __( 'Referrer', 'formidable' ) . ': ' . $data['referrer'] . "\r\n";
306 }
307
308 $this->message = $mail_body;
309
310 $this->message = do_shortcode( $this->message );
311
312 if ( $this->is_plain_text ) {
313 $this->message = wp_specialchars_decode( strip_tags( $this->message ), ENT_QUOTES );
314 }
315
316 $this->message = apply_filters( 'frm_email_message', $this->message, $this->package_atts() );
317 }
318
319 private function maybe_add_ip( &$mail_body ) {
320 if ( ! empty( $this->entry->ip ) ) {
321 $mail_body .= __( 'IP Address', 'formidable' ) . ': ' . $this->entry->ip . "\r\n";
322 }
323 }
324
325 /**
326 * Set the attachments for an email message
327 *
328 * @since 2.03.04
329 */
330 private function set_attachments() {
331 $args = array(
332 'entry' => $this->entry,
333 'email_key' => $this->email_key,
334 );
335
336 $this->attachments = apply_filters( 'frm_notification_attachment', array(), $this->form, $args );
337 }
338
339 /**
340 * Check if an email should send
341 *
342 * @since 2.03.04
343 *
344 * @return bool|mixed|void
345 */
346 public function should_send() {
347 if ( ! $this->has_recipients() ) {
348 $send = false;
349 } else {
350
351 $filter_args = array(
352 'message' => $this->message,
353 'subject' => $this->subject,
354 'recipient' => $this->to,
355 'header' => $this->package_header(),
356 );
357
358 /**
359 * Stop an email based on the message, subject, recipient,
360 * or any information included in the email header
361 *
362 * @since 2.2.8
363 */
364 $send = apply_filters( 'frm_send_email', true, $filter_args );
365 }
366
367 return $send;
368 }
369
370 /**
371 * Check if an email has any recipients
372 *
373 * @since 2.03.04
374 *
375 * @return bool
376 */
377 private function has_recipients() {
378 if ( empty( $this->to ) && empty( $this->cc ) && empty( $this->bcc ) ) {
379 return false;
380 } else {
381 return true;
382 }
383 }
384
385 /**
386 * Send an email
387 *
388 * @since 2.03.04
389 *
390 * @return bool
391 */
392 public function send() {
393 $this->remove_buddypress_filters();
394 $this->add_mandrill_filter();
395
396 $sent = false;
397 if ( count( $this->to ) > 1 && $this->is_single_recipient ) {
398 foreach ( $this->to as $recipient ) {
399 $sent = $this->send_single( $recipient );
400 }
401 } else {
402 $sent = $this->send_single( $this->to );
403 }
404
405 $this->remove_mandrill_filter();
406
407 return $sent;
408 }
409
410 /**
411 * Send a single email
412 *
413 * @since 2.03.04
414 *
415 * @param array|string $recipient
416 *
417 * @return bool
418 */
419 private function send_single( $recipient ) {
420 $header = apply_filters(
421 'frm_email_header',
422 $this->package_header(),
423 array(
424 'to_email' => $recipient,
425 'subject' => $this->subject,
426 )
427 );
428
429 $subject = $this->encode_subject( $this->subject );
430
431 $sent = wp_mail( $recipient, $subject, $this->message, $header, $this->attachments );
432
433 if ( ! $sent ) {
434 $header = 'From: ' . $this->from . "\r\n";
435 $recipient = implode( ',', (array) $recipient );
436 $sent = mail( $recipient, $subject, $this->message, $header );
437 }
438
439 do_action( 'frm_notification', $recipient, $subject, $this->message );
440
441 return $sent;
442 }
443
444 /**
445 * Package the email header
446 *
447 * @since 2.03.04
448 *
449 * @return array
450 */
451 private function package_header() {
452 $header = array();
453
454 if ( ! empty( $this->cc ) ) {
455 $header[] = 'CC: ' . implode( ',', $this->cc );
456 }
457
458 if ( ! empty( $this->bcc ) ) {
459 $header[] = 'BCC: ' . implode( ',', $this->bcc );
460 }
461
462 $header[] = 'From: ' . $this->from;
463 $header[] = 'Reply-To: ' . $this->reply_to;
464 $header[] = 'Content-Type: ' . $this->content_type . '; charset="' . esc_attr( $this->charset ) . '"';
465
466 return $header;
467 }
468
469 /**
470 * Get the userID field ID and key for email settings
471 *
472 * @since 2.03.04
473 *
474 * @param $form_id
475 *
476 * @return array
477 */
478 private function get_user_id_args( $form_id ) {
479 $user_id_args = array(
480 'field_id' => '',
481 'field_key' => '',
482 );
483
484 $user_id_args['field_id'] = FrmEmailHelper::get_user_id_field_for_form( $form_id );
485 if ( $user_id_args['field_id'] ) {
486 $user_id_args['field_key'] = FrmField::get_key_by_id( $user_id_args['field_id'] );
487 }
488
489 return $user_id_args;
490 }
491
492 /**
493 * Prepare the to, cc, bcc, reply_to, and from setting
494 *
495 * @since 2.03.04
496 *
497 * @param string $value
498 * @param array $user_id_args
499 *
500 * @return string
501 */
502 private function prepare_email_setting( $value, $user_id_args ) {
503 if ( strpos( $value, '[' . $user_id_args['field_id'] . ']' ) !== false ) {
504 $value = str_replace( '[' . $user_id_args['field_id'] . ']', '[' . $user_id_args['field_id'] . ' show="user_email"]', $value );
505 } elseif ( strpos( $value, '[' . $user_id_args['field_key'] . ']' ) !== false ) {
506 $value = str_replace( '[' . $user_id_args['field_key'] . ']', '[' . $user_id_args['field_key'] . ' show="user_email"]', $value );
507 }
508
509 $value = FrmFieldsHelper::basic_replace_shortcodes( $value, $this->form, $this->entry );
510
511 // Remove brackets and add a space in case there isn't one
512 $value = str_replace( '<', ' ', $value );
513 $value = str_replace( array( '"', '>' ), '', $value );
514
515 return $value;
516 }
517
518 /**
519 * Extract the emails from cc and bcc. Allow separation by , or ;.
520 * Trim the emails here as well
521 *
522 * @since 2.03.04
523 *
524 * @param string $emails
525 * @return array|string $emails
526 */
527 private function explode_emails( $emails ) {
528 $emails = ( ! empty( $emails ) ? preg_split( '/(,|;)/', $emails ) : '' );
529 if ( is_array( $emails ) ) {
530 $emails = array_map( 'trim', $emails );
531 } else {
532 $emails = trim( $emails );
533 }
534
535 return $emails;
536 }
537
538 /**
539 * Format the recipients( to, cc, bcc)
540 *
541 * @param array $recipients
542 *
543 * @return array
544 */
545 private function format_recipients( $recipients ) {
546 if ( empty( $recipients ) ) {
547 return $recipients;
548 }
549
550 foreach ( $recipients as $key => $val ) {
551 $val = trim( $val );
552
553 if ( is_email( $val ) ) {
554 // If a plain email is used, no formatting is needed
555 continue;
556 } else {
557 $parts = explode( ' ', $val );
558 $email = end( $parts );
559
560 if ( is_email( $email ) ) {
561 // If user enters a name and email
562 $name = trim( str_replace( $email, '', $val ) );
563 } else {
564 // If user enters a name without an email
565 unset( $recipients[ $key ] );
566 continue;
567 }
568 }
569
570 $recipients[ $key ] = $this->format_from_email( $name, $email );
571 }
572
573 return $recipients;
574 }
575
576 /**
577 * Format the From header
578 *
579 * @param string $from
580 *
581 * @return string
582 */
583 private function format_from( $from ) {
584 $from = trim( $from );
585
586 if ( is_email( $from ) ) {
587 // If a plain email is used, add the site name so "WordPress" doesn't get added
588 $from_name = wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
589 $from_email = $from;
590 } else {
591 list( $from_name, $from_email ) = $this->get_name_and_email_for_sender( $from );
592 }
593
594 // if sending the email from a yahoo address, change it to the WordPress default
595 if ( strpos( $from_email, '@yahoo.com' ) ) {
596
597 // Get the site domain and get rid of www.
598 $sitename = strtolower( FrmAppHelper::get_server_value( 'SERVER_NAME' ) );
599 if ( substr( $sitename, 0, 4 ) === 'www.' ) {
600 $sitename = substr( $sitename, 4 );
601 }
602
603 $from_email = 'wordpress@' . $sitename;
604 }
605
606 return $this->format_from_email( $from_name, $from_email );
607 }
608
609 /**
610 * Format the Reply To property
611 *
612 * @since 2.03.04
613 *
614 * @param string $reply_to
615 *
616 * @return string
617 */
618 private function format_reply_to( $reply_to ) {
619 $reply_to = trim( $reply_to );
620
621 if ( ! is_email( $reply_to ) ) {
622 list( $name, $email ) = $this->get_name_and_email_for_sender( $reply_to );
623 $reply_to = $this->format_from_email( $name, $email );
624 }
625
626 return $reply_to;
627 }
628
629 /**
630 * Get only the email if the name and email have been combined
631 *
632 * @since 3.0.06
633 */
634 private function get_email_from_name( $name ) {
635 $email = trim( trim( $name, '>' ), '<' );
636 if ( strpos( $email, '<' ) !== false ) {
637 $parts = explode( '<', $email );
638 $email = trim( $parts[1], '>' );
639 }
640 return $email;
641 }
642
643 /**
644 * Get the name and email for the From or Reply To header
645 *
646 * @since 2.03.04
647 *
648 * @param string $sender
649 *
650 * @return array
651 */
652 private function get_name_and_email_for_sender( $sender ) {
653 $parts = explode( ' ', $sender );
654 $end = end( $parts );
655
656 if ( is_email( $end ) ) {
657 $name = trim( str_replace( $end, '', $sender ) );
658 } else {
659 // Only a name was entered in the From or Reply To field
660 $name = $sender;
661 $end = get_option( 'admin_email' );
662 }
663
664 return array( $name, $end );
665 }
666
667 /**
668 * @since 3.0.06
669 */
670 private function format_from_email( $name, $email ) {
671 if ( '' !== $name ) {
672 $email = $name . ' <' . $email . '>';
673 }
674 return $email;
675 }
676
677 /**
678 * Remove phone numbers from To addresses
679 * Send the phone numbers to the frm_send_to_not_email hook
680 *
681 * @since 2.03.04
682 */
683 private function handle_phone_numbers() {
684
685 foreach ( $this->to as $key => $recipient ) {
686 if ( '[admin_email]' !== $recipient && ! is_email( $recipient ) ) {
687 $recipient = explode( ' ', $recipient );
688
689 if ( is_email( end( $recipient ) ) ) {
690 continue;
691 }
692
693 do_action(
694 'frm_send_to_not_email',
695 array(
696 'e' => $recipient,
697 'subject' => $this->subject,
698 'mail_body' => $this->message,
699 'reply_to' => $this->reply_to,
700 'from' => $this->from,
701 'plain_text' => $this->is_plain_text,
702 'attachments' => $this->attachments,
703 'form' => $this->form,
704 'email_key' => $key,
705 )
706 );
707
708 // Remove phone number from to addresses
709 unset( $this->to[ $key ] );
710 }
711 }
712 }
713
714 /**
715 * Package an array of FrmEmail properties
716 *
717 * @since 2.03.04
718 *
719 * @return array
720 */
721 public function package_atts() {
722 return array(
723 'to_email' => $this->to,
724 'cc' => $this->cc,
725 'bcc' => $this->bcc,
726 'from' => $this->from,
727 'reply_to' => $this->reply_to,
728 'subject' => $this->subject,
729 'message' => $this->message,
730 'attachments' => $this->attachments,
731 'plain_text' => $this->is_plain_text,
732 'form' => $this->form,
733 'entry' => $this->entry,
734 );
735 }
736
737 /**
738 * Remove the Buddypress email filters
739 *
740 * @since 2.03.04
741 */
742 private function remove_buddypress_filters() {
743 remove_filter( 'wp_mail_from', 'bp_core_email_from_address_filter' );
744 remove_filter( 'wp_mail_from_name', 'bp_core_email_from_name_filter' );
745 }
746
747 /**
748 * Add Mandrill line break filter
749 * Remove line breaks in HTML emails to prevent conflicts with Mandrill
750 *
751 * @since 2.03.04
752 */
753 private function add_mandrill_filter() {
754 if ( ! $this->is_plain_text ) {
755 add_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
756 }
757 }
758
759 /**
760 * Remove Mandrill line break filter
761 *
762 * @since 2.03.04
763 */
764 private function remove_mandrill_filter() {
765 remove_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
766 }
767
768 /**
769 * Encode the email subject
770 *
771 * @param string $subject
772 *
773 * @return string
774 */
775 private function encode_subject( $subject ) {
776 if ( apply_filters( 'frm_encode_subject', 1, $subject ) ) {
777 $subject = '=?' . $this->charset . '?B?' . base64_encode( $subject ) . '?=';
778 }
779
780 return $subject;
781 }
782 }
783