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

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. class HeaderBag implements \IteratorAggregate\Countable
  17. {
  18.     protected $headers = [];
  19.     protected $cacheControl = [];
  20.     /**
  21.      * @param array $headers An array of HTTP headers
  22.      */
  23.     public function __construct(array $headers = [])
  24.     {
  25.         foreach ($headers as $key => $values) {
  26.             $this->set($key$values);
  27.         }
  28.     }
  29.     /**
  30.      * Returns the headers as a string.
  31.      *
  32.      * @return string The headers
  33.      */
  34.     public function __toString()
  35.     {
  36.         if (!$headers $this->all()) {
  37.             return '';
  38.         }
  39.         ksort($headers);
  40.         $max max(array_map('strlen'array_keys($headers))) + 1;
  41.         $content '';
  42.         foreach ($headers as $name => $values) {
  43.             $name implode('-'array_map('ucfirst'explode('-'$name)));
  44.             foreach ($values as $value) {
  45.                 $content .= sprintf("%-{$max}s %s\r\n"$name.':'$value);
  46.             }
  47.         }
  48.         return $content;
  49.     }
  50.     /**
  51.      * Returns the headers.
  52.      *
  53.      * @return array An array of headers
  54.      */
  55.     public function all()
  56.     {
  57.         return $this->headers;
  58.     }
  59.     /**
  60.      * Returns the parameter keys.
  61.      *
  62.      * @return array An array of parameter keys
  63.      */
  64.     public function keys()
  65.     {
  66.         return array_keys($this->all());
  67.     }
  68.     /**
  69.      * Replaces the current HTTP headers by a new set.
  70.      *
  71.      * @param array $headers An array of HTTP headers
  72.      */
  73.     public function replace(array $headers = [])
  74.     {
  75.         $this->headers = [];
  76.         $this->add($headers);
  77.     }
  78.     /**
  79.      * Adds new headers the current HTTP headers set.
  80.      *
  81.      * @param array $headers An array of HTTP headers
  82.      */
  83.     public function add(array $headers)
  84.     {
  85.         foreach ($headers as $key => $values) {
  86.             $this->set($key$values);
  87.         }
  88.     }
  89.     /**
  90.      * Returns a header value by name.
  91.      *
  92.      * @param string      $key     The header name
  93.      * @param string|null $default The default value
  94.      * @param bool        $first   Whether to return the first value or all header values
  95.      *
  96.      * @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise
  97.      */
  98.     public function get($key$default null$first true)
  99.     {
  100.         $key str_replace('_''-'strtolower($key));
  101.         $headers $this->all();
  102.         if (!\array_key_exists($key$headers)) {
  103.             if (null === $default) {
  104.                 return $first null : [];
  105.             }
  106.             return $first $default : [$default];
  107.         }
  108.         if ($first) {
  109.             if (!$headers[$key]) {
  110.                 return $default;
  111.             }
  112.             if (null === $headers[$key][0]) {
  113.                 return null;
  114.             }
  115.             return (string) $headers[$key][0];
  116.         }
  117.         return $headers[$key];
  118.     }
  119.     /**
  120.      * Sets a header by name.
  121.      *
  122.      * @param string          $key     The key
  123.      * @param string|string[] $values  The value or an array of values
  124.      * @param bool            $replace Whether to replace the actual value or not (true by default)
  125.      */
  126.     public function set($key$values$replace true)
  127.     {
  128.         $key str_replace('_''-'strtolower($key));
  129.         if (\is_array($values)) {
  130.             $values array_values($values);
  131.             if (true === $replace || !isset($this->headers[$key])) {
  132.                 $this->headers[$key] = $values;
  133.             } else {
  134.                 $this->headers[$key] = array_merge($this->headers[$key], $values);
  135.             }
  136.         } else {
  137.             if (true === $replace || !isset($this->headers[$key])) {
  138.                 $this->headers[$key] = [$values];
  139.             } else {
  140.                 $this->headers[$key][] = $values;
  141.             }
  142.         }
  143.         if ('cache-control' === $key) {
  144.             $this->cacheControl $this->parseCacheControl(implode(', '$this->headers[$key]));
  145.         }
  146.     }
  147.     /**
  148.      * Returns true if the HTTP header is defined.
  149.      *
  150.      * @param string $key The HTTP header
  151.      *
  152.      * @return bool true if the parameter exists, false otherwise
  153.      */
  154.     public function has($key)
  155.     {
  156.         return \array_key_exists(str_replace('_''-'strtolower($key)), $this->all());
  157.     }
  158.     /**
  159.      * Returns true if the given HTTP header contains the given value.
  160.      *
  161.      * @param string $key   The HTTP header name
  162.      * @param string $value The HTTP value
  163.      *
  164.      * @return bool true if the value is contained in the header, false otherwise
  165.      */
  166.     public function contains($key$value)
  167.     {
  168.         return \in_array($value$this->get($keynullfalse));
  169.     }
  170.     /**
  171.      * Removes a header.
  172.      *
  173.      * @param string $key The HTTP header name
  174.      */
  175.     public function remove($key)
  176.     {
  177.         $key str_replace('_''-'strtolower($key));
  178.         unset($this->headers[$key]);
  179.         if ('cache-control' === $key) {
  180.             $this->cacheControl = [];
  181.         }
  182.     }
  183.     /**
  184.      * Returns the HTTP header value converted to a date.
  185.      *
  186.      * @param string    $key     The parameter key
  187.      * @param \DateTime $default The default value
  188.      *
  189.      * @return \DateTime|null The parsed DateTime or the default value if the header does not exist
  190.      *
  191.      * @throws \RuntimeException When the HTTP header is not parseable
  192.      */
  193.     public function getDate($key\DateTime $default null)
  194.     {
  195.         if (null === $value $this->get($key)) {
  196.             return $default;
  197.         }
  198.         if (false === $date \DateTime::createFromFormat(DATE_RFC2822$value)) {
  199.             throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).'$key$value));
  200.         }
  201.         return $date;
  202.     }
  203.     /**
  204.      * Adds a custom Cache-Control directive.
  205.      *
  206.      * @param string $key   The Cache-Control directive name
  207.      * @param mixed  $value The Cache-Control directive value
  208.      */
  209.     public function addCacheControlDirective($key$value true)
  210.     {
  211.         $this->cacheControl[$key] = $value;
  212.         $this->set('Cache-Control'$this->getCacheControlHeader());
  213.     }
  214.     /**
  215.      * Returns true if the Cache-Control directive is defined.
  216.      *
  217.      * @param string $key The Cache-Control directive
  218.      *
  219.      * @return bool true if the directive exists, false otherwise
  220.      */
  221.     public function hasCacheControlDirective($key)
  222.     {
  223.         return \array_key_exists($key$this->cacheControl);
  224.     }
  225.     /**
  226.      * Returns a Cache-Control directive value by name.
  227.      *
  228.      * @param string $key The directive name
  229.      *
  230.      * @return mixed|null The directive value if defined, null otherwise
  231.      */
  232.     public function getCacheControlDirective($key)
  233.     {
  234.         return \array_key_exists($key$this->cacheControl) ? $this->cacheControl[$key] : null;
  235.     }
  236.     /**
  237.      * Removes a Cache-Control directive.
  238.      *
  239.      * @param string $key The Cache-Control directive
  240.      */
  241.     public function removeCacheControlDirective($key)
  242.     {
  243.         unset($this->cacheControl[$key]);
  244.         $this->set('Cache-Control'$this->getCacheControlHeader());
  245.     }
  246.     /**
  247.      * Returns an iterator for headers.
  248.      *
  249.      * @return \ArrayIterator An \ArrayIterator instance
  250.      */
  251.     public function getIterator()
  252.     {
  253.         return new \ArrayIterator($this->headers);
  254.     }
  255.     /**
  256.      * Returns the number of headers.
  257.      *
  258.      * @return int The number of headers
  259.      */
  260.     public function count()
  261.     {
  262.         return \count($this->headers);
  263.     }
  264.     protected function getCacheControlHeader()
  265.     {
  266.         $parts = [];
  267.         ksort($this->cacheControl);
  268.         foreach ($this->cacheControl as $key => $value) {
  269.             if (true === $value) {
  270.                 $parts[] = $key;
  271.             } else {
  272.                 if (preg_match('#[^a-zA-Z0-9._-]#'$value)) {
  273.                     $value '"'.$value.'"';
  274.                 }
  275.                 $parts[] = "$key=$value";
  276.             }
  277.         }
  278.         return implode(', '$parts);
  279.     }
  280.     /**
  281.      * Parses a Cache-Control HTTP header.
  282.      *
  283.      * @param string $header The value of the Cache-Control HTTP header
  284.      *
  285.      * @return array An array representing the attribute values
  286.      */
  287.     protected function parseCacheControl($header)
  288.     {
  289.         $cacheControl = [];
  290.         preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#'$header$matchesPREG_SET_ORDER);
  291.         foreach ($matches as $match) {
  292.             $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
  293.         }
  294.         return $cacheControl;
  295.     }
  296. }