Chris@0: array of values */ Chris@0: private $headers = []; Chris@0: Chris@0: /** @var array Map of lowercase header name => original name at registration */ Chris@0: private $headerNames = []; Chris@0: Chris@0: /** @var string */ Chris@0: private $protocol = '1.1'; Chris@0: Chris@0: /** @var StreamInterface */ Chris@0: private $stream; Chris@0: Chris@0: public function getProtocolVersion() Chris@0: { Chris@0: return $this->protocol; Chris@0: } Chris@0: Chris@0: public function withProtocolVersion($version) Chris@0: { Chris@0: if ($this->protocol === $version) { Chris@0: return $this; Chris@0: } Chris@0: Chris@0: $new = clone $this; Chris@0: $new->protocol = $version; Chris@0: return $new; Chris@0: } Chris@0: Chris@0: public function getHeaders() Chris@0: { Chris@0: return $this->headers; Chris@0: } Chris@0: Chris@0: public function hasHeader($header) Chris@0: { Chris@0: return isset($this->headerNames[strtolower($header)]); Chris@0: } Chris@0: Chris@0: public function getHeader($header) Chris@0: { Chris@0: $header = strtolower($header); Chris@0: Chris@0: if (!isset($this->headerNames[$header])) { Chris@0: return []; Chris@0: } Chris@0: Chris@0: $header = $this->headerNames[$header]; Chris@0: Chris@0: return $this->headers[$header]; Chris@0: } Chris@0: Chris@0: public function getHeaderLine($header) Chris@0: { Chris@0: return implode(', ', $this->getHeader($header)); Chris@0: } Chris@0: Chris@0: public function withHeader($header, $value) Chris@0: { Chris@0: if (!is_array($value)) { Chris@0: $value = [$value]; Chris@0: } Chris@0: Chris@0: $value = $this->trimHeaderValues($value); Chris@0: $normalized = strtolower($header); Chris@0: Chris@0: $new = clone $this; Chris@0: if (isset($new->headerNames[$normalized])) { Chris@0: unset($new->headers[$new->headerNames[$normalized]]); Chris@0: } Chris@0: $new->headerNames[$normalized] = $header; Chris@0: $new->headers[$header] = $value; Chris@0: Chris@0: return $new; Chris@0: } Chris@0: Chris@0: public function withAddedHeader($header, $value) Chris@0: { Chris@0: if (!is_array($value)) { Chris@0: $value = [$value]; Chris@0: } Chris@0: Chris@0: $value = $this->trimHeaderValues($value); Chris@0: $normalized = strtolower($header); Chris@0: Chris@0: $new = clone $this; Chris@0: if (isset($new->headerNames[$normalized])) { Chris@0: $header = $this->headerNames[$normalized]; Chris@0: $new->headers[$header] = array_merge($this->headers[$header], $value); Chris@0: } else { Chris@0: $new->headerNames[$normalized] = $header; Chris@0: $new->headers[$header] = $value; Chris@0: } Chris@0: Chris@0: return $new; Chris@0: } Chris@0: Chris@0: public function withoutHeader($header) Chris@0: { Chris@0: $normalized = strtolower($header); Chris@0: Chris@0: if (!isset($this->headerNames[$normalized])) { Chris@0: return $this; Chris@0: } Chris@0: Chris@0: $header = $this->headerNames[$normalized]; Chris@0: Chris@0: $new = clone $this; Chris@0: unset($new->headers[$header], $new->headerNames[$normalized]); Chris@0: Chris@0: return $new; Chris@0: } Chris@0: Chris@0: public function getBody() Chris@0: { Chris@0: if (!$this->stream) { Chris@0: $this->stream = stream_for(''); Chris@0: } Chris@0: Chris@0: return $this->stream; Chris@0: } Chris@0: Chris@0: public function withBody(StreamInterface $body) Chris@0: { Chris@0: if ($body === $this->stream) { Chris@0: return $this; Chris@0: } Chris@0: Chris@0: $new = clone $this; Chris@0: $new->stream = $body; Chris@0: return $new; Chris@0: } Chris@0: Chris@0: private function setHeaders(array $headers) Chris@0: { Chris@0: $this->headerNames = $this->headers = []; Chris@0: foreach ($headers as $header => $value) { Chris@0: if (!is_array($value)) { Chris@0: $value = [$value]; Chris@0: } Chris@0: Chris@0: $value = $this->trimHeaderValues($value); Chris@0: $normalized = strtolower($header); Chris@0: if (isset($this->headerNames[$normalized])) { Chris@0: $header = $this->headerNames[$normalized]; Chris@0: $this->headers[$header] = array_merge($this->headers[$header], $value); Chris@0: } else { Chris@0: $this->headerNames[$normalized] = $header; Chris@0: $this->headers[$header] = $value; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Trims whitespace from the header values. Chris@0: * Chris@0: * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field. Chris@0: * Chris@0: * header-field = field-name ":" OWS field-value OWS Chris@0: * OWS = *( SP / HTAB ) Chris@0: * Chris@0: * @param string[] $values Header values Chris@0: * Chris@0: * @return string[] Trimmed header values Chris@0: * Chris@0: * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 Chris@0: */ Chris@0: private function trimHeaderValues(array $values) Chris@0: { Chris@0: return array_map(function ($value) { Chris@0: return trim($value, " \t"); Chris@0: }, $values); Chris@0: } Chris@0: }