[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
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 [email protected] so we can send you a copy immediately. 15 * 16 * @category Zend 17 * @package Zend_Http 18 * @subpackage Response 19 * @version $Id: Response.php 24593 2012-01-05 20:35:02Z 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |