|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Mail |
|
17 * @subpackage Transport |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Abstract.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 |
|
24 /** |
|
25 * @see Zend_Mime |
|
26 */ |
|
27 require_once 'Zend/Mime.php'; |
|
28 |
|
29 |
|
30 /** |
|
31 * Abstract for sending eMails through different |
|
32 * ways of transport |
|
33 * |
|
34 * @category Zend |
|
35 * @package Zend_Mail |
|
36 * @subpackage Transport |
|
37 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
38 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
39 */ |
|
40 abstract class Zend_Mail_Transport_Abstract |
|
41 { |
|
42 /** |
|
43 * Mail body |
|
44 * @var string |
|
45 * @access public |
|
46 */ |
|
47 public $body = ''; |
|
48 |
|
49 /** |
|
50 * MIME boundary |
|
51 * @var string |
|
52 * @access public |
|
53 */ |
|
54 public $boundary = ''; |
|
55 |
|
56 /** |
|
57 * Mail header string |
|
58 * @var string |
|
59 * @access public |
|
60 */ |
|
61 public $header = ''; |
|
62 |
|
63 /** |
|
64 * Array of message headers |
|
65 * @var array |
|
66 * @access protected |
|
67 */ |
|
68 protected $_headers = array(); |
|
69 |
|
70 /** |
|
71 * Message is a multipart message |
|
72 * @var boolean |
|
73 * @access protected |
|
74 */ |
|
75 protected $_isMultipart = false; |
|
76 |
|
77 /** |
|
78 * Zend_Mail object |
|
79 * @var false|Zend_Mail |
|
80 * @access protected |
|
81 */ |
|
82 protected $_mail = false; |
|
83 |
|
84 /** |
|
85 * Array of message parts |
|
86 * @var array |
|
87 * @access protected |
|
88 */ |
|
89 protected $_parts = array(); |
|
90 |
|
91 /** |
|
92 * Recipients string |
|
93 * @var string |
|
94 * @access public |
|
95 */ |
|
96 public $recipients = ''; |
|
97 |
|
98 /** |
|
99 * EOL character string used by transport |
|
100 * @var string |
|
101 * @access public |
|
102 */ |
|
103 public $EOL = "\r\n"; |
|
104 |
|
105 /** |
|
106 * Send an email independent from the used transport |
|
107 * |
|
108 * The requisite information for the email will be found in the following |
|
109 * properties: |
|
110 * |
|
111 * - {@link $recipients} - list of recipients (string) |
|
112 * - {@link $header} - message header |
|
113 * - {@link $body} - message body |
|
114 */ |
|
115 abstract protected function _sendMail(); |
|
116 |
|
117 /** |
|
118 * Return all mail headers as an array |
|
119 * |
|
120 * If a boundary is given, a multipart header is generated with a |
|
121 * Content-Type of either multipart/alternative or multipart/mixed depending |
|
122 * on the mail parts present in the {@link $_mail Zend_Mail object} present. |
|
123 * |
|
124 * @param string $boundary |
|
125 * @return array |
|
126 */ |
|
127 protected function _getHeaders($boundary) |
|
128 { |
|
129 if (null !== $boundary) { |
|
130 // Build multipart mail |
|
131 $type = $this->_mail->getType(); |
|
132 if (!$type) { |
|
133 if ($this->_mail->hasAttachments) { |
|
134 $type = Zend_Mime::MULTIPART_MIXED; |
|
135 } elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) { |
|
136 $type = Zend_Mime::MULTIPART_ALTERNATIVE; |
|
137 } else { |
|
138 $type = Zend_Mime::MULTIPART_MIXED; |
|
139 } |
|
140 } |
|
141 |
|
142 $this->_headers['Content-Type'] = array( |
|
143 $type . ';' |
|
144 . $this->EOL |
|
145 . " " . 'boundary="' . $boundary . '"' |
|
146 ); |
|
147 $this->boundary = $boundary; |
|
148 } |
|
149 |
|
150 $this->_headers['MIME-Version'] = array('1.0'); |
|
151 |
|
152 return $this->_headers; |
|
153 } |
|
154 |
|
155 /** |
|
156 * Prepend header name to header value |
|
157 * |
|
158 * @param string $item |
|
159 * @param string $key |
|
160 * @param string $prefix |
|
161 * @static |
|
162 * @access protected |
|
163 * @return void |
|
164 */ |
|
165 protected static function _formatHeader(&$item, $key, $prefix) |
|
166 { |
|
167 $item = $prefix . ': ' . $item; |
|
168 } |
|
169 |
|
170 /** |
|
171 * Prepare header string for use in transport |
|
172 * |
|
173 * Prepares and generates {@link $header} based on the headers provided. |
|
174 * |
|
175 * @param mixed $headers |
|
176 * @access protected |
|
177 * @return void |
|
178 * @throws Zend_Mail_Transport_Exception if any header lines exceed 998 |
|
179 * characters |
|
180 */ |
|
181 protected function _prepareHeaders($headers) |
|
182 { |
|
183 if (!$this->_mail) { |
|
184 /** |
|
185 * @see Zend_Mail_Transport_Exception |
|
186 */ |
|
187 require_once 'Zend/Mail/Transport/Exception.php'; |
|
188 throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property'); |
|
189 } |
|
190 |
|
191 $this->header = ''; |
|
192 |
|
193 foreach ($headers as $header => $content) { |
|
194 if (isset($content['append'])) { |
|
195 unset($content['append']); |
|
196 $value = implode(',' . $this->EOL . ' ', $content); |
|
197 $this->header .= $header . ': ' . $value . $this->EOL; |
|
198 } else { |
|
199 array_walk($content, array(get_class($this), '_formatHeader'), $header); |
|
200 $this->header .= implode($this->EOL, $content) . $this->EOL; |
|
201 } |
|
202 } |
|
203 |
|
204 // Sanity check on headers -- should not be > 998 characters |
|
205 $sane = true; |
|
206 foreach (explode($this->EOL, $this->header) as $line) { |
|
207 if (strlen(trim($line)) > 998) { |
|
208 $sane = false; |
|
209 break; |
|
210 } |
|
211 } |
|
212 if (!$sane) { |
|
213 /** |
|
214 * @see Zend_Mail_Transport_Exception |
|
215 */ |
|
216 require_once 'Zend/Mail/Transport/Exception.php'; |
|
217 throw new Zend_Mail_Exception('At least one mail header line is too long'); |
|
218 } |
|
219 } |
|
220 |
|
221 /** |
|
222 * Generate MIME compliant message from the current configuration |
|
223 * |
|
224 * If both a text and HTML body are present, generates a |
|
225 * multipart/alternative Zend_Mime_Part containing the headers and contents |
|
226 * of each. Otherwise, uses whichever of the text or HTML parts present. |
|
227 * |
|
228 * The content part is then prepended to the list of Zend_Mime_Parts for |
|
229 * this message. |
|
230 * |
|
231 * @return void |
|
232 */ |
|
233 protected function _buildBody() |
|
234 { |
|
235 if (($text = $this->_mail->getBodyText()) |
|
236 && ($html = $this->_mail->getBodyHtml())) |
|
237 { |
|
238 // Generate unique boundary for multipart/alternative |
|
239 $mime = new Zend_Mime(null); |
|
240 $boundaryLine = $mime->boundaryLine($this->EOL); |
|
241 $boundaryEnd = $mime->mimeEnd($this->EOL); |
|
242 |
|
243 $text->disposition = false; |
|
244 $html->disposition = false; |
|
245 |
|
246 $body = $boundaryLine |
|
247 . $text->getHeaders($this->EOL) |
|
248 . $this->EOL |
|
249 . $text->getContent($this->EOL) |
|
250 . $this->EOL |
|
251 . $boundaryLine |
|
252 . $html->getHeaders($this->EOL) |
|
253 . $this->EOL |
|
254 . $html->getContent($this->EOL) |
|
255 . $this->EOL |
|
256 . $boundaryEnd; |
|
257 |
|
258 $mp = new Zend_Mime_Part($body); |
|
259 $mp->type = Zend_Mime::MULTIPART_ALTERNATIVE; |
|
260 $mp->boundary = $mime->boundary(); |
|
261 |
|
262 $this->_isMultipart = true; |
|
263 |
|
264 // Ensure first part contains text alternatives |
|
265 array_unshift($this->_parts, $mp); |
|
266 |
|
267 // Get headers |
|
268 $this->_headers = $this->_mail->getHeaders(); |
|
269 return; |
|
270 } |
|
271 |
|
272 // If not multipart, then get the body |
|
273 if (false !== ($body = $this->_mail->getBodyHtml())) { |
|
274 array_unshift($this->_parts, $body); |
|
275 } elseif (false !== ($body = $this->_mail->getBodyText())) { |
|
276 array_unshift($this->_parts, $body); |
|
277 } |
|
278 |
|
279 if (!$body) { |
|
280 /** |
|
281 * @see Zend_Mail_Transport_Exception |
|
282 */ |
|
283 require_once 'Zend/Mail/Transport/Exception.php'; |
|
284 throw new Zend_Mail_Transport_Exception('No body specified'); |
|
285 } |
|
286 |
|
287 // Get headers |
|
288 $this->_headers = $this->_mail->getHeaders(); |
|
289 $headers = $body->getHeadersArray($this->EOL); |
|
290 foreach ($headers as $header) { |
|
291 // Headers in Zend_Mime_Part are kept as arrays with two elements, a |
|
292 // key and a value |
|
293 $this->_headers[$header[0]] = array($header[1]); |
|
294 } |
|
295 } |
|
296 |
|
297 /** |
|
298 * Send a mail using this transport |
|
299 * |
|
300 * @param Zend_Mail $mail |
|
301 * @access public |
|
302 * @return void |
|
303 * @throws Zend_Mail_Transport_Exception if mail is empty |
|
304 */ |
|
305 public function send(Zend_Mail $mail) |
|
306 { |
|
307 $this->_isMultipart = false; |
|
308 $this->_mail = $mail; |
|
309 $this->_parts = $mail->getParts(); |
|
310 $mime = $mail->getMime(); |
|
311 |
|
312 // Build body content |
|
313 $this->_buildBody(); |
|
314 |
|
315 // Determine number of parts and boundary |
|
316 $count = count($this->_parts); |
|
317 $boundary = null; |
|
318 if ($count < 1) { |
|
319 /** |
|
320 * @see Zend_Mail_Transport_Exception |
|
321 */ |
|
322 require_once 'Zend/Mail/Transport/Exception.php'; |
|
323 throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent'); |
|
324 } |
|
325 |
|
326 if ($count > 1) { |
|
327 // Multipart message; create new MIME object and boundary |
|
328 $mime = new Zend_Mime($this->_mail->getMimeBoundary()); |
|
329 $boundary = $mime->boundary(); |
|
330 } elseif ($this->_isMultipart) { |
|
331 // multipart/alternative -- grab boundary |
|
332 $boundary = $this->_parts[0]->boundary; |
|
333 } |
|
334 |
|
335 // Determine recipients, and prepare headers |
|
336 $this->recipients = implode(',', $mail->getRecipients()); |
|
337 $this->_prepareHeaders($this->_getHeaders($boundary)); |
|
338 |
|
339 // Create message body |
|
340 // This is done so that the same Zend_Mail object can be used in |
|
341 // multiple transports |
|
342 $message = new Zend_Mime_Message(); |
|
343 $message->setParts($this->_parts); |
|
344 $message->setMime($mime); |
|
345 $this->body = $message->generateMessage($this->EOL); |
|
346 |
|
347 // Send to transport! |
|
348 $this->_sendMail(); |
|
349 } |
|
350 } |