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

FrmNotification::send_notification_email()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 8
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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