1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * Zend Framework |
---|
5 | * |
---|
6 | * LICENSE |
---|
7 | * |
---|
8 | * This source file is subject to the new BSD license that is bundled |
---|
9 | * with this package in the file LICENSE.txt. |
---|
10 | * It is also available through the world-wide-web at this URL: |
---|
11 | * http://framework.zend.com/license/new-bsd |
---|
12 | * If you did not receive a copy of the license and are unable to |
---|
13 | * obtain it through the world-wide-web, please send an email |
---|
14 | * to license@zend.com so we can send you a copy immediately. |
---|
15 | * |
---|
16 | * @category Zend |
---|
17 | * @package Zend_Http |
---|
18 | * @subpackage Response |
---|
19 | * @version $Id: Response.php 24594 2012-01-05 21:27:01Z matthew $ |
---|
20 | * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
---|
21 | * @license http://framework.zend.com/license/new-bsd New BSD License |
---|
22 | */ |
---|
23 | |
---|
24 | /** |
---|
25 | * Zend_Http_Response represents an HTTP 1.0 / 1.1 response message. It |
---|
26 | * includes easy access to all the response's different elemts, as well as some |
---|
27 | * convenience methods for parsing and validating HTTP responses. |
---|
28 | * |
---|
29 | * @package Zend_Http |
---|
30 | * @subpackage Response |
---|
31 | * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
---|
32 | * @license http://framework.zend.com/license/new-bsd New BSD License |
---|
33 | */ |
---|
34 | class Zend_Http_Response |
---|
35 | { |
---|
36 | /** |
---|
37 | * List of all known HTTP response codes - used by responseCodeAsText() to |
---|
38 | * translate numeric codes to messages. |
---|
39 | * |
---|
40 | * @var array |
---|
41 | */ |
---|
42 | protected static $messages = array( |
---|
43 | // Informational 1xx |
---|
44 | 100 => 'Continue', |
---|
45 | 101 => 'Switching Protocols', |
---|
46 | |
---|
47 | // Success 2xx |
---|
48 | 200 => 'OK', |
---|
49 | 201 => 'Created', |
---|
50 | 202 => 'Accepted', |
---|
51 | 203 => 'Non-Authoritative Information', |
---|
52 | 204 => 'No Content', |
---|
53 | 205 => 'Reset Content', |
---|
54 | 206 => 'Partial Content', |
---|
55 | |
---|
56 | // Redirection 3xx |
---|
57 | 300 => 'Multiple Choices', |
---|
58 | 301 => 'Moved Permanently', |
---|
59 | 302 => 'Found', // 1.1 |
---|
60 | 303 => 'See Other', |
---|
61 | 304 => 'Not Modified', |
---|
62 | 305 => 'Use Proxy', |
---|
63 | // 306 is deprecated but reserved |
---|
64 | 307 => 'Temporary Redirect', |
---|
65 | |
---|
66 | // Client Error 4xx |
---|
67 | 400 => 'Bad Request', |
---|
68 | 401 => 'Unauthorized', |
---|
69 | 402 => 'Payment Required', |
---|
70 | 403 => 'Forbidden', |
---|
71 | 404 => 'Not Found', |
---|
72 | 405 => 'Method Not Allowed', |
---|
73 | 406 => 'Not Acceptable', |
---|
74 | 407 => 'Proxy Authentication Required', |
---|
75 | 408 => 'Request Timeout', |
---|
76 | 409 => 'Conflict', |
---|
77 | 410 => 'Gone', |
---|
78 | 411 => 'Length Required', |
---|
79 | 412 => 'Precondition Failed', |
---|
80 | 413 => 'Request Entity Too Large', |
---|
81 | 414 => 'Request-URI Too Long', |
---|
82 | 415 => 'Unsupported Media Type', |
---|
83 | 416 => 'Requested Range Not Satisfiable', |
---|
84 | 417 => 'Expectation Failed', |
---|
85 | |
---|
86 | // Server Error 5xx |
---|
87 | 500 => 'Internal Server Error', |
---|
88 | 501 => 'Not Implemented', |
---|
89 | 502 => 'Bad Gateway', |
---|
90 | 503 => 'Service Unavailable', |
---|
91 | 504 => 'Gateway Timeout', |
---|
92 | 505 => 'HTTP Version Not Supported', |
---|
93 | 509 => 'Bandwidth Limit Exceeded' |
---|
94 | ); |
---|
95 | |
---|
96 | /** |
---|
97 | * The HTTP version (1.0, 1.1) |
---|
98 | * |
---|
99 | * @var string |
---|
100 | */ |
---|
101 | protected $version; |
---|
102 | |
---|
103 | /** |
---|
104 | * The HTTP response code |
---|
105 | * |
---|
106 | * @var int |
---|
107 | */ |
---|
108 | protected $code; |
---|
109 | |
---|
110 | /** |
---|
111 | * The HTTP response code as string |
---|
112 | * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500) |
---|
113 | * |
---|
114 | * @var string |
---|
115 | */ |
---|
116 | protected $message; |
---|
117 | |
---|
118 | /** |
---|
119 | * The HTTP response headers array |
---|
120 | * |
---|
121 | * @var array |
---|
122 | */ |
---|
123 | protected $headers = array(); |
---|
124 | |
---|
125 | /** |
---|
126 | * The HTTP response body |
---|
127 | * |
---|
128 | * @var string |
---|
129 | */ |
---|
130 | protected $body; |
---|
131 | |
---|
132 | /** |
---|
133 | * HTTP response constructor |
---|
134 | * |
---|
135 | * In most cases, you would use Zend_Http_Response::fromString to parse an HTTP |
---|
136 | * response string and create a new Zend_Http_Response object. |
---|
137 | * |
---|
138 | * NOTE: The constructor no longer accepts nulls or empty values for the code and |
---|
139 | * headers and will throw an exception if the passed values do not form a valid HTTP |
---|
140 | * responses. |
---|
141 | * |
---|
142 | * If no message is passed, the message will be guessed according to the response code. |
---|
143 | * |
---|
144 | * @param int $code Response code (200, 404, ...) |
---|
145 | * @param array $headers Headers array |
---|
146 | * @param string $body Response body |
---|
147 | * @param string $version HTTP version |
---|
148 | * @param string $message Response code as text |
---|
149 | * @throws Zend_Http_Exception |
---|
150 | */ |
---|
151 | public function __construct($code, array $headers, $body = null, $version = '1.1', $message = null) |
---|
152 | { |
---|
153 | // Make sure the response code is valid and set it |
---|
154 | if (self::responseCodeAsText($code) === null) { |
---|
155 | require_once 'Zend/Http/Exception.php'; |
---|
156 | throw new Zend_Http_Exception("{$code} is not a valid HTTP response code"); |
---|
157 | } |
---|
158 | |
---|
159 | $this->code = $code; |
---|
160 | |
---|
161 | foreach ($headers as $name => $value) { |
---|
162 | if (is_int($name)) { |
---|
163 | $header = explode(":", $value, 2); |
---|
164 | if (count($header) != 2) { |
---|
165 | require_once 'Zend/Http/Exception.php'; |
---|
166 | throw new Zend_Http_Exception("'{$value}' is not a valid HTTP header"); |
---|
167 | } |
---|
168 | |
---|
169 | $name = trim($header[0]); |
---|
170 | $value = trim($header[1]); |
---|
171 | } |
---|
172 | |
---|
173 | $this->headers[ucwords(strtolower($name))] = $value; |
---|
174 | } |
---|
175 | |
---|
176 | // Set the body |
---|
177 | $this->body = $body; |
---|
178 | |
---|
179 | // Set the HTTP version |
---|
180 | if (! preg_match('|^\d\.\d$|', $version)) { |
---|
181 | require_once 'Zend/Http/Exception.php'; |
---|
182 | throw new Zend_Http_Exception("Invalid HTTP response version: $version"); |
---|
183 | } |
---|
184 | |
---|
185 | $this->version = $version; |
---|
186 | |
---|
187 | // If we got the response message, set it. Else, set it according to |
---|
188 | // the response code |
---|
189 | if (is_string($message)) { |
---|
190 | $this->message = $message; |
---|
191 | } else { |
---|
192 | $this->message = self::responseCodeAsText($code); |
---|
193 | } |
---|
194 | } |
---|
195 | |
---|
196 | /** |
---|
197 | * Check whether the response is an error |
---|
198 | * |
---|
199 | * @return boolean |
---|
200 | */ |
---|
201 | public function isError() |
---|
202 | { |
---|
203 | $restype = floor($this->code / 100); |
---|
204 | if ($restype == 4 || $restype == 5) { |
---|
205 | return true; |
---|
206 | } |
---|
207 | |
---|
208 | return false; |
---|
209 | } |
---|
210 | |
---|
211 | /** |
---|
212 | * Check whether the response in successful |
---|
213 | * |
---|
214 | * @return boolean |
---|
215 | */ |
---|
216 | public function isSuccessful() |
---|
217 | { |
---|
218 | $restype = floor($this->code / 100); |
---|
219 | if ($restype == 2 || $restype == 1) { // Shouldn't 3xx count as success as well ??? |
---|
220 | return true; |
---|
221 | } |
---|
222 | |
---|
223 | return false; |
---|
224 | } |
---|
225 | |
---|
226 | /** |
---|
227 | * Check whether the response is a redirection |
---|
228 | * |
---|
229 | * @return boolean |
---|
230 | */ |
---|
231 | public function isRedirect() |
---|
232 | { |
---|
233 | $restype = floor($this->code / 100); |
---|
234 | if ($restype == 3) { |
---|
235 | return true; |
---|
236 | } |
---|
237 | |
---|
238 | return false; |
---|
239 | } |
---|
240 | |
---|
241 | /** |
---|
242 | * Get the response body as string |
---|
243 | * |
---|
244 | * This method returns the body of the HTTP response (the content), as it |
---|
245 | * should be in it's readable version - that is, after decoding it (if it |
---|
246 | * was decoded), deflating it (if it was gzip compressed), etc. |
---|
247 | * |
---|
248 | * If you want to get the raw body (as transfered on wire) use |
---|
249 | * $this->getRawBody() instead. |
---|
250 | * |
---|
251 | * @return string |
---|
252 | */ |
---|
253 | public function getBody() |
---|
254 | { |
---|
255 | $body = ''; |
---|
256 | |
---|
257 | // Decode the body if it was transfer-encoded |
---|
258 | switch (strtolower($this->getHeader('transfer-encoding'))) { |
---|
259 | |
---|
260 | // Handle chunked body |
---|
261 | case 'chunked': |
---|
262 | $body = self::decodeChunkedBody($this->body); |
---|
263 | break; |
---|
264 | |
---|
265 | // No transfer encoding, or unknown encoding extension: |
---|
266 | // return body as is |
---|
267 | default: |
---|
268 | $body = $this->body; |
---|
269 | break; |
---|
270 | } |
---|
271 | |
---|
272 | // Decode any content-encoding (gzip or deflate) if needed |
---|
273 | switch (strtolower($this->getHeader('content-encoding'))) { |
---|
274 | |
---|
275 | // Handle gzip encoding |
---|
276 | case 'gzip': |
---|
277 | $body = self::decodeGzip($body); |
---|
278 | break; |
---|
279 | |
---|
280 | // Handle deflate encoding |
---|
281 | case 'deflate': |
---|
282 | $body = self::decodeDeflate($body); |
---|
283 | break; |
---|
284 | |
---|
285 | default: |
---|
286 | break; |
---|
287 | } |
---|
288 | |
---|
289 | return $body; |
---|
290 | } |
---|
291 | |
---|
292 | /** |
---|
293 | * Get the raw response body (as transfered "on wire") as string |
---|
294 | * |
---|
295 | * If the body is encoded (with Transfer-Encoding, not content-encoding - |
---|
296 | * IE "chunked" body), gzip compressed, etc. it will not be decoded. |
---|
297 | * |
---|
298 | * @return string |
---|
299 | */ |
---|
300 | public function getRawBody() |
---|
301 | { |
---|
302 | return $this->body; |
---|
303 | } |
---|
304 | |
---|
305 | /** |
---|
306 | * Get the HTTP version of the response |
---|
307 | * |
---|
308 | * @return string |
---|
309 | */ |
---|
310 | public function getVersion() |
---|
311 | { |
---|
312 | return $this->version; |
---|
313 | } |
---|
314 | |
---|
315 | /** |
---|
316 | * Get the HTTP response status code |
---|
317 | * |
---|
318 | * @return int |
---|
319 | */ |
---|
320 | public function getStatus() |
---|
321 | { |
---|
322 | return $this->code; |
---|
323 | } |
---|
324 | |
---|
325 | /** |
---|
326 | * Return a message describing the HTTP response code |
---|
327 | * (Eg. "OK", "Not Found", "Moved Permanently") |
---|
328 | * |
---|
329 | * @return string |
---|
330 | */ |
---|
331 | public function getMessage() |
---|
332 | { |
---|
333 | return $this->message; |
---|
334 | } |
---|
335 | |
---|
336 | /** |
---|
337 | * Get the response headers |
---|
338 | * |
---|
339 | * @return array |
---|
340 | */ |
---|
341 | public function getHeaders() |
---|
342 | { |
---|
343 | return $this->headers; |
---|
344 | } |
---|
345 | |
---|
346 | /** |
---|
347 | * Get a specific header as string, or null if it is not set |
---|
348 | * |
---|
349 | * @param string$header |
---|
350 | * @return string|array|null |
---|
351 | */ |
---|
352 | public function getHeader($header) |
---|
353 | { |
---|
354 | $header = ucwords(strtolower($header)); |
---|
355 | if (! is_string($header) || ! isset($this->headers[$header])) return null; |
---|
356 | |
---|
357 | return $this->headers[$header]; |
---|
358 | } |
---|
359 | |
---|
360 | /** |
---|
361 | * Get all headers as string |
---|
362 | * |
---|
363 | * @param boolean $status_line Whether to return the first status line (IE "HTTP 200 OK") |
---|
364 | * @param string $br Line breaks (eg. "\n", "\r\n", "<br />") |
---|
365 | * @return string |
---|
366 | */ |
---|
367 | public function getHeadersAsString($status_line = true, $br = "\n") |
---|
368 | { |
---|
369 | $str = ''; |
---|
370 | |
---|
371 | if ($status_line) { |
---|
372 | $str = "HTTP/{$this->version} {$this->code} {$this->message}{$br}"; |
---|
373 | } |
---|
374 | |
---|
375 | // Iterate over the headers and stringify them |
---|
376 | foreach ($this->headers as $name => $value) |
---|
377 | { |
---|
378 | if (is_string($value)) |
---|
379 | $str .= "{$name}: {$value}{$br}"; |
---|
380 | |
---|
381 | elseif (is_array($value)) { |
---|
382 | foreach ($value as $subval) { |
---|
383 | $str .= "{$name}: {$subval}{$br}"; |
---|
384 | } |
---|
385 | } |
---|
386 | } |
---|
387 | |
---|
388 | return $str; |
---|
389 | } |
---|
390 | |
---|
391 | /** |
---|
392 | * Get the entire response as string |
---|
393 | * |
---|
394 | * @param string $br Line breaks (eg. "\n", "\r\n", "<br />") |
---|
395 | * @return string |
---|
396 | */ |
---|
397 | public function asString($br = "\n") |
---|
398 | { |
---|
399 | return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); |
---|
400 | } |
---|
401 | |
---|
402 | /** |
---|
403 | * Implements magic __toString() |
---|
404 | * |
---|
405 | * @return string |
---|
406 | */ |
---|
407 | public function __toString() |
---|
408 | { |
---|
409 | return $this->asString(); |
---|
410 | } |
---|
411 | |
---|
412 | /** |
---|
413 | * A convenience function that returns a text representation of |
---|
414 | * HTTP response codes. Returns 'Unknown' for unknown codes. |
---|
415 | * Returns array of all codes, if $code is not specified. |
---|
416 | * |
---|
417 | * Conforms to HTTP/1.1 as defined in RFC 2616 (except for 'Unknown') |
---|
418 | * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 for reference |
---|
419 | * |
---|
420 | * @param int $code HTTP response code |
---|
421 | * @param boolean $http11 Use HTTP version 1.1 |
---|
422 | * @return string |
---|
423 | */ |
---|
424 | public static function responseCodeAsText($code = null, $http11 = true) |
---|
425 | { |
---|
426 | $messages = self::$messages; |
---|
427 | if (! $http11) $messages[302] = 'Moved Temporarily'; |
---|
428 | |
---|
429 | if ($code === null) { |
---|
430 | return $messages; |
---|
431 | } elseif (isset($messages[$code])) { |
---|
432 | return $messages[$code]; |
---|
433 | } else { |
---|
434 | return 'Unknown'; |
---|
435 | } |
---|
436 | } |
---|
437 | |
---|
438 | /** |
---|
439 | * Extract the response code from a response string |
---|
440 | * |
---|
441 | * @param string $response_str |
---|
442 | * @return int |
---|
443 | */ |
---|
444 | public static function extractCode($response_str) |
---|
445 | { |
---|
446 | preg_match("|^HTTP/[\d\.x]+ (\d+)|", $response_str, $m); |
---|
447 | |
---|
448 | if (isset($m[1])) { |
---|
449 | return (int) $m[1]; |
---|
450 | } else { |
---|
451 | return false; |
---|
452 | } |
---|
453 | } |
---|
454 | |
---|
455 | /** |
---|
456 | * Extract the HTTP message from a response |
---|
457 | * |
---|
458 | * @param string $response_str |
---|
459 | * @return string |
---|
460 | */ |
---|
461 | public static function extractMessage($response_str) |
---|
462 | { |
---|
463 | preg_match("|^HTTP/[\d\.x]+ \d+ ([^\r\n]+)|", $response_str, $m); |
---|
464 | |
---|
465 | if (isset($m[1])) { |
---|
466 | return $m[1]; |
---|
467 | } else { |
---|
468 | return false; |
---|
469 | } |
---|
470 | } |
---|
471 | |
---|
472 | /** |
---|
473 | * Extract the HTTP version from a response |
---|
474 | * |
---|
475 | * @param string $response_str |
---|
476 | * @return string |
---|
477 | */ |
---|
478 | public static function extractVersion($response_str) |
---|
479 | { |
---|
480 | preg_match("|^HTTP/([\d\.x]+) \d+|", $response_str, $m); |
---|
481 | |
---|
482 | if (isset($m[1])) { |
---|
483 | return $m[1]; |
---|
484 | } else { |
---|
485 | return false; |
---|
486 | } |
---|
487 | } |
---|
488 | |
---|
489 | /** |
---|
490 | * Extract the headers from a response string |
---|
491 | * |
---|
492 | * @param string $response_str |
---|
493 | * @return array |
---|
494 | */ |
---|
495 | public static function extractHeaders($response_str) |
---|
496 | { |
---|
497 | $headers = array(); |
---|
498 | |
---|
499 | // First, split body and headers |
---|
500 | $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); |
---|
501 | if (! $parts[0]) return $headers; |
---|
502 | |
---|
503 | // Split headers part to lines |
---|
504 | $lines = explode("\n", $parts[0]); |
---|
505 | unset($parts); |
---|
506 | $last_header = null; |
---|
507 | |
---|
508 | foreach($lines as $line) { |
---|
509 | $line = trim($line, "\r\n"); |
---|
510 | if ($line == "") break; |
---|
511 | |
---|
512 | // Locate headers like 'Location: ...' and 'Location:...' (note the missing space) |
---|
513 | if (preg_match("|^([\w-]+):\s*(.+)|", $line, $m)) { |
---|
514 | unset($last_header); |
---|
515 | $h_name = strtolower($m[1]); |
---|
516 | $h_value = $m[2]; |
---|
517 | |
---|
518 | if (isset($headers[$h_name])) { |
---|
519 | if (! is_array($headers[$h_name])) { |
---|
520 | $headers[$h_name] = array($headers[$h_name]); |
---|
521 | } |
---|
522 | |
---|
523 | $headers[$h_name][] = $h_value; |
---|
524 | } else { |
---|
525 | $headers[$h_name] = $h_value; |
---|
526 | } |
---|
527 | $last_header = $h_name; |
---|
528 | } elseif (preg_match("|^\s+(.+)$|", $line, $m) && $last_header !== null) { |
---|
529 | if (is_array($headers[$last_header])) { |
---|
530 | end($headers[$last_header]); |
---|
531 | $last_header_key = key($headers[$last_header]); |
---|
532 | $headers[$last_header][$last_header_key] .= $m[1]; |
---|
533 | } else { |
---|
534 | $headers[$last_header] .= $m[1]; |
---|
535 | } |
---|
536 | } |
---|
537 | } |
---|
538 | |
---|
539 | return $headers; |
---|
540 | } |
---|
541 | |
---|
542 | /** |
---|
543 | * Extract the body from a response string |
---|
544 | * |
---|
545 | * @param string $response_str |
---|
546 | * @return string |
---|
547 | */ |
---|
548 | public static function extractBody($response_str) |
---|
549 | { |
---|
550 | $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); |
---|
551 | if (isset($parts[1])) { |
---|
552 | return $parts[1]; |
---|
553 | } |
---|
554 | return ''; |
---|
555 | } |
---|
556 | |
---|
557 | /** |
---|
558 | * Decode a "chunked" transfer-encoded body and return the decoded text |
---|
559 | * |
---|
560 | * @param string $body |
---|
561 | * @return string |
---|
562 | */ |
---|
563 | public static function decodeChunkedBody($body) |
---|
564 | { |
---|
565 | $decBody = ''; |
---|
566 | |
---|
567 | // If mbstring overloads substr and strlen functions, we have to |
---|
568 | // override it's internal encoding |
---|
569 | if (function_exists('mb_internal_encoding') && |
---|
570 | ((int) ini_get('mbstring.func_overload')) & 2) { |
---|
571 | |
---|
572 | $mbIntEnc = mb_internal_encoding(); |
---|
573 | mb_internal_encoding('ASCII'); |
---|
574 | } |
---|
575 | |
---|
576 | while (trim($body)) { |
---|
577 | if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) { |
---|
578 | require_once 'Zend/Http/Exception.php'; |
---|
579 | throw new Zend_Http_Exception("Error parsing body - doesn't seem to be a chunked message"); |
---|
580 | } |
---|
581 | |
---|
582 | $length = hexdec(trim($m[1])); |
---|
583 | $cut = strlen($m[0]); |
---|
584 | $decBody .= substr($body, $cut, $length); |
---|
585 | $body = substr($body, $cut + $length + 2); |
---|
586 | } |
---|
587 | |
---|
588 | if (isset($mbIntEnc)) { |
---|
589 | mb_internal_encoding($mbIntEnc); |
---|
590 | } |
---|
591 | |
---|
592 | return $decBody; |
---|
593 | } |
---|
594 | |
---|
595 | /** |
---|
596 | * Decode a gzip encoded message (when Content-encoding = gzip) |
---|
597 | * |
---|
598 | * Currently requires PHP with zlib support |
---|
599 | * |
---|
600 | * @param string $body |
---|
601 | * @return string |
---|
602 | */ |
---|
603 | public static function decodeGzip($body) |
---|
604 | { |
---|
605 | if (! function_exists('gzinflate')) { |
---|
606 | require_once 'Zend/Http/Exception.php'; |
---|
607 | throw new Zend_Http_Exception( |
---|
608 | 'zlib extension is required in order to decode "gzip" encoding' |
---|
609 | ); |
---|
610 | } |
---|
611 | |
---|
612 | return gzinflate(substr($body, 10)); |
---|
613 | } |
---|
614 | |
---|
615 | /** |
---|
616 | * Decode a zlib deflated message (when Content-encoding = deflate) |
---|
617 | * |
---|
618 | * Currently requires PHP with zlib support |
---|
619 | * |
---|
620 | * @param string $body |
---|
621 | * @return string |
---|
622 | */ |
---|
623 | public static function decodeDeflate($body) |
---|
624 | { |
---|
625 | if (! function_exists('gzuncompress')) { |
---|
626 | require_once 'Zend/Http/Exception.php'; |
---|
627 | throw new Zend_Http_Exception( |
---|
628 | 'zlib extension is required in order to decode "deflate" encoding' |
---|
629 | ); |
---|
630 | } |
---|
631 | |
---|
632 | /** |
---|
633 | * Some servers (IIS ?) send a broken deflate response, without the |
---|
634 | * RFC-required zlib header. |
---|
635 | * |
---|
636 | * We try to detect the zlib header, and if it does not exsit we |
---|
637 | * teat the body is plain DEFLATE content. |
---|
638 | * |
---|
639 | * This method was adapted from PEAR HTTP_Request2 by (c) Alexey Borzov |
---|
640 | * |
---|
641 | * @link http://framework.zend.com/issues/browse/ZF-6040 |
---|
642 | */ |
---|
643 | $zlibHeader = unpack('n', substr($body, 0, 2)); |
---|
644 | if ($zlibHeader[1] % 31 == 0) { |
---|
645 | return gzuncompress($body); |
---|
646 | } else { |
---|
647 | return gzinflate($body); |
---|
648 | } |
---|
649 | } |
---|
650 | |
---|
651 | /** |
---|
652 | * Create a new Zend_Http_Response object from a string |
---|
653 | * |
---|
654 | * @param string $response_str |
---|
655 | * @return Zend_Http_Response |
---|
656 | */ |
---|
657 | public static function fromString($response_str) |
---|
658 | { |
---|
659 | $code = self::extractCode($response_str); |
---|
660 | $headers = self::extractHeaders($response_str); |
---|
661 | $body = self::extractBody($response_str); |
---|
662 | $version = self::extractVersion($response_str); |
---|
663 | $message = self::extractMessage($response_str); |
---|
664 | |
---|
665 | return new Zend_Http_Response($code, $headers, $body, $version, $message); |
---|
666 | } |
---|
667 | } |
---|