1: <?php
2: /**
3: * Copyright 2007-2012 Horde LLC (http://www.horde.org/)
4: *
5: * @author Chuck Hagenbuch <chuck@horde.org>
6: * @license http://www.horde.org/licenses/bsd BSD
7: * @category Horde
8: * @package Http
9: */
10:
11: /**
12: * @author Chuck Hagenbuch <chuck@horde.org>
13: * @license http://www.horde.org/licenses/bsd BSD
14: * @category Horde
15: * @package Http
16: */
17: abstract class Horde_Http_Response_Base
18: {
19: /**
20: * Fetched URI.
21: *
22: * @var string
23: */
24: public $uri;
25:
26: /**
27: * HTTP protocol version that was used.
28: *
29: * @var float
30: */
31: public $httpVersion;
32:
33: /**
34: * HTTP response code.
35: *
36: * @var integer
37: */
38: public $code;
39:
40: /**
41: * Response headers.
42: *
43: * @var array
44: */
45: public $headers;
46:
47: /**
48: * Parses an array of response headers, mindful of line continuations, etc.
49: *
50: * @param array $headers
51: *
52: * @return array
53: */
54: protected function _parseHeaders($headers)
55: {
56: if (!is_array($headers)) {
57: $headers = preg_split("/\r?\n/", $headers);
58: }
59:
60: $this->headers = array();
61:
62: $lastHeader = null;
63: foreach ($headers as $headerLine) {
64: // stream_get_meta returns all headers generated while processing
65: // a request, including ones for redirects before an eventually
66: // successful request. We just want the last one, so whenever we
67: // hit a new HTTP header, throw out anything parsed previously and
68: // start over.
69: if (preg_match('/^HTTP\/(\d.\d) (\d{3})/', $headerLine, $httpMatches)) {
70: $this->httpVersion = $httpMatches[1];
71: $this->code = (int)$httpMatches[2];
72: $this->headers = array();
73: $lastHeader = null;
74: }
75:
76: $headerLine = trim($headerLine, "\r\n");
77: if ($headerLine == '') {
78: break;
79: }
80: if (preg_match('|^([\w-]+):\s+(.+)|', $headerLine, $m)) {
81: unset($lastHeader);
82: $headerName = strtolower($m[1]);
83: $headerValue = $m[2];
84:
85: if (isset($this->headers[$headerName])) {
86: if (!is_array($this->headers[$headerName])) {
87: $this->headers[$headerName] = array($this->headers[$headerName]);
88: }
89:
90: $this->headers[$headerName][] = $headerValue;
91: } else {
92: $this->headers[$headerName] = $headerValue;
93: }
94: $lastHeader = $headerName;
95: } elseif (preg_match("|^\s+(.+)$|", $headerLine, $m) && !is_null($lastHeader)) {
96: if (is_array($this->headers[$lastHeader])) {
97: end($this->headers[$lastHeader]);
98: $this->headers[$lastHeader][key($this->headers[$lastHeader])] .= $m[1];
99: } else {
100: $this->headers[$lastHeader] .= $m[1];
101: }
102: }
103: }
104: }
105:
106: /**
107: * Returns the body of the HTTP response.
108: *
109: * @throws Horde_Http_Exception
110: * @return string HTTP response body.
111: */
112: abstract public function getBody();
113:
114: /**
115: * Returns a stream pointing to the response body that can be used with all
116: * standard PHP stream functions.
117: */
118: public function getStream()
119: {
120: $string_body = $this->getBody();
121: $body = new Horde_Support_StringStream($string_body);
122: return $body->fopen();
123: }
124:
125: /**
126: * Returns the value of a single response header.
127: *
128: * @param string $header Header name to get ('Content-Type',
129: * 'Content-Length', etc.). This is case sensitive.
130: *
131: * @return string HTTP header value.
132: */
133: public function getHeader($header)
134: {
135: return isset($this->headers[$header]) ? $this->headers[$header] : null;
136: }
137: }
138: