vendor/symfony/http-foundation/HeaderBag.php line 109

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\HttpFoundation;
  11. /**
  12.  * HeaderBag is a container for HTTP headers.
  13.  *
  14.  * @author Fabien Potencier <fabien@symfony.com>
  15.  *
  16.  * @implements \IteratorAggregate<string, list<string|null>>
  17.  */
  18. class HeaderBag implements \IteratorAggregate\Countable
  19. {
  20.     protected const UPPER '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  21.     protected const LOWER '-abcdefghijklmnopqrstuvwxyz';
  22.     /**
  23.      * @var array<string, list<string|null>>
  24.      */
  25.     protected $headers = [];
  26.     protected $cacheControl = [];
  27.     public function __construct(array $headers = [])
  28.     {
  29.         foreach ($headers as $key => $values) {
  30.             $this->set($key$values);
  31.         }
  32.     }
  33.     /**
  34.      * Returns the headers as a string.
  35.      */
  36.     public function __toString(): string
  37.     {
  38.         if (!$headers $this->all()) {
  39.             return '';
  40.         }
  41.         ksort($headers);
  42.         $max max(array_map('strlen'array_keys($headers))) + 1;
  43.         $content '';
  44.         foreach ($headers as $name => $values) {
  45.             $name ucwords($name'-');
  46.             foreach ($values as $value) {
  47.                 $content .= sprintf("%-{$max}s %s\r\n"$name.':'$value);
  48.             }
  49.         }
  50.         return $content;
  51.     }
  52.     /**
  53.      * Returns the headers.
  54.      *
  55.      * @param string|null $key The name of the headers to return or null to get them all
  56.      *
  57.      * @return array<string, array<int, string|null>>|array<int, string|null>
  58.      */
  59.     public function all(string $key null): array
  60.     {
  61.         if (null !== $key) {
  62.             return $this->headers[strtr($keyself::UPPERself::LOWER)] ?? [];
  63.         }
  64.         return $this->headers;
  65.     }
  66.     /**
  67.      * Returns the parameter keys.
  68.      *
  69.      * @return string[]
  70.      */
  71.     public function keys(): array
  72.     {
  73.         return array_keys($this->all());
  74.     }
  75.     /**
  76.      * Replaces the current HTTP headers by a new set.
  77.      */
  78.     public function replace(array $headers = [])
  79.     {
  80.         $this->headers = [];
  81.         $this->add($headers);
  82.     }
  83.     /**
  84.      * Adds new headers the current HTTP headers set.
  85.      */
  86.     public function add(array $headers)
  87.     {
  88.         foreach ($headers as $key => $values) {
  89.             $this->set($key$values);
  90.         }
  91.     }
  92.     /**
  93.      * Returns the first header by name or the default one.
  94.      */
  95.     public function get(string $keystring $default null): ?string
  96.     {
  97.         $headers $this->all($key);
  98.         if (!$headers) {
  99.             return $default;
  100.         }
  101.         if (null === $headers[0]) {
  102.             return null;
  103.         }
  104.         return (string) $headers[0];
  105.     }
  106.     /**
  107.      * Sets a header by name.
  108.      *
  109.      * @param string|string[]|null $values  The value or an array of values
  110.      * @param bool                 $replace Whether to replace the actual value or not (true by default)
  111.      */
  112.     public function set(string $keystring|array|null $valuesbool $replace true)
  113.     {
  114.         $key strtr($keyself::UPPERself::LOWER);
  115.         if (\is_array($values)) {
  116.             $values array_values($values);
  117.             if (true === $replace || !isset($this->headers[$key])) {
  118.                 $this->headers[$key] = $values;
  119.             } else {
  120.                 $this->headers[$key] = array_merge($this->headers[$key], $values);
  121.             }
  122.         } else {
  123.             if (true === $replace || !isset($this->headers[$key])) {
  124.                 $this->headers[$key] = [$values];
  125.             } else {
  126.                 $this->headers[$key][] = $values;
  127.             }
  128.         }
  129.         if ('cache-control' === $key) {
  130.             $this->cacheControl $this->parseCacheControl(implode(', '$this->headers[$key]));
  131.         }
  132.     }
  133.     /**
  134.      * Returns true if the HTTP header is defined.
  135.      */
  136.     public function has(string $key): bool
  137.     {
  138.         return \array_key_exists(strtr($keyself::UPPERself::LOWER), $this->all());
  139.     }
  140.     /**
  141.      * Returns true if the given HTTP header contains the given value.
  142.      */
  143.     public function contains(string $keystring $value): bool
  144.     {
  145.         return \in_array($value$this->all($key));
  146.     }
  147.     /**
  148.      * Removes a header.
  149.      */
  150.     public function remove(string $key)
  151.     {
  152.         $key strtr($keyself::UPPERself::LOWER);
  153.         unset($this->headers[$key]);
  154.         if ('cache-control' === $key) {
  155.             $this->cacheControl = [];
  156.         }
  157.     }
  158.     /**
  159.      * Returns the HTTP header value converted to a date.
  160.      *
  161.      * @throws \RuntimeException When the HTTP header is not parseable
  162.      */
  163.     public function getDate(string $key\DateTime $default null): ?\DateTimeInterface
  164.     {
  165.         if (null === $value $this->get($key)) {
  166.             return $default;
  167.         }
  168.         if (false === $date \DateTime::createFromFormat(\DATE_RFC2822$value)) {
  169.             throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).'$key$value));
  170.         }
  171.         return $date;
  172.     }
  173.     /**
  174.      * Adds a custom Cache-Control directive.
  175.      */
  176.     public function addCacheControlDirective(string $keybool|string $value true)
  177.     {
  178.         $this->cacheControl[$key] = $value;
  179.         $this->set('Cache-Control'$this->getCacheControlHeader());
  180.     }
  181.     /**
  182.      * Returns true if the Cache-Control directive is defined.
  183.      */
  184.     public function hasCacheControlDirective(string $key): bool
  185.     {
  186.         return \array_key_exists($key$this->cacheControl);
  187.     }
  188.     /**
  189.      * Returns a Cache-Control directive value by name.
  190.      */
  191.     public function getCacheControlDirective(string $key): bool|string|null
  192.     {
  193.         return $this->cacheControl[$key] ?? null;
  194.     }
  195.     /**
  196.      * Removes a Cache-Control directive.
  197.      */
  198.     public function removeCacheControlDirective(string $key)
  199.     {
  200.         unset($this->cacheControl[$key]);
  201.         $this->set('Cache-Control'$this->getCacheControlHeader());
  202.     }
  203.     /**
  204.      * Returns an iterator for headers.
  205.      *
  206.      * @return \ArrayIterator<string, list<string|null>>
  207.      */
  208.     public function getIterator(): \ArrayIterator
  209.     {
  210.         return new \ArrayIterator($this->headers);
  211.     }
  212.     /**
  213.      * Returns the number of headers.
  214.      */
  215.     public function count(): int
  216.     {
  217.         return \count($this->headers);
  218.     }
  219.     protected function getCacheControlHeader()
  220.     {
  221.         ksort($this->cacheControl);
  222.         return HeaderUtils::toString($this->cacheControl',');
  223.     }
  224.     /**
  225.      * Parses a Cache-Control HTTP header.
  226.      */
  227.     protected function parseCacheControl(string $header): array
  228.     {
  229.         $parts HeaderUtils::split($header',=');
  230.         return HeaderUtils::combine($parts);
  231.     }
  232. }