[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/externals/httpful/src/Httpful/ -> Response.php (source)

   1  <?php
   2  
   3  namespace Httpful;
   4  
   5  /**
   6   * Models an HTTP response
   7   *
   8   * @author Nate Good <[email protected]>
   9   */
  10  class Response
  11  {
  12  
  13      public $body,
  14             $raw_body,
  15             $headers,
  16             $raw_headers,
  17             $request,
  18             $code = 0,
  19             $content_type,
  20             $parent_type,
  21             $charset,
  22             $is_mime_vendor_specific = false,
  23             $is_mime_personal = false;
  24  
  25      private $parsers;
  26      /**
  27       * @param string $body
  28       * @param string $headers
  29       * @param Request $request
  30       */
  31      public function __construct($body, $headers, Request $request)
  32      {
  33          $this->request      = $request;
  34          $this->raw_headers  = $headers;
  35          $this->raw_body     = $body;
  36  
  37          $this->code         = $this->_parseCode($headers);
  38          $this->headers      = Response\Headers::fromString($headers);
  39  
  40          $this->_interpretHeaders();
  41  
  42          $this->body         = $this->_parse($body);
  43      }
  44  
  45      /**
  46       * Status Code Definitions
  47       *
  48       * Informational 1xx
  49       * Successful    2xx
  50       * Redirection   3xx
  51       * Client Error  4xx
  52       * Server Error  5xx
  53       *
  54       * http://pretty-rfc.herokuapp.com/RFC2616#status.codes
  55       *
  56       * @return bool Did we receive a 4xx or 5xx?
  57       */
  58      public function hasErrors()
  59      {
  60          return $this->code >= 400;
  61      }
  62  
  63      /**
  64       * @return return bool
  65       */
  66      public function hasBody()
  67      {
  68          return !empty($this->body);
  69      }
  70  
  71      /**
  72       * Parse the response into a clean data structure
  73       * (most often an associative array) based on the expected
  74       * Mime type.
  75       * @return array|string|object the response parse accordingly
  76       * @param string Http response body
  77       */
  78      public function _parse($body)
  79      {
  80          // If the user decided to forgo the automatic
  81          // smart parsing, short circuit.
  82          if (!$this->request->auto_parse) {
  83              return $body;
  84          }
  85  
  86          // If provided, use custom parsing callback
  87          if (isset($this->request->parse_callback)) {
  88              return call_user_func($this->request->parse_callback, $body);
  89          }
  90  
  91          // Decide how to parse the body of the response in the following order
  92          //  1. If provided, use the mime type specifically set as part of the `Request`
  93          //  2. If a MimeHandler is registered for the content type, use it
  94          //  3. If provided, use the "parent type" of the mime type from the response
  95          //  4. Default to the content-type provided in the response
  96          $parse_with = $this->request->expected_type;
  97          if (empty($this->request->expected_type)) {
  98              $parse_with = Httpful::hasParserRegistered($this->content_type)
  99                  ? $this->content_type
 100                  : $this->parent_type;
 101          }
 102  
 103         return Httpful::get($parse_with)->parse($body);
 104      }
 105  
 106      /**
 107       * Parse text headers from response into
 108       * array of key value pairs
 109       * @return array parse headers
 110       * @param string $headers raw headers
 111       */
 112      public function _parseHeaders($headers)
 113      {
 114          $headers = preg_split("/(\r|\n)+/", $headers, -1, \PREG_SPLIT_NO_EMPTY);
 115          $parse_headers = array();
 116          for ($i = 1; $i < count($headers); $i++) {
 117              list($key, $raw_value) = explode(':', $headers[$i], 2);
 118              $key = trim($key);
 119              $value = trim($raw_value);
 120              if (array_key_exists($key, $parse_headers)) {
 121                  // See HTTP RFC Sec 4.2 Paragraph 5
 122                  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
 123                  // If a header appears more than once, it must also be able to
 124                  // be represented as a single header with a comma-separated
 125                  // list of values.  We transform accordingly.
 126                  $parse_headers[$key] .= ',' . $value;
 127              } else {
 128                  $parse_headers[$key] = $value;
 129              }
 130          }
 131          return $parse_headers;
 132      }
 133  
 134      public function _parseCode($headers)
 135      {
 136          $parts = explode(' ', substr($headers, 0, strpos($headers, "\r\n")));
 137          if (count($parts) < 2 || !is_numeric($parts[1])) {
 138              throw new \Exception("Unable to parse response code from HTTP response due to malformed response");
 139          }
 140          return intval($parts[1]);
 141      }
 142  
 143      /**
 144       * After we've parse the headers, let's clean things
 145       * up a bit and treat some headers specially
 146       */
 147      public function _interpretHeaders()
 148      {
 149          // Parse the Content-Type and charset
 150          $content_type = isset($this->headers['Content-Type']) ? $this->headers['Content-Type'] : '';
 151          $content_type = explode(';', $content_type);
 152  
 153          $this->content_type = $content_type[0];
 154          if (count($content_type) == 2 && strpos($content_type[1], '=') !== false) {
 155              list($nill, $this->charset) = explode('=', $content_type[1]);
 156          }
 157  
 158          // RFC 2616 states "text/*" Content-Types should have a default
 159          // charset of ISO-8859-1. "application/*" and other Content-Types
 160          // are assumed to have UTF-8 unless otherwise specified.
 161          // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
 162          // http://www.w3.org/International/O-HTTP-charset.en.php
 163          if (!isset($this->charset)) {
 164              $this->charset = substr($this->content_type, 5) === 'text/' ? 'iso-8859-1' : 'utf-8';
 165          }
 166  
 167          // Is vendor type? Is personal type?
 168          if (strpos($this->content_type, '/') !== false) {
 169              list($type, $sub_type) = explode('/', $this->content_type);
 170              $this->is_mime_vendor_specific = substr($sub_type, 0, 4) === 'vnd.';
 171              $this->is_mime_personal = substr($sub_type, 0, 4) === 'prs.';
 172          }
 173  
 174          // Parent type (e.g. xml for application/vnd.github.message+xml)
 175          $this->parent_type = $this->content_type;
 176          if (strpos($this->content_type, '+') !== false) {
 177              list($vendor, $this->parent_type) = explode('+', $this->content_type, 2);
 178              $this->parent_type = Mime::getFullMime($this->parent_type);
 179          }
 180      }
 181  
 182      /**
 183       * @return string
 184       */
 185      public function __toString()
 186      {
 187          return $this->raw_body;
 188      }
 189  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1