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

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