[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/include/Zend/Http/ -> Response.php (source)

   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  }


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1