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