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

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