‪TYPO3CMS  9.5
Message.php
Go to the documentation of this file.
1 <?php
2 namespace ‪TYPO3\CMS\Core\Http;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Psr\Http\Message\MessageInterface;
18 use Psr\Http\Message\StreamInterface;
19 
28 class ‪Message implements MessageInterface
29 {
34  protected ‪$protocolVersion = '1.1';
35 
41  protected ‪$headers = [];
42 
48  protected ‪$lowercasedHeaderNames = [];
49 
54  protected ‪$body;
55 
63  public function ‪getProtocolVersion()
64  {
66  }
67 
81  public function ‪withProtocolVersion($version)
82  {
83  $clonedObject = clone $this;
84  $clonedObject->protocolVersion = $version;
85  return $clonedObject;
86  }
87 
113  public function ‪getHeaders()
114  {
115  return ‪$this->headers;
116  }
117 
126  public function ‪hasHeader($name)
127  {
128  return isset($this->lowercasedHeaderNames[strtolower($name)]);
129  }
130 
145  public function ‪getHeader($name)
146  {
147  if (!$this->‪hasHeader($name)) {
148  return [];
149  }
150  $header = $this->lowercasedHeaderNames[strtolower($name)];
151  $headerValue = $this->headers[$header];
152  if (is_array($headerValue)) {
153  return $headerValue;
154  }
155  return [$headerValue];
156  }
157 
177  public function ‪getHeaderLine($name)
178  {
179  $headerValue = $this->‪getHeader($name);
180  if (empty($headerValue)) {
181  return '';
182  }
183  return implode(',', $headerValue);
184  }
185 
201  public function ‪withHeader($name, $value)
202  {
203  if (is_string($value)) {
204  $value = [$value];
205  }
206 
207  if (!is_array($value) || !$this->‪arrayContainsOnlyStrings($value)) {
208  throw new \InvalidArgumentException('Invalid header value for header "' . $name . '". The value must be a string or an array of strings.', 1436717266);
209  }
210 
211  $this->‪validateHeaderName($name);
212  $this->‪validateHeaderValues($value);
213  $lowercasedHeaderName = strtolower($name);
214 
215  $clonedObject = clone $this;
216  $clonedObject->headers[$name] = $value;
217  $clonedObject->lowercasedHeaderNames[$lowercasedHeaderName] = $name;
218  return $clonedObject;
219  }
220 
237  public function ‪withAddedHeader($name, $value)
238  {
239  if (is_string($value)) {
240  $value = [$value];
241  }
242  if (!is_array($value) || !$this->‪arrayContainsOnlyStrings($value)) {
243  throw new \InvalidArgumentException('Invalid header value for header "' . $name . '". The header value must be a string or array of strings', 1436717267);
244  }
245  $this->‪validateHeaderName($name);
246  $this->‪validateHeaderValues($value);
247  if (!$this->‪hasHeader($name)) {
248  return $this->‪withHeader($name, $value);
249  }
250  $name = $this->lowercasedHeaderNames[strtolower($name)];
251  $clonedObject = clone $this;
252  $clonedObject->headers[$name] = array_merge($this->headers[$name], $value);
253  return $clonedObject;
254  }
255 
268  public function ‪withoutHeader($name)
269  {
270  if (!$this->‪hasHeader($name)) {
271  return clone $this;
272  }
273  // fetch the original header from the lowercased version
274  $lowercasedHeader = strtolower($name);
275  $name = $this->lowercasedHeaderNames[$lowercasedHeader];
276  $clonedObject = clone $this;
277  unset($clonedObject->headers[$name], $clonedObject->lowercasedHeaderNames[$lowercasedHeader]);
278  return $clonedObject;
279  }
280 
286  public function ‪getBody()
287  {
288  return ‪$this->body;
289  }
290 
304  public function ‪withBody(StreamInterface ‪$body)
305  {
306  $clonedObject = clone $this;
307  $clonedObject->body = ‪$body;
308  return $clonedObject;
309  }
310 
317  protected function ‪assertHeaders(array ‪$headers)
318  {
319  foreach (‪$headers as $name => $headerValues) {
320  $this->‪validateHeaderName($name);
321  // check if all values are correct
322  array_walk($headerValues, function ($value, $key, ‪Message $messageObject) {
323  if (!$messageObject->‪isValidHeaderValue($value)) {
324  throw new \InvalidArgumentException('Invalid header value for header "' . $key . '"', 1436717268);
325  }
326  }, $this);
327  }
328  }
329 
338  protected function ‪filterHeaders(array $originalHeaders)
339  {
340  $headerNames = ‪$headers = [];
341  foreach ($originalHeaders as $header => $value) {
342  if (!is_string($header) || (!is_array($value) && !is_string($value))) {
343  continue;
344  }
345  if (!is_array($value)) {
346  $value = [$value];
347  }
348  $headerNames[strtolower($header)] = $header;
349  ‪$headers[$header] = $value;
350  }
351  return [$headerNames, ‪$headers];
352  }
353 
360  protected function ‪arrayContainsOnlyStrings(array $data)
361  {
362  return array_reduce($data, function ($original, $item) {
363  return is_string($item) ? $original : false;
364  }, true);
365  }
366 
374  protected function ‪validateHeaderValues(array $values)
375  {
376  array_walk($values, function ($value, $key, ‪Message $messageObject) {
377  if (!$messageObject->‪isValidHeaderValue($value)) {
378  throw new \InvalidArgumentException('Invalid header value for header "' . $key . '"', 1436717269);
379  }
380  }, $this);
381  }
382 
399  public function ‪filter($value)
400  {
401  $value = (string)$value;
402  $length = strlen($value);
403  $string = '';
404  for ($i = 0; $i < $length; $i += 1) {
405  $ascii = ord($value[$i]);
406 
407  // Detect continuation sequences
408  if ($ascii === 13) {
409  $lf = ord($value[$i + 1]);
410  $ws = ord($value[$i + 2]);
411  if ($lf === 10 && in_array($ws, [9, 32], true)) {
412  $string .= $value[$i] . $value[$i + 1];
413  $i += 1;
414  }
415  continue;
416  }
417 
418  // Non-visible, non-whitespace characters
419  // 9 === horizontal tab
420  // 32-126, 128-254 === visible
421  // 127 === DEL
422  // 255 === null byte
423  if (($ascii < 32 && $ascii !== 9) || $ascii === 127 || $ascii > 254) {
424  continue;
425  }
426 
427  $string .= $value[$i];
428  }
429 
430  return $string;
431  }
432 
440  public function ‪validateHeaderName($name)
441  {
442  if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
443  throw new \InvalidArgumentException('Invalid header name, given "' . $name . '"', 1436717270);
444  }
445  }
446 
458  public function ‪isValidHeaderValue($value)
459  {
460  $value = (string)$value;
461 
462  // Any occurrence of \r or \n is invalid
463  if (strpbrk($value, "\r\n") !== false) {
464  return false;
465  }
466 
467  $length = strlen($value);
468  for ($i = 0; $i < $length; $i += 1) {
469  $ascii = ord($value[$i]);
470 
471  // Non-visible, non-whitespace characters
472  // 9 === horizontal tab
473  // 10 === line feed
474  // 13 === carriage return
475  // 32-126, 128-254 === visible
476  // 127 === DEL
477  // 255 === null byte
478  if (($ascii < 32 && !in_array($ascii, [9, 10, 13], true)) || $ascii === 127 || $ascii > 254) {
479  return false;
480  }
481  }
482 
483  return true;
484  }
485 }
‪TYPO3\CMS\Core\Http\Message\filter
‪string filter($value)
Definition: Message.php:395
‪TYPO3\CMS\Core\Http\Message\getHeaders
‪array getHeaders()
Definition: Message.php:109
‪TYPO3\CMS\Core\Http\Message\validateHeaderName
‪validateHeaderName($name)
Definition: Message.php:436
‪TYPO3\CMS\Core\Http\Message\assertHeaders
‪assertHeaders(array $headers)
Definition: Message.php:313
‪TYPO3\CMS\Core\Http\Message\$protocolVersion
‪string $protocolVersion
Definition: Message.php:33
‪TYPO3\CMS\Core\Http\Message\arrayContainsOnlyStrings
‪bool arrayContainsOnlyStrings(array $data)
Definition: Message.php:356
‪TYPO3\CMS\Core\Http\Message\withHeader
‪static withHeader($name, $value)
Definition: Message.php:197
‪TYPO3\CMS\Core\Http\Message\hasHeader
‪bool hasHeader($name)
Definition: Message.php:122
‪TYPO3\CMS\Core\Http\Message
Definition: Message.php:29
‪TYPO3\CMS\Core\Http\Message\getHeader
‪string[] getHeader($name)
Definition: Message.php:141
‪TYPO3\CMS\Core\Http\Message\withoutHeader
‪static withoutHeader($name)
Definition: Message.php:264
‪TYPO3\CMS\Core\Http\Message\getBody
‪Psr Http Message StreamInterface getBody()
Definition: Message.php:282
‪TYPO3\CMS\Core\Http\Message\$body
‪StreamInterface $body
Definition: Message.php:50
‪TYPO3\CMS\Core\Http\Message\withAddedHeader
‪static withAddedHeader($name, $value)
Definition: Message.php:233
‪TYPO3\CMS\Core\Http\Message\getProtocolVersion
‪string getProtocolVersion()
Definition: Message.php:59
‪TYPO3\CMS\Core\Http\Message\isValidHeaderValue
‪bool isValidHeaderValue($value)
Definition: Message.php:454
‪TYPO3\CMS\Core\Http\Message\withBody
‪static withBody(StreamInterface $body)
Definition: Message.php:300
‪TYPO3\CMS\Core\Http\Message\validateHeaderValues
‪validateHeaderValues(array $values)
Definition: Message.php:370
‪TYPO3\CMS\Core\Http\Message\$lowercasedHeaderNames
‪array $lowercasedHeaderNames
Definition: Message.php:45
‪TYPO3\CMS\Core\Http\Message\filterHeaders
‪array filterHeaders(array $originalHeaders)
Definition: Message.php:334
‪TYPO3\CMS\Core\Http\Message\$headers
‪array $headers
Definition: Message.php:39
‪TYPO3\CMS\Core\Http\Message\getHeaderLine
‪string getHeaderLine($name)
Definition: Message.php:173
‪TYPO3\CMS\Core\Http
Definition: AbstractApplication.php:3
‪TYPO3\CMS\Core\Http\Message\withProtocolVersion
‪static withProtocolVersion($version)
Definition: Message.php:77