1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Swift Mailer Message Component |
5
|
|
|
* Composes MIME 1.0 messages meeting various RFC standards |
6
|
|
|
* Deals with attachments, embedded images, multipart bodies, forwarded messages... |
7
|
|
|
* Please read the LICENSE file |
8
|
|
|
* @copyright Chris Corbyn <[email protected]> |
9
|
|
|
* @author Chris Corbyn <[email protected]> |
10
|
|
|
* @package Swift_Message |
11
|
|
|
* @license GNU Lesser General Public License |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
require_once dirname(__FILE__) . "/ClassLoader.php"; |
15
|
|
|
Swift_ClassLoader::load("Swift_Address"); |
16
|
|
|
Swift_ClassLoader::load("Swift_Message_Mime"); |
17
|
|
|
Swift_ClassLoader::load("Swift_Message_Image"); |
18
|
|
|
Swift_ClassLoader::load("Swift_Message_Part"); |
19
|
|
|
|
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Swift Message class |
23
|
|
|
* @package Swift_Message |
24
|
|
|
* @author Chris Corbyn <[email protected]> |
25
|
|
|
*/ |
26
|
|
|
class Swift_Message extends Swift_Message_Mime |
27
|
|
|
{ |
28
|
|
|
/** |
29
|
|
|
* Constant from a high priority message (pretty meaningless) |
30
|
|
|
*/ |
31
|
|
|
const PRIORITY_HIGH = 1; |
32
|
|
|
/** |
33
|
|
|
* Constant for a low priority message |
34
|
|
|
*/ |
35
|
|
|
const PRIORITY_LOW = 5; |
36
|
|
|
/** |
37
|
|
|
* Constant for a normal priority message |
38
|
|
|
*/ |
39
|
|
|
const PRIORITY_NORMAL = 3; |
40
|
|
|
/** |
41
|
|
|
* The MIME warning for client not supporting multipart content |
42
|
|
|
* @var string |
43
|
|
|
*/ |
44
|
|
|
protected $mimeWarning = null; |
45
|
|
|
/** |
46
|
|
|
* The version of the library (Swift) if known. |
47
|
|
|
* @var string |
48
|
|
|
*/ |
49
|
|
|
protected $libVersion = ""; |
50
|
|
|
/** |
51
|
|
|
* A container for references to other objects. |
52
|
|
|
* This is used in some very complex logic when sub-parts get shifted around. |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
protected $references = array( |
56
|
|
|
"parent" => array("alternative" => null, "mixed" => null, "related" => null), |
57
|
|
|
"alternative" => array(), |
58
|
|
|
"mixed" => array(), |
59
|
|
|
"related" => array() |
60
|
|
|
); |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Ctor. |
64
|
|
|
* @param string Message subject |
65
|
|
|
* @param string Body |
66
|
|
|
* @param string Content-type |
67
|
|
|
* @param string Encoding |
68
|
|
|
* @param string Charset |
69
|
|
|
* @param string $encoding |
|
|
|
|
70
|
|
|
* @param string $charset |
|
|
|
|
71
|
|
|
*/ |
72
|
|
|
public function __construct($subject="", $body=null, $type="text/plain", $encoding=null, $charset=null) |
73
|
|
|
{ |
74
|
|
|
parent::__construct(); |
75
|
|
|
if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get")) |
76
|
|
|
{ |
77
|
|
|
date_default_timezone_set(@date_default_timezone_get()); |
78
|
|
|
} |
79
|
|
|
$this->setReturnPath(null); |
80
|
|
|
$this->setTo(""); |
81
|
|
|
$this->setFrom(""); |
82
|
|
|
$this->setCc(null); |
83
|
|
|
$this->setBcc(null); |
84
|
|
|
$this->setReplyTo(null); |
85
|
|
|
$this->setSubject($subject); |
86
|
|
|
$this->setDate(time()); |
87
|
|
|
if (defined("Swift::VERSION")) |
88
|
|
|
{ |
89
|
|
|
$this->libVersion = Swift::VERSION; |
90
|
|
|
$this->headers->set("X-LibVersion", $this->libVersion); |
91
|
|
|
} |
92
|
|
|
$this->headers->set("MIME-Version", "1.0"); |
93
|
|
|
$this->setContentType($type); |
94
|
|
|
$this->setCharset($charset); |
95
|
|
|
$this->setFlowed(true); |
96
|
|
|
$this->setEncoding($encoding); |
97
|
|
|
|
98
|
|
|
foreach (array_keys($this->references["parent"]) as $key) |
99
|
|
|
{ |
100
|
|
|
$this->setReference("parent", $key, $this); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$this->setMimeWarning( |
104
|
|
|
"This is a message in multipart MIME format. Your mail client should not be displaying this. " . |
105
|
|
|
"Consider upgrading your mail client to view this message correctly." |
106
|
|
|
); |
107
|
|
|
|
108
|
|
View Code Duplication |
if ($body !== null) |
|
|
|
|
109
|
|
|
{ |
110
|
|
|
$this->setData($body); |
111
|
|
|
if ($charset === null) |
112
|
|
|
{ |
113
|
|
|
Swift_ClassLoader::load("Swift_Message_Encoder"); |
114
|
|
|
if (Swift_Message_Encoder::instance()->isUTF8($body)) $this->setCharset("utf-8"); |
115
|
|
|
else $this->setCharset("iso-8859-1"); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
/** |
120
|
|
|
* Sets a reference so when nodes are nested, operations can be redirected. |
121
|
|
|
* This really should be refactored to use just one array rather than dynamic variables. |
122
|
|
|
* @param string Key 1 |
123
|
|
|
* @param string Key 2 |
124
|
|
|
* @param Object Reference |
125
|
|
|
* @param string $where |
126
|
|
|
*/ |
127
|
|
|
protected function setReference($where, $key, $ref) |
128
|
|
|
{ |
129
|
|
|
if ($ref === $this) $this->references[$where][$key] = false; |
130
|
|
|
else $this->references[$where][$key] = $ref; |
131
|
|
|
} |
132
|
|
|
/** |
133
|
|
|
* Get a reference to an object (for complex reasons). |
134
|
|
|
* @param string Key 1 |
135
|
|
|
* @param string Key 2 |
136
|
|
|
* @param string $where |
137
|
|
|
* @return Object |
138
|
|
|
*/ |
139
|
|
|
protected function getReference($where, $key) |
140
|
|
|
{ |
141
|
|
|
if (!$this->references[$where][$key]) return $this; |
142
|
|
|
else return $this->references[$where][$key]; |
143
|
|
|
} |
144
|
|
|
/** |
145
|
|
|
* Get the level in the MIME hierarchy at which this section should appear. |
146
|
|
|
* @return string |
147
|
|
|
*/ |
148
|
|
|
public function getLevel() |
149
|
|
|
{ |
150
|
|
|
return Swift_Message_Mime::LEVEL_TOP; |
151
|
|
|
} |
152
|
|
|
/** |
153
|
|
|
* Set the message id literally. |
154
|
|
|
* Unless you know what you are doing you should be using generateId() rather than this method, |
155
|
|
|
* otherwise you may break compliancy with RFC 2822. |
156
|
|
|
* @param string The message ID string. |
157
|
|
|
* @param null|string $id |
158
|
|
|
*/ |
159
|
|
|
public function setId($id) |
160
|
|
|
{ |
161
|
|
|
$this->headers->set("Message-ID", $id); |
162
|
|
|
} |
163
|
|
|
/** |
164
|
|
|
* Create a RFC 2822 compliant message id, optionally based upon $idstring. |
165
|
|
|
* The message ID includes information about the current time, the server and some random characters. |
166
|
|
|
* @param string An optional string the base the ID on |
167
|
|
|
* @return string The generated message ID, including the <> quotes. |
|
|
|
|
168
|
|
|
* @author Cristian Rodriguez <[email protected]> |
169
|
|
|
*/ |
170
|
|
|
public function generateId($idstring=null) |
|
|
|
|
171
|
|
|
{ |
172
|
|
|
$midparams = array( |
173
|
|
|
"utctime" => gmstrftime("%Y%m%d%H%M%S"), |
174
|
|
|
"pid" => getmypid(), |
175
|
|
|
"randint" => mt_rand(), |
176
|
|
|
"customstr" => (preg_match("/^(?<!\\.)[a-z0-9\\.]+(?!\\.)\$/iD", $idstring) ? $idstring : "swift") , |
177
|
|
|
"hostname" => (isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : php_uname("n")), |
178
|
|
|
); |
179
|
|
|
$this->setId(vsprintf("<%s.%d.%d.%s@%s>", $midparams)); |
180
|
|
|
return $this->getId(); |
181
|
|
|
} |
182
|
|
|
/** |
183
|
|
|
* Get the generated message ID for this message, including the <> quotes. |
184
|
|
|
* If generated automatically, or using generateId() this method returns a RFC2822 compliant Message-ID. |
185
|
|
|
* @return string |
|
|
|
|
186
|
|
|
* @author Cristian Rodriguez <[email protected]> |
187
|
|
|
*/ |
188
|
|
|
public function getId() |
189
|
|
|
{ |
190
|
|
|
return $this->headers->has("Message-ID") ? $this->headers->get("Message-ID") : null; |
191
|
|
|
} |
192
|
|
|
/** |
193
|
|
|
* Set the address in the Return-Path: header |
194
|
|
|
* @param string The bounce-detect address |
195
|
|
|
*/ |
196
|
|
|
public function setReturnPath($address) |
197
|
|
|
{ |
198
|
|
|
if ($address instanceof Swift_Address) $address = $address->build(true); |
199
|
|
|
$this->headers->set("Return-Path", $address); |
200
|
|
|
} |
201
|
|
|
/** |
202
|
|
|
* Return the address used in the Return-Path: header |
203
|
|
|
* @return string |
|
|
|
|
204
|
|
|
* @param boolean Return the address for SMTP command |
205
|
|
|
*/ |
206
|
|
|
public function getReturnPath($smtp=false) |
207
|
|
|
{ |
208
|
|
|
if ($this->headers->has("Return-Path")) |
209
|
|
|
{ |
210
|
|
|
if (!$smtp) return $this->headers->get("Return-Path"); |
211
|
|
|
else |
212
|
|
|
{ |
213
|
|
|
$path = $this->headers->get("Return-Path"); |
214
|
|
|
if (strpos($path, ">") > strpos($path, "<")) return substr($path, ($start = strpos($path, "<")), ($start + strrpos($path, ">") + 1)); |
215
|
|
|
else return "<" . $path . ">"; |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
/** |
220
|
|
|
* Set the address in the From: header |
221
|
|
|
* @param string The address to set as From |
222
|
|
|
*/ |
223
|
|
|
public function setFrom($from) |
224
|
|
|
{ |
225
|
|
|
if ($from instanceof Swift_Address) $from = $from->build(); |
226
|
|
|
$this->headers->set("From", $from); |
227
|
|
|
} |
228
|
|
|
/** |
229
|
|
|
* Get the address used in the From: header |
230
|
|
|
* @return string |
|
|
|
|
231
|
|
|
*/ |
232
|
|
|
public function getFrom() |
233
|
|
|
{ |
234
|
|
|
if ($this->headers->has("From")) return $this->headers->get("From"); |
235
|
|
|
} |
236
|
|
|
/** |
237
|
|
|
* Set the list of recipients in the To: header |
238
|
|
|
* @param mixed An array or a string |
239
|
|
|
*/ |
240
|
|
View Code Duplication |
public function setTo($to) |
|
|
|
|
241
|
|
|
{ |
242
|
|
|
if ($to) |
243
|
|
|
{ |
244
|
|
|
if (!is_array($to)) $to = array($to); |
245
|
|
|
foreach ($to as $key => $value) |
246
|
|
|
{ |
247
|
|
|
if ($value instanceof Swift_Address) $to[$key] = $value->build(); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
$this->headers->set("To", $to); |
251
|
|
|
} |
252
|
|
|
/** |
253
|
|
|
* Return the list of recipients in the To: header |
254
|
|
|
* @return array |
|
|
|
|
255
|
|
|
*/ |
256
|
|
|
public function getTo() |
257
|
|
|
{ |
258
|
|
|
if ($this->headers->has("To")) |
259
|
|
|
{ |
260
|
|
|
$to = $this->headers->get("To"); |
|
|
|
|
261
|
|
|
if ($to == "") return array(); |
262
|
|
|
else return (array) $to; |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
/** |
266
|
|
|
* Set the list of recipients in the Reply-To: header |
267
|
|
|
* @param mixed An array or a string |
268
|
|
|
*/ |
269
|
|
View Code Duplication |
public function setReplyTo($replyto) |
|
|
|
|
270
|
|
|
{ |
271
|
|
|
if ($replyto) |
272
|
|
|
{ |
273
|
|
|
if (!is_array($replyto)) $replyto = array($replyto); |
274
|
|
|
foreach ($replyto as $key => $value) |
275
|
|
|
{ |
276
|
|
|
if ($value instanceof Swift_Address) $replyto[$key] = $value->build(); |
277
|
|
|
} |
278
|
|
|
} |
279
|
|
|
$this->headers->set("Reply-To", $replyto); |
280
|
|
|
} |
281
|
|
|
/** |
282
|
|
|
* Return the list of recipients in the Reply-To: header |
283
|
|
|
* @return array |
|
|
|
|
284
|
|
|
*/ |
285
|
|
|
public function getReplyTo() |
286
|
|
|
{ |
287
|
|
|
if ($this->headers->has("Reply-To")) |
288
|
|
|
{ |
289
|
|
|
$reply_to = $this->headers->get("Reply-To"); |
290
|
|
|
if ($reply_to == "") return array(); |
291
|
|
|
else return (array) $reply_to; |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
/** |
295
|
|
|
* Set the list of recipients in the Cc: header |
296
|
|
|
* @param mixed An array or a string |
297
|
|
|
*/ |
298
|
|
View Code Duplication |
public function setCc($cc) |
|
|
|
|
299
|
|
|
{ |
300
|
|
|
if ($cc) |
301
|
|
|
{ |
302
|
|
|
if (!is_array($cc)) $cc = array($cc); |
303
|
|
|
foreach ($cc as $key => $value) |
304
|
|
|
{ |
305
|
|
|
if ($value instanceof Swift_Address) $cc[$key] = $value->build(); |
306
|
|
|
} |
307
|
|
|
} |
308
|
|
|
$this->headers->set("Cc", $cc); |
309
|
|
|
} |
310
|
|
|
/** |
311
|
|
|
* Return the list of recipients in the Cc: header |
312
|
|
|
* @return array |
|
|
|
|
313
|
|
|
*/ |
314
|
|
View Code Duplication |
public function getCc() |
|
|
|
|
315
|
|
|
{ |
316
|
|
|
if ($this->headers->has("Cc")) |
317
|
|
|
{ |
318
|
|
|
$cc = $this->headers->get("Cc"); |
|
|
|
|
319
|
|
|
if ($cc == "") return array(); |
320
|
|
|
else return (array) $cc; |
321
|
|
|
} |
322
|
|
|
} |
323
|
|
|
/** |
324
|
|
|
* Set the list of recipients in the Bcc: header |
325
|
|
|
* @param mixed An array or a string |
326
|
|
|
*/ |
327
|
|
View Code Duplication |
public function setBcc($bcc) |
|
|
|
|
328
|
|
|
{ |
329
|
|
|
if ($bcc) |
330
|
|
|
{ |
331
|
|
|
if (!is_array($bcc)) $bcc = array($bcc); |
332
|
|
|
foreach ($bcc as $key => $value) |
333
|
|
|
{ |
334
|
|
|
if ($value instanceof Swift_Address) $bcc[$key] = $value->build(); |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
$this->headers->set("Bcc", $bcc); |
338
|
|
|
} |
339
|
|
|
/** |
340
|
|
|
* Return the list of recipients in the Bcc: header |
341
|
|
|
* @return array |
|
|
|
|
342
|
|
|
*/ |
343
|
|
View Code Duplication |
public function getBcc() |
|
|
|
|
344
|
|
|
{ |
345
|
|
|
if ($this->headers->has("Bcc")) |
346
|
|
|
{ |
347
|
|
|
$bcc = $this->headers->get("Bcc"); |
348
|
|
|
if ($bcc == "") return array(); |
349
|
|
|
else return (array) $bcc; |
350
|
|
|
} |
351
|
|
|
} |
352
|
|
|
/** |
353
|
|
|
* Set the subject in the headers |
354
|
|
|
* @param string The subject of the email |
355
|
|
|
*/ |
356
|
|
|
public function setSubject($subject) |
357
|
|
|
{ |
358
|
|
|
$this->headers->set("Subject", $subject); |
359
|
|
|
} |
360
|
|
|
/** |
361
|
|
|
* Get the current subject used in the headers |
362
|
|
|
* @return string |
363
|
|
|
*/ |
364
|
|
|
public function getSubject() |
365
|
|
|
{ |
366
|
|
|
return $this->headers->get("Subject"); |
367
|
|
|
} |
368
|
|
|
/** |
369
|
|
|
* Set the date in the headers in RFC 2822 format |
370
|
|
|
* @param int The time as a UNIX timestamp |
371
|
|
|
* @param integer $date |
372
|
|
|
*/ |
373
|
|
|
public function setDate($date) |
374
|
|
|
{ |
375
|
|
|
$this->headers->set("Date", date("r", $date)); |
376
|
|
|
} |
377
|
|
|
/** |
378
|
|
|
* Get the date as it looks in the headers |
379
|
|
|
* @return integer |
380
|
|
|
*/ |
381
|
|
|
public function getDate() |
382
|
|
|
{ |
383
|
|
|
return strtotime($this->headers->get("Date")); |
384
|
|
|
} |
385
|
|
|
/** |
386
|
|
|
* Set the charset of the document |
387
|
|
|
* @param string The charset used |
388
|
|
|
*/ |
389
|
|
|
public function setCharset($charset) |
390
|
|
|
{ |
391
|
|
|
$this->headers->setAttribute("Content-Type", "charset", $charset); |
392
|
|
View Code Duplication |
if (($this->getEncoding() == "7bit") && (strtolower($charset) == "utf-8" || strtolower($charset) == "utf8")) $this->setEncoding("8bit"); |
|
|
|
|
393
|
|
|
} |
394
|
|
|
/** |
395
|
|
|
* Get the charset used in the document |
396
|
|
|
* Returns null if none is set |
397
|
|
|
* @return string |
|
|
|
|
398
|
|
|
*/ |
399
|
|
|
public function getCharset() |
400
|
|
|
{ |
401
|
|
|
if ($this->headers->hasAttribute("Content-Type", "charset")) |
402
|
|
|
{ |
403
|
|
|
return $this->headers->getAttribute("Content-Type", "charset"); |
404
|
|
|
} |
405
|
|
|
else |
406
|
|
|
{ |
407
|
|
|
return null; |
408
|
|
|
} |
409
|
|
|
} |
410
|
|
|
/** |
411
|
|
|
* Set the "format" attribute to flowed |
412
|
|
|
* @param boolean On or Off |
413
|
|
|
*/ |
414
|
|
|
public function setFlowed($flowed=true) |
415
|
|
|
{ |
416
|
|
|
$value = null; |
417
|
|
|
if ($flowed) $value = "flowed"; |
418
|
|
|
$this->headers->setAttribute("Content-Type", "format", $value); |
419
|
|
|
} |
420
|
|
|
/** |
421
|
|
|
* Check if the message format is set as flowed |
422
|
|
|
* @return boolean |
423
|
|
|
*/ |
424
|
|
View Code Duplication |
public function isFlowed() |
|
|
|
|
425
|
|
|
{ |
426
|
|
|
if ($this->headers->hasAttribute("Content-Type", "format") |
|
|
|
|
427
|
|
|
&& $this->headers->getAttribute("Content-Type", "format") == "flowed") |
428
|
|
|
{ |
429
|
|
|
return true; |
430
|
|
|
} |
431
|
|
|
else return false; |
432
|
|
|
} |
433
|
|
|
/** |
434
|
|
|
* Set the message prioirty in the mail client (don't rely on this) |
435
|
|
|
* @param int The priority as a value between 1 (high) and 5 (low) |
436
|
|
|
*/ |
437
|
|
|
public function setPriority($priority) |
438
|
|
|
{ |
439
|
|
|
$priority = (int) $priority; |
440
|
|
|
if ($priority > self::PRIORITY_LOW) $priority = self::PRIORITY_LOW; |
441
|
|
|
if ($priority < self::PRIORITY_HIGH) $priority = self::PRIORITY_HIGH; |
442
|
|
|
$label = array(1 => "High", 2 => "High", 3 => "Normal", 4 => "Low", 5 => "Low"); |
443
|
|
|
$this->headers->set("X-Priority", $priority); |
444
|
|
|
$this->headers->set("X-MSMail-Priority", $label[$priority]); |
445
|
|
|
$this->headers->set("X-MimeOLE", "Produced by SwiftMailer " . $this->libVersion); |
446
|
|
|
} |
447
|
|
|
/** |
448
|
|
|
* Request that the client send back a read-receipt (don't rely on this!) |
449
|
|
|
* @param string Request address |
450
|
|
|
*/ |
451
|
|
|
public function requestReadReceipt($request) |
452
|
|
|
{ |
453
|
|
|
if ($request instanceof Swift_Address) $request = $request->build(); |
454
|
|
|
if (!$request) |
455
|
|
|
{ |
456
|
|
|
$this->headers->set("Disposition-Notification-To", null); |
457
|
|
|
$this->headers->set("X-Confirm-Reading-To", null); |
458
|
|
|
$this->headers->set("Return-Receipt-To", null); |
459
|
|
|
} |
460
|
|
|
else |
461
|
|
|
{ |
462
|
|
|
$this->headers->set("Disposition-Notification-To", $request); |
463
|
|
|
$this->headers->set("X-Confirm-Reading-To", $request); |
464
|
|
|
$this->headers->set("Return-Receipt-To", $request); |
465
|
|
|
} |
466
|
|
|
} |
467
|
|
|
/** |
468
|
|
|
* Check if a read receipt has been requested for this message |
469
|
|
|
* @return boolean |
470
|
|
|
*/ |
471
|
|
|
public function wantsReadReceipt() |
472
|
|
|
{ |
473
|
|
|
return $this->headers->has("Disposition-Notification-To"); |
474
|
|
|
} |
475
|
|
|
/** |
476
|
|
|
* Get the current message priority |
477
|
|
|
* Returns NULL if none set |
478
|
|
|
* @return string|null |
479
|
|
|
*/ |
480
|
|
|
public function getPriority() |
481
|
|
|
{ |
482
|
|
|
if ($this->headers->has("X-Priority")) return $this->headers->get("X-Priority"); |
483
|
|
|
else return null; |
484
|
|
|
} |
485
|
|
|
/** |
486
|
|
|
* Alias for setData() |
487
|
|
|
* @param mixed Body |
488
|
|
|
*/ |
489
|
|
|
public function setBody($body) |
490
|
|
|
{ |
491
|
|
|
$this->setData($body); |
492
|
|
|
} |
493
|
|
|
/** |
494
|
|
|
* Alias for getData() |
495
|
|
|
* @return string The document body |
496
|
|
|
*/ |
497
|
|
|
public function getBody() |
498
|
|
|
{ |
499
|
|
|
return $this->getData(); |
500
|
|
|
} |
501
|
|
|
/** |
502
|
|
|
* Set the MIME warning message which is displayed to old clients |
503
|
|
|
* @var string The full warning message (in 7bit ascii) |
504
|
|
|
*/ |
505
|
|
|
public function setMimeWarning($text) |
506
|
|
|
{ |
507
|
|
|
$this->mimeWarning = (string) $text; |
508
|
|
|
} |
509
|
|
|
/** |
510
|
|
|
* Get the MIME warning which is displayed to old clients |
511
|
|
|
* @return string |
512
|
|
|
*/ |
513
|
|
|
public function getMimeWarning() |
514
|
|
|
{ |
515
|
|
|
return $this->mimeWarning; |
516
|
|
|
} |
517
|
|
|
/** |
518
|
|
|
* Attach a mime part or an attachment of some sort |
519
|
|
|
* Any descendant of Swift_Message_Mime can be added safely (including other Swift_Message objects for mail forwarding!!) |
520
|
|
|
* @param Swift_Message_Mime The document to attach |
521
|
|
|
* @param string An identifier to use (one is returned otherwise) |
522
|
|
|
* @return string The identifier for the part |
523
|
|
|
*/ |
524
|
|
|
public function attach(Swift_Message_Mime $child, $id=null) |
525
|
|
|
{ |
526
|
|
|
try { |
527
|
|
|
switch ($child->getLevel()) |
528
|
|
|
{ |
529
|
|
View Code Duplication |
case Swift_Message_Mime::LEVEL_ALTERNATIVE: |
|
|
|
|
530
|
|
|
$sign = (strtolower($child->getContentType()) == "text/plain") ? -1 : 1; |
531
|
|
|
$id = $this->getReference("parent", "alternative")->addChild($child, $id, $sign); |
532
|
|
|
$this->setReference("alternative", $id, $child); |
533
|
|
|
break; |
534
|
|
View Code Duplication |
case Swift_Message_Mime::LEVEL_RELATED: |
|
|
|
|
535
|
|
|
$id = "cid:" . $child->getContentId(); |
|
|
|
|
536
|
|
|
$id = $this->getReference("parent", "related")->addChild($child, $id, 1); |
537
|
|
|
$this->setReference("related", $id, $child); |
538
|
|
|
break; |
539
|
|
|
case Swift_Message_Mime::LEVEL_MIXED: default: |
540
|
|
|
$id = $this->getReference("parent", "mixed")->addChild($child, $id, 1); |
541
|
|
|
$this->setReference("mixed", $id, $child); |
542
|
|
|
break; |
543
|
|
|
} |
544
|
|
|
$this->postAttachFixStructure(); |
545
|
|
|
$this->fixContentType(); |
546
|
|
|
return $id; |
547
|
|
|
} catch (Swift_Message_MimeException $e) { |
548
|
|
|
throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during an attach(). " . |
549
|
|
|
"The MIME component threw an exception:<br />" . $e->getMessage()); |
550
|
|
|
} |
551
|
|
|
} |
552
|
|
|
/** |
553
|
|
|
* Remove a nested MIME part |
554
|
|
|
* @param string The ID of the attached part |
555
|
|
|
* @throws Swift_Message_MimeException If no such part exists |
556
|
|
|
*/ |
557
|
|
|
public function detach($id) |
558
|
|
|
{ |
559
|
|
|
try { |
560
|
|
|
switch (true) |
561
|
|
|
{ |
562
|
|
View Code Duplication |
case array_key_exists($id, $this->references["alternative"]): |
|
|
|
|
563
|
|
|
$this->getReference("parent", "alternative")->removeChild($id); |
564
|
|
|
unset($this->references["alternative"][$id]); |
565
|
|
|
break; |
566
|
|
View Code Duplication |
case array_key_exists($id, $this->references["related"]): |
|
|
|
|
567
|
|
|
$this->getReference("parent", "related")->removeChild($id); |
568
|
|
|
unset($this->references["related"][$id]); |
569
|
|
|
break; |
570
|
|
View Code Duplication |
case array_key_exists($id, $this->references["mixed"]): |
|
|
|
|
571
|
|
|
$this->getReference("parent", "mixed")->removeChild($id); |
572
|
|
|
unset($this->references["mixed"][$id]); |
573
|
|
|
break; |
574
|
|
|
default: |
575
|
|
|
throw new Swift_Message_MimeException("Unable to detach part identified by ID '" . $id . "' since it's not registered."); |
576
|
|
|
break; |
|
|
|
|
577
|
|
|
} |
578
|
|
|
$this->postDetachFixStructure(); |
579
|
|
|
$this->fixContentType(); |
580
|
|
|
} catch (Swift_Message_MimeException $e) { |
581
|
|
|
throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during a detach(). " . |
582
|
|
|
"The MIME component threw an exception:<br />" . $e->getMessage()); |
583
|
|
|
} |
584
|
|
|
} |
585
|
|
|
/** |
586
|
|
|
* Sets the correct content type header by looking at what types of data we have set |
587
|
|
|
*/ |
588
|
|
|
protected function fixContentType() |
589
|
|
|
{ |
590
|
|
|
if (!empty($this->references["mixed"])) $this->setContentType("multipart/mixed"); |
591
|
|
|
elseif (!empty($this->references["related"])) $this->setContentType("multipart/related"); |
592
|
|
|
elseif (!empty($this->references["alternative"])) $this->setContentType("multipart/alternative"); |
593
|
|
|
} |
594
|
|
|
/** |
595
|
|
|
* Move a branch of the tree, containing all it's MIME parts onto another branch |
596
|
|
|
* @param string The content type on the branch itself |
597
|
|
|
* @param string The content type which may exist in the branch's parent |
598
|
|
|
* @param array The array containing all the nodes presently |
599
|
|
|
* @param string The location of the branch now |
600
|
|
|
* @param string The location of the branch after moving |
601
|
|
|
* @param string The key to identify the branch by in it's new location |
602
|
|
|
* @param string $type |
603
|
|
|
* @param string|null $nested_type |
604
|
|
|
* @param string $old_branch |
605
|
|
|
* @param string $new_branch |
606
|
|
|
* @param string $tag |
607
|
|
|
*/ |
608
|
|
|
protected function moveBranchIn($type, $nested_type, $from, $old_branch, $new_branch, $tag) |
609
|
|
|
{ |
610
|
|
|
$new = new Swift_Message_Part(); |
611
|
|
|
$new->setContentType($type); |
612
|
|
|
$this->getReference("parent", $new_branch)->addChild($new, $tag, -1); |
613
|
|
|
|
614
|
|
|
switch ($new_branch) |
615
|
|
|
{ |
616
|
|
|
case "related": $this->setReference("related", $tag, $new);//relatedRefs[$tag] = $new; |
617
|
|
|
break; |
618
|
|
|
case "mixed": $this->setReference("mixed", $tag, $new);//mixedRefs[$tag] = $new; |
619
|
|
|
break; |
620
|
|
|
} |
621
|
|
|
|
622
|
|
|
foreach ($from as $id => $ref) |
623
|
|
|
{ |
624
|
|
|
if (!$ref) $ref = $this; |
625
|
|
|
$sign = (strtolower($ref->getContentType()) == "text/plain" |
626
|
|
|
|| strtolower($ref->getContentType()) == $nested_type) ? -1 : 1; |
627
|
|
|
switch ($new_branch) |
628
|
|
|
{ |
629
|
|
|
case "related": $this->getReference("related", $tag)->addChild($ref, $id, $sign); |
630
|
|
|
break; |
631
|
|
|
case "mixed": $this->getReference("mixed", $tag)->addChild($ref, $id, $sign); |
632
|
|
|
break; |
633
|
|
|
} |
634
|
|
|
$this->getReference("parent", $old_branch)->removeChild($id); |
635
|
|
|
} |
636
|
|
|
$this->setReference("parent", $old_branch, $new); //parentRefs[$old_branch] = $new; |
637
|
|
|
} |
638
|
|
|
/** |
639
|
|
|
* Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed |
640
|
|
|
* It looks complicated and long winded but the concept is pretty simple, even if putting it |
641
|
|
|
* in code does me make want to cry! |
642
|
|
|
*/ |
643
|
|
|
protected function postAttachFixStructure() |
644
|
|
|
{ |
645
|
|
|
switch (true) |
646
|
|
|
{ |
647
|
|
|
case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])): |
648
|
|
|
if (!isset($this->references["related"]["_alternative"])) |
649
|
|
|
{ |
650
|
|
|
$this->moveBranchIn( |
651
|
|
|
"multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative"); |
652
|
|
|
} |
653
|
|
|
if (!isset($this->references["mixed"]["_related"])) |
654
|
|
|
{ |
655
|
|
|
$this->moveBranchIn( |
656
|
|
|
"multipart/related", "multipart/alternative", $this->references["related"], "related", "mixed", "_related"); |
657
|
|
|
} |
658
|
|
|
break; |
659
|
|
|
case (!empty($this->references["mixed"]) && !empty($this->references["related"])): |
660
|
|
|
if (!isset($this->references["mixed"]["_related"])) |
661
|
|
|
{ |
662
|
|
|
$this->moveBranchIn( |
663
|
|
|
"multipart/related", "multipart/related", $this->references["related"], "related", "mixed", "_related"); |
664
|
|
|
} |
665
|
|
|
break; |
666
|
|
View Code Duplication |
case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])): |
|
|
|
|
667
|
|
|
if (!isset($this->references["mixed"]["_alternative"])) |
668
|
|
|
{ |
669
|
|
|
$this->moveBranchIn( |
670
|
|
|
"multipart/alternative", null, $this->references["alternative"], "alternative", "mixed", "_alternative"); |
671
|
|
|
} |
672
|
|
|
break; |
673
|
|
|
case (!empty($this->references["related"]) && !empty($this->references["alternative"])): |
674
|
|
|
if (!isset($this->references["related"]["_alternative"])) |
675
|
|
|
{ |
676
|
|
|
$this->moveBranchIn( |
677
|
|
|
"multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative"); |
678
|
|
|
} |
679
|
|
|
break; |
680
|
|
|
} |
681
|
|
|
} |
682
|
|
|
/** |
683
|
|
|
* Move a branch further toward the top of the tree |
684
|
|
|
* @param array The array containing MIME parts from the old branch |
685
|
|
|
* @param string The name of the old branch |
686
|
|
|
* @param string The name of the new branch |
687
|
|
|
* @param string The key of the branch being moved |
688
|
|
|
* @param string $old_branch |
689
|
|
|
* @param string $new_branch |
690
|
|
|
* @param string $tag |
691
|
|
|
*/ |
692
|
|
|
protected function moveBranchOut($from, $old_branch, $new_branch, $tag) |
693
|
|
|
{ |
694
|
|
|
foreach ($from as $id => $ref) |
695
|
|
|
{ |
696
|
|
|
if (!$ref) $ref = $this; |
697
|
|
|
$sign = (strtolower($ref->getContentType()) == "text/html" |
698
|
|
|
|| strtolower($ref->getContentType()) == "multipart/alternative") ? -1 : 1; |
699
|
|
|
$this->getReference("parent", $new_branch)->addChild($ref, $id, $sign); |
700
|
|
|
switch ($new_branch) |
701
|
|
|
{ |
702
|
|
|
case "related": $this->getReference("related", $tag)->removeChild($id); |
703
|
|
|
break; |
704
|
|
|
case "mixed": $this->getReference("parent", $old_branch)->removeChild($id); |
705
|
|
|
break; |
706
|
|
|
} |
707
|
|
|
} |
708
|
|
|
$this->getReference("parent", $new_branch)->removeChild($tag); |
709
|
|
|
$mixed = $this->getReference("parent", $new_branch);//parentRefs[$new_branch]; |
710
|
|
|
$this->setReference("parent", $old_branch, $mixed);//parentRefs[$old_branch] = $mixed; |
711
|
|
|
switch ($new_branch) |
712
|
|
|
{ |
713
|
|
|
case "related": unset($this->references["related"][$tag]); |
714
|
|
|
break; |
715
|
|
|
case "mixed": unset($this->references["mixed"][$tag]); |
716
|
|
|
break; |
717
|
|
|
} |
718
|
|
|
} |
719
|
|
|
/** |
720
|
|
|
* Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed |
721
|
|
|
* It looks complicated and long winded but the concept is pretty simple, even if putting it |
722
|
|
|
* in code does me make want to cry! |
723
|
|
|
*/ |
724
|
|
|
protected function postDetachFixStructure() |
725
|
|
|
{ |
726
|
|
|
switch (true) |
727
|
|
|
{ |
728
|
|
|
case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])): |
729
|
|
|
if (array_keys($this->references["related"]) == array("_alternative")) |
730
|
|
|
{ |
731
|
|
|
$alt = $this->getReference("parent", "related")->getChild("_alternative"); |
732
|
|
|
$this->getReference("parent", "mixed")->addChild($alt, "_alternative", -1); |
733
|
|
|
$this->setReference("mixed", "_alternative", $alt);//mixedRefs["_alternative"] = $alt; |
734
|
|
|
$this->getReference("parent", "related")->removeChild("_alternative"); |
735
|
|
|
unset($this->references["related"]["_alternative"]); |
736
|
|
|
$this->getReference("parent", "mixed")->removeChild("_related"); |
737
|
|
|
unset($this->references["mixed"]["_related"]); |
738
|
|
|
} |
739
|
|
View Code Duplication |
if (array_keys($this->references["mixed"]) == array("_related")) |
|
|
|
|
740
|
|
|
{ |
741
|
|
|
$this->moveBranchOut($this->references["related"], "related", "mixed", "_related"); |
742
|
|
|
} |
743
|
|
|
break; |
744
|
|
|
case (!empty($this->references["mixed"]) && !empty($this->references["related"])): |
745
|
|
View Code Duplication |
if (array_keys($this->references["mixed"]) == array("_related")) |
|
|
|
|
746
|
|
|
{ |
747
|
|
|
$this->moveBranchOut($this->references["related"], "related", "mixed", "_related"); |
748
|
|
|
} |
749
|
|
|
if (isset($this->references["related"]["_alternative"])) |
750
|
|
|
{ |
751
|
|
|
$this->detach("_alternative"); |
752
|
|
|
} |
753
|
|
|
break; |
754
|
|
View Code Duplication |
case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])): |
|
|
|
|
755
|
|
|
if (array_keys($this->references["mixed"]) == array("_alternative")) |
756
|
|
|
{ |
757
|
|
|
$this->moveBranchOut($this->references["alternative"], "alternative", "mixed", "_alternative"); |
758
|
|
|
} |
759
|
|
|
break; |
760
|
|
View Code Duplication |
case (!empty($this->references["related"]) && !empty($this->references["alternative"])): |
|
|
|
|
761
|
|
|
if (array_keys($this->references["related"]) == array("_alternative")) |
762
|
|
|
{ |
763
|
|
|
$this->moveBranchOut($this->references["alternative"], "alternative", "related", "_alternative"); |
764
|
|
|
} |
765
|
|
|
break; |
766
|
|
|
case (!empty($this->references["mixed"])): |
767
|
|
|
if (isset($this->references["mixed"]["_related"])) $this->detach("_related"); |
768
|
|
|
case (!empty($this->references["related"])): |
769
|
|
|
if (isset($this->references["related"]["_alternative"]) || isset($this->references["mixed"]["_alternative"])) |
770
|
|
|
$this->detach("_alternative"); |
771
|
|
|
break; |
772
|
|
|
} |
773
|
|
|
} |
774
|
|
|
/** |
775
|
|
|
* Execute needed logic prior to compilation |
776
|
|
|
*/ |
777
|
|
|
public function preBuild() |
778
|
|
|
{ |
779
|
|
|
$data = $this->getData(); |
780
|
|
|
if (!($enc = $this->getEncoding())) |
781
|
|
|
{ |
782
|
|
|
$this->setEncoding("8bit"); |
783
|
|
|
} |
784
|
|
|
if ($this->getCharset() === null && !$this->numChildren()) |
785
|
|
|
{ |
786
|
|
|
Swift_ClassLoader::load("Swift_Message_Encoder"); |
787
|
|
View Code Duplication |
if (is_string($data) && Swift_Message_Encoder::instance()->isUTF8($data)) |
|
|
|
|
788
|
|
|
{ |
789
|
|
|
$this->setCharset("utf-8"); |
790
|
|
|
} |
791
|
|
|
elseif(is_string($data) && Swift_Message_Encoder::instance()->is7BitAscii($data)) |
792
|
|
|
{ |
793
|
|
|
$this->setCharset("us-ascii"); |
794
|
|
|
if (!$enc) $this->setEncoding("7bit"); |
|
|
|
|
795
|
|
|
} |
796
|
|
|
else $this->setCharset("iso-8859-1"); |
797
|
|
|
} |
798
|
|
|
elseif ($this->numChildren()) |
799
|
|
|
{ |
800
|
|
|
if (!$this->getData()) |
801
|
|
|
{ |
802
|
|
|
$this->setData($this->getMimeWarning()); |
803
|
|
|
$this->setLineWrap(76); |
804
|
|
|
} |
805
|
|
|
|
806
|
|
|
if ($this->getCharset() !== null) $this->setCharset(null); |
807
|
|
|
if ($this->isFlowed()) $this->setFlowed(false); |
808
|
|
|
$this->setEncoding("7bit"); |
809
|
|
|
} |
810
|
|
|
} |
811
|
|
|
} |
812
|
|
|
|
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.