Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Http / Response.php
bloba43bbaf6b6280e5ea6fc7d3fefd3a4a25751a468
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Http;
12 use Zend\Stdlib\ErrorHandler;
13 use Zend\Stdlib\ResponseInterface;
15 /**
16 * HTTP Response
18 * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6
20 class Response extends AbstractMessage implements ResponseInterface
22 /**#@+
23 * @const int Status codes
25 const STATUS_CODE_CUSTOM = 0;
26 const STATUS_CODE_100 = 100;
27 const STATUS_CODE_101 = 101;
28 const STATUS_CODE_102 = 102;
29 const STATUS_CODE_200 = 200;
30 const STATUS_CODE_201 = 201;
31 const STATUS_CODE_202 = 202;
32 const STATUS_CODE_203 = 203;
33 const STATUS_CODE_204 = 204;
34 const STATUS_CODE_205 = 205;
35 const STATUS_CODE_206 = 206;
36 const STATUS_CODE_207 = 207;
37 const STATUS_CODE_208 = 208;
38 const STATUS_CODE_300 = 300;
39 const STATUS_CODE_301 = 301;
40 const STATUS_CODE_302 = 302;
41 const STATUS_CODE_303 = 303;
42 const STATUS_CODE_304 = 304;
43 const STATUS_CODE_305 = 305;
44 const STATUS_CODE_306 = 306;
45 const STATUS_CODE_307 = 307;
46 const STATUS_CODE_400 = 400;
47 const STATUS_CODE_401 = 401;
48 const STATUS_CODE_402 = 402;
49 const STATUS_CODE_403 = 403;
50 const STATUS_CODE_404 = 404;
51 const STATUS_CODE_405 = 405;
52 const STATUS_CODE_406 = 406;
53 const STATUS_CODE_407 = 407;
54 const STATUS_CODE_408 = 408;
55 const STATUS_CODE_409 = 409;
56 const STATUS_CODE_410 = 410;
57 const STATUS_CODE_411 = 411;
58 const STATUS_CODE_412 = 412;
59 const STATUS_CODE_413 = 413;
60 const STATUS_CODE_414 = 414;
61 const STATUS_CODE_415 = 415;
62 const STATUS_CODE_416 = 416;
63 const STATUS_CODE_417 = 417;
64 const STATUS_CODE_418 = 418;
65 const STATUS_CODE_422 = 422;
66 const STATUS_CODE_423 = 423;
67 const STATUS_CODE_424 = 424;
68 const STATUS_CODE_425 = 425;
69 const STATUS_CODE_426 = 426;
70 const STATUS_CODE_428 = 428;
71 const STATUS_CODE_429 = 429;
72 const STATUS_CODE_431 = 431;
73 const STATUS_CODE_500 = 500;
74 const STATUS_CODE_501 = 501;
75 const STATUS_CODE_502 = 502;
76 const STATUS_CODE_503 = 503;
77 const STATUS_CODE_504 = 504;
78 const STATUS_CODE_505 = 505;
79 const STATUS_CODE_506 = 506;
80 const STATUS_CODE_507 = 507;
81 const STATUS_CODE_508 = 508;
82 const STATUS_CODE_511 = 511;
83 /**#@-*/
85 /**
86 * @var array Recommended Reason Phrases
88 protected $recommendedReasonPhrases = array(
89 // INFORMATIONAL CODES
90 100 => 'Continue',
91 101 => 'Switching Protocols',
92 102 => 'Processing',
93 // SUCCESS CODES
94 200 => 'OK',
95 201 => 'Created',
96 202 => 'Accepted',
97 203 => 'Non-Authoritative Information',
98 204 => 'No Content',
99 205 => 'Reset Content',
100 206 => 'Partial Content',
101 207 => 'Multi-status',
102 208 => 'Already Reported',
103 // REDIRECTION CODES
104 300 => 'Multiple Choices',
105 301 => 'Moved Permanently',
106 302 => 'Found',
107 303 => 'See Other',
108 304 => 'Not Modified',
109 305 => 'Use Proxy',
110 306 => 'Switch Proxy', // Deprecated
111 307 => 'Temporary Redirect',
112 // CLIENT ERROR
113 400 => 'Bad Request',
114 401 => 'Unauthorized',
115 402 => 'Payment Required',
116 403 => 'Forbidden',
117 404 => 'Not Found',
118 405 => 'Method Not Allowed',
119 406 => 'Not Acceptable',
120 407 => 'Proxy Authentication Required',
121 408 => 'Request Time-out',
122 409 => 'Conflict',
123 410 => 'Gone',
124 411 => 'Length Required',
125 412 => 'Precondition Failed',
126 413 => 'Request Entity Too Large',
127 414 => 'Request-URI Too Large',
128 415 => 'Unsupported Media Type',
129 416 => 'Requested range not satisfiable',
130 417 => 'Expectation Failed',
131 418 => 'I\'m a teapot',
132 422 => 'Unprocessable Entity',
133 423 => 'Locked',
134 424 => 'Failed Dependency',
135 425 => 'Unordered Collection',
136 426 => 'Upgrade Required',
137 428 => 'Precondition Required',
138 429 => 'Too Many Requests',
139 431 => 'Request Header Fields Too Large',
140 // SERVER ERROR
141 500 => 'Internal Server Error',
142 501 => 'Not Implemented',
143 502 => 'Bad Gateway',
144 503 => 'Service Unavailable',
145 504 => 'Gateway Time-out',
146 505 => 'HTTP Version not supported',
147 506 => 'Variant Also Negotiates',
148 507 => 'Insufficient Storage',
149 508 => 'Loop Detected',
150 511 => 'Network Authentication Required',
154 * @var int Status code
156 protected $statusCode = 200;
159 * @var string|null Null means it will be looked up from the $reasonPhrase list above
161 protected $reasonPhrase = null;
164 * Populate object from string
166 * @param string $string
167 * @return Response
168 * @throws Exception\InvalidArgumentException
170 public static function fromString($string)
172 $lines = explode("\r\n", $string);
173 if (!is_array($lines) || count($lines) == 1) {
174 $lines = explode("\n", $string);
177 $firstLine = array_shift($lines);
179 $response = new static();
181 $regex = '/^HTTP\/(?P<version>1\.[01]) (?P<status>\d{3})(?:[ ]+(?P<reason>.*))?$/';
182 $matches = array();
183 if (!preg_match($regex, $firstLine, $matches)) {
184 throw new Exception\InvalidArgumentException(
185 'A valid response status line was not found in the provided string'
189 $response->version = $matches['version'];
190 $response->setStatusCode($matches['status']);
191 $response->setReasonPhrase((isset($matches['reason']) ? $matches['reason'] : ''));
193 if (count($lines) == 0) {
194 return $response;
197 $isHeader = true;
198 $headers = $content = array();
200 while ($lines) {
201 $nextLine = array_shift($lines);
203 if ($isHeader && $nextLine == '') {
204 $isHeader = false;
205 continue;
207 if ($isHeader) {
208 $headers[] = $nextLine;
209 } else {
210 $content[] = $nextLine;
214 if ($headers) {
215 $response->headers = implode("\r\n", $headers);
218 if ($content) {
219 $response->setContent(implode("\r\n", $content));
222 return $response;
226 * @return Header\SetCookie[]
228 public function getCookie()
230 return $this->getHeaders()->get('Set-Cookie');
234 * Set HTTP status code and (optionally) message
236 * @param int $code
237 * @throws Exception\InvalidArgumentException
238 * @return Response
240 public function setStatusCode($code)
242 if (!is_numeric($code)) {
243 $code = is_scalar($code) ? $code : gettype($code);
244 throw new Exception\InvalidArgumentException(sprintf(
245 'Invalid status code provided: "%s"',
246 $code
249 $this->statusCode = (int) $code;
250 return $this;
254 * Retrieve HTTP status code
256 * @return int
258 public function getStatusCode()
260 return $this->statusCode;
264 * @param string $reasonPhrase
265 * @return Response
267 public function setReasonPhrase($reasonPhrase)
269 $this->reasonPhrase = trim($reasonPhrase);
270 return $this;
274 * Get HTTP status message
276 * @return string
278 public function getReasonPhrase()
280 if ($this->reasonPhrase == null) {
281 return $this->recommendedReasonPhrases[$this->statusCode];
283 return $this->reasonPhrase;
287 * Get the body of the response
289 * @return string
291 public function getBody()
293 $body = (string) $this->getContent();
295 $transferEncoding = $this->getHeaders()->get('Transfer-Encoding');
297 if (!empty($transferEncoding)) {
298 if (strtolower($transferEncoding->getFieldValue()) == 'chunked') {
299 $body = $this->decodeChunkedBody($body);
303 $contentEncoding = $this->getHeaders()->get('Content-Encoding');
305 if (!empty($contentEncoding)) {
306 $contentEncoding = $contentEncoding->getFieldValue();
307 if ($contentEncoding =='gzip') {
308 $body = $this->decodeGzip($body);
309 } elseif ($contentEncoding == 'deflate') {
310 $body = $this->decodeDeflate($body);
314 return $body;
318 * Does the status code indicate a client error?
320 * @return bool
322 public function isClientError()
324 $code = $this->getStatusCode();
325 return ($code < 500 && $code >= 400);
329 * Is the request forbidden due to ACLs?
331 * @return bool
333 public function isForbidden()
335 return (403 == $this->getStatusCode());
339 * Is the current status "informational"?
341 * @return bool
343 public function isInformational()
345 $code = $this->getStatusCode();
346 return ($code >= 100 && $code < 200);
350 * Does the status code indicate the resource is not found?
352 * @return bool
354 public function isNotFound()
356 return (404 === $this->getStatusCode());
360 * Do we have a normal, OK response?
362 * @return bool
364 public function isOk()
366 return (200 === $this->getStatusCode());
370 * Does the status code reflect a server error?
372 * @return bool
374 public function isServerError()
376 $code = $this->getStatusCode();
377 return (500 <= $code && 600 > $code);
381 * Do we have a redirect?
383 * @return bool
385 public function isRedirect()
387 $code = $this->getStatusCode();
388 return (300 <= $code && 400 > $code);
392 * Was the response successful?
394 * @return bool
396 public function isSuccess()
398 $code = $this->getStatusCode();
399 return (200 <= $code && 300 > $code);
403 * Render the status line header
405 * @return string
407 public function renderStatusLine()
409 $status = sprintf(
410 'HTTP/%s %d %s',
411 $this->getVersion(),
412 $this->getStatusCode(),
413 $this->getReasonPhrase()
415 return trim($status);
419 * Render entire response as HTTP response string
421 * @return string
423 public function toString()
425 $str = $this->renderStatusLine() . "\r\n";
426 $str .= $this->getHeaders()->toString();
427 $str .= "\r\n";
428 $str .= $this->getContent();
429 return $str;
433 * Decode a "chunked" transfer-encoded body and return the decoded text
435 * @param string $body
436 * @return string
437 * @throws Exception\RuntimeException
439 protected function decodeChunkedBody($body)
441 $decBody = '';
443 while (trim($body)) {
444 if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) {
445 throw new Exception\RuntimeException(
446 "Error parsing body - doesn't seem to be a chunked message"
450 $length = hexdec(trim($m[1]));
451 $cut = strlen($m[0]);
452 $decBody .= substr($body, $cut, $length);
453 $body = substr($body, $cut + $length + 2);
456 return $decBody;
460 * Decode a gzip encoded message (when Content-encoding = gzip)
462 * Currently requires PHP with zlib support
464 * @param string $body
465 * @return string
466 * @throws Exception\RuntimeException
468 protected function decodeGzip($body)
470 if (!function_exists('gzinflate')) {
471 throw new Exception\RuntimeException(
472 'zlib extension is required in order to decode "gzip" encoding'
476 ErrorHandler::start();
477 $return = gzinflate(substr($body, 10));
478 $test = ErrorHandler::stop();
479 if ($test) {
480 throw new Exception\RuntimeException(
481 'Error occurred during gzip inflation',
483 $test
486 return $return;
490 * Decode a zlib deflated message (when Content-encoding = deflate)
492 * Currently requires PHP with zlib support
494 * @param string $body
495 * @return string
496 * @throws Exception\RuntimeException
498 protected function decodeDeflate($body)
500 if (!function_exists('gzuncompress')) {
501 throw new Exception\RuntimeException(
502 'zlib extension is required in order to decode "deflate" encoding'
507 * Some servers (IIS ?) send a broken deflate response, without the
508 * RFC-required zlib header.
510 * We try to detect the zlib header, and if it does not exist we
511 * teat the body is plain DEFLATE content.
513 * This method was adapted from PEAR HTTP_Request2 by (c) Alexey Borzov
515 * @link http://framework.zend.com/issues/browse/ZF-6040
517 $zlibHeader = unpack('n', substr($body, 0, 2));
519 if ($zlibHeader[1] % 31 == 0) {
520 return gzuncompress($body);
522 return gzinflate($body);