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

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.      * @return string
  37.      */
  38.     public function __toString()
  39.     {
  40.         if (!$headers $this->all()) {
  41.             return '';
  42.         }
  43.         ksort($headers);
  44.         $max max(array_map('strlen'array_keys($headers))) + 1;
  45.         $content '';
  46.         foreach ($headers as $name => $values) {
  47.             $name ucwords($name'-');
  48.             foreach ($values as $value) {
  49.                 $content .= sprintf("%-{$max}s %s\r\n"$name.':'$value);
  50.             }
  51.         }
  52.         return $content;
  53.     }
  54.     /**
  55.      * Returns the headers.
  56.      *
  57.      * @param string|null $key The name of the headers to return or null to get them all
  58.      *
  59.      * @return array<string, array<int, string|null>>|array<int, string|null>
  60.      */
  61.     public function all(string $key null)
  62.     {
  63.         if (null !== $key) {
  64.             return $this->headers[strtr($keyself::UPPERself::LOWER)] ?? [];
  65.         }
  66.         return $this->headers;
  67.     }
  68.     /**
  69.      * Returns the parameter keys.
  70.      *
  71.      * @return string[]
  72.      */
  73.     public function keys()
  74.     {
  75.         return array_keys($this->all());
  76.     }
  77.     /**
  78.      * Replaces the current HTTP headers by a new set.
  79.      */
  80.     public function replace(array $headers = [])
  81.     {
  82.         $this->headers = [];
  83.         $this->add($headers);
  84.     }
  85.     /**
  86.      * Adds new headers the current HTTP headers set.
  87.      */
  88.     public function add(array $headers)
  89.     {
  90.         foreach ($headers as $key => $values) {
  91.             $this->set($key$values);
  92.         }
  93.     }
  94.     /**
  95.      * Returns the first header by name or the default one.
  96.      *
  97.      * @return string|null
  98.      */
  99.     public function get(string $keystring $default null)
  100.     {
  101.         $headers $this->all($key);
  102.         if (!$headers) {
  103.             return $default;
  104.         }
  105.         if (null === $headers[0]) {
  106.             return null;
  107.         }
  108.         return (string) $headers[0];
  109.     }
  110.     /**
  111.      * Sets a header by name.
  112.      *
  113.      * @param string|string[]|null $values  The value or an array of values
  114.      * @param bool                 $replace Whether to replace the actual value or not (true by default)
  115.      */
  116.     public function set(string $key$valuesbool $replace true)
  117.     {
  118.         $key strtr($keyself::UPPERself::LOWER);
  119.         if (\is_array($values)) {
  120.             $values array_values($values);
  121.             if (true === $replace || !isset($this->headers[$key])) {
  122.                 $this->headers[$key] = $values;
  123.             } else {
  124.                 $this->headers[$key] = array_merge($this->headers[$key], $values);
  125.             }
  126.         } else {
  127.             if (true === $replace || !isset($this->headers[$key])) {
  128.                 $this->headers[$key] = [$values];
  129.             } else {
  130.                 $this->headers[$key][] = $values;
  131.             }
  132.         }
  133.         if ('cache-control' === $key) {
  134.             $this->cacheControl $this->parseCacheControl(implode(', '$this->headers[$key]));
  135.         }
  136.     }
  137.     /**
  138.      * Returns true if the HTTP header is defined.
  139.      *
  140.      * @return bool
  141.      */
  142.     public function has(string $key)
  143.     {
  144.         return \array_key_exists(strtr($keyself::UPPERself::LOWER), $this->all());
  145.     }
  146.     /**
  147.      * Returns true if the given HTTP header contains the given value.
  148.      *
  149.      * @return bool
  150.      */
  151.     public function contains(string $keystring $value)
  152.     {
  153.         return \in_array($value$this->all($key));
  154.     }
  155.     /**
  156.      * Removes a header.
  157.      */
  158.     public function remove(string $key)
  159.     {
  160.         $key strtr($keyself::UPPERself::LOWER);
  161.         unset($this->headers[$key]);
  162.         if ('cache-control' === $key) {
  163.             $this->cacheControl = [];
  164.         }
  165.     }
  166.     /**
  167.      * Returns the HTTP header value converted to a date.
  168.      *
  169.      * @return \DateTimeInterface|null
  170.      *
  171.      * @throws \RuntimeException When the HTTP header is not parseable
  172.      */
  173.     public function getDate(string $key, \DateTime $default null)
  174.     {
  175.         if (null === $value $this->get($key)) {
  176.             return $default;
  177.         }
  178.         if (false === $date = \DateTime::createFromFormat(\DATE_RFC2822$value)) {
  179.             throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).'$key$value));
  180.         }
  181.         return $date;
  182.     }
  183.     /**
  184.      * Adds a custom Cache-Control directive.
  185.      *
  186.      * @param bool|string $value The Cache-Control directive value
  187.      */
  188.     public function addCacheControlDirective(string $key$value true)
  189.     {
  190.         $this->cacheControl[$key] = $value;
  191.         $this->set('Cache-Control'$this->getCacheControlHeader());
  192.     }
  193.     /**
  194.      * Returns true if the Cache-Control directive is defined.
  195.      *
  196.      * @return bool
  197.      */
  198.     public function hasCacheControlDirective(string $key)
  199.     {
  200.         return \array_key_exists($key$this->cacheControl);
  201.     }
  202.     /**
  203.      * Returns a Cache-Control directive value by name.
  204.      *
  205.      * @return bool|string|null
  206.      */
  207.     public function getCacheControlDirective(string $key)
  208.     {
  209.         return $this->cacheControl[$key] ?? null;
  210.     }
  211.     /**
  212.      * Removes a Cache-Control directive.
  213.      */
  214.     public function removeCacheControlDirective(string $key)
  215.     {
  216.         unset($this->cacheControl[$key]);
  217.         $this->set('Cache-Control'$this->getCacheControlHeader());
  218.     }
  219.     /**
  220.      * Returns an iterator for headers.
  221.      *
  222.      * @return \ArrayIterator<string, list<string|null>>
  223.      */
  224.     #[\ReturnTypeWillChange]
  225.     public function getIterator()
  226.     {
  227.         return new \ArrayIterator($this->headers);
  228.     }
  229.     /**
  230.      * Returns the number of headers.
  231.      *
  232.      * @return int
  233.      */
  234.     #[\ReturnTypeWillChange]
  235.     public function count()
  236.     {
  237.         return \count($this->headers);
  238.     }
  239.     protected function getCacheControlHeader()
  240.     {
  241.         ksort($this->cacheControl);
  242.         return HeaderUtils::toString($this->cacheControl',');
  243.     }
  244.     /**
  245.      * Parses a Cache-Control HTTP header.
  246.      *
  247.      * @return array
  248.      */
  249.     protected function parseCacheControl(string $header)
  250.     {
  251.         $parts HeaderUtils::split($header',=');
  252.         return HeaderUtils::combine($parts);
  253.     }
  254. }