web/lib/Zend/Mail/Part.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Part.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  */
       
    21 
       
    22 
       
    23 /**
       
    24  * @see Zend_Mime_Decode
       
    25  */
       
    26 require_once 'Zend/Mime/Decode.php';
       
    27 
       
    28 /**
       
    29  * @see Zend_Mail_Part_Interface
       
    30  */
       
    31 require_once 'Zend/Mail/Part/Interface.php';
       
    32 
       
    33 
       
    34 /**
       
    35  * @category   Zend
       
    36  * @package    Zend_Mail
       
    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 class Zend_Mail_Part implements RecursiveIterator, Zend_Mail_Part_Interface
       
    41 {
       
    42     /**
       
    43      * headers of part as array
       
    44      * @var null|array
       
    45      */
       
    46     protected $_headers;
       
    47 
       
    48     /**
       
    49      * raw part body
       
    50      * @var null|string
       
    51      */
       
    52     protected $_content;
       
    53 
       
    54     /**
       
    55      * toplines as fetched with headers
       
    56      * @var string
       
    57      */
       
    58     protected $_topLines = '';
       
    59 
       
    60     /**
       
    61      * parts of multipart message
       
    62      * @var array
       
    63      */
       
    64     protected $_parts = array();
       
    65 
       
    66     /**
       
    67      * count of parts of a multipart message
       
    68      * @var null|int
       
    69      */
       
    70     protected $_countParts;
       
    71 
       
    72     /**
       
    73      * current position of iterator
       
    74      * @var int
       
    75      */
       
    76     protected $_iterationPos = 1;
       
    77 
       
    78     /**
       
    79      * mail handler, if late fetch is active
       
    80      * @var null|Zend_Mail_Storage_Abstract
       
    81      */
       
    82     protected $_mail;
       
    83 
       
    84     /**
       
    85      * message number for mail handler
       
    86      * @var int
       
    87      */
       
    88     protected $_messageNum = 0;
       
    89 
       
    90     /**
       
    91      * Public constructor
       
    92      *
       
    93      * Zend_Mail_Part supports different sources for content. The possible params are:
       
    94      * - handler    a instance of Zend_Mail_Storage_Abstract for late fetch
       
    95      * - id         number of message for handler
       
    96      * - raw        raw content with header and body as string
       
    97      * - headers    headers as array (name => value) or string, if a content part is found it's used as toplines
       
    98      * - noToplines ignore content found after headers in param 'headers'
       
    99      * - content    content as string
       
   100      *
       
   101      * @param   array $params  full message with or without headers
       
   102      * @throws  Zend_Mail_Exception
       
   103      */
       
   104     public function __construct(array $params)
       
   105     {
       
   106         if (isset($params['handler'])) {
       
   107             if (!$params['handler'] instanceof Zend_Mail_Storage_Abstract) {
       
   108                 /**
       
   109                  * @see Zend_Mail_Exception
       
   110                  */
       
   111                 require_once 'Zend/Mail/Exception.php';
       
   112                 throw new Zend_Mail_Exception('handler is not a valid mail handler');
       
   113             }
       
   114             if (!isset($params['id'])) {
       
   115                 /**
       
   116                  * @see Zend_Mail_Exception
       
   117                  */
       
   118                 require_once 'Zend/Mail/Exception.php';
       
   119                 throw new Zend_Mail_Exception('need a message id with a handler');
       
   120             }
       
   121 
       
   122             $this->_mail       = $params['handler'];
       
   123             $this->_messageNum = $params['id'];
       
   124         }
       
   125 
       
   126         if (isset($params['raw'])) {
       
   127             Zend_Mime_Decode::splitMessage($params['raw'], $this->_headers, $this->_content);
       
   128         } else if (isset($params['headers'])) {
       
   129             if (is_array($params['headers'])) {
       
   130                 $this->_headers = $params['headers'];
       
   131             } else {
       
   132                 if (!empty($params['noToplines'])) {
       
   133                     Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $null);
       
   134                 } else {
       
   135                     Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $this->_topLines);
       
   136                 }
       
   137             }
       
   138             if (isset($params['content'])) {
       
   139                 $this->_content = $params['content'];
       
   140             }
       
   141         }
       
   142     }
       
   143 
       
   144     /**
       
   145      * Check if part is a multipart message
       
   146      *
       
   147      * @return bool if part is multipart
       
   148      */
       
   149     public function isMultipart()
       
   150     {
       
   151         try {
       
   152             return stripos($this->contentType, 'multipart/') === 0;
       
   153         } catch(Zend_Mail_Exception $e) {
       
   154             return false;
       
   155         }
       
   156     }
       
   157 
       
   158 
       
   159     /**
       
   160      * Body of part
       
   161      *
       
   162      * If part is multipart the raw content of this part with all sub parts is returned
       
   163      *
       
   164      * @return string body
       
   165      * @throws Zend_Mail_Exception
       
   166      */
       
   167     public function getContent()
       
   168     {
       
   169         if ($this->_content !== null) {
       
   170             return $this->_content;
       
   171         }
       
   172 
       
   173         if ($this->_mail) {
       
   174             return $this->_mail->getRawContent($this->_messageNum);
       
   175         } else {
       
   176             /**
       
   177              * @see Zend_Mail_Exception
       
   178              */
       
   179             require_once 'Zend/Mail/Exception.php';
       
   180             throw new Zend_Mail_Exception('no content');
       
   181         }
       
   182     }
       
   183 
       
   184     /**
       
   185      * Return size of part
       
   186      *
       
   187      * Quite simple implemented currently (not decoding). Handle with care.
       
   188      *
       
   189      * @return int size
       
   190      */
       
   191     public function getSize() {
       
   192         return strlen($this->getContent());
       
   193     }
       
   194 
       
   195 
       
   196     /**
       
   197      * Cache content and split in parts if multipart
       
   198      *
       
   199      * @return null
       
   200      * @throws Zend_Mail_Exception
       
   201      */
       
   202     protected function _cacheContent()
       
   203     {
       
   204         // caching content if we can't fetch parts
       
   205         if ($this->_content === null && $this->_mail) {
       
   206             $this->_content = $this->_mail->getRawContent($this->_messageNum);
       
   207         }
       
   208 
       
   209         if (!$this->isMultipart()) {
       
   210             return;
       
   211         }
       
   212 
       
   213         // split content in parts
       
   214         $boundary = $this->getHeaderField('content-type', 'boundary');
       
   215         if (!$boundary) {
       
   216             /**
       
   217              * @see Zend_Mail_Exception
       
   218              */
       
   219             require_once 'Zend/Mail/Exception.php';
       
   220             throw new Zend_Mail_Exception('no boundary found in content type to split message');
       
   221         }
       
   222         $parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
       
   223         if ($parts === null) {
       
   224             return;
       
   225         }
       
   226         $counter = 1;
       
   227         foreach ($parts as $part) {
       
   228             $this->_parts[$counter++] = new self(array('headers' => $part['header'], 'content' => $part['body']));
       
   229         }
       
   230     }
       
   231 
       
   232     /**
       
   233      * Get part of multipart message
       
   234      *
       
   235      * @param  int $num number of part starting with 1 for first part
       
   236      * @return Zend_Mail_Part wanted part
       
   237      * @throws Zend_Mail_Exception
       
   238      */
       
   239     public function getPart($num)
       
   240     {
       
   241         if (isset($this->_parts[$num])) {
       
   242             return $this->_parts[$num];
       
   243         }
       
   244 
       
   245         if (!$this->_mail && $this->_content === null) {
       
   246             /**
       
   247              * @see Zend_Mail_Exception
       
   248              */
       
   249             require_once 'Zend/Mail/Exception.php';
       
   250             throw new Zend_Mail_Exception('part not found');
       
   251         }
       
   252 
       
   253         if ($this->_mail && $this->_mail->hasFetchPart) {
       
   254             // TODO: fetch part
       
   255             // return
       
   256         }
       
   257 
       
   258         $this->_cacheContent();
       
   259 
       
   260         if (!isset($this->_parts[$num])) {
       
   261             /**
       
   262              * @see Zend_Mail_Exception
       
   263              */
       
   264             require_once 'Zend/Mail/Exception.php';
       
   265             throw new Zend_Mail_Exception('part not found');
       
   266         }
       
   267 
       
   268         return $this->_parts[$num];
       
   269     }
       
   270 
       
   271     /**
       
   272      * Count parts of a multipart part
       
   273      *
       
   274      * @return int number of sub-parts
       
   275      */
       
   276     public function countParts()
       
   277     {
       
   278         if ($this->_countParts) {
       
   279             return $this->_countParts;
       
   280         }
       
   281 
       
   282         $this->_countParts = count($this->_parts);
       
   283         if ($this->_countParts) {
       
   284             return $this->_countParts;
       
   285         }
       
   286 
       
   287         if ($this->_mail && $this->_mail->hasFetchPart) {
       
   288             // TODO: fetch part
       
   289             // return
       
   290         }
       
   291 
       
   292         $this->_cacheContent();
       
   293 
       
   294         $this->_countParts = count($this->_parts);
       
   295         return $this->_countParts;
       
   296     }
       
   297 
       
   298 
       
   299     /**
       
   300      * Get all headers
       
   301      *
       
   302      * The returned headers are as saved internally. All names are lowercased. The value is a string or an array
       
   303      * if a header with the same name occurs more than once.
       
   304      *
       
   305      * @return array headers as array(name => value)
       
   306      */
       
   307     public function getHeaders()
       
   308     {
       
   309         if ($this->_headers === null) {
       
   310             if (!$this->_mail) {
       
   311                 $this->_headers = array();
       
   312             } else {
       
   313                 $part = $this->_mail->getRawHeader($this->_messageNum);
       
   314                 Zend_Mime_Decode::splitMessage($part, $this->_headers, $null);
       
   315             }
       
   316         }
       
   317 
       
   318         return $this->_headers;
       
   319     }
       
   320 
       
   321     /**
       
   322      * Get a header in specificed format
       
   323      *
       
   324      * Internally headers that occur more than once are saved as array, all other as string. If $format
       
   325      * is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
       
   326      *
       
   327      * @param  string $name   name of header, matches case-insensitive, but camel-case is replaced with dashes
       
   328      * @param  string $format change type of return value to 'string' or 'array'
       
   329      * @return string|array value of header in wanted or internal format
       
   330      * @throws Zend_Mail_Exception
       
   331      */
       
   332     public function getHeader($name, $format = null)
       
   333     {
       
   334         if ($this->_headers === null) {
       
   335             $this->getHeaders();
       
   336         }
       
   337 
       
   338         $lowerName = strtolower($name);
       
   339 
       
   340         if ($this->headerExists($name) == false) {
       
   341             $lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
       
   342             if($this->headerExists($lowerName) == false) {
       
   343                 /**
       
   344                  * @see Zend_Mail_Exception
       
   345                  */
       
   346                 require_once 'Zend/Mail/Exception.php';
       
   347                 throw new Zend_Mail_Exception("no Header with Name $name or $lowerName found");
       
   348             }
       
   349         }
       
   350         $name = $lowerName;
       
   351 
       
   352         $header = $this->_headers[$name];
       
   353 
       
   354         switch ($format) {
       
   355             case 'string':
       
   356                 if (is_array($header)) {
       
   357                     $header = implode(Zend_Mime::LINEEND, $header);
       
   358                 }
       
   359                 break;
       
   360             case 'array':
       
   361                 $header = (array)$header;
       
   362             default:
       
   363                 // do nothing
       
   364         }
       
   365 
       
   366         return $header;
       
   367     }
       
   368 
       
   369     /**
       
   370      * Check wheater the Mail part has a specific header.
       
   371      *
       
   372      * @param  string $name
       
   373      * @return boolean
       
   374      */
       
   375     public function headerExists($name)
       
   376     {
       
   377         $name = strtolower($name);
       
   378         if(isset($this->_headers[$name])) {
       
   379             return true;
       
   380         } else {
       
   381             return false;
       
   382         }
       
   383     }
       
   384 
       
   385     /**
       
   386      * Get a specific field from a header like content type or all fields as array
       
   387      *
       
   388      * If the header occurs more than once, only the value from the first header
       
   389      * is returned.
       
   390      *
       
   391      * Throws a Zend_Mail_Exception if the requested header does not exist. If
       
   392      * the specific header field does not exist, returns null.
       
   393      *
       
   394      * @param  string $name       name of header, like in getHeader()
       
   395      * @param  string $wantedPart the wanted part, default is first, if null an array with all parts is returned
       
   396      * @param  string $firstName  key name for the first part
       
   397      * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
       
   398      * @throws Zend_Exception, Zend_Mail_Exception
       
   399      */
       
   400     public function getHeaderField($name, $wantedPart = 0, $firstName = 0) {
       
   401         return Zend_Mime_Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName);
       
   402     }
       
   403 
       
   404 
       
   405     /**
       
   406      * Getter for mail headers - name is matched in lowercase
       
   407      *
       
   408      * This getter is short for Zend_Mail_Part::getHeader($name, 'string')
       
   409      *
       
   410      * @see Zend_Mail_Part::getHeader()
       
   411      *
       
   412      * @param  string $name header name
       
   413      * @return string value of header
       
   414      * @throws Zend_Mail_Exception
       
   415      */
       
   416     public function __get($name)
       
   417     {
       
   418         return $this->getHeader($name, 'string');
       
   419     }
       
   420 
       
   421     /**
       
   422      * Isset magic method proxy to hasHeader
       
   423      *
       
   424      * This method is short syntax for Zend_Mail_Part::hasHeader($name);
       
   425      *
       
   426      * @see Zend_Mail_Part::hasHeader
       
   427      *
       
   428      * @param  string
       
   429      * @return boolean
       
   430      */
       
   431     public function __isset($name)
       
   432     {
       
   433         return $this->headerExists($name);
       
   434     }
       
   435 
       
   436     /**
       
   437      * magic method to get content of part
       
   438      *
       
   439      * @return string content
       
   440      */
       
   441     public function __toString()
       
   442     {
       
   443         return $this->getContent();
       
   444     }
       
   445 
       
   446     /**
       
   447      * implements RecursiveIterator::hasChildren()
       
   448      *
       
   449      * @return bool current element has children/is multipart
       
   450      */
       
   451     public function hasChildren()
       
   452     {
       
   453         $current = $this->current();
       
   454         return $current && $current instanceof Zend_Mail_Part && $current->isMultipart();
       
   455     }
       
   456 
       
   457     /**
       
   458      * implements RecursiveIterator::getChildren()
       
   459      *
       
   460      * @return Zend_Mail_Part same as self::current()
       
   461      */
       
   462     public function getChildren()
       
   463     {
       
   464         return $this->current();
       
   465     }
       
   466 
       
   467     /**
       
   468      * implements Iterator::valid()
       
   469      *
       
   470      * @return bool check if there's a current element
       
   471      */
       
   472     public function valid()
       
   473     {
       
   474         if ($this->_countParts === null) {
       
   475             $this->countParts();
       
   476         }
       
   477         return $this->_iterationPos && $this->_iterationPos <= $this->_countParts;
       
   478     }
       
   479 
       
   480     /**
       
   481      * implements Iterator::next()
       
   482      *
       
   483      * @return null
       
   484      */
       
   485     public function next()
       
   486     {
       
   487         ++$this->_iterationPos;
       
   488     }
       
   489 
       
   490     /**
       
   491      * implements Iterator::key()
       
   492      *
       
   493      * @return string key/number of current part
       
   494      */
       
   495     public function key()
       
   496     {
       
   497         return $this->_iterationPos;
       
   498     }
       
   499 
       
   500     /**
       
   501      * implements Iterator::current()
       
   502      *
       
   503      * @return Zend_Mail_Part current part
       
   504      */
       
   505     public function current()
       
   506     {
       
   507         return $this->getPart($this->_iterationPos);
       
   508     }
       
   509 
       
   510     /**
       
   511      * implements Iterator::rewind()
       
   512      *
       
   513      * @return null
       
   514      */
       
   515     public function rewind()
       
   516     {
       
   517         $this->countParts();
       
   518         $this->_iterationPos = 1;
       
   519     }
       
   520 }