PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/ezcomponents/Mail/src/parser/interfaces/part_parser.php

http://hppg.googlecode.com/
PHP | 261 lines | 132 code | 17 blank | 112 comment | 12 complexity | 5841d49b93deaf2c5595ea5baefd001b MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * File containing the ezcMailPartParser class
  4. *
  5. * @package Mail
  6. * @version 1.7.1
  7. * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. */
  10. /**
  11. * Base class for all parser parts.
  12. *
  13. * Parse process
  14. * 1. Figure out the headers of the next part.
  15. * 2. Based on the headers, create the parser for the bodyPart corresponding to
  16. * the headers.
  17. * 3. Parse the body line by line. In the case of a multipart or a digest recursively
  18. * start this process. Note that in the case of RFC822 messages the body contains
  19. * headers.
  20. * 4. call finish() on the partParser and retrieve the ezcMailPart
  21. *
  22. * Each parser part gets the header for that part through the constructor
  23. * and is responsible for parsing the body of that part.
  24. * Parsing of the body is done on a push basis trough the parseBody() method
  25. * which is called repeatedly by the parent part for each line in the message.
  26. *
  27. * When there are no more lines the parent part will call finish() and the mail
  28. * part corresponding to the part you are parsing should be returned.
  29. *
  30. * @todo case on headers
  31. * @package Mail
  32. * @version 1.7.1
  33. * @access private
  34. */
  35. abstract class ezcMailPartParser
  36. {
  37. /**
  38. * Mail headers which can appear maximum one time in a mail message,
  39. * as defined by RFC 2822.
  40. *
  41. * @var array(string)
  42. */
  43. protected static $uniqueHeaders = array( 'bcc', 'cc', 'content-type',
  44. 'content-disposition', 'from',
  45. 'content-transfer-encoding',
  46. 'return-path',
  47. 'in-reply-to', 'references',
  48. 'message-id', 'date', 'reply-to',
  49. 'sender', 'subject', 'sender', 'to' );
  50. /**
  51. * The default is to parse text attachments into ezcMailTextPart objects.
  52. *
  53. * Setting this to true before calling the parser will parse text attachments
  54. * into ezcMailFile objects. Use the parser options for this:
  55. *
  56. * <code>
  57. * $parser = new ezcMailParser();
  58. * $parser->options->parseTextAttachmentsAsFiles = true;
  59. * // call $parser->parseMail( $set );
  60. * </code>
  61. *
  62. * @var bool
  63. */
  64. public static $parseTextAttachmentsAsFiles = false;
  65. /**
  66. * The name of the last header parsed.
  67. *
  68. * This variable is used when glueing together multi-line headers.
  69. *
  70. * @var string
  71. */
  72. private $lastParsedHeader = null;
  73. /**
  74. * Parse the body of a message line by line.
  75. *
  76. * This method is called by the parent part on a push basis. When there
  77. * are no more lines the parent part will call finish() to retrieve the
  78. * mailPart.
  79. *
  80. * @param string $line
  81. */
  82. abstract public function parseBody( $line );
  83. /**
  84. * Return the result of the parsed part.
  85. *
  86. * This method is called when all the lines of this part have been parsed.
  87. *
  88. * @return ezcMailPart
  89. */
  90. abstract public function finish();
  91. /**
  92. * Returns a part parser corresponding to the given $headers.
  93. *
  94. * @throws ezcBaseFileNotFoundException
  95. * if a neccessary temporary file could not be openened.
  96. * @param ezcMailHeadersHolder $headers
  97. * @return ezcMailPartParser
  98. */
  99. static public function createPartParserForHeaders( ezcMailHeadersHolder $headers )
  100. {
  101. // default as specified by RFC2045 - #5.2
  102. $mainType = 'text';
  103. $subType = 'plain';
  104. // parse the Content-Type header
  105. if ( isset( $headers['Content-Type'] ) )
  106. {
  107. $matches = array();
  108. // matches "type/subtype; blahblahblah"
  109. preg_match_all( '/^(\S+)\/([^;]+)/',
  110. $headers['Content-Type'], $matches, PREG_SET_ORDER );
  111. if ( count( $matches ) > 0 )
  112. {
  113. $mainType = strtolower( $matches[0][1] );
  114. $subType = strtolower( $matches[0][2] );
  115. }
  116. }
  117. $bodyParser = null;
  118. // create the correct type parser for this the detected type of part
  119. switch ( $mainType )
  120. {
  121. /* RFC 2045 defined types */
  122. case 'image':
  123. case 'audio':
  124. case 'video':
  125. case 'application':
  126. $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
  127. break;
  128. case 'message':
  129. switch ( $subType )
  130. {
  131. case "rfc822":
  132. $bodyParser = new ezcMailRfc822DigestParser( $headers );
  133. break;
  134. case "delivery-status":
  135. $bodyParser = new ezcMailDeliveryStatusParser( $headers );
  136. break;
  137. default:
  138. $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
  139. break;
  140. }
  141. break;
  142. case 'text':
  143. if ( ezcMailPartParser::$parseTextAttachmentsAsFiles === true )
  144. {
  145. $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
  146. }
  147. else
  148. {
  149. $bodyParser = new ezcMailTextParser( $subType, $headers );
  150. }
  151. break;
  152. case 'multipart':
  153. switch ( $subType )
  154. {
  155. case 'mixed':
  156. $bodyParser = new ezcMailMultipartMixedParser( $headers );
  157. break;
  158. case 'alternative':
  159. $bodyParser = new ezcMailMultipartAlternativeParser( $headers );
  160. break;
  161. case 'related':
  162. $bodyParser = new ezcMailMultipartRelatedParser( $headers );
  163. break;
  164. case 'digest':
  165. $bodyParser = new ezcMailMultipartDigestParser( $headers );
  166. break;
  167. case 'report':
  168. $bodyParser = new ezcMailMultipartReportParser( $headers );
  169. break;
  170. default:
  171. $bodyParser = new ezcMailMultipartMixedParser( $headers );
  172. break;
  173. }
  174. break;
  175. /* extensions */
  176. default:
  177. // we treat the body as binary if no main content type is set
  178. // or if it is unknown
  179. $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
  180. break;
  181. }
  182. return $bodyParser;
  183. }
  184. /**
  185. * Parses the header given by $line and adds to $headers.
  186. *
  187. * This method is usually used to parse the headers for a subpart. The
  188. * only exception is RFC822 parts since you know the type in advance.
  189. *
  190. * @todo deal with headers that are listed several times
  191. * @param string $line
  192. * @param ezcMailHeadersHolder $headers
  193. */
  194. protected function parseHeader( $line, ezcMailHeadersHolder $headers )
  195. {
  196. $matches = array();
  197. preg_match_all( "/^([\w-_]*):\s?(.*)/", $line, $matches, PREG_SET_ORDER );
  198. if ( count( $matches ) > 0 )
  199. {
  200. if ( !in_array( strtolower( $matches[0][1] ), self::$uniqueHeaders ) )
  201. {
  202. $arr = $headers[$matches[0][1]];
  203. $arr[0][] = str_replace( "\t", " ", trim( $matches[0][2] ) );
  204. $headers[$matches[0][1]] = $arr;
  205. }
  206. else
  207. {
  208. $headers[$matches[0][1]] = str_replace( "\t", " ", trim( $matches[0][2] ) );
  209. }
  210. $this->lastParsedHeader = $matches[0][1];
  211. }
  212. else if ( $this->lastParsedHeader !== null ) // take care of folding
  213. {
  214. if ( !in_array( strtolower( $this->lastParsedHeader ), self::$uniqueHeaders ) )
  215. {
  216. $arr = $headers[$this->lastParsedHeader];
  217. $arr[0][count( $arr[0] ) - 1] .= str_replace( "\t", " ", $line );
  218. $headers[$this->lastParsedHeader] = $arr;
  219. }
  220. else
  221. {
  222. $headers[$this->lastParsedHeader] .= str_replace( "\t", " ", $line );
  223. }
  224. }
  225. // else -invalid syntax, this should never happen.
  226. }
  227. /**
  228. * Scans through $headers and sets any specific header properties on $part.
  229. *
  230. * Currently we only have Content-Disposition on the ezcMailPart level.
  231. * All parser parts must call this method once.
  232. *
  233. * @param ezcMailHeadersHolder $headers
  234. * @param ezcMailPart $part
  235. */
  236. static public function parsePartHeaders( ezcMailHeadersHolder $headers, ezcMailPart $part )
  237. {
  238. if ( isset( $headers['Content-Disposition'] ) )
  239. {
  240. $part->contentDisposition = ezcMailRfc2231Implementation::parseContentDisposition( $headers['Content-Disposition'] );
  241. }
  242. }
  243. }
  244. ?>