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

792 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 if ( is_array( $header ) ) {
439 $header = implode( "\r\n", $header );
440 }
441 $recipient = implode( ',', (array) $recipient );
442 $sent = mail( $recipient, $subject, $this->message, $header );
443 }
444
445 do_action( 'frm_notification', $recipient, $subject, $this->message );
446
447 return $sent;
448 }
449
450 /**
451 * Package the email header
452 *
453 * @since 2.03.04
454 *
455 * @return array
456 */
457 private function package_header() {
458 $header = array();
459
460 if ( ! empty( $this->cc ) ) {
461 $header[] = 'CC: ' . implode( ',', $this->cc );
462 }
463
464 if ( ! empty( $this->bcc ) ) {
465 $header[] = 'BCC: ' . implode( ',', $this->bcc );
466 }
467
468 $header[] = 'From: ' . $this->from;
469 $header[] = 'Reply-To: ' . $this->reply_to;
470 $header[] = 'Content-Type: ' . $this->content_type . '; charset="' . esc_attr( $this->charset ) . '"';
471
472 return $header;
473 }
474
475 /**
476 * Get the userID field ID and key for email settings
477 *
478 * @since 2.03.04
479 *
480 * @param $form_id
481 *
482 * @return array
483 */
484 private function get_user_id_args( $form_id ) {
485 $user_id_args = array(
486 'field_id' => '',
487 'field_key' => '',
488 );
489
490 $user_id_args['field_id'] = FrmEmailHelper::get_user_id_field_for_form( $form_id );
491 if ( $user_id_args['field_id'] ) {
492 $user_id_args['field_key'] = FrmField::get_key_by_id( $user_id_args['field_id'] );
493 }
494
495 return $user_id_args;
496 }
497
498 /**
499 * Prepare the to, cc, bcc, reply_to, and from setting
500 *
501 * @since 2.03.04
502 *
503 * @param string $value
504 * @param array $user_id_args
505 *
506 * @return string
507 */
508 private function prepare_email_setting( $value, $user_id_args ) {
509 if ( strpos( $value, '[' . $user_id_args['field_id'] . ']' ) !== false ) {
510 $value = str_replace( '[' . $user_id_args['field_id'] . ']', '[' . $user_id_args['field_id'] . ' show="user_email"]', $value );
511 } elseif ( strpos( $value, '[' . $user_id_args['field_key'] . ']' ) !== false ) {
512 $value = str_replace( '[' . $user_id_args['field_key'] . ']', '[' . $user_id_args['field_key'] . ' show="user_email"]', $value );
513 }
514
515 $value = FrmFieldsHelper::basic_replace_shortcodes( $value, $this->form, $this->entry );
516
517 // Remove brackets and add a space in case there isn't one
518 $value = str_replace( '<', ' ', $value );
519 $value = str_replace( array( '"', '>' ), '', $value );
520
521 return $value;
522 }
523
524 /**
525 * Extract the emails from cc and bcc. Allow separation by , or ;.
526 * Trim the emails here as well
527 *
528 * @since 2.03.04
529 *
530 * @param string $emails
531 *
532 * @return array|string $emails
533 */
534 private function explode_emails( $emails ) {
535 $emails = ( ! empty( $emails ) ? preg_split( '/(,|;)/', $emails ) : '' );
536 if ( is_array( $emails ) ) {
537 $emails = array_map( 'trim', $emails );
538 } else {
539 $emails = trim( $emails );
540 }
541
542 return $emails;
543 }
544
545 /**
546 * Format the recipients( to, cc, bcc)
547 *
548 * @param array $recipients
549 *
550 * @return array
551 */
552 private function format_recipients( $recipients ) {
553 if ( empty( $recipients ) ) {
554 return $recipients;
555 }
556
557 foreach ( $recipients as $key => $val ) {
558 $val = trim( $val );
559
560 if ( is_email( $val ) ) {
561 // If a plain email is used, no formatting is needed
562 continue;
563 } else {
564 $parts = explode( ' ', $val );
565 $email = end( $parts );
566
567 if ( is_email( $email ) ) {
568 // If user enters a name and email
569 $name = trim( str_replace( $email, '', $val ) );
570 } else {
571 // If user enters a name without an email
572 unset( $recipients[ $key ] );
573 continue;
574 }
575 }
576
577 $recipients[ $key ] = $this->format_from_email( $name, $email );
578 }
579
580 return $recipients;
581 }
582
583 /**
584 * Format the From header
585 *
586 * @param string $from
587 *
588 * @return string
589 */
590 private function format_from( $from ) {
591 $from = trim( $from );
592
593 if ( is_email( $from ) ) {
594 // If a plain email is used, add the site name so "WordPress" doesn't get added
595 $from_name = wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
596 $from_email = $from;
597 } else {
598 list( $from_name, $from_email ) = $this->get_name_and_email_for_sender( $from );
599 }
600
601 // if sending the email from a yahoo address, change it to the WordPress default
602 if ( strpos( $from_email, '@yahoo.com' ) ) {
603
604 // Get the site domain and get rid of www.
605 $sitename = strtolower( FrmAppHelper::get_server_value( 'SERVER_NAME' ) );
606 if ( substr( $sitename, 0, 4 ) === 'www.' ) {
607 $sitename = substr( $sitename, 4 );
608 }
609
610 $from_email = 'wordpress@' . $sitename;
611 }
612
613 return $this->format_from_email( $from_name, $from_email );
614 }
615
616 /**
617 * Format the Reply To property
618 *
619 * @since 2.03.04
620 *
621 * @param string $reply_to
622 *
623 * @return string
624 */
625 private function format_reply_to( $reply_to ) {
626 $reply_to = trim( $reply_to );
627
628 if ( ! is_email( $reply_to ) ) {
629 list( $name, $email ) = $this->get_name_and_email_for_sender( $reply_to );
630 $reply_to = $this->format_from_email( $name, $email );
631 }
632
633 return $reply_to;
634 }
635
636 /**
637 * Get only the email if the name and email have been combined
638 *
639 * @since 3.0.06
640 */
641 private function get_email_from_name( $name ) {
642 $email = trim( trim( $name, '>' ), '<' );
643 if ( strpos( $email, '<' ) !== false ) {
644 $parts = explode( '<', $email );
645 $email = trim( $parts[1], '>' );
646 }
647
648 return $email;
649 }
650
651 /**
652 * Get the name and email for the From or Reply To header
653 *
654 * @since 2.03.04
655 *
656 * @param string $sender
657 *
658 * @return array
659 */
660 private function get_name_and_email_for_sender( $sender ) {
661 $parts = explode( ' ', $sender );
662 $end = end( $parts );
663
664 if ( is_email( $end ) ) {
665 $name = trim( str_replace( $end, '', $sender ) );
666 } else {
667 // Only a name was entered in the From or Reply To field
668 $name = $sender;
669 $end = get_option( 'admin_email' );
670 }
671
672 return array( $name, $end );
673 }
674
675 /**
676 * @since 3.0.06
677 */
678 private function format_from_email( $name, $email ) {
679 if ( '' !== $name ) {
680 $email = $name . ' <' . $email . '>';
681 }
682
683 return $email;
684 }
685
686 /**
687 * Remove phone numbers from To addresses
688 * Send the phone numbers to the frm_send_to_not_email hook
689 *
690 * @since 2.03.04
691 */
692 private function handle_phone_numbers() {
693
694 foreach ( $this->to as $key => $recipient ) {
695 if ( '[admin_email]' !== $recipient && ! is_email( $recipient ) ) {
696 $recipient = explode( ' ', $recipient );
697
698 if ( is_email( end( $recipient ) ) ) {
699 continue;
700 }
701
702 do_action(
703 'frm_send_to_not_email',
704 array(
705 'e' => $recipient,
706 'subject' => $this->subject,
707 'mail_body' => $this->message,
708 'reply_to' => $this->reply_to,
709 'from' => $this->from,
710 'plain_text' => $this->is_plain_text,
711 'attachments' => $this->attachments,
712 'form' => $this->form,
713 'email_key' => $key,
714 )
715 );
716
717 // Remove phone number from to addresses
718 unset( $this->to[ $key ] );
719 }
720 }
721 }
722
723 /**
724 * Package an array of FrmEmail properties
725 *
726 * @since 2.03.04
727 *
728 * @return array
729 */
730 public function package_atts() {
731 return array(
732 'to_email' => $this->to,
733 'cc' => $this->cc,
734 'bcc' => $this->bcc,
735 'from' => $this->from,
736 'reply_to' => $this->reply_to,
737 'subject' => $this->subject,
738 'message' => $this->message,
739 'attachments' => $this->attachments,
740 'plain_text' => $this->is_plain_text,
741 'form' => $this->form,
742 'entry' => $this->entry,
743 );
744 }
745
746 /**
747 * Remove the Buddypress email filters
748 *
749 * @since 2.03.04
750 */
751 private function remove_buddypress_filters() {
752 remove_filter( 'wp_mail_from', 'bp_core_email_from_address_filter' );
753 remove_filter( 'wp_mail_from_name', 'bp_core_email_from_name_filter' );
754 }
755
756 /**
757 * Add Mandrill line break filter
758 * Remove line breaks in HTML emails to prevent conflicts with Mandrill
759 *
760 * @since 2.03.04
761 */
762 private function add_mandrill_filter() {
763 if ( ! $this->is_plain_text ) {
764 add_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
765 }
766 }
767
768 /**
769 * Remove Mandrill line break filter
770 *
771 * @since 2.03.04
772 */
773 private function remove_mandrill_filter() {
774 remove_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
775 }
776
777 /**
778 * Encode the email subject
779 *
780 * @param string $subject
781 *
782 * @return string
783 */
784 private function encode_subject( $subject ) {
785 if ( apply_filters( 'frm_encode_subject', false, $subject ) ) {
786 $subject = '=?' . $this->charset . '?B?' . base64_encode( $subject ) . '?=';
787 }
788
789 return $subject;
790 }
791 }
792