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

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