12 * obtain it through the world-wide-web, please send an email |
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. |
13 * to license@zend.com so we can send you a copy immediately. |
14 * |
14 * |
15 * @category Zend |
15 * @category Zend |
16 * @package Zend_Mime |
16 * @package Zend_Mime |
17 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
17 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) |
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
19 * @version $Id: Decode.php 24593 2012-01-05 20:35:02Z matthew $ |
19 * @version $Id$ |
20 */ |
20 */ |
21 |
21 |
22 /** |
22 /** |
23 * @see Zend_Mime |
23 * @see Zend_Mime |
24 */ |
24 */ |
25 require_once 'Zend/Mime.php'; |
25 require_once 'Zend/Mime.php'; |
26 |
26 |
27 /** |
27 /** |
28 * @category Zend |
28 * @category Zend |
29 * @package Zend_Mime |
29 * @package Zend_Mime |
30 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
30 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) |
31 * @license http://framework.zend.com/license/new-bsd New BSD License |
31 * @license http://framework.zend.com/license/new-bsd New BSD License |
32 */ |
32 */ |
33 class Zend_Mime_Decode |
33 class Zend_Mime_Decode |
34 { |
34 { |
35 /** |
35 /** |
66 $start = $p + 3 + strlen($boundary); |
66 $start = $p + 3 + strlen($boundary); |
67 } |
67 } |
68 |
68 |
69 // no more parts, find end boundary |
69 // no more parts, find end boundary |
70 $p = strpos($body, '--' . $boundary . '--', $start); |
70 $p = strpos($body, '--' . $boundary . '--', $start); |
71 if ($p===false) { |
71 if ($p === false) { |
72 throw new Zend_Exception('Not a valid Mime Message: End Missing'); |
72 throw new Zend_Exception('Not a valid Mime Message: End Missing'); |
73 } |
73 } |
74 |
74 |
75 // the remaining part also needs to be parsed: |
75 // the remaining part also needs to be parsed: |
76 $res[] = substr($body, $start, $p-$start); |
76 $res[] = substr($body, $start, $p - $start); |
|
77 |
77 return $res; |
78 return $res; |
78 } |
79 } |
79 |
80 |
80 /** |
81 /** |
81 * decodes a mime encoded String and returns a |
82 * decodes a mime encoded String and returns a |
82 * struct of parts with header and body |
83 * struct of parts with header and body |
83 * |
84 * |
84 * @param string $message raw message content |
85 * @param string $message raw message content |
85 * @param string $boundary boundary as found in content-type |
86 * @param string $boundary boundary as found in content-type |
86 * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} |
87 * @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 * @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found |
88 * @throws Zend_Exception |
89 * @throws Zend_Exception |
89 */ |
90 */ |
90 public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND) |
91 public static function splitMessageStruct( |
|
92 $message, $boundary, $EOL = Zend_Mime::LINEEND |
|
93 ) |
91 { |
94 { |
92 $parts = self::splitMime($message, $boundary); |
95 $parts = self::splitMime($message, $boundary); |
93 if (count($parts) <= 0) { |
96 if (count($parts) <= 0) { |
94 return null; |
97 return null; |
95 } |
98 } |
96 $result = array(); |
99 $result = array(); |
97 foreach ($parts as $part) { |
100 foreach ($parts as $part) { |
98 self::splitMessage($part, $headers, $body, $EOL); |
101 self::splitMessage($part, $headers, $body, $EOL); |
99 $result[] = array('header' => $headers, |
102 $result[] = array( |
100 'body' => $body ); |
103 'header' => $headers, |
101 } |
104 'body' => $body |
|
105 ); |
|
106 } |
|
107 |
102 return $result; |
108 return $result; |
103 } |
109 } |
104 |
110 |
105 /** |
111 /** |
106 * split a message in header and body part, if no header or an |
112 * split a message in header and body part, if no header or an |
109 * The charset of the returned headers depend on your iconv settings. |
115 * The charset of the returned headers depend on your iconv settings. |
110 * |
116 * |
111 * @param string $message raw message with header and optional content |
117 * @param string $message raw message with header and optional content |
112 * @param array $headers output param, array with headers as array(name => value) |
118 * @param array $headers output param, array with headers as array(name => value) |
113 * @param string $body output param, content of message |
119 * @param string $body output param, content of message |
114 * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} |
120 * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND} |
115 * @return null |
121 * @return null |
116 */ |
122 */ |
117 public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND) |
123 public static function splitMessage( |
|
124 $message, &$headers, &$body, $EOL = Zend_Mime::LINEEND |
|
125 ) |
118 { |
126 { |
119 // check for valid header at first line |
127 // check for valid header at first line |
120 $firstline = strtok($message, "\n"); |
128 $firstline = strtok($message, "\n"); |
121 if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) { |
129 if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) { |
122 $headers = array(); |
130 $headers = array(); |
123 // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r? |
131 // 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); |
132 $body = str_replace( |
|
133 array( |
|
134 "\r", |
|
135 "\n" |
|
136 ), array( |
|
137 '', |
|
138 $EOL |
|
139 ), $message |
|
140 ); |
|
141 |
125 return; |
142 return; |
126 } |
143 } |
127 |
144 |
128 // find an empty line between headers and body |
145 // find an empty line between headers and body |
129 // default is set new line |
146 // default is set new line |
130 if (strpos($message, $EOL . $EOL)) { |
147 if (strpos($message, $EOL . $EOL)) { |
131 list($headers, $body) = explode($EOL . $EOL, $message, 2); |
148 list($headers, $body) = explode($EOL . $EOL, $message, 2); |
132 // next is the standard new line |
149 // 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 { |
150 } else { |
140 @list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2); |
151 if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) { |
141 } |
152 list($headers, $body) = explode("\r\n\r\n", $message, 2); |
142 |
153 // next is the other "standard" new line |
143 $headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR); |
154 } else { |
144 |
155 if ($EOL != "\n" && strpos($message, "\n\n")) { |
145 if ($headers === false ) { |
156 list($headers, $body) = explode("\n\n", $message, 2); |
|
157 // at last resort find anything that looks like a new line |
|
158 } else { |
|
159 @list($headers, $body) = |
|
160 @preg_split("%([\r\n]+)\\1%U", $message, 2); |
|
161 } |
|
162 } |
|
163 } |
|
164 |
|
165 $headers = iconv_mime_decode_headers( |
|
166 $headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR |
|
167 ); |
|
168 |
|
169 if ($headers === false) { |
146 // an error occurs during the decoding |
170 // an error occurs during the decoding |
147 return; |
171 return; |
148 } |
172 } |
149 |
173 |
150 // normalize header names |
174 // normalize header names |
179 } |
206 } |
180 |
207 |
181 /** |
208 /** |
182 * split a header field like content type in its different parts |
209 * split a header field like content type in its different parts |
183 * |
210 * |
184 * @param string $type header field |
211 * @param string $field |
185 * @param string $wantedPart the wanted part, else an array with all parts is returned |
212 * @param string $wantedPart the wanted part, else an array with all parts is returned |
186 * @param string $firstName key name for the first part |
213 * @param int|string $firstName key name for the first part |
|
214 * @throws Zend_Exception |
187 * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value) |
215 * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value) |
188 * @throws Zend_Exception |
216 */ |
189 */ |
217 public static function splitHeaderField( |
190 public static function splitHeaderField($field, $wantedPart = null, $firstName = 0) |
218 $field, $wantedPart = null, $firstName = 0 |
|
219 ) |
191 { |
220 { |
192 $wantedPart = strtolower($wantedPart); |
221 $wantedPart = strtolower($wantedPart); |
193 $firstName = strtolower($firstName); |
222 $firstName = strtolower($firstName); |
194 |
223 |
195 // special case - a bit optimized |
224 // special case - a bit optimized |
196 if ($firstName === $wantedPart) { |
225 if ($firstName === $wantedPart) { |
197 $field = strtok($field, ';'); |
226 $field = strtok($field, ';'); |
|
227 |
198 return $field[0] == '"' ? substr($field, 1, -1) : $field; |
228 return $field[0] == '"' ? substr($field, 1, -1) : $field; |
199 } |
229 } |
200 |
230 |
201 $field = $firstName . '=' . $field; |
231 $field = $firstName . '=' . $field; |
202 if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) { |
232 if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) { |