PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Mime/Decode.php

https://github.com/jverkoey/snaapilookup
PHP | 243 lines | 121 code | 21 blank | 101 comment | 30 complexity | a6a56674b9068a975b85b4183f37643d 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_Mime
  17. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * @see Zend_Mime
  22. */
  23. require_once 'Zend/Mime.php';
  24. /**
  25. * @category Zend
  26. * @package Zend_Mime
  27. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  28. * @license http://framework.zend.com/license/new-bsd New BSD License
  29. */
  30. class Zend_Mime_Decode
  31. {
  32. /**
  33. * Explode MIME multipart string into seperate parts
  34. *
  35. * Parts consist of the header and the body of each MIME part.
  36. *
  37. * @param string $body raw body of message
  38. * @param string $boundary boundary as found in content-type
  39. * @return array parts with content of each part, empty if no parts found
  40. * @throws Zend_Exception
  41. */
  42. public static function splitMime($body, $boundary)
  43. {
  44. // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
  45. $body = str_replace("\r", '', $body);
  46. $start = 0;
  47. $res = array();
  48. // find every mime part limiter and cut out the
  49. // string before it.
  50. // the part before the first boundary string is discarded:
  51. $p = strpos($body, '--' . $boundary . "\n", $start);
  52. if ($p === false) {
  53. // no parts found!
  54. return array();
  55. }
  56. // position after first boundary line
  57. $start = $p + 3 + strlen($boundary);
  58. while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
  59. $res[] = substr($body, $start, $p-$start);
  60. $start = $p + 3 + strlen($boundary);
  61. }
  62. // no more parts, find end boundary
  63. $p = strpos($body, '--' . $boundary . '--', $start);
  64. if ($p===false) {
  65. throw new Zend_Exception('Not a valid Mime Message: End Missing');
  66. }
  67. // the remaining part also needs to be parsed:
  68. $res[] = substr($body, $start, $p-$start);
  69. return $res;
  70. }
  71. /**
  72. * decodes a mime encoded String and returns a
  73. * struct of parts with header and body
  74. *
  75. * @param string $message raw message content
  76. * @param string $boundary boundary as found in content-type
  77. * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
  78. * @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found
  79. * @throws Zend_Exception
  80. */
  81. public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND)
  82. {
  83. $parts = self::splitMime($message, $boundary);
  84. if (count($parts) <= 0) {
  85. return null;
  86. }
  87. $result = array();
  88. foreach ($parts as $part) {
  89. self::splitMessage($part, $headers, $body, $EOL);
  90. $result[] = array('header' => $headers,
  91. 'body' => $body );
  92. }
  93. return $result;
  94. }
  95. /**
  96. * split a message in header and body part, if no header or an
  97. * invalid header is found $headers is empty
  98. *
  99. * The charset of the returned headers depend on your iconv settings.
  100. *
  101. * @param string $message raw message with header and optional content
  102. * @param array $headers output param, array with headers as array(name => value)
  103. * @param string $body output param, content of message
  104. * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
  105. * @return null
  106. */
  107. public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND)
  108. {
  109. // check for valid header at first line
  110. $firstline = strtok($message, "\n");
  111. if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) {
  112. $headers = array();
  113. // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
  114. $body = str_replace(array("\r", "\n"), array('', $EOL), $message);
  115. return;
  116. }
  117. // find an empty line between headers and body
  118. // default is set new line
  119. if (strpos($message, $EOL . $EOL)) {
  120. list($headers, $body) = explode($EOL . $EOL, $message, 2);
  121. // next is the standard new line
  122. } else if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) {
  123. list($headers, $body) = explode("\r\n\r\n", $message, 2);
  124. // next is the other "standard" new line
  125. } else if ($EOL != "\n" && strpos($message, "\n\n")) {
  126. list($headers, $body) = explode("\n\n", $message, 2);
  127. // at last resort find anything that looks like a new line
  128. } else {
  129. @list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2);
  130. }
  131. $headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
  132. if ($headers === false ) {
  133. // an error occurs during the decoding
  134. return;
  135. }
  136. // normalize header names
  137. foreach ($headers as $name => $header) {
  138. $lower = strtolower($name);
  139. if ($lower == $name) {
  140. continue;
  141. }
  142. unset($headers[$name]);
  143. if (!isset($headers[$lower])) {
  144. $headers[$lower] = $header;
  145. continue;
  146. }
  147. if (is_array($headers[$lower])) {
  148. $headers[$lower][] = $header;
  149. continue;
  150. }
  151. $headers[$lower] = array($headers[$lower], $header);
  152. }
  153. }
  154. /**
  155. * split a content type in its different parts
  156. *
  157. * @param string $type content-type
  158. * @param string $wantedPart the wanted part, else an array with all parts is returned
  159. * @return string|array wanted part or all parts as array('type' => content-type, partname => value)
  160. */
  161. public static function splitContentType($type, $wantedPart = null)
  162. {
  163. return self::splitHeaderField($type, $wantedPart, 'type');
  164. }
  165. /**
  166. * split a header field like content type in its different parts
  167. *
  168. * @param string $type header field
  169. * @param string $wantedPart the wanted part, else an array with all parts is returned
  170. * @param string $firstName key name for the first part
  171. * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
  172. * @throws Zend_Exception
  173. */
  174. public static function splitHeaderField($field, $wantedPart = null, $firstName = 0)
  175. {
  176. $wantedPart = strtolower($wantedPart);
  177. $firstName = strtolower($firstName);
  178. // special case - a bit optimized
  179. if ($firstName === $wantedPart) {
  180. $field = strtok($field, ';');
  181. return $field[0] == '"' ? substr($field, 1, -1) : $field;
  182. }
  183. $field = $firstName . '=' . $field;
  184. if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) {
  185. throw new Zend_Exception('not a valid header field');
  186. }
  187. if ($wantedPart) {
  188. foreach ($matches[1] as $key => $name) {
  189. if (strcasecmp($name, $wantedPart)) {
  190. continue;
  191. }
  192. if ($matches[2][$key][0] != '"') {
  193. return $matches[2][$key];
  194. }
  195. return substr($matches[2][$key], 1, -1);
  196. }
  197. return null;
  198. }
  199. $split = array();
  200. foreach ($matches[1] as $key => $name) {
  201. $name = strtolower($name);
  202. if ($matches[2][$key][0] == '"') {
  203. $split[$name] = substr($matches[2][$key], 1, -1);
  204. } else {
  205. $split[$name] = $matches[2][$key];
  206. }
  207. }
  208. return $split;
  209. }
  210. /**
  211. * decode a quoted printable encoded string
  212. *
  213. * The charset of the returned string depends on your iconv settings.
  214. *
  215. * @param string encoded string
  216. * @return string decoded string
  217. */
  218. public static function decodeQuotedPrintable($string)
  219. {
  220. return iconv_mime_decode($string, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
  221. }
  222. }