1<?php 2/** 3 * Copyright 2007-2016 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 */ 17abstract 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 * Case-insensitive list of headers. 49 * 50 * @var Horde_Support_CaseInsensitiveArray 51 */ 52 protected $_headers; 53 54 /** 55 * Parses an array of response headers, mindful of line continuations, etc. 56 * 57 * @param array $headers 58 * 59 * @return array 60 */ 61 protected function _parseHeaders($headers) 62 { 63 if (!is_array($headers)) { 64 $headers = preg_split("/\r?\n/", $headers); 65 } 66 67 $this->_headers = new Horde_Support_CaseInsensitiveArray(); 68 69 $lastHeader = null; 70 foreach ($headers as $headerLine) { 71 // stream_get_meta returns all headers generated while processing 72 // a request, including ones for redirects before an eventually 73 // successful request. We just want the last one, so whenever we 74 // hit a new HTTP header, throw out anything parsed previously and 75 // start over. 76 if (preg_match('/^HTTP\/(\d.\d) (\d{3})/', $headerLine, $httpMatches)) { 77 $this->httpVersion = $httpMatches[1]; 78 $this->code = (int)$httpMatches[2]; 79 $this->_headers = new Horde_Support_CaseInsensitiveArray(); 80 $lastHeader = null; 81 } 82 83 $headerLine = trim($headerLine, "\r\n"); 84 if ($headerLine == '') { 85 break; 86 } 87 if (preg_match('|^([\w-]+):\s+(.+)|', $headerLine, $m)) { 88 $headerName = $m[1]; 89 $headerValue = $m[2]; 90 91 if ($tmp = $this->_headers[$headerName]) { 92 if (!is_array($tmp)) { 93 $tmp = array($tmp); 94 } 95 $tmp[] = $headerValue; 96 $headerValue = $tmp; 97 } 98 99 $this->_headers[$headerName] = $headerValue; 100 $lastHeader = $headerName; 101 } elseif (preg_match("|^\s+(.+)$|", $headerLine, $m) && 102 !is_null($lastHeader)) { 103 if (is_array($this->_headers[$lastHeader])) { 104 $tmp = $this->_headers[$lastHeader]; 105 end($tmp); 106 $tmp[key($tmp)] .= $m[1]; 107 $this->_headers[$lastHeader] = $tmp; 108 } else { 109 $this->_headers[$lastHeader] .= $m[1]; 110 } 111 } 112 } 113 114 $this->headers = array_change_key_case($this->_headers->getArrayCopy()); 115 } 116 117 /** 118 * Returns the body of the HTTP response. 119 * 120 * @throws Horde_Http_Exception 121 * @return string HTTP response body. 122 */ 123 abstract public function getBody(); 124 125 /** 126 * Returns a stream pointing to the response body that can be used with all 127 * standard PHP stream functions. 128 */ 129 public function getStream() 130 { 131 $string_body = $this->getBody(); 132 $body = new Horde_Support_StringStream($string_body); 133 return $body->fopen(); 134 } 135 136 /** 137 * Returns the value of a single response header. 138 * 139 * @param string $header Header name to get ('Content-Type', 140 * 'Content-Length', etc.). 141 * 142 * @return string HTTP header value. 143 */ 144 public function getHeader($header) 145 { 146 return $this->_headers[$header]; 147 } 148} 149