PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0.13
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0.13
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 5.0.13, at classes/models/FrmEmail.php

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