File indexing completed on 2024-12-22 05:36:51

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Mail
0017  * @subpackage Transport
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Mime
0026  */
0027 // require_once 'Zend/Mime.php';
0028 
0029 
0030 /**
0031  * Abstract for sending eMails through different
0032  * ways of transport
0033  *
0034  * @category   Zend
0035  * @package    Zend_Mail
0036  * @subpackage Transport
0037  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0038  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0039  */
0040 abstract class Zend_Mail_Transport_Abstract
0041 {
0042     /**
0043      * Mail body
0044      * @var string
0045      * @access public
0046      */
0047     public $body = '';
0048 
0049     /**
0050      * MIME boundary
0051      * @var string
0052      * @access public
0053      */
0054     public $boundary = '';
0055 
0056     /**
0057      * Mail header string
0058      * @var string
0059      * @access public
0060      */
0061     public $header = '';
0062 
0063     /**
0064      * Array of message headers
0065      * @var array
0066      * @access protected
0067      */
0068     protected $_headers = array();
0069 
0070     /**
0071      * Message is a multipart message
0072      * @var boolean
0073      * @access protected
0074      */
0075     protected $_isMultipart = false;
0076 
0077     /**
0078      * Zend_Mail object
0079      * @var false|Zend_Mail
0080      * @access protected
0081      */
0082     protected $_mail = false;
0083 
0084     /**
0085      * Array of message parts
0086      * @var array
0087      * @access protected
0088      */
0089     protected $_parts = array();
0090 
0091     /**
0092      * Recipients string
0093      * @var string
0094      * @access public
0095      */
0096     public $recipients = '';
0097 
0098     /**
0099      * EOL character string used by transport
0100      * @var string
0101      * @access public
0102      */
0103     public $EOL = "\r\n";
0104 
0105     /**
0106      * Send an email independent from the used transport
0107      *
0108      * The requisite information for the email will be found in the following
0109      * properties:
0110      *
0111      * - {@link $recipients} - list of recipients (string)
0112      * - {@link $header} - message header
0113      * - {@link $body} - message body
0114      */
0115     abstract protected function _sendMail();
0116 
0117     /**
0118      * Return all mail headers as an array
0119      *
0120      * If a boundary is given, a multipart header is generated with a
0121      * Content-Type of either multipart/alternative or multipart/mixed depending
0122      * on the mail parts present in the {@link $_mail Zend_Mail object} present.
0123      *
0124      * @param string $boundary
0125      * @return array
0126      */
0127     protected function _getHeaders($boundary)
0128     {
0129         if (null !== $boundary) {
0130             // Build multipart mail
0131             $type = $this->_mail->getType();
0132             if (!$type) {
0133                 if ($this->_mail->hasAttachments) {
0134                     $type = Zend_Mime::MULTIPART_MIXED;
0135                 } elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) {
0136                     $type = Zend_Mime::MULTIPART_ALTERNATIVE;
0137                 } else {
0138                     $type = Zend_Mime::MULTIPART_MIXED;
0139                 }
0140             }
0141 
0142             $this->_headers['Content-Type'] = array(
0143                 $type . ';'
0144                 . $this->EOL
0145                 . " " . 'boundary="' . $boundary . '"'
0146             );
0147             $this->boundary = $boundary;
0148         }
0149 
0150         $this->_headers['MIME-Version'] = array('1.0');
0151 
0152         return $this->_headers;
0153     }
0154 
0155     /**
0156      * Prepend header name to header value
0157      *
0158      * @param string $item
0159      * @param string $key
0160      * @param string $prefix
0161      * @static
0162      * @access protected
0163      * @return void
0164      */
0165     protected static function _formatHeader(&$item, $key, $prefix)
0166     {
0167         $item = $prefix . ': ' . $item;
0168     }
0169 
0170     /**
0171      * Prepare header string for use in transport
0172      *
0173      * Prepares and generates {@link $header} based on the headers provided.
0174      *
0175      * @param mixed $headers
0176      * @access protected
0177      * @return void
0178      * @throws Zend_Mail_Transport_Exception if any header lines exceed 998
0179      * characters
0180      */
0181     protected function _prepareHeaders($headers)
0182     {
0183         if (!$this->_mail) {
0184             /**
0185              * @see Zend_Mail_Transport_Exception
0186              */
0187             // require_once 'Zend/Mail/Transport/Exception.php';
0188             throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property');
0189         }
0190 
0191         $this->header = '';
0192 
0193         foreach ($headers as $header => $content) {
0194             if (isset($content['append'])) {
0195                 unset($content['append']);
0196                 $value = implode(',' . $this->EOL . ' ', $content);
0197                 $this->header .= $header . ': ' . $value . $this->EOL;
0198             } else {
0199                 array_walk($content, array(get_class($this), '_formatHeader'), $header);
0200                 $this->header .= implode($this->EOL, $content) . $this->EOL;
0201             }
0202         }
0203 
0204         // Sanity check on headers -- should not be > 998 characters
0205         $sane = true;
0206         foreach (explode($this->EOL, $this->header) as $line) {
0207             if (strlen(trim($line)) > 998) {
0208                 $sane = false;
0209                 break;
0210             }
0211         }
0212         if (!$sane) {
0213             /**
0214              * @see Zend_Mail_Transport_Exception
0215              */
0216             // require_once 'Zend/Mail/Transport/Exception.php';
0217             throw new Zend_Mail_Exception('At least one mail header line is too long');
0218         }
0219     }
0220 
0221     /**
0222      * Generate MIME compliant message from the current configuration
0223      *
0224      * If both a text and HTML body are present, generates a
0225      * multipart/alternative Zend_Mime_Part containing the headers and contents
0226      * of each. Otherwise, uses whichever of the text or HTML parts present.
0227      *
0228      * The content part is then prepended to the list of Zend_Mime_Parts for
0229      * this message.
0230      *
0231      * @return void
0232      */
0233     protected function _buildBody()
0234     {
0235         if (($text = $this->_mail->getBodyText())
0236             && ($html = $this->_mail->getBodyHtml()))
0237         {
0238             // Generate unique boundary for multipart/alternative
0239             $mime = new Zend_Mime(null);
0240             $boundaryLine = $mime->boundaryLine($this->EOL);
0241             $boundaryEnd  = $mime->mimeEnd($this->EOL);
0242 
0243             $text->disposition = false;
0244             $html->disposition = false;
0245 
0246             $body = $boundaryLine
0247                   . $text->getHeaders($this->EOL)
0248                   . $this->EOL
0249                   . $text->getContent($this->EOL)
0250                   . $this->EOL
0251                   . $boundaryLine
0252                   . $html->getHeaders($this->EOL)
0253                   . $this->EOL
0254                   . $html->getContent($this->EOL)
0255                   . $this->EOL
0256                   . $boundaryEnd;
0257 
0258             $mp           = new Zend_Mime_Part($body);
0259             $mp->type     = Zend_Mime::MULTIPART_ALTERNATIVE;
0260             $mp->boundary = $mime->boundary();
0261 
0262             $this->_isMultipart = true;
0263 
0264             // Ensure first part contains text alternatives
0265             array_unshift($this->_parts, $mp);
0266 
0267             // Get headers
0268             $this->_headers = $this->_mail->getHeaders();
0269             return;
0270         }
0271 
0272         // If not multipart, then get the body
0273         if (false !== ($body = $this->_mail->getBodyHtml())) {
0274             array_unshift($this->_parts, $body);
0275         } elseif (false !== ($body = $this->_mail->getBodyText())) {
0276             array_unshift($this->_parts, $body);
0277         }
0278 
0279         if (!$body) {
0280             /**
0281              * @see Zend_Mail_Transport_Exception
0282              */
0283             // require_once 'Zend/Mail/Transport/Exception.php';
0284             throw new Zend_Mail_Transport_Exception('No body specified');
0285         }
0286 
0287         // Get headers
0288         $this->_headers = $this->_mail->getHeaders();
0289         $headers = $body->getHeadersArray($this->EOL);
0290         foreach ($headers as $header) {
0291             // Headers in Zend_Mime_Part are kept as arrays with two elements, a
0292             // key and a value
0293             $this->_headers[$header[0]] = array($header[1]);
0294         }
0295     }
0296 
0297     /**
0298      * Send a mail using this transport
0299      *
0300      * @param  Zend_Mail $mail
0301      * @access public
0302      * @return void
0303      * @throws Zend_Mail_Transport_Exception if mail is empty
0304      */
0305     public function send(Zend_Mail $mail)
0306     {
0307         $this->_isMultipart = false;
0308         $this->_mail        = $mail;
0309         $this->_parts       = $mail->getParts();
0310         $mime               = $mail->getMime();
0311 
0312         // Build body content
0313         $this->_buildBody();
0314 
0315         // Determine number of parts and boundary
0316         $count    = count($this->_parts);
0317         $boundary = null;
0318         if ($count < 1) {
0319             /**
0320              * @see Zend_Mail_Transport_Exception
0321              */
0322             // require_once 'Zend/Mail/Transport/Exception.php';
0323             throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent');
0324         }
0325 
0326         if ($count > 1) {
0327             // Multipart message; create new MIME object and boundary
0328             $mime     = new Zend_Mime($this->_mail->getMimeBoundary());
0329             $boundary = $mime->boundary();
0330         } elseif ($this->_isMultipart) {
0331             // multipart/alternative -- grab boundary
0332             $boundary = $this->_parts[0]->boundary;
0333         }
0334 
0335         // Determine recipients, and prepare headers
0336         $this->recipients = implode(',', $mail->getRecipients());
0337         $this->_prepareHeaders($this->_getHeaders($boundary));
0338 
0339         // Create message body
0340         // This is done so that the same Zend_Mail object can be used in
0341         // multiple transports
0342         $message = new Zend_Mime_Message();
0343         $message->setParts($this->_parts);
0344         $message->setMime($mime);
0345         $this->body = $message->generateMessage($this->EOL);
0346 
0347         // Send to transport!
0348         $this->_sendMail();
0349     }
0350 }