You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.2 KiB
239 lines
6.2 KiB
<?php |
|
|
|
/** |
|
* This file is part of CodeIgniter 4 framework. |
|
* |
|
* (c) CodeIgniter Foundation <admin@codeigniter.com> |
|
* |
|
* For the full copyright and license information, please view |
|
* the LICENSE file that was distributed with this source code. |
|
*/ |
|
|
|
namespace CodeIgniter\HTTP; |
|
|
|
use CodeIgniter\HTTP\Exceptions\HTTPException; |
|
|
|
/** |
|
* Message Trait |
|
* Additional methods to make a PSR-7 Message class |
|
* compliant with the framework's own MessageInterface. |
|
* |
|
* @see https://github.com/php-fig/http-message/blob/master/src/MessageInterface.php |
|
*/ |
|
trait MessageTrait |
|
{ |
|
/** |
|
* List of all HTTP request headers. |
|
* |
|
* @var array<string, Header> |
|
*/ |
|
protected $headers = []; |
|
|
|
/** |
|
* Holds a map of lower-case header names |
|
* and their normal-case key as it is in $headers. |
|
* Used for case-insensitive header access. |
|
* |
|
* @var array |
|
*/ |
|
protected $headerMap = []; |
|
|
|
// -------------------------------------------------------------------- |
|
// Body |
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Sets the body of the current message. |
|
* |
|
* @param string $data |
|
* |
|
* @return $this |
|
*/ |
|
public function setBody($data): self |
|
{ |
|
$this->body = $data; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Appends data to the body of the current message. |
|
* |
|
* @param string $data |
|
* |
|
* @return $this |
|
*/ |
|
public function appendBody($data): self |
|
{ |
|
$this->body .= (string) $data; |
|
|
|
return $this; |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
// Headers |
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
* Populates the $headers array with any headers the server knows about. |
|
*/ |
|
public function populateHeaders(): void |
|
{ |
|
$contentType = $_SERVER['CONTENT_TYPE'] ?? getenv('CONTENT_TYPE'); |
|
if (! empty($contentType)) { |
|
$this->setHeader('Content-Type', $contentType); |
|
} |
|
unset($contentType); |
|
|
|
foreach (array_keys($_SERVER) as $key) { |
|
if (sscanf($key, 'HTTP_%s', $header) === 1) { |
|
// take SOME_HEADER and turn it into Some-Header |
|
$header = str_replace('_', ' ', strtolower($header)); |
|
$header = str_replace(' ', '-', ucwords($header)); |
|
|
|
$this->setHeader($header, $_SERVER[$key]); |
|
|
|
// Add us to the header map so we can find them case-insensitively |
|
$this->headerMap[strtolower($header)] = $header; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Returns an array containing all Headers. |
|
* |
|
* @return array<string, Header> An array of the Header objects |
|
*/ |
|
public function headers(): array |
|
{ |
|
// If no headers are defined, but the user is |
|
// requesting it, then it's likely they want |
|
// it to be populated so do that... |
|
if (empty($this->headers)) { |
|
$this->populateHeaders(); |
|
} |
|
|
|
return $this->headers; |
|
} |
|
|
|
/** |
|
* Returns a single Header object. If multiple headers with the same |
|
* name exist, then will return an array of header objects. |
|
* |
|
* @param string $name |
|
* |
|
* @return array|Header|null |
|
*/ |
|
public function header($name) |
|
{ |
|
$origName = $this->getHeaderName($name); |
|
|
|
return $this->headers[$origName] ?? null; |
|
} |
|
|
|
/** |
|
* Sets a header and it's value. |
|
* |
|
* @param array|string|null $value |
|
* |
|
* @return $this |
|
*/ |
|
public function setHeader(string $name, $value): self |
|
{ |
|
$origName = $this->getHeaderName($name); |
|
|
|
if (isset($this->headers[$origName]) && is_array($this->headers[$origName]->getValue())) { |
|
if (! is_array($value)) { |
|
$value = [$value]; |
|
} |
|
|
|
foreach ($value as $v) { |
|
$this->appendHeader($origName, $v); |
|
} |
|
} else { |
|
$this->headers[$origName] = new Header($origName, $value); |
|
$this->headerMap[strtolower($origName)] = $origName; |
|
} |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Removes a header from the list of headers we track. |
|
* |
|
* @return $this |
|
*/ |
|
public function removeHeader(string $name): self |
|
{ |
|
$origName = $this->getHeaderName($name); |
|
unset($this->headers[$origName], $this->headerMap[strtolower($name)]); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Adds an additional header value to any headers that accept |
|
* multiple values (i.e. are an array or implement ArrayAccess) |
|
* |
|
* @return $this |
|
*/ |
|
public function appendHeader(string $name, ?string $value): self |
|
{ |
|
$origName = $this->getHeaderName($name); |
|
|
|
array_key_exists($origName, $this->headers) |
|
? $this->headers[$origName]->appendValue($value) |
|
: $this->setHeader($name, $value); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Adds an additional header value to any headers that accept |
|
* multiple values (i.e. are an array or implement ArrayAccess) |
|
* |
|
* @return $this |
|
*/ |
|
public function prependHeader(string $name, string $value): self |
|
{ |
|
$origName = $this->getHeaderName($name); |
|
|
|
$this->headers[$origName]->prependValue($value); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Takes a header name in any case, and returns the |
|
* normal-case version of the header. |
|
*/ |
|
protected function getHeaderName(string $name): string |
|
{ |
|
return $this->headerMap[strtolower($name)] ?? $name; |
|
} |
|
|
|
/** |
|
* Sets the HTTP protocol version. |
|
* |
|
* @return $this |
|
* |
|
* @throws HTTPException For invalid protocols |
|
*/ |
|
public function setProtocolVersion(string $version): self |
|
{ |
|
if (! is_numeric($version)) { |
|
$version = substr($version, strpos($version, '/') + 1); |
|
} |
|
|
|
// Make sure that version is in the correct format |
|
$version = number_format((float) $version, 1); |
|
|
|
if (! in_array($version, $this->validProtocolVersions, true)) { |
|
throw HTTPException::forInvalidHTTPProtocol($version); |
|
} |
|
|
|
$this->protocolVersion = $version; |
|
|
|
return $this; |
|
} |
|
}
|
|
|