Completed
Push — master ( a49d14...9cdc95 )
by Jacob
02:01
created

Archangel::addTo()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 7
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 7
loc 7
rs 9.2
cc 4
eloc 4
nc 3
nop 2
1
<?php
2
3
namespace Jacobemerick\Archangel;
4
5
/**
6
 * This is the main class for Archangel mailer
7
 * For licensing and examples:
8
 *
9
 * @see https://github.com/jacobemerick/archangel
10
 *
11
 * @author jacobemerick (http://home.jacobemerick.com/)
12
 * @version 1.0 (2013-04-12)
13
 */
14
15
class Archangel
16
{
17
18
	/**
19
	 * These variables are set with setter methods below
20
	 */
21
	private $subject;
22
	private $reply_to;
0 ignored issues
show
Unused Code introduced by
The property $reply_to is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
23
	private $plain_message;
24
	private $html_message;
25
26
	/**
27
	 * Holder for error handling and validation
28
	 */
29
	private $passed_validation = TRUE;
30
	private $validation_error = array();
31
32
	/**
33
	 * Holders for some of the more list-y variable handling
34
	 */
35
	private $to_array = array();
36
	private $cc_array = array();
37
	private $bcc_array = array();
38
	private $header_array = array();
39
	private $attachment_array = array();
40
41
	/**
42
	 * Static pieces that really don't need to change
43
	 */
44
	private static $MAILER = 'PHP/%s';
45
	private static $LINE_BREAK = "\r\n";
46
	private static $BOUNDARY_FORMAT = 'PHP-mixed-%s';
47
	private static $BOUNDARY_SALT = 'Boundary Salt';
48
	private static $ALTERNATIVE_BOUNDARY_FORMAT = 'PHP-alternative-%s';
49
	private static $ALTERNATIVE_BOUNDARY_SALT = 'Alternative Boundary Salt';
50
51
	/**
52
	 * Standard constructor, sets some of the base (unchanging) fields
53
	 */
54
	public function __construct()
55
	{
56
		$this->header_array['X-Mailer'] = sprintf(self::$MAILER, phpversion());
57
	}
58
59
	/**
60
	 * Setter method for adding recipients
61
	 * This class only sends a single email, so all recipients can see each other
62
	 *
63
	 * @param	string	$address	email address for the recipient
64
	 * @param	string	$title		name of the recipient (optional)
65
	 * @return	object	instantiated $this
66
	 */
67 View Code Duplication
	public function addTo($address, $title = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
68
	{
69
		if($this->is_valid_email_address($address) && $this->is_valid_email_title($title))
70
			$this->to_array[] = ($title != '') ? "\"{$title}\" <{$address}>" : "{$address}";
71
		
72
		return $this;
73
	}
74
75
	/**
76
	 * Setter method for adding cc recipients
77
	 *
78
	 * @param	string	$address	email address for the cc recipient
79
	 * @param	string	$title		name of the cc recipient (optional)
80
	 * @return	object	instantiated $this
81
	 */
82 View Code Duplication
	public function addCC($address, $title = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
	{
84
		if($this->is_valid_email_address($address) && $this->is_valid_email_title($title))
85
			$this->cc_array[] = ($title != '') ? "\"{$title}\" <{$address}>" : "{$address}";
86
		
87
		return $this;
88
	}
89
90
	/**
91
	 * Setter method for adding bcc recipients
92
	 *
93
	 * @param	string	$address	email address for the bcc recipient
94
	 * @param	string	$title		name of the bcc recipient (optional)
95
	 * @return	object	instantiated $this
96
	 */
97 View Code Duplication
	public function addBCC($address, $title = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
98
	{
99
		if($this->is_valid_email_address($address) && $this->is_valid_email_title($title))
100
			$this->bcc_array[] = ($title != '') ? "\"{$title}\" <{$address}>" : "{$address}";
101
		
102
		return $this;
103
	}
104
105
	/**
106
	 * Setter method for setting the single 'from' field
107
	 *
108
	 * @param	string	$address	email address for the sender
109
	 * @param	string	$title		name of the sender (optional)
110
	 * @return	object	instantiated $this
111
	 */
112 View Code Duplication
	public function setFrom($address, $title = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
	{
114
		if($this->is_valid_email_address($address) && $this->is_valid_email_title($title))
115
			$this->header_array['From'] = ($title != '') ? "\"{$title}\" <{$address}>" : "{$address}";
116
		
117
		return $this;
118
	}
119
120
	/**
121
	 * Setter method for setting the single 'reply-to' field
122
	 *
123
	 * @param	string	$address	email address for the reply-to
124
	 * @param	string	$title		name of the reply-to (optional)
125
	 * @return	object	instantiated $this
126
	 */
127 View Code Duplication
	public function setReplyTo($address, $title = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
	{
129
		if($this->is_valid_email_address($address) && $this->is_valid_email_title($title))
130
			$this->header_array['Reply-To'] = ($title != '') ? "\"{$title}\" <{$address}>" : "{$address}";
131
		
132
		return $this;
133
	}
134
135
	/**
136
	 * Setter method for setting a subject
137
	 *
138
	 * @param	string	$subject	subject for the email
139
	 * @return	object	instantiated $this
140
	 */
141
	public function setSubject($subject)
142
	{
143
		if($this->is_valid_subject($subject))
144
			$this->subject = $subject;
145
		
146
		return $this;
147
	}
148
149
	/**
150
	 * Setter method for the plain text message
151
	 *
152
	 * @param	string	$message	the plain-text message
153
	 * @return	object	insantiated $this
154
	 */
155
	public function setPlainMessage($message)
156
	{
157
		$this->plain_message = $message;
158
		
159
		return $this;
160
	}
161
162
	/**
163
	 * Setter method for the html message
164
	 *
165
	 * @param	string	$message	the html message
166
	 * @return	object	insantiated $this
167
	 */
168
	public function setHTMLMessage($message)
169
	{
170
		$this->html_message = $message;
171
		
172
		return $this;
173
	}
174
175
	/**
176
	 * Setter method for adding attachments
177
	 *
178
	 * @param	string	$path	the full path of the attachment
179
	 * @param	string	$type	mime type of the file
180
	 * @param	string	$title	the title of the attachment (optional)
181
	 * @return	object	insantiated $this
182
	 */
183
	public function addAttachment($path, $type, $title = '')
184
	{
185
		$this->attachment_array[] = (object) array(
186
			'path' => $path,
187
			'type' => $type,
188
			'title' => $title);
189
		
190
		return $this;
191
	}
192
193
	/**
194
	 * The executing step, the actual sending of the email
195
	 * First checks to make sure the minimum fields are set (returns false if they are not)
196
	 * Second it attempts to send the mail with php's mail() (returns false if it fails)
197
	 *
198
	 * return	boolean	whether or not the email was valid & sent
199
	 */
200
	public function send()
201
	{
202
		if($this->passed_validation === FALSE)
203
			return false;
204
		
205
		if(!$this->check_required_fields())
206
			return false;
207
		
208
		$to = $this->get_to();
209
		$subject = $this->subject;
210
		$message = $this->get_message();
211
		$additional_headers = $this->get_additional_headers();
212
		
213
		return mail($to, $subject, $message, $additional_headers);
214
	}
215
216
	/**
217
	 * Main instantiator for the class
218
	 *
219
	 * @return	object	instantiated $this
220
	 */
221
	public static function instance()
222
	{
223
		return new Archangel();
224
	}
225
226
	/**
227
	 * Private call to check the minimum required fields
228
	 *
229
	 * @return	boolean	whether or not the email meets the minimum required fields
230
	 */
231
	private function check_required_fields()
232
	{
233
		return (
234
			count($this->to_array) > 0 &&
235
			(isset($this->subject) && strlen($this->subject) > 0) &&
236
			(
237
				(isset($this->plain_message) && strlen($this->plain_message) > 0) ||
238
				(isset($this->html_message) && strlen($this->html_message) > 0) ||
239
				(isset($this->attachment_array) && count($this->attachment_array) > 0)));
240
	}
241
242
	/**
243
	 * Private function to collect the recipients from to_array
244
	 *
245
	 * @return	string	comma-separated lit of recipients
246
	 */
247
	private function get_to()
248
	{
249
		return implode(', ', $this->to_array);
250
	}
251
252
	/**
253
	 * Long, nasty creater of the actual message, with all the multipart logic you'd never want to see
254
	 *
255
	 * @return	string	email message
256
	 */
257
	private function get_message()
258
	{
259
		$message = '';
260
		
261
		if(isset($this->attachment_array) && count($this->attachment_array) > 0)
262
			$message .= "--{$this->get_boundary()}" . self::$LINE_BREAK;
263
		
264
		if(
265
			isset($this->plain_message) && strlen($this->plain_message) > 0 &&
266
			isset($this->html_message) && strlen($this->html_message) > 0)
267
		{
268 View Code Duplication
			if(isset($this->attachment_array) && count($this->attachment_array) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
269
			{
270
				$message .= "Content-Type: multipart/alternative; boundary={$this->get_alternative_boundary()}" . self::$LINE_BREAK;
271
				$message .= self::$LINE_BREAK;
272
			}
273
			$message .= "--{$this->get_alternative_boundary()}" . self::$LINE_BREAK;
274
			$message .= 'Content-Type: text/plain; charset="iso-8859"' . self::$LINE_BREAK;
275
			$message .= 'Content-Transfer-Encoding: 7bit' . self::$LINE_BREAK;
276
			$message .= self::$LINE_BREAK;
277
			$message .= $this->plain_message;
278
			$message .= self::$LINE_BREAK;
279
			$message .= "--{$this->get_alternative_boundary()}" . self::$LINE_BREAK;
280
			$message .= 'Content-Type: text/html; charset="iso-8859-1"' . self::$LINE_BREAK;
281
			$message .= 'Content-Transfer-Encoding: 7bit' . self::$LINE_BREAK;
282
			$message .= self::$LINE_BREAK;
283
			$message .= $this->html_message;
284
			$message .= self::$LINE_BREAK;
285
			$message .= "--{$this->get_alternative_boundary()}--" . self::$LINE_BREAK;
286
			$message .= self::$LINE_BREAK;
287
		}
288
		else if(isset($this->plain_message) && strlen($this->plain_message))
289
		{
290 View Code Duplication
			if(isset($this->attachment_array) && count($this->attachment_array) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
			{
292
				$message .= 'Content-Type: text/plain; charset="iso-8859"' . self::$LINE_BREAK;
293
				$message .= 'Content-Transfer-Encoding: 7bit' . self::$LINE_BREAK;
294
				$message .= self::$LINE_BREAK;
295
			}
296
			$message .= $this->plain_message;
297
			$message .= self::$LINE_BREAK;
298
		}
299
		else if(isset($this->html_message) && strlen($this->html_message))
300
		{
301 View Code Duplication
			if(isset($this->attachment_array) && count($this->attachment_array) > 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
302
			{
303
				$message .= 'Content-Type: text/html; charset="iso-8859-1"' . self::$LINE_BREAK;
304
				$message .= 'Content-Transfer-Encoding: 7bit' . self::$LINE_BREAK;
305
				$message .= self::$LINE_BREAK;
306
			}
307
			$message .= $this->html_message;
308
			$message .= self::$LINE_BREAK;
309
		}
310
		if(isset($this->attachment_array) && count($this->attachment_array) > 0)
311
		{
312
			foreach($this->attachment_array as $attachment)
313
			{
314
				$message .= "--{$this->get_boundary()}" . self::$LINE_BREAK;
315
				$message .= "Content-Type: {$attachment->type}; name=\"{$attachment->title}\"" . self::$LINE_BREAK;
316
				$message .= 'Content-Transfer-Encoding: base64' . self::$LINE_BREAK;
317
				$message .= 'Content-Disposition: attachment' . self::$LINE_BREAK;
318
				$message .= self::$LINE_BREAK;
319
				$message .= $this->get_attachment_content($attachment);
320
				$message .= self::$LINE_BREAK;
321
			}
322
			$message .= "--{$this->get_boundary()}--" . self::$LINE_BREAK;
323
		}
324
		return $message;
325
	}
326
327
	/**
328
	 * Private holder for the boundry logic
329
	 * Not called/created unless it's needed
330
	 *
331
	 * @return	string	boundary
332
	 */
333
	private $boundary;
334
	private function get_boundary()
335
	{
336
		if(!isset($this->boundary))
337
			$this->boundary = sprintf(self::$BOUNDARY_FORMAT, md5(date('r', time()) . self::$BOUNDARY_SALT));
338
		return $this->boundary;
339
	}
340
341
	/**
342
	 * Private holder for the alternative boundry logic
343
	 * Not called/created unless it's needed
344
	 *
345
	 * @return	string	alternative boundary
346
	 */
347
	private $alternative_boundary;
348
	private function get_alternative_boundary()
349
	{
350
		if(!isset($this->alternative_boundary))
351
			$this->alternative_boundary = sprintf(self::$ALTERNATIVE_BOUNDARY_FORMAT, md5(date('r', time()) . self::$ALTERNATIVE_BOUNDARY_SALT));
352
		return $this->alternative_boundary;
353
	}
354
355
	/**
356
	 * Fetcher for the additional headers needed for multipart emails
357
	 *
358
	 * @return	string	headers needed for multipart
359
	 */
360
	private function get_additional_headers()
361
	{
362
		$headers = '';
363
		foreach($this->header_array as $key => $value)
364
		{
365
			$headers .= "{$key}: {$value}" . self::$LINE_BREAK;
366
		}
367
		
368
		if(count($this->cc_array) > 0)
369
			$headers .= 'CC: ' . implode(', ', $this->cc_array) . self::$LINE_BREAK;
370
		if(count($this->bcc_array) > 0)
371
			$headers .= 'BCC: ' . implode(', ', $this->bcc_array) . self::$LINE_BREAK;
372
		
373
		if(isset($this->attachment_array) && count($this->attachment_array) > 0)
374
			$headers .= "Content-Type: multipart/mixed; boundary=\"{$this->get_boundary()}\"";
375
		else if(
376
			isset($this->plain_message) && strlen($this->plain_message) > 0 &&
377
			isset($this->html_message) && strlen($this->html_message) > 0)
378
		{
379
			$headers .= "Content-Type: multipart/alternative; boundary=\"{$this->get_alternative_boundary()}\"";
380
		}
381
		else if(isset($this->html_message) && strlen($this->html_message) > 0)
382
			$headers .= 'Content-type: text/html; charset="iso-8859-1"';
383
		
384
		return $headers;
385
	}
386
387
	/**
388
	 * File reader for attachments
389
	 *
390
	 * @return	string	binary representation of file, base64'd
391
	 */
392
	private function get_attachment_content($attachment)
393
	{
394
		$handle = fopen($attachment->path, 'r');
395
		$contents = fread($handle, filesize($attachment->path));
396
		fclose($handle);
397
		
398
		$contents = base64_encode($contents);
399
		$contents = chunk_split($contents);
400
		return $contents;
401
	}
402
403
	/**
404
	 * stub for email address checking
405
	 */
406
	private function is_valid_email_address($string)
407
	{
408
		if(strlen($string) < 1)
409
			return $this->fail_validation("{$string} is an invalid email address!");
410
		
411
		return true;
412
	}
413
414
	/**
415
	 * stub for email title checking
416
	 */
417
	private function is_valid_email_title($string)
0 ignored issues
show
Unused Code introduced by
The parameter $string is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
418
	{
419
		return true;
420
	}
421
422
	/**
423
	 * stub for subject checking
424
	 */
425
	private function is_valid_subject($string)
426
	{
427
		if(strlen($string) < 1)
428
			return $this->fail_validation("{$string} is an invalid email subject!");
429
		
430
		return true;
431
	}
432
433
	/**
434
	 * holder for all validation fails
435
	 */
436
	private function fail_validation($message)
437
	{
438
		$this->passed_validation = FALSE;
439
		$this->validation_error[] = $message;
440
		
441
		return false;
442
	}
443
444
	public function get_validation_errors()
445
	{
446
		return $this->validation_error();
0 ignored issues
show
Bug introduced by
The method validation_error() does not exist on Jacobemerick\Archangel\Archangel. Did you maybe mean get_validation_errors()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
447
	}
448
449
}
450