‪TYPO3CMS  10.4
Message.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
16 namespace ‪TYPO3\CMS\Core\Http;
17 
18 use Psr\Http\Message\MessageInterface;
19 use Psr\Http\Message\StreamInterface;
20 
29 class ‪Message implements MessageInterface
30 {
35  protected ‪$protocolVersion = '1.1';
36 
42  protected ‪$headers = [];
43 
49  protected ‪$lowercasedHeaderNames = [];
50 
55  protected ‪$body;
56 
64  public function ‪getProtocolVersion()
65  {
67  }
68 
82  public function ‪withProtocolVersion($version)
83  {
84  $clonedObject = clone $this;
85  $clonedObject->protocolVersion = $version;
86  return $clonedObject;
87  }
88 
114  public function ‪getHeaders()
115  {
116  return ‪$this->headers;
117  }
118 
127  public function ‪hasHeader($name)
128  {
129  return isset($this->lowercasedHeaderNames[strtolower($name)]);
130  }
131 
146  public function ‪getHeader($name)
147  {
148  if (!$this->‪hasHeader($name)) {
149  return [];
150  }
151  $header = $this->lowercasedHeaderNames[strtolower($name)];
152  $headerValue = $this->headers[$header];
153  if (is_array($headerValue)) {
154  return $headerValue;
155  }
156  return [$headerValue];
157  }
158 
178  public function ‪getHeaderLine($name)
179  {
180  $headerValue = $this->‪getHeader($name);
181  if (empty($headerValue)) {
182  return '';
183  }
184  return implode(',', $headerValue);
185  }
186 
202  public function ‪withHeader($name, $value)
203  {
204  if (is_string($value)) {
205  $value = [$value];
206  }
207 
208  if (!is_array($value) || !$this->‪arrayContainsOnlyStrings($value)) {
209  throw new \InvalidArgumentException('Invalid header value for header "' . $name . '". The value must be a string or an array of strings.', 1436717266);
210  }
211 
212  $this->‪validateHeaderName($name);
213  $this->‪validateHeaderValues($value);
214  $lowercasedHeaderName = strtolower($name);
215 
216  $clonedObject = clone $this;
217  $clonedObject->headers[$name] = $value;
218  $clonedObject->lowercasedHeaderNames[$lowercasedHeaderName] = $name;
219  return $clonedObject;
220  }
221 
238  public function ‪withAddedHeader($name, $value)
239  {
240  if (is_string($value)) {
241  $value = [$value];
242  }
243  if (!is_array($value) || !$this->‪arrayContainsOnlyStrings($value)) {
244  throw new \InvalidArgumentException('Invalid header value for header "' . $name . '". The header value must be a string or array of strings', 1436717267);
245  }
246  $this->‪validateHeaderName($name);
247  $this->‪validateHeaderValues($value);
248  if (!$this->‪hasHeader($name)) {
249  return $this->‪withHeader($name, $value);
250  }
251  $name = $this->lowercasedHeaderNames[strtolower($name)];
252  $clonedObject = clone $this;
253  $clonedObject->headers[$name] = array_merge($this->headers[$name], $value);
254  return $clonedObject;
255  }
256 
269  public function ‪withoutHeader($name)
270  {
271  if (!$this->‪hasHeader($name)) {
272  return clone $this;
273  }
274  // fetch the original header from the lowercased version
275  $lowercasedHeader = strtolower($name);
276  $name = $this->lowercasedHeaderNames[$lowercasedHeader];
277  $clonedObject = clone $this;
278  unset($clonedObject->headers[$name], $clonedObject->lowercasedHeaderNames[$lowercasedHeader]);
279  return $clonedObject;
280  }
281 
287  public function ‪getBody()
288  {
289  if ($this->body === null) {
290  $this->body = new ‪Stream('php://temp', 'r+');
291  }
292  return ‪$this->body;
293  }
294 
308  public function ‪withBody(StreamInterface ‪$body)
309  {
310  $clonedObject = clone $this;
311  $clonedObject->body = ‪$body;
312  return $clonedObject;
313  }
314 
321  protected function ‪assertHeaders(array ‪$headers)
322  {
323  foreach (‪$headers as $name => $headerValues) {
324  $this->‪validateHeaderName($name);
325  // check if all values are correct
326  array_walk($headerValues, function ($value, $key, ‪Message $messageObject) {
327  if (!$messageObject->‪isValidHeaderValue($value)) {
328  throw new \InvalidArgumentException('Invalid header value for header "' . $key . '"', 1436717268);
329  }
330  }, $this);
331  }
332  }
333 
342  protected function ‪filterHeaders(array $originalHeaders)
343  {
344  $headerNames = ‪$headers = [];
345  foreach ($originalHeaders as $header => $value) {
346  if (!is_string($header) || (!is_array($value) && !is_string($value))) {
347  continue;
348  }
349  if (!is_array($value)) {
350  $value = [$value];
351  }
352  $headerNames[strtolower($header)] = $header;
353  ‪$headers[$header] = $value;
354  }
355  return [$headerNames, ‪$headers];
356  }
357 
364  protected function ‪arrayContainsOnlyStrings(array $data)
365  {
366  return array_reduce($data, function ($original, $item) {
367  return is_string($item) ? $original : false;
368  }, true);
369  }
370 
378  protected function ‪validateHeaderValues(array $values)
379  {
380  array_walk($values, function ($value, $key, ‪Message $messageObject) {
381  if (!$messageObject->‪isValidHeaderValue($value)) {
382  throw new \InvalidArgumentException('Invalid header value for header "' . $key . '"', 1436717269);
383  }
384  }, $this);
385  }
386 
403  public function ‪filter($value)
404  {
405  $value = (string)$value;
406  $length = strlen($value);
407  $string = '';
408  for ($i = 0; $i < $length; $i += 1) {
409  $ascii = ord($value[$i]);
410 
411  // Detect continuation sequences
412  if ($ascii === 13) {
413  $lf = ord($value[$i + 1]);
414  $ws = ord($value[$i + 2]);
415  if ($lf === 10 && in_array($ws, [9, 32], true)) {
416  $string .= $value[$i] . $value[$i + 1];
417  $i += 1;
418  }
419  continue;
420  }
421 
422  // Non-visible, non-whitespace characters
423  // 9 === horizontal tab
424  // 32-126, 128-254 === visible
425  // 127 === DEL
426  // 255 === null byte
427  if (($ascii < 32 && $ascii !== 9) || $ascii === 127 || $ascii > 254) {
428  continue;
429  }
430 
431  $string .= $value[$i];
432  }
433 
434  return $string;
435  }
436 
444  public function ‪validateHeaderName($name)
445  {
446  if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
447  throw new \InvalidArgumentException('Invalid header name, given "' . $name . '"', 1436717270);
448  }
449  }
450 
462  public function ‪isValidHeaderValue($value)
463  {
464  $value = (string)$value;
465 
466  // Any occurrence of \r or \n is invalid
467  if (strpbrk($value, "\r\n") !== false) {
468  return false;
469  }
470 
471  foreach (unpack('C*', $value) as $ascii) {
472 
473  // Non-visible, non-whitespace characters
474  // 9 === horizontal tab
475  // 32-126, 128-254 === visible
476  // 127 === DEL
477  // 255 === null byte
478  if (($ascii < 32 && $ascii !== 9) || $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:399
‪TYPO3\CMS\Core\Http\Message\getHeaders
‪array getHeaders()
Definition: Message.php:110
‪TYPO3\CMS\Core\Http\Message\validateHeaderName
‪validateHeaderName($name)
Definition: Message.php:440
‪TYPO3\CMS\Core\Http\Message\assertHeaders
‪assertHeaders(array $headers)
Definition: Message.php:317
‪TYPO3\CMS\Core\Http\Message\$protocolVersion
‪string $protocolVersion
Definition: Message.php:34
‪TYPO3\CMS\Core\Http\Message\arrayContainsOnlyStrings
‪bool arrayContainsOnlyStrings(array $data)
Definition: Message.php:360
‪TYPO3\CMS\Core\Http\Message\withHeader
‪static withHeader($name, $value)
Definition: Message.php:198
‪TYPO3\CMS\Core\Http\Message\hasHeader
‪bool hasHeader($name)
Definition: Message.php:123
‪TYPO3\CMS\Core\Http\Message
Definition: Message.php:30
‪TYPO3\CMS\Core\Http\Message\getHeader
‪string[] getHeader($name)
Definition: Message.php:142
‪TYPO3\CMS\Core\Http\Message\withoutHeader
‪static withoutHeader($name)
Definition: Message.php:265
‪TYPO3\CMS\Core\Http\Stream
Definition: Stream.php:29
‪TYPO3\CMS\Core\Http\Message\getBody
‪Psr Http Message StreamInterface getBody()
Definition: Message.php:283
‪TYPO3\CMS\Core\Http\Message\$body
‪StreamInterface $body
Definition: Message.php:51
‪TYPO3\CMS\Core\Http\Message\withAddedHeader
‪static withAddedHeader($name, $value)
Definition: Message.php:234
‪TYPO3\CMS\Core\Http\Message\getProtocolVersion
‪string getProtocolVersion()
Definition: Message.php:60
‪TYPO3\CMS\Core\Http\Message\isValidHeaderValue
‪bool isValidHeaderValue($value)
Definition: Message.php:458
‪TYPO3\CMS\Core\Http\Message\withBody
‪static withBody(StreamInterface $body)
Definition: Message.php:304
‪TYPO3\CMS\Core\Http\Message\validateHeaderValues
‪validateHeaderValues(array $values)
Definition: Message.php:374
‪TYPO3\CMS\Core\Http\Message\$lowercasedHeaderNames
‪array $lowercasedHeaderNames
Definition: Message.php:46
‪TYPO3\CMS\Core\Http\Message\filterHeaders
‪array filterHeaders(array $originalHeaders)
Definition: Message.php:338
‪TYPO3\CMS\Core\Http\Message\$headers
‪array $headers
Definition: Message.php:40
‪TYPO3\CMS\Core\Http\Message\getHeaderLine
‪string getHeaderLine($name)
Definition: Message.php:174
‪TYPO3\CMS\Core\Http
Definition: AbstractApplication.php:18
‪TYPO3\CMS\Core\Http\Message\withProtocolVersion
‪static withProtocolVersion($version)
Definition: Message.php:78