Completed
Push — master ( 57f28a...e69f1e )
by Stephanie
02:55
created

FrmNotification::send_email()   D

Complexity

Conditions 12
Paths 160

Size

Total Lines 89
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 54
nc 160
nop 1
dl 0
loc 89
rs 4.6933
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
class FrmNotification {
4
	public function __construct() {
5
        if ( ! defined('ABSPATH') ) {
6
            die('You are not allowed to call this page directly.');
7
        }
8
        add_action('frm_trigger_email_action', 'FrmNotification::trigger_email', 10, 3);
9
    }
10
11
	public static function trigger_email( $action, $entry, $form ) {
12
        $notification = $action->post_content;
13
        $email_key = $action->ID;
14
15
        // Set the subject
16
        if ( empty($notification['email_subject']) ) {
17
            $notification['email_subject'] = sprintf(__( '%1$s Form submitted on %2$s', 'formidable' ), $form->name, '[sitename]');
18
        }
19
20
        $plain_text = $notification['plain_text'] ? true : false;
21
22
        //Filter these fields
23
        $filter_fields = array(
24
            'email_to', 'cc', 'bcc',
25
            'reply_to', 'from',
26
            'email_subject', 'email_message',
27
        );
28
29
        add_filter('frm_plain_text_email', ($plain_text ? '__return_true' : '__return_false'));
30
31
        //Get all values in entry in order to get User ID field ID
32
        $values = FrmEntryMeta::getAll( array( 'it.field_id !' => 0, 'it.item_id' => $entry->id ), ' ORDER BY fi.field_order' );
33
        $user_id_field = $user_id_key = '';
34
        foreach ( $values as $value ) {
35
            if ( $value->field_type == 'user_id' ) {
36
                $user_id_field = $value->field_id;
37
                $user_id_key = $value->field_key;
38
                break;
39
            }
40
            unset($value);
41
        }
42
43
        //Filter and prepare the email fields
44
        foreach ( $filter_fields as $f ) {
45
            //Don't allow empty From
46
			if ( $f == 'from' && empty( $notification[ $f ] ) ) {
47
				$notification[ $f ] = '[admin_email]';
48
			} else if ( in_array( $f, array( 'email_to', 'cc', 'bcc', 'reply_to', 'from' ) ) ) {
49
				//Remove brackets
50
                //Add a space in case there isn't one
51
				$notification[ $f ] = str_replace( '<', ' ', $notification[ $f ] );
52
				$notification[ $f ] = str_replace( array( '"', '>' ), '', $notification[ $f ] );
53
54
                //Switch userID shortcode to email address
55
				if ( strpos( $notification[ $f ], '[' . $user_id_field . ']' ) !== false || strpos( $notification[ $f ], '[' . $user_id_key . ']' ) !== false ) {
56
					$user_data = get_userdata( $entry->metas[ $user_id_field ] );
57
                    $user_email = $user_data->user_email;
58
					$notification[ $f ] = str_replace( array( '[' . $user_id_field . ']', '[' . $user_id_key . ']' ), $user_email, $notification[ $f ] );
59
                }
60
            }
61
62
			$notification[ $f ] = FrmFieldsHelper::basic_replace_shortcodes( $notification[ $f ], $form, $entry );
63
        }
64
65
        //Put recipients, cc, and bcc into an array if they aren't empty
66
		$to_emails = self::explode_emails( $notification['email_to'] );
67
		$cc = self::explode_emails( $notification['cc'] );
68
		$bcc = self::explode_emails( $notification['bcc'] );
69
70
        $to_emails = apply_filters('frm_to_email', $to_emails, $values, $form->id, compact('email_key', 'entry', 'form'));
71
72
        // Stop now if there aren't any recipients
73
        if ( empty( $to_emails ) && empty( $cc ) && empty( $bcc ) ) {
74
            return;
75
        }
76
77
        $to_emails = array_unique( (array) $to_emails );
78
79
        $prev_mail_body = $mail_body = $notification['email_message'];
80
        $mail_body = FrmEntriesHelper::replace_default_message($mail_body, array(
81
            'id' => $entry->id, 'entry' => $entry, 'plain_text' => $plain_text,
82
            'user_info' => (isset($notification['inc_user_info']) ? $notification['inc_user_info'] : false),
83
        ) );
84
85
        // Add the user info if it isn't already included
86
        if ( $notification['inc_user_info'] && $prev_mail_body == $mail_body ) {
87
            $data = maybe_unserialize($entry->description);
88
			$mail_body .= "\r\n\r\n" . __( 'User Information', 'formidable' ) . "\r\n";
89
			$mail_body .= __( 'IP Address', 'formidable' ) . ': ' . $entry->ip . "\r\n";
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$entry'
Loading history...
90
			$mail_body .= __( 'User-Agent (Browser/OS)', 'formidable' ) . ': ' . FrmEntryFormat::get_browser( $data['browser'] ) . "\r\n";
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'FrmEntryFormat'
Loading history...
91
			$mail_body .= __( 'Referrer', 'formidable' ) . ': ' . $data['referrer'] . "\r\n";
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$data'
Loading history...
92
        }
93
        unset($prev_mail_body);
94
95
        // Add attachments
96
        $attachments = apply_filters('frm_notification_attachment', array(), $form, compact('entry', 'email_key') );
97
98
        if ( ! empty($notification['email_subject']) ) {
99
            $notification['email_subject'] = apply_filters('frm_email_subject', $notification['email_subject'], compact('form', 'entry', 'email_key'));
100
        }
101
102
        // check for a phone number
103
        foreach ( (array) $to_emails as $email_key => $e ) {
104
            if ( $e != '[admin_email]' && ! is_email($e) ) {
105
                $e = explode(' ', $e);
106
107
                //If to_email has name <[email protected]> format
108
                if ( is_email(end($e)) ) {
109
                    continue;
110
                }
111
112
                do_action('frm_send_to_not_email', array(
113
                    'e'         => $e,
114
                    'subject'   => $notification['email_subject'],
115
                    'mail_body' => $mail_body,
116
                    'reply_to'  => $notification['reply_to'],
117
                    'from'      => $notification['from'],
118
                    'plain_text' => $plain_text,
119
                    'attachments' => $attachments,
120
                    'form'      => $form,
121
                    'email_key' => $email_key,
122
                ) );
123
124
				unset( $to_emails[ $email_key ] );
125
            }
126
        }
127
128
		/**
129
		 * Send a separate email for email address in the "to" section
130
		 * @since 2.2.13
131
		 */
132
		$send_single_recipient = apply_filters( 'frm_send_separate_emails', false, compact( 'action', 'entry', 'form' ) );
133
134
        // Send the email now
135
        $sent_to = self::send_email( array(
136
            'to_email'      => $to_emails,
137
            'subject'       => $notification['email_subject'],
138
            'message'       => $mail_body,
139
            'from'          => $notification['from'],
140
            'plain_text'    => $plain_text,
141
            'reply_to'      => $notification['reply_to'],
142
            'attachments'   => $attachments,
143
            'cc'            => $cc,
144
            'bcc'           => $bcc,
145
			'single_recipient' => $send_single_recipient,
146
        ) );
147
148
        return $sent_to;
149
    }
150
151
	public function entry_created( $entry_id, $form_id ) {
152
		$new_function = 'FrmFormActionsController::trigger_actions("create", ' . $form_id . ', ' . $entry_id . ', "email")';
153
		_deprecated_function( __FUNCTION__, '2.0', $new_function );
154
        FrmFormActionsController::trigger_actions('create', $form_id, $entry_id, 'email');
155
    }
156
157
	public function send_notification_email( $to_email, $subject, $message, $from = '', $from_name = '', $plain_text = true, $attachments = array(), $reply_to = '' ) {
158
        _deprecated_function( __FUNCTION__, '2.0', 'FrmNotification::send_email' );
159
160
        return self::send_email(compact(
161
            'to_email', 'subject', 'message',
162
            'from', 'from_name', 'plain_text',
163
            'attachments', 'reply_to'
164
        ));
165
    }
166
167
	/**
168
	 * Extract the emails from cc and bcc. Allow separation by , or ;.
169
	 * Trim the emails here as well
170
	 *
171
	 * @since 2.0.1
172
	 */
173
	private static function explode_emails( $emails ) {
174
		$emails = ( ! empty( $emails ) ? preg_split( '/(,|;)/', $emails ) : '' );
175
		if ( is_array( $emails ) ) {
176
			$emails = array_map( 'trim', $emails );
177
		} else {
178
			$emails = trim( $emails );
179
		}
180
		return $emails;
181
	}
182
183
    /**
184
    * Put To, BCC, CC, Reply To, and From fields in Name <[email protected]> format
185
    * Formats that should work: Name, "Name", [email protected], <[email protected]>, Name <[email protected]>,
186
    * "Name" <[email protected]>, Name [email protected], "Name" [email protected], Name<[email protected]>, "Name"<[email protected]>
187
    * "First Last" <[email protected]>
188
    *
189
    * Things that won't work: First Last (with no email entered)
190
    * @since 2.0
191
    * @param array $atts array of email fields, pass by reference
192
    * @param $admin_email
193
    */
194
    private static function format_email_fields( &$atts, $admin_email ) {
195
196
        // If from is empty or is set to admin_email, set it now
197
        $atts['from'] = ( empty($atts['from']) || $atts['from'] == '[admin_email]' ) ? $admin_email : $atts['from'];
198
199
        // Filter values in these fields
200
		$filter_fields = array( 'to_email', 'bcc', 'cc', 'from', 'reply_to' );
201
202
        foreach ( $filter_fields as $f ) {
203
            // If empty, just skip it
204
			if ( empty( $atts[ $f ] ) ) {
205
                continue;
206
            }
207
208
            // to_email, cc, and bcc can be an array
209
			if ( is_array( $atts[ $f ] ) ) {
210
				foreach ( $atts[ $f ] as $key => $val ) {
211
                    self::format_single_field( $atts, $f, $val, $key );
212
                    unset( $key, $val );
213
                }
214
                unset($f);
215
                continue;
216
            }
217
218
			self::format_single_field( $atts, $f, $atts[ $f ] );
219
        }
220
221
        // If reply-to isn't set, make it match the from settings
222
        if ( empty( $atts['reply_to'] ) ) {
223
            $atts['reply_to'] = self::get_email_from_formatted_string( $atts['from'] );
224
        }
225
226
        if ( ! is_array($atts['to_email']) && '[admin_email]' == $atts['to_email'] ) {
227
            $atts['to_email'] = $admin_email;
228
        }
229
    }
230
231
	private static function get_email_from_formatted_string( $value ) {
232
		if ( strpos( $value, '<' ) !== false ) {
233
			preg_match_all( '/\<([^)]+)\>/', $value, $emails );
234
			$value = $emails[1][0];
235
		}
236
		return $value;
237
	}
238
239
    /**
240
    * Format individual email fields
241
    *
242
    * @since 2.0
243
    * @param array $atts pass by reference
244
    * @param string $f (to, from, reply_to, etc)
245
    * @param string $val value saved in field
246
    * @param int $key if in array, this will be set
247
    */
248
    private static function format_single_field( &$atts, $f, $val, $key = false ) {
249
        $val = trim($val);
250
251
        // If just a plain email is used
252
        if ( is_email($val) ) {
253
            // add sender's name if not included in $from
254
            if ( $f == 'from' ) {
255
				$part_2 = $atts[ $f ];
256
                $part_1  = $atts['from_name'] ? $atts['from_name'] : wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
257
            } else {
258
                return;
259
            }
260
        } else {
261
            $parts = explode(' ', $val);
262
            $part_2 = end($parts);
263
264
            // If inputted correcly, $part_2 should be an email
265
            if ( is_email( $part_2 ) ) {
266
                $part_1 = trim( str_replace( $part_2, '', $val ) );
267
            } else if ( in_array( $f, array( 'from', 'reply_to' ) ) ) {
268
				// In case someone just puts a name in the From or Reply To field
269
				$part_1 = $val;
270
                $part_2 = get_option('admin_email');
271
            } else {
272
				// In case someone just puts a name in any other email field
273
                if ( false !== $key ) {
274
					unset( $atts[ $f ][ $key ] );
275
                    return;
276
                }
277
				$atts[ $f ] = '';
278
                return;
279
            }
280
        }
281
282
		// if sending the email from a yahoo address, change it to the WordPress default
283
		if ( $f == 'from' && strpos( $part_2, '@yahoo.com' ) ) {
284
			// Get the site domain and get rid of www.
285
			$sitename = strtolower( FrmAppHelper::get_server_value( 'SERVER_NAME' ) );
286
			if ( substr( $sitename, 0, 4 ) == 'www.' ) {
287
				$sitename = substr( $sitename, 4 );
288
			}
289
290
			$part_2 = 'wordpress@' . $sitename;
291
		}
292
293
        // Set up formatted value
294
		$final_val = str_replace( '"', '', $part_1 ) . ' <' . $part_2 . '>';
295
296
        // If value is an array
297
        if ( false !== $key ) {
298
			$atts[ $f ][ $key ] = $final_val;
299
            return;
300
        }
301
		$atts[ $f ] = $final_val;
302
    }
303
304
	public static function send_email( $atts ) {
305
        $admin_email = get_option('admin_email');
306
        $defaults = array(
307
            'to_email'      => $admin_email,
308
            'subject'       => '',
309
            'message'       => '',
310
            'from'          => $admin_email,
311
            'from_name'     => '',
312
            'cc'            => '',
313
            'bcc'           => '',
314
            'plain_text'    => true,
315
            'reply_to'      => $admin_email,
316
            'attachments'   => array(),
317
			'single_recipient' => false,
318
        );
319
        $atts = wp_parse_args($atts, $defaults);
320
321
        // Put To, BCC, CC, Reply To, and From fields in the correct format
322
        self::format_email_fields( $atts, $admin_email );
323
324
        $header         = array();
325
        $header[]       = 'From: ' . $atts['from'];
326
327
        //Allow for cc and bcc arrays
328
		$array_fields = array( 'CC' => $atts['cc'], 'BCC' => $atts['bcc'] );
329
		$cc = array( 'CC' => array(), 'BCC' => array() );
330
        foreach ( $array_fields as $key => $a_field ) {
331
            if ( empty($a_field) ) {
332
                continue;
333
            }
334
335
			foreach ( (array) $a_field as $email ) {
336
				$cc[ $key ][] = $email;
337
            }
338
            unset($key, $a_field);
339
        }
340
		$cc = array_filter( $cc ); // remove cc and bcc if they are empty
341
342
		foreach ( $cc as $k => $v ) {
343
			$header[] = $k . ': ' . implode( ',', $v );
344
		}
345
346
        $content_type   = $atts['plain_text'] ? 'text/plain' : 'text/html';
347
		$atts['charset'] = get_option('blog_charset');
348
349
		$header[]       = 'Reply-To: ' . $atts['reply_to'];
350
		$header[]       = 'Content-Type: ' . $content_type . '; charset="' . esc_attr( $atts['charset'] ) . '"';
351
		$atts['subject'] = wp_specialchars_decode( strip_tags( stripslashes( $atts['subject'] ) ), ENT_QUOTES );
352
353
		$atts['message'] = do_shortcode( $atts['message'] );
354
355
        if ( $atts['plain_text'] ) {
356
			$atts['message'] = wp_specialchars_decode( strip_tags( $atts['message'] ), ENT_QUOTES );
357
        } else {
358
			// remove line breaks in HTML emails to prevent conflicts with Mandrill
359
        	add_filter( 'mandrill_nl2br', 'FrmNotification::remove_mandrill_br' );
360
        }
361
		$atts['message'] = apply_filters( 'frm_email_message', $atts['message'], $atts );
362
363
		/**
364
		 * Stop an email based on the message, subject, recipient,
365
		 * or any information included in the email header
366
		 * @since 2.2.8
367
		 */
368
		$continue_sending = apply_filters( 'frm_send_email', true, array(
369
			'message' => $atts['message'], 'subject' => $atts['subject'],
370
			'recipient' => $atts['to_email'], 'header' => $header,
371
		) );
372
		if ( ! $continue_sending ) {
373
			return;
374
		}
375
376
		self::remove_buddypress_filters();
377
378
		if ( is_array( $atts['to_email'] ) && $atts['single_recipient'] ) {
379
			foreach ( $atts['to_email'] as $recipient ) {
380
				$sent = self::send_single_email( $recipient, $atts, $header );
381
			}
382
		} else {
383
			$sent = self::send_single_email( $atts['to_email'], $atts, $header );
384
		}
385
386
		// remove the filter now so other emails can still use it
387
		remove_filter( 'mandrill_nl2br', 'FrmNotification::remove_mandrill_br' );
388
389
        if ( $sent ) {
0 ignored issues
show
Bug introduced by
The variable $sent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
390
			return self::return_emails_sent( $atts );
391
        }
392
    }
393
394
	private static function send_single_email( $recipient, $atts, $header ) {
395
		$header = apply_filters( 'frm_email_header', $header, array(
396
			'to_email' => $recipient, 'subject' => $atts['subject'],
397
		) );
398
399
		self::encode_subject( $atts['charset'], $atts['subject'] );
400
401
		$sent = wp_mail( $recipient, $atts['subject'], $atts['message'], $header, $atts['attachments'] );
402
		if ( ! $sent ) {
403
			$header = 'From: ' . $atts['from'] . "\r\n";
404
			$recipient = implode( ',', (array) $recipient );
405
			$sent = mail( $recipient, $atts['subject'], $atts['message'], $header );
406
		}
407
408
		do_action( 'frm_notification', $recipient, $atts['subject'], $atts['message'] );
409
410
		return $sent;
411
	}
412
413
	private static function encode_subject( $charset, &$subject ) {
414
		if ( apply_filters('frm_encode_subject', 1, $subject ) ) {
415
			$subject = '=?' . $charset . '?B?' . base64_encode( $subject ) . '?=';
416
		}
417
	}
418
419
	private static function remove_buddypress_filters() {
420
		remove_filter( 'wp_mail_from', 'bp_core_email_from_address_filter' );
421
		remove_filter( 'wp_mail_from_name', 'bp_core_email_from_name_filter' );
422
	}
423
424
	private static function return_emails_sent( $atts ) {
425
		$sent_to = array_merge( (array) $atts['to_email'], (array) $atts['cc'], (array) $atts['bcc'] );
426
		$sent_to = array_filter( $sent_to );
427
428
		if ( apply_filters( 'frm_echo_emails', false ) ) {
429
			$temp = str_replace( '<', '&lt;', $sent_to );
430
			echo ' ' . FrmAppHelper::kses( implode(', ', (array) $temp ) );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'FrmAppHelper'
Loading history...
431
		}
432
		return $sent_to;
433
	}
434
435
	/**
436
	 * This function should only be fired when Mandrill is sending an HTML email
437
	 * This will make sure Mandrill doesn't mess with our HTML emails
438
	 *
439
	 * @since 2.0
440
	 */
441
	public static function remove_mandrill_br() {
442
		return false;
443
	}
444
}
445