[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |