PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.6.1
JetFormBuilder — Dynamic Blocks Form Builder v3.6.6.1
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
jetformbuilder / modules / actions-v2 / send-email / send-email-action.php

send-email-action.php in JetFormBuilder — Dynamic Blocks Form Builder 3.6.6.1, at modules/actions-v2/send-email/send-email-action.php

664 lines 14.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace JFB_Modules\Actions_V2\Send_Email;
4
5 use Jet_Form_Builder\Actions\Action_Handler;
6 use Jet_Form_Builder\Actions\Types\Base;
7 use Jet_Form_Builder\Classes\Http\Http_Tools;
8 use Jet_Form_Builder\Classes\Resources\Uploaded_File;
9 use Jet_Form_Builder\Classes\Tools;
10 use Jet_Form_Builder\Exceptions\Action_Exception;
11 use Jet_Form_Builder\Request\Request_Tools;
12
13 // If this file is called directly, abort.
14 if ( ! defined( 'WPINC' ) ) {
15 die;
16 }
17
18 /**
19 * Define Base_Type class
20 */
21 class Send_Email_Action extends Base {
22
23 private $content_type = '';
24 private $mail_to = array();
25 private $cc = array();
26 private $bcc = array();
27 private $reply_to = '';
28 private $from_email = '';
29 private $content = '';
30 private $subject = '';
31 private $from_name = '';
32 private $attachments = array();
33 private $headers = '';
34
35 public function get_name() {
36 return __( 'Send Email', 'jet-form-builder' );
37 }
38
39 public function get_id() {
40 return 'send_email';
41 }
42
43 public function self_script_name() {
44 return 'jetFormEmailData';
45 }
46
47 public function editor_labels() {
48 return array(
49 'mail_to' => __( 'Mail To:', 'jet-form-builder' ),
50 'custom_email' => __( 'Email Address:', 'jet-form-builder' ),
51 'from_field' => __( 'From Field:', 'jet-form-builder' ),
52 'reply_to' => __( 'Reply To:', 'jet-form-builder' ),
53 'reply_to_email' => __( 'Reply to Email Address:', 'jet-form-builder' ),
54 'reply_from_field' => __( 'Reply To Email From Field:', 'jet-form-builder' ),
55 'subject' => __( 'Subject:', 'jet-form-builder' ),
56 'from_name' => __( 'From Name:', 'jet-form-builder' ),
57 'from_address' => __( 'From Email Address:', 'jet-form-builder' ),
58 'content_type' => __( 'Content type:', 'jet-form-builder' ),
59 'disable_format' => __( 'Disable Auto-Formatting', 'jet-form-builder' ),
60 'content' => __( 'Content:', 'jet-form-builder' ),
61 'attachments' => __( 'Attachments:', 'jet-form-builder' ),
62 'add_attachment' => __( 'Add form field with attachment', 'jet-form-builder' ),
63 );
64 }
65
66 public function action_attributes() {
67 return array(
68 'mail_to' => array(
69 'default' => '',
70 ),
71 'custom_email' => array(
72 'default' => '',
73 ),
74 'from_field' => array(
75 'default' => '',
76 ),
77 'reply_to' => array(
78 'default' => '',
79 ),
80 'reply_to_email' => array(
81 'default' => '',
82 ),
83 'reply_from_field' => array(
84 'default' => '',
85 ),
86 'subject' => array(
87 'default' => '',
88 'path' => 'email/subject',
89 ),
90 'from_name' => array(
91 'default' => '',
92 'path' => 'email/from_name',
93 ),
94 'from_address' => array(
95 'default' => '',
96 'path' => 'email/from_address',
97 ),
98 'content_type' => array(
99 'default' => '',
100 'path' => 'email/content_type',
101 ),
102 'content' => array(
103 'default' => '',
104 'path' => 'email/content',
105 ),
106 );
107 }
108
109 /**
110 * Regsiter custom action data for the editor
111 *
112 * @return [type] [description]
113 */
114 public function action_data() {
115 return array(
116 'replyTo' => Tools::with_placeholder(
117 array(
118 array(
119 'value' => 'form',
120 'label' => __( 'Email from submitted form field', 'jet-form-builder' ),
121 ),
122 array(
123 'value' => 'custom',
124 'label' => __( 'Custom email', 'jet-form-builder' ),
125 ),
126 )
127 ),
128 'content_type' => Tools::with_placeholder(
129 array(
130 array(
131 'value' => 'text/plain',
132 'label' => __( 'Plain text', 'jet-form-builder' ),
133 ),
134 array(
135 'value' => 'text/html',
136 'label' => __( 'HTML', 'jet-form-builder' ),
137 ),
138 )
139 ),
140 'customMacros' => apply_filters( 'jet-form-builder/actions/send-email/custom-macros', false ),
141 );
142 }
143
144 /**
145 * @param array $request
146 * @param Action_Handler $handler
147 *
148 * @throws Action_Exception
149 */
150 public function do_action( array $request, Action_Handler $handler ) {
151 $message = apply_filters(
152 'jet-form-builder/send-email/message_content',
153 $this->settings['content'] ?? '',
154 $this
155 );
156 $this->set_content( $message );
157
158 $content_type = apply_filters(
159 'jet-form-builder/send-email/content-type',
160 $this->get_default_content_type(),
161 $this
162 );
163 $this->set_content_type( $content_type );
164
165 $from_name = apply_filters(
166 'jet-form-builder/send-email/from-name',
167 $this->get_default_from_name(),
168 $this
169 );
170 $this->set_from_name( $from_name );
171
172 $reply_to = apply_filters(
173 'jet-form-builder/send-email/reply-to',
174 $this->get_default_reply_to(),
175 $this
176 );
177 $this->set_reply_to( $reply_to );
178
179 $from_email = apply_filters(
180 'jet-form-builder/send-email/from-address',
181 $this->get_default_from_address(),
182 $this
183 );
184 $this->set_from_address( $from_email );
185
186 $this->set_mail_to( $this->get_default_mail_to() );
187 $this->set_cc( $this->get_default_cc() );
188 $this->set_bcc( $this->get_default_bcc() );
189 $this->set_subject( $this->get_default_subject() );
190 $this->set_attachments( $this->get_default_attachments() );
191
192 $headers = apply_filters(
193 'jet-form-builder/send-email/headers',
194 $this->get_default_headers(),
195 $this
196 );
197 $this->set_headers( $headers );
198
199 /**
200 * Hooks before the email is sent
201 */
202 do_action( 'jet-form-builder/send-email/send-before', $this );
203
204 if ( jet_form_builder()->has_module( 'dev' ) ) {
205 add_action(
206 'wp_mail_failed',
207 function ( \WP_Error $wp_error ) {
208 new Action_Exception( 'failed', $wp_error->get_error_message(), $wp_error->get_error_data() );
209 }
210 );
211 }
212
213 $this->validate();
214
215 $sent = wp_mail(
216 $this->get_mail_to(),
217 $this->get_subject(),
218 $this->get_content(),
219 $this->get_headers(),
220 $this->get_attachments()
221 );
222
223 if ( ! $sent ) {
224 throw new Action_Exception(
225 'failed',
226 array(
227 // phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped
228 'to' => $this->get_mail_to(),
229 'subject' => $this->get_subject(),
230 'message' => $message,
231 'headers' => $this->get_headers(),
232 // phpcs:enable
233 )
234 );
235 }
236
237 /**
238 * Hooks after the email is sent
239 *
240 * @since 2.1
241 */
242 do_action( 'jet-form-builder/send-email/send-after', $this );
243 }
244
245 /**
246 * @throws Action_Exception
247 */
248 protected function validate() {
249 $this->validate_mail_to();
250 $this->validate_reply_to();
251 }
252
253 /**
254 * @throws Action_Exception
255 */
256 protected function validate_mail_to() {
257 foreach ( $this->mail_to as $value ) {
258 if ( ! $value || ! is_email( $value ) ) {
259 throw new Action_Exception( 'invalid_email' );
260 }
261 }
262 }
263
264 protected function validate_reply_to() {
265 $emails = explode( ',', $this->get_reply_to() );
266
267 foreach ( $emails as &$value ) {
268 $value = trim( $value );
269 }
270
271 $emails = array_filter( $emails, 'is_email' );
272
273 if ( count( $emails ) ) {
274 $this->set_reply_to( $emails );
275
276 return;
277 }
278
279 $this->set_reply_to( 'noreply@' . Http_Tools::get_site_host() );
280 }
281
282 public function get_default_mail_to() {
283 $mail_to = ! empty( $this->settings['mail_to'] ) ? $this->settings['mail_to'] : 'admin';
284
285 switch ( $mail_to ) {
286 case 'form':
287 $field = $this->settings['from_field'] ?? '';
288 $email = jet_fb_context()->get_value( $field );
289
290 return $email ?: '';
291 case 'custom':
292 return ! empty( $this->settings['custom_email'] ) ? $this->settings['custom_email'] : '';
293 case 'admin':
294 default:
295 return get_option( 'admin_email' );
296 }
297 }
298
299 public function get_default_cc() {
300 if ( empty( $this->settings['use_cc_bcc'] ) ) {
301 return array();
302 }
303
304 $mail_to = ! empty( $this->settings['cc_from'] ) ? $this->settings['cc_from'] : '';
305
306 switch ( $mail_to ) {
307 case 'form':
308 $field = $this->settings['cc_field'] ?? '';
309 $email = jet_fb_context()->get_value( $field );
310
311 return $email ?: '';
312 case 'custom':
313 return ! empty( $this->settings['cc_email'] ) ? $this->settings['cc_email'] : '';
314 case 'admin':
315 return get_option( 'admin_email' );
316 default:
317 return '';
318 }
319 }
320
321 public function get_default_bcc() {
322 if ( empty( $this->settings['use_cc_bcc'] ) ) {
323 return array();
324 }
325
326 $mail_to = ! empty( $this->settings['bcc_from'] ) ? $this->settings['bcc_from'] : '';
327
328 switch ( $mail_to ) {
329 case 'form':
330 $field = $this->settings['bcc_field'] ?? '';
331 $email = jet_fb_context()->get_value( $field );
332
333 return $email ?: '';
334 case 'custom':
335 return ! empty( $this->settings['bcc_email'] ) ? $this->settings['bcc_email'] : '';
336 case 'admin':
337 return get_option( 'admin_email' );
338 default:
339 return '';
340 }
341 }
342
343 public function get_default_reply_to(): string {
344 $reply_to = ! empty( $this->settings['reply_to'] ) ? $this->settings['reply_to'] : 'form';
345
346 switch ( $reply_to ) {
347 case 'form':
348 $field = $this->settings['reply_from_field'] ?? '';
349
350 return Tools::to_string( jet_fb_context()->get_value( $field ) );
351 case 'custom':
352 return ! empty( $this->settings['reply_to_email'] ) ? $this->settings['reply_to_email'] : '';
353 default:
354 return '';
355 }
356 }
357
358 public function get_default_subject(): string {
359 return empty( $this->settings['subject'] )
360 ? sprintf(
361 /* translators: %s - site url */
362 __( 'Form on %s Submitted', 'jet-form-builder' ),
363 home_url( '' )
364 )
365 : $this->settings['subject'];
366 }
367
368 public function get_default_content_type(): string {
369 $type = $this->settings['content_type'] ?? 'text/html';
370
371 return empty( $type ) ? 'text/html' : $type;
372 }
373
374 public function get_default_from_name(): string {
375 return empty( $this->settings['from_name'] )
376 ? Tools::get_site_name()
377 : $this->settings['from_name'];
378 }
379
380 public function get_default_from_address(): string {
381 return ! empty( $this->settings['from_address'] ) ? $this->settings['from_address'] : '';
382 }
383
384 public function get_default_attachments(): array {
385 $fields = $this->settings['attachments'] ?? array();
386 $attachments = array();
387
388 foreach ( $fields as $field ) {
389 $value = Request_Tools::get_file( $field );
390
391 if ( ! $value ) {
392 continue;
393 }
394
395 array_push(
396 $attachments,
397 ...explode( ',', $value->get_attachment_file() )
398 );
399 }
400
401 return $this->filter_safe_attachments( $attachments );
402 }
403
404 /**
405 * Allow only readable files within the uploads directory.
406 */
407 private function filter_safe_attachments( array $attachments ): array {
408 $safe = array();
409
410 foreach ( $attachments as $attachment ) {
411 if ( ! is_string( $attachment ) || '' === $attachment ) {
412 continue;
413 }
414
415 $allowed = Uploaded_File::normalize_allowed_upload_file_path( $attachment );
416 if ( '' === $allowed || ! is_file( $allowed ) || ! is_readable( $allowed ) ) {
417 continue;
418 }
419
420 $safe[] = $allowed;
421 }
422
423 return array_values( array_unique( $safe ) );
424 }
425
426 public function update_headers() {
427 $this->set_headers( $this->get_default_headers() );
428 }
429
430 /**
431 * Get the email headers
432 *
433 * @since 2.1
434 */
435 public function get_default_headers(): string {
436 $from_name = $this->get_from_name();
437 $from_address = $this->get_from_address();
438 $reply_to = $this->get_reply_to();
439 $content_type = $this->get_content_type();
440 $cc_emails = $this->get_cc();
441 $bcc_emails = $this->get_bcc();
442
443 $this->validate_header_values(
444 array_merge(
445 array(
446 $from_name,
447 $from_address,
448 $reply_to,
449 $content_type,
450 ),
451 $cc_emails,
452 $bcc_emails
453 )
454 );
455
456 $headers = array(
457 "From: {$from_name} <{$from_address}>",
458 "Reply-To: {$reply_to}",
459 "Content-Type: {$content_type}; charset=utf-8",
460 );
461
462 foreach ( $cc_emails as $cc_email ) {
463 $headers[] = 'Cc: ' . $cc_email;
464 }
465 foreach ( $bcc_emails as $bcc_email ) {
466 $headers[] = 'Bcc: ' . $bcc_email;
467 }
468
469 return implode( "\r\n", $headers );
470 }
471
472 /**
473 * @throws Action_Exception
474 */
475 private function validate_header_values( array $values ) {
476
477 foreach ( $values as $value ) {
478 if ( false !== strpos( $value, "\r" ) || false !== strpos( $value, "\n" ) ) {
479 throw new Action_Exception( 'invalid_email' );
480 }
481 }
482 }
483
484 /**
485 * @param string|array $email
486 */
487 public function set_mail_to( $email ) {
488 if ( ! is_array( $email ) && ! is_string( $email ) ) {
489 return;
490 }
491
492 $this->mail_to = $this->parse_email( $email );
493 }
494
495 /**
496 * @param $email
497 *
498 * @return void
499 */
500 public function set_cc( $email ): void {
501 if ( ! is_array( $email ) && ! is_string( $email ) ) {
502 return;
503 }
504
505 $this->cc = $this->parse_email( $email );
506 }
507
508 /**
509 * @param $email
510 *
511 * @return void
512 */
513 public function set_bcc( $email ): void {
514 if ( ! is_array( $email ) && ! is_string( $email ) ) {
515 return;
516 }
517
518 $this->bcc = $this->parse_email( $email );
519 }
520
521 /**
522 * @param $email
523 *
524 * @return string[]
525 */
526 private function parse_email( $email ): array {
527 if ( ! is_array( $email ) ) {
528 $email = explode( ',', $email );
529 }
530
531 foreach ( $email as &$value ) {
532 $value = trim( $value );
533 }
534
535 return $email;
536 }
537
538 public function set_reply_to( $email ) {
539 if ( ! is_string( $email ) && ! is_array( $email ) ) {
540 return;
541 }
542
543 $this->reply_to = Tools::to_string( $email );
544 }
545
546 public function set_content( $content ) {
547 if ( ! is_string( $content ) ) {
548 return;
549 }
550
551 $this->content = $content;
552 }
553
554 public function set_subject( $subject ) {
555 if ( ! is_string( $subject ) ) {
556 return;
557 }
558
559 $this->subject = $subject;
560 }
561
562 public function set_content_type( string $type ) {
563 $this->content_type = $type;
564 }
565
566 public function set_from_name( string $name ) {
567 $this->from_name = $name;
568 }
569
570 public function set_from_address( string $email ) {
571 $this->from_email = $email;
572 }
573
574 /**
575 * @param array $attachments
576 */
577 public function set_attachments( array $attachments ) {
578 $this->attachments = $attachments;
579 }
580
581 public function set_headers( string $headers ) {
582 $this->headers = $headers;
583 }
584
585 public function get_attachments(): array {
586 return $this->attachments;
587 }
588
589 /**
590 * @return array
591 */
592 public function get_mail_to(): array {
593 return $this->mail_to;
594 }
595
596 /**
597 * @return array
598 */
599 public function get_cc(): array {
600 return $this->cc;
601 }
602
603 /**
604 * @return array
605 */
606 public function get_bcc(): array {
607 return $this->bcc;
608 }
609
610 /**
611 * @return string
612 */
613 public function get_subject(): string {
614 return $this->subject;
615 }
616
617 /**
618 * @return string
619 */
620 public function get_content(): string {
621 return $this->content;
622 }
623
624 /**
625 * Get the email from name
626 */
627 public function get_from_name(): string {
628 return $this->from_name;
629 }
630
631 /**
632 * Returns e-mail address to set into Reply-to email header
633 */
634 public function get_reply_to(): string {
635 return $this->reply_to;
636 }
637
638 /**
639 * Get the email from address
640 */
641 public function get_from_address(): string {
642 return $this->from_email;
643 }
644
645 public function is_html(): bool {
646 return 'text/html' === $this->get_content_type();
647 }
648
649 /**
650 * Get the email content type
651 */
652 public function get_content_type(): string {
653 return $this->content_type;
654 }
655
656 /**
657 * @return string
658 */
659 public function get_headers(): string {
660 return $this->headers;
661 }
662
663 }
664