PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Mail/AbstractTransport.php

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