1<?php 2 3namespace Sabre\HTTP; 4 5/** 6 * This is the abstract base class for both the Request and Response objects. 7 * 8 * This object contains a few simple methods that are shared by both. 9 * 10 * @copyright Copyright (C) fruux GmbH (https://fruux.com/) 11 * @author Evert Pot (http://evertpot.com/) 12 * @license http://sabre.io/license/ Modified BSD License 13 */ 14abstract class Message implements MessageInterface { 15 16 /** 17 * Request body 18 * 19 * This should be a stream resource 20 * 21 * @var resource 22 */ 23 protected $body; 24 25 /** 26 * Contains the list of HTTP headers 27 * 28 * @var array 29 */ 30 protected $headers = []; 31 32 /** 33 * HTTP message version (1.0 or 1.1) 34 * 35 * @var string 36 */ 37 protected $httpVersion = '1.1'; 38 39 /** 40 * Returns the body as a readable stream resource. 41 * 42 * Note that the stream may not be rewindable, and therefore may only be 43 * read once. 44 * 45 * @return resource 46 */ 47 function getBodyAsStream() { 48 49 $body = $this->getBody(); 50 if (is_string($body) || is_null($body)) { 51 $stream = fopen('php://temp', 'r+'); 52 fwrite($stream, $body); 53 rewind($stream); 54 return $stream; 55 } 56 return $body; 57 58 } 59 60 /** 61 * Returns the body as a string. 62 * 63 * Note that because the underlying data may be based on a stream, this 64 * method could only work correctly the first time. 65 * 66 * @return string 67 */ 68 function getBodyAsString() { 69 70 $body = $this->getBody(); 71 if (is_string($body)) { 72 return $body; 73 } 74 if (is_null($body)) { 75 return ''; 76 } 77 $contentLength = $this->getHeader('Content-Length'); 78 if (is_int($contentLength) || ctype_digit($contentLength)) { 79 return stream_get_contents($body, $contentLength); 80 } else { 81 return stream_get_contents($body); 82 } 83 } 84 85 /** 86 * Returns the message body, as it's internal representation. 87 * 88 * This could be either a string or a stream. 89 * 90 * @return resource|string 91 */ 92 function getBody() { 93 94 return $this->body; 95 96 } 97 98 /** 99 * Replaces the body resource with a new stream or string. 100 * 101 * @param resource|string $body 102 */ 103 function setBody($body) { 104 105 $this->body = $body; 106 107 } 108 109 /** 110 * Returns all the HTTP headers as an array. 111 * 112 * Every header is returned as an array, with one or more values. 113 * 114 * @return array 115 */ 116 function getHeaders() { 117 118 $result = []; 119 foreach ($this->headers as $headerInfo) { 120 $result[$headerInfo[0]] = $headerInfo[1]; 121 } 122 return $result; 123 124 } 125 126 /** 127 * Will return true or false, depending on if a HTTP header exists. 128 * 129 * @param string $name 130 * @return bool 131 */ 132 function hasHeader($name) { 133 134 return isset($this->headers[strtolower($name)]); 135 136 } 137 138 /** 139 * Returns a specific HTTP header, based on it's name. 140 * 141 * The name must be treated as case-insensitive. 142 * If the header does not exist, this method must return null. 143 * 144 * If a header appeared more than once in a HTTP request, this method will 145 * concatenate all the values with a comma. 146 * 147 * Note that this not make sense for all headers. Some, such as 148 * `Set-Cookie` cannot be logically combined with a comma. In those cases 149 * you *should* use getHeaderAsArray(). 150 * 151 * @param string $name 152 * @return string|null 153 */ 154 function getHeader($name) { 155 156 $name = strtolower($name); 157 158 if (isset($this->headers[$name])) { 159 return implode(',', $this->headers[$name][1]); 160 } 161 return null; 162 163 } 164 165 /** 166 * Returns a HTTP header as an array. 167 * 168 * For every time the HTTP header appeared in the request or response, an 169 * item will appear in the array. 170 * 171 * If the header did not exists, this method will return an empty array. 172 * 173 * @param string $name 174 * @return string[] 175 */ 176 function getHeaderAsArray($name) { 177 178 $name = strtolower($name); 179 180 if (isset($this->headers[$name])) { 181 return $this->headers[$name][1]; 182 } 183 184 return []; 185 186 } 187 188 /** 189 * Updates a HTTP header. 190 * 191 * The case-sensitivity of the name value must be retained as-is. 192 * 193 * If the header already existed, it will be overwritten. 194 * 195 * @param string $name 196 * @param string|string[] $value 197 * @return void 198 */ 199 function setHeader($name, $value) { 200 201 $this->headers[strtolower($name)] = [$name, (array)$value]; 202 203 } 204 205 /** 206 * Sets a new set of HTTP headers. 207 * 208 * The headers array should contain headernames for keys, and their value 209 * should be specified as either a string or an array. 210 * 211 * Any header that already existed will be overwritten. 212 * 213 * @param array $headers 214 * @return void 215 */ 216 function setHeaders(array $headers) { 217 218 foreach ($headers as $name => $value) { 219 $this->setHeader($name, $value); 220 } 221 222 } 223 224 /** 225 * Adds a HTTP header. 226 * 227 * This method will not overwrite any existing HTTP header, but instead add 228 * another value. Individual values can be retrieved with 229 * getHeadersAsArray. 230 * 231 * @param string $name 232 * @param string $value 233 * @return void 234 */ 235 function addHeader($name, $value) { 236 237 $lName = strtolower($name); 238 if (isset($this->headers[$lName])) { 239 $this->headers[$lName][1] = array_merge( 240 $this->headers[$lName][1], 241 (array)$value 242 ); 243 } else { 244 $this->headers[$lName] = [ 245 $name, 246 (array)$value 247 ]; 248 } 249 250 } 251 252 /** 253 * Adds a new set of HTTP headers. 254 * 255 * Any existing headers will not be overwritten. 256 * 257 * @param array $headers 258 * @return void 259 */ 260 function addHeaders(array $headers) { 261 262 foreach ($headers as $name => $value) { 263 $this->addHeader($name, $value); 264 } 265 266 } 267 268 269 /** 270 * Removes a HTTP header. 271 * 272 * The specified header name must be treated as case-insensitive. 273 * This method should return true if the header was successfully deleted, 274 * and false if the header did not exist. 275 * 276 * @param string $name 277 * @return bool 278 */ 279 function removeHeader($name) { 280 281 $name = strtolower($name); 282 if (!isset($this->headers[$name])) { 283 return false; 284 } 285 unset($this->headers[$name]); 286 return true; 287 288 } 289 290 /** 291 * Sets the HTTP version. 292 * 293 * Should be 1.0 or 1.1. 294 * 295 * @param string $version 296 * @return void 297 */ 298 function setHttpVersion($version) { 299 300 $this->httpVersion = $version; 301 302 } 303 304 /** 305 * Returns the HTTP version. 306 * 307 * @return string 308 */ 309 function getHttpVersion() { 310 311 return $this->httpVersion; 312 313 } 314} 315