PageRenderTime 24ms CodeModel.GetById 11ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/framework/vendor/zend/Zend/Mime/Decode.php

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