method = $this->filterMethod($method); $this->uri = $uri; $this->headers = $headers; $this->cookies = $cookies; $this->serverParams = $serverParams; $this->attributes = []; $this->body = $body; $this->uploadedFiles = $uploadedFiles; if (isset($serverParams['SERVER_PROTOCOL'])) { $this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']); } if (!$this->headers->hasHeader('Host') || $this->uri->getHost() !== '') { $this->headers->setHeader('Host', $this->uri->getHost()); } } /** * This method is applied to the cloned object after PHP performs an initial shallow-copy. * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers. */ public function __clone() { $this->headers = clone $this->headers; $this->body = clone $this->body; } /** * {@inheritdoc} */ public function getMethod(): string { return $this->method; } /** * {@inheritdoc} */ public function withMethod($method) { $method = $this->filterMethod($method); $clone = clone $this; $clone->method = $method; return $clone; } /** * Validate the HTTP method * * @param string $method * * @return string * * @throws InvalidArgumentException on invalid HTTP method. */ protected function filterMethod($method): string { /** @var mixed $method */ if (!is_string($method)) { throw new InvalidArgumentException(sprintf( 'Unsupported HTTP method; must be a string, received %s', (is_object($method) ? get_class($method) : gettype($method)) )); } if (preg_match("/^[!#$%&'*+.^_`|~0-9a-z-]+$/i", $method) !== 1) { throw new InvalidArgumentException(sprintf( 'Unsupported HTTP method "%s" provided', $method )); } return $method; } /** * {@inheritdoc} */ public function getRequestTarget(): string { if ($this->requestTarget) { return $this->requestTarget; } if ($this->uri === null) { return '/'; } $path = $this->uri->getPath(); $path = '/' . ltrim($path, '/'); $query = $this->uri->getQuery(); if ($query) { $path .= '?' . $query; } return $path; } /** * {@inheritdoc} */ public function withRequestTarget($requestTarget) { if (preg_match('#\s#', $requestTarget)) { throw new InvalidArgumentException( 'Invalid request target provided; must be a string and cannot contain whitespace' ); } $clone = clone $this; $clone->requestTarget = $requestTarget; return $clone; } /** * {@inheritdoc} */ public function getUri(): UriInterface { return $this->uri; } /** * {@inheritdoc} */ public function withUri(UriInterface $uri, $preserveHost = false) { $clone = clone $this; $clone->uri = $uri; if (!$preserveHost && $uri->getHost() !== '') { $clone->headers->setHeader('Host', $uri->getHost()); return $clone; } if (($uri->getHost() !== '' && !$this->hasHeader('Host') || $this->getHeaderLine('Host') === '')) { $clone->headers->setHeader('Host', $uri->getHost()); return $clone; } return $clone; } /** * {@inheritdoc} */ public function getCookieParams(): array { return $this->cookies; } /** * {@inheritdoc} */ public function withCookieParams(array $cookies) { $clone = clone $this; $clone->cookies = $cookies; return $clone; } /** * {@inheritdoc} */ public function getQueryParams(): array { if (is_array($this->queryParams)) { return $this->queryParams; } if ($this->uri === null) { return []; } parse_str($this->uri->getQuery(), $this->queryParams); // <-- URL decodes data assert(is_array($this->queryParams)); return $this->queryParams; } /** * {@inheritdoc} */ public function withQueryParams(array $query) { $clone = clone $this; $clone->queryParams = $query; return $clone; } /** * {@inheritdoc} */ public function getUploadedFiles(): array { return $this->uploadedFiles; } /** * {@inheritdoc} */ public function withUploadedFiles(array $uploadedFiles) { $clone = clone $this; $clone->uploadedFiles = $uploadedFiles; return $clone; } /** * {@inheritdoc} */ public function getServerParams(): array { return $this->serverParams; } /** * {@inheritdoc} */ public function getAttributes(): array { return $this->attributes; } /** * {@inheritdoc} */ public function getAttribute($name, $default = null) { return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; } /** * {@inheritdoc} */ public function withAttribute($name, $value) { $clone = clone $this; $clone->attributes[$name] = $value; return $clone; } /** * {@inheritdoc} */ public function withoutAttribute($name) { $clone = clone $this; unset($clone->attributes[$name]); return $clone; } /** * {@inheritdoc} */ public function getParsedBody() { return $this->parsedBody; } /** * {@inheritdoc} */ public function withParsedBody($data) { /** @var mixed $data */ if (!is_null($data) && !is_object($data) && !is_array($data)) { throw new InvalidArgumentException('Parsed body value must be an array, an object, or null'); } $clone = clone $this; $clone->parsedBody = $data; return $clone; } }