Minor dependency updates
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / Http / Response.php
1 <?php
2
3 /**
4  * EasyRdf
5  *
6  * LICENSE
7  *
8  * Copyright (c) 2009-2013 Nicholas J Humfrey.
9  * Copyright (c) 2005-2009 Zend Technologies USA Inc.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
20  *    promote products derived from this software without specific prior
21  *    written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * @package    EasyRdf
36  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
37  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc.
38  * @license    http://www.opensource.org/licenses/bsd-license.php
39  */
40
41 /**
42  * Class that represents an HTTP 1.0 / 1.1 response message.
43  *
44  * @package    EasyRdf
45  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
46  *             Copyright (c) 2005-2009 Zend Technologies USA Inc.
47  * @license    http://www.opensource.org/licenses/bsd-license.php
48  */
49 class EasyRdf_Http_Response
50 {
51
52     /**
53      * The HTTP response status code
54      *
55      * @var int
56      */
57     private $status;
58
59     /**
60      * The HTTP response code as string
61      * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500)
62      *
63      * @var string
64      */
65     private $message;
66
67     /**
68      * The HTTP response headers array
69      *
70      * @var array
71      */
72     private $headers = array();
73
74     /**
75      * The HTTP response body
76      *
77      * @var string
78      */
79     private $body;
80
81     /**
82      * Constructor.
83      *
84      * @param  int     $status HTTP Status code
85      * @param  array   $headers The HTTP response headers
86      * @param  string  $body The content of the response
87      * @param  string  $version The HTTP Version (1.0 or 1.1)
88      * @param  string  $message The HTTP response Message
89      * @return object  EasyRdf_Http_Response
90      */
91     public function __construct(
92         $status,
93         $headers,
94         $body = null,
95         $version = '1.1',
96         $message = null
97     ) {
98         $this->status = intval($status);
99         $this->body = $body;
100         $this->version = $version;
101         $this->message = $message;
102
103         foreach ($headers as $k => $v) {
104             $k = ucwords(strtolower($k));
105             $this->headers[$k] = $v;
106         }
107     }
108
109     /**
110      * Check whether the response in successful
111      *
112      * @return boolean
113      */
114     public function isSuccessful()
115     {
116         return ($this->status >= 200 && $this->status < 300);
117     }
118
119     /**
120      * Check whether the response is an error
121      *
122      * @return boolean
123      */
124     public function isError()
125     {
126         return ($this->status >= 400 && $this->status < 600);
127     }
128
129     /**
130      * Check whether the response is a redirection
131      *
132      * @return boolean
133      */
134     public function isRedirect()
135     {
136         return ($this->status >= 300 && $this->status < 400);
137     }
138
139     /**
140      * Get the HTTP response status code
141      *
142      * @return int
143      */
144     public function getStatus()
145     {
146         return $this->status;
147     }
148
149     /**
150      * Return a message describing the HTTP response code
151      * (Eg. "OK", "Not Found", "Moved Permanently")
152      *
153      * @return string
154      */
155     public function getMessage()
156     {
157         return $this->message;
158     }
159
160     /**
161      * Get the response body as string
162      *
163      * @return string
164      */
165     public function getBody()
166     {
167         // Decode the body if it was transfer-encoded
168         switch (strtolower($this->getHeader('transfer-encoding'))) {
169             // Handle chunked body
170             case 'chunked':
171                 return self::decodeChunkedBody($this->body);
172                 break;
173
174             // No transfer encoding, or unknown encoding extension:
175             // return body as is
176             default:
177                 return $this->body;
178                 break;
179         }
180     }
181
182     /**
183      * Get the raw response body (as transfered "on wire") as string
184      *
185      * If the body is encoded (with Transfer-Encoding, not content-encoding -
186      * IE "chunked" body), gzip compressed, etc. it will not be decoded.
187      *
188      * @return string
189      */
190     public function getRawBody()
191     {
192         return $this->body;
193     }
194
195     /**
196      * Get the HTTP version of the response
197      *
198      * @return string
199      */
200     public function getVersion()
201     {
202         return $this->version;
203     }
204
205     /**
206      * Get the response headers
207      *
208      * @return array
209      */
210     public function getHeaders()
211     {
212         return $this->headers;
213     }
214
215     /**
216      * Get a specific header as string, or null if it is not set
217      *
218      * @param string$header
219      * @return string|array|null
220      */
221     public function getHeader($header)
222     {
223         $header = ucwords(strtolower($header));
224         if (array_key_exists($header, $this->headers)) {
225             return $this->headers[$header];
226         } else {
227             return null;
228         }
229     }
230
231     /**
232      * Get all headers as string
233      *
234      * @param boolean $statusLine Whether to return the first status line (ie "HTTP 200 OK")
235      * @param string  $br         Line breaks (eg. "\n", "\r\n", "<br />")
236      * @return string
237      */
238     public function getHeadersAsString($statusLine = true, $br = "\n")
239     {
240         $str = '';
241
242         if ($statusLine) {
243             $str = "HTTP/{$this->version} {$this->status} {$this->message}{$br}";
244         }
245
246         // Iterate over the headers and stringify them
247         foreach ($this->headers as $name => $value) {
248             if (is_string($value)) {
249                 $str .= "{$name}: {$value}{$br}";
250             } elseif (is_array($value)) {
251                 foreach ($value as $subval) {
252                     $str .= "{$name}: {$subval}{$br}";
253                 }
254             }
255         }
256
257         return $str;
258     }
259
260     /**
261      * Create an EasyRdf_Http_Response object from a HTTP response string
262      *
263      * @param string $responseStr
264      * @return EasyRdf_Http_Response
265      */
266     public static function fromString($responseStr)
267     {
268         // First, split body and headers
269         $matches = preg_split('|(?:\r?\n){2}|m', $responseStr, 2);
270         if ($matches and sizeof($matches) == 2) {
271             list ($headerLines, $body) = $matches;
272         } else {
273             throw new EasyRdf_Exception(
274                 "Failed to parse HTTP response."
275             );
276         }
277
278         // Split headers part to lines
279         $headerLines = preg_split('|[\r\n]+|m', $headerLines);
280         $status = array_shift($headerLines);
281         if (preg_match("|^HTTP/([\d\.x]+) (\d+) ([^\r\n]+)|", $status, $m)) {
282             $version = $m[1];
283             $status = $m[2];
284             $message = $m[3];
285         } else {
286             throw new EasyRdf_Exception(
287                 "Failed to parse HTTP response status line."
288             );
289         }
290
291         // Process the rest of the header lines
292         $headers = array();
293         foreach ($headerLines as $line) {
294             if (preg_match("|^([\w-]+):\s+(.+)$|", $line, $m)) {
295                 $hName = ucwords(strtolower($m[1]));
296                 $hValue = $m[2];
297
298                 if (isset($headers[$hName])) {
299                     if (! is_array($headers[$hName])) {
300                         $headers[$hName] = array($headers[$hName]);
301                     }
302                     $headers[$hName][] = $hValue;
303                 } else {
304                     $headers[$hName] = $hValue;
305                 }
306             }
307         }
308
309         return new EasyRdf_Http_Response($status, $headers, $body, $version, $message);
310     }
311
312
313     /**
314      * Decode a "chunked" transfer-encoded body and return the decoded text
315      *
316      * @param string $body
317      * @return string
318      */
319     public static function decodeChunkedBody($body)
320     {
321         $decBody = '';
322
323         while (trim($body)) {
324             if (preg_match('/^([\da-fA-F]+)[^\r\n]*\r\n/sm', $body, $m)) {
325                 $length = hexdec(trim($m[1]));
326                 $cut = strlen($m[0]);
327                 $decBody .= substr($body, $cut, $length);
328                 $body = substr($body, $cut + $length + 2);
329             } else {
330                 throw new EasyRdf_Exception(
331                     "Failed to decode chunked body in HTTP response."
332                 );
333             }
334         }
335
336         return $decBody;
337     }
338
339
340     /**
341      * Get the entire response as string
342      *
343      * @param string $br Line breaks (eg. "\n", "\r\n", "<br />")
344      * @return string
345      */
346     public function asString($br = "\n")
347     {
348         return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody();
349     }
350
351     /**
352      * Implements magic __toString()
353      *
354      * @return string
355      */
356     public function __toString()
357     {
358         return $this->asString();
359     }
360 }