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

786 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 );
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 *
526 * @return array|string $emails
527 */
528 private function explode_emails( $emails ) {
529 $emails = ( ! empty( $emails ) ? preg_split( '/(,|;)/', $emails ) : '' );
530 if ( is_array( $emails ) ) {
531 $emails = array_map( 'trim', $emails );
532 } else {
533 $emails = trim( $emails );
534 }
535
536 return $emails;
537 }
538
539 /**
540 * Format the recipients( to, cc, bcc)
541 *
542 * @param array $recipients
543 *
544 * @return array
545 */
546 private function format_recipients( $recipients ) {
547 if ( empty( $recipients ) ) {
548 return $recipients;
549 }
550
551 foreach ( $recipients as $key => $val ) {
552 $val = trim( $val );
553
554 if ( is_email( $val ) ) {
555 // If a plain email is used, no formatting is needed
556 continue;
557 } else {
558 $parts = explode( ' ', $val );
559 $email = end( $parts );
560
561 if ( is_email( $email ) ) {
562 // If user enters a name and email
563 $name = trim( str_replace( $email, '', $val ) );
564 } else {
565 // If user enters a name without an email
566 unset( $recipients[ $key ] );
567 continue;
568 }
569 }
570
571 $recipients[ $key ] = $this->format_from_email( $name, $email );
572 }
573
574 return $recipients;
575 }
576
577 /**
578 * Format the From header
579 *
580 * @param string $from
581 *
582 * @return string
583 */
584 private function format_from( $from ) {
585 $from = trim( $from );
586
587 if ( is_email( $from ) ) {
588 // If a plain email is used, add the site name so "WordPress" doesn't get added
589 $from_name = wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
590 $from_email = $from;
591 } else {
592 list( $from_name, $from_email ) = $this->get_name_and_email_for_sender( $from );
593 }
594
595 // if sending the email from a yahoo address, change it to the WordPress default
596 if ( strpos( $from_email, '@yahoo.com' ) ) {
597
598 // Get the site domain and get rid of www.
599 $sitename = strtolower( FrmAppHelper::get_server_value( 'SERVER_NAME' ) );
600 if ( substr( $sitename, 0, 4 ) === 'www.' ) {
601 $sitename = substr( $sitename, 4 );
602 }
603
604 $from_email = 'wordpress@' . $sitename;
605 }
606
607 return $this->format_from_email( $from_name, $from_email );
608 }
609
610 /**
611 * Format the Reply To property
612 *
613 * @since 2.03.04
614 *
615 * @param string $reply_to
616 *
617 * @return string
618 */
619 private function format_reply_to( $reply_to ) {
620 $reply_to = trim( $reply_to );
621
622 if ( ! is_email( $reply_to ) ) {
623 list( $name, $email ) = $this->get_name_and_email_for_sender( $reply_to );
624 $reply_to = $this->format_from_email( $name, $email );
625 }
626
627 return $reply_to;
628 }
629
630 /**
631 * Get only the email if the name and email have been combined
632 *
633 * @since 3.0.06
634 */
635 private function get_email_from_name( $name ) {
636 $email = trim( trim( $name, '>' ), '<' );
637 if ( strpos( $email, '<' ) !== false ) {
638 $parts = explode( '<', $email );
639 $email = trim( $parts[1], '>' );
640 }
641
642 return $email;
643 }
644
645 /**
646 * Get the name and email for the From or Reply To header
647 *
648 * @since 2.03.04
649 *
650 * @param string $sender
651 *
652 * @return array
653 */
654 private function get_name_and_email_for_sender( $sender ) {
655 $parts = explode( ' ', $sender );
656 $end = end( $parts );
657
658 if ( is_email( $end ) ) {
659 $name = trim( str_replace( $end, '', $sender ) );
660 } else {
661 // Only a name was entered in the From or Reply To field
662 $name = $sender;
663 $end = get_option( 'admin_email' );
664 }
665
666 return array( $name, $end );
667 }
668
669 /**
670 * @since 3.0.06
671 */
672 private function format_from_email( $name, $email ) {
673 if ( '' !== $name ) {
674 $email = $name . ' <' . $email . '>';
675 }
676
677 return $email;
678 }
679
680 /**
681 * Remove phone numbers from To addresses
682 * Send the phone numbers to the frm_send_to_not_email hook
683 *
684 * @since 2.03.04
685 */
686 private function handle_phone_numbers() {
687
688 foreach ( $this->to as $key => $recipient ) {
689 if ( '[admin_email]' !== $recipient && ! is_email( $recipient ) ) {
690 $recipient = explode( ' ', $recipient );
691
692 if ( is_email( end( $recipient ) ) ) {
693 continue;
694 }
695
696 do_action(
697 'frm_send_to_not_email',
698 array(
699 'e' => $recipient,
700 'subject' => $this->subject,
701 'mail_body' => $this->message,
702 'reply_to' => $this->reply_to,
703 'from' => $this->from,
704 'plain_text' => $this->is_plain_text,
705 'attachments' => $this->attachments,
706 'form' => $this->form,
707 'email_key' => $key,
708 )
709 );
710
711 // Remove phone number from to addresses
712 unset( $this->to[ $key ] );
713 }
714 }
715 }
716
717 /**
718 * Package an array of FrmEmail properties
719 *
720 * @since 2.03.04
721 *
722 * @return array
723 */
724 public function package_atts() {
725 return array(
726 'to_email' => $this->to,
727 'cc' => $this->cc,
728 'bcc' => $this->bcc,
729 'from' => $this->from,
730 'reply_to' => $this->reply_to,
731 'subject' => $this->subject,
732 'message' => $this->message,
733 'attachments' => $this->attachments,
734 'plain_text' => $this->is_plain_text,
735 'form' => $this->form,
736 'entry' => $this->entry,
737 );
738 }
739
740 /**
741 * Remove the Buddypress email filters
742 *
743 * @since 2.03.04
744 */
745 private function remove_buddypress_filters() {
746 remove_filter( 'wp_mail_from', 'bp_core_email_from_address_filter' );
747 remove_filter( 'wp_mail_from_name', 'bp_core_email_from_name_filter' );
748 }
749
750 /**
751 * Add Mandrill line break filter
752 * Remove line breaks in HTML emails to prevent conflicts with Mandrill
753 *
754 * @since 2.03.04
755 */
756 private function add_mandrill_filter() {
757 if ( ! $this->is_plain_text ) {
758 add_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
759 }
760 }
761
762 /**
763 * Remove Mandrill line break filter
764 *
765 * @since 2.03.04
766 */
767 private function remove_mandrill_filter() {
768 remove_filter( 'mandrill_nl2br', 'FrmEmailHelper::remove_mandrill_br' );
769 }
770
771 /**
772 * Encode the email subject
773 *
774 * @param string $subject
775 *
776 * @return string
777 */
778 private function encode_subject( $subject ) {
779 if ( apply_filters( 'frm_encode_subject', 1, $subject ) ) {
780 $subject = '=?' . $this->charset . '?B?' . base64_encode( $subject ) . '?=';
781 }
782
783 return $subject;
784 }
785 }
786