2017-07-03 19:04:27 +02:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\HttpFoundation ;
/**
* HeaderBag is a container for HTTP headers .
*
* @ author Fabien Potencier < fabien @ symfony . com >
*/
class HeaderBag implements \IteratorAggregate , \Countable
{
2020-01-17 10:58:01 +01:00
protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ' ;
protected const LOWER = '-abcdefghijklmnopqrstuvwxyz' ;
2017-07-03 19:04:27 +02:00
2020-01-17 10:58:01 +01:00
protected $headers = [];
protected $cacheControl = [];
public function __construct ( array $headers = [])
2017-07-03 19:04:27 +02:00
{
foreach ( $headers as $key => $values ) {
$this -> set ( $key , $values );
}
}
/**
* Returns the headers as a string .
*
* @ return string The headers
*/
public function __toString ()
{
if ( ! $headers = $this -> all ()) {
return '' ;
}
ksort ( $headers );
$max = max ( array_map ( 'strlen' , array_keys ( $headers ))) + 1 ;
$content = '' ;
foreach ( $headers as $name => $values ) {
2020-01-17 10:58:01 +01:00
$name = ucwords ( $name , '-' );
2017-07-03 19:04:27 +02:00
foreach ( $values as $value ) {
$content .= sprintf ( " %- { $max } s %s \r \n " , $name . ':' , $value );
}
}
return $content ;
}
/**
* Returns the headers .
*
2020-01-17 10:58:01 +01:00
* @ param string | null $key The name of the headers to return or null to get them all
*
2017-07-03 19:04:27 +02:00
* @ return array An array of headers
*/
2020-01-17 10:58:01 +01:00
public function all ( /*string $key = null*/ )
2017-07-03 19:04:27 +02:00
{
2020-01-17 10:58:01 +01:00
if ( 1 <= \func_num_args () && null !== $key = func_get_arg ( 0 )) {
return $this -> headers [ strtr ( $key , self :: UPPER , self :: LOWER )] ? ? [];
}
2017-07-03 19:04:27 +02:00
return $this -> headers ;
}
/**
* Returns the parameter keys .
*
* @ return array An array of parameter keys
*/
public function keys ()
{
return array_keys ( $this -> all ());
}
/**
* Replaces the current HTTP headers by a new set .
*/
2020-01-17 10:58:01 +01:00
public function replace ( array $headers = [])
2017-07-03 19:04:27 +02:00
{
2020-01-17 10:58:01 +01:00
$this -> headers = [];
2017-07-03 19:04:27 +02:00
$this -> add ( $headers );
}
/**
* Adds new headers the current HTTP headers set .
*/
public function add ( array $headers )
{
foreach ( $headers as $key => $values ) {
$this -> set ( $key , $values );
}
}
/**
* Returns a header value by name .
*
2020-01-17 10:58:01 +01:00
* @ param string $key The header name
* @ param string | null $default The default value
2017-07-03 19:04:27 +02:00
*
2020-01-17 10:58:01 +01:00
* @ return string | null The first header value or default value
2017-07-03 19:04:27 +02:00
*/
2020-01-17 10:58:01 +01:00
public function get ( $key , $default = null )
2017-07-03 19:04:27 +02:00
{
2020-01-17 10:58:01 +01:00
$headers = $this -> all (( string ) $key );
if ( 2 < \func_num_args ()) {
@ trigger_error ( sprintf ( 'Passing a third argument to "%s()" is deprecated since Symfony 4.4, use method "all()" instead' , __METHOD__ ), E_USER_DEPRECATED );
2017-07-03 19:04:27 +02:00
2020-01-17 10:58:01 +01:00
if ( ! func_get_arg ( 2 )) {
return $headers ;
2017-07-03 19:04:27 +02:00
}
2020-01-17 10:58:01 +01:00
}
2017-07-03 19:04:27 +02:00
2020-01-17 10:58:01 +01:00
if ( ! $headers ) {
return $default ;
2017-07-03 19:04:27 +02:00
}
2020-01-17 10:58:01 +01:00
if ( null === $headers [ 0 ]) {
return null ;
2017-07-03 19:04:27 +02:00
}
2020-01-17 10:58:01 +01:00
return ( string ) $headers [ 0 ];
2017-07-03 19:04:27 +02:00
}
/**
* Sets a header by name .
*
2018-08-07 10:42:11 +02:00
* @ param string $key The key
* @ param string | string [] $values The value or an array of values
* @ param bool $replace Whether to replace the actual value or not ( true by default )
2017-07-03 19:04:27 +02:00
*/
public function set ( $key , $values , $replace = true )
{
2020-01-17 10:58:01 +01:00
$key = strtr ( $key , self :: UPPER , self :: LOWER );
2017-07-03 19:04:27 +02:00
2018-08-07 10:42:11 +02:00
if ( \is_array ( $values )) {
$values = array_values ( $values );
2017-07-03 19:04:27 +02:00
2018-08-07 10:42:11 +02:00
if ( true === $replace || ! isset ( $this -> headers [ $key ])) {
$this -> headers [ $key ] = $values ;
} else {
$this -> headers [ $key ] = array_merge ( $this -> headers [ $key ], $values );
}
2017-07-03 19:04:27 +02:00
} else {
2018-08-07 10:42:11 +02:00
if ( true === $replace || ! isset ( $this -> headers [ $key ])) {
2020-01-17 10:58:01 +01:00
$this -> headers [ $key ] = [ $values ];
2018-08-07 10:42:11 +02:00
} else {
$this -> headers [ $key ][] = $values ;
}
2017-07-03 19:04:27 +02:00
}
if ( 'cache-control' === $key ) {
2018-08-07 10:42:11 +02:00
$this -> cacheControl = $this -> parseCacheControl ( implode ( ', ' , $this -> headers [ $key ]));
2017-07-03 19:04:27 +02:00
}
}
/**
* Returns true if the HTTP header is defined .
*
* @ param string $key The HTTP header
*
* @ return bool true if the parameter exists , false otherwise
*/
public function has ( $key )
{
2020-01-17 10:58:01 +01:00
return \array_key_exists ( strtr ( $key , self :: UPPER , self :: LOWER ), $this -> all ());
2017-07-03 19:04:27 +02:00
}
/**
* Returns true if the given HTTP header contains the given value .
*
* @ param string $key The HTTP header name
* @ param string $value The HTTP value
*
* @ return bool true if the value is contained in the header , false otherwise
*/
public function contains ( $key , $value )
{
2020-01-17 10:58:01 +01:00
return \in_array ( $value , $this -> all (( string ) $key ));
2017-07-03 19:04:27 +02:00
}
/**
* Removes a header .
*
* @ param string $key The HTTP header name
*/
public function remove ( $key )
{
2020-01-17 10:58:01 +01:00
$key = strtr ( $key , self :: UPPER , self :: LOWER );
2017-07-03 19:04:27 +02:00
unset ( $this -> headers [ $key ]);
if ( 'cache-control' === $key ) {
2020-01-17 10:58:01 +01:00
$this -> cacheControl = [];
2017-07-03 19:04:27 +02:00
}
}
/**
* Returns the HTTP header value converted to a date .
*
2020-01-17 10:58:01 +01:00
* @ param string $key The parameter key
2017-07-03 19:04:27 +02:00
*
2020-01-17 10:58:01 +01:00
* @ return \DateTimeInterface | null The parsed DateTime or the default value if the header does not exist
2017-07-03 19:04:27 +02:00
*
* @ throws \RuntimeException When the HTTP header is not parseable
*/
public function getDate ( $key , \DateTime $default = null )
{
if ( null === $value = $this -> get ( $key )) {
return $default ;
}
if ( false === $date = \DateTime :: createFromFormat ( DATE_RFC2822 , $value )) {
throw new \RuntimeException ( sprintf ( 'The %s HTTP header is not parseable (%s).' , $key , $value ));
}
return $date ;
}
/**
* Adds a custom Cache - Control directive .
*
* @ param string $key The Cache - Control directive name
* @ param mixed $value The Cache - Control directive value
*/
public function addCacheControlDirective ( $key , $value = true )
{
$this -> cacheControl [ $key ] = $value ;
$this -> set ( 'Cache-Control' , $this -> getCacheControlHeader ());
}
/**
* Returns true if the Cache - Control directive is defined .
*
* @ param string $key The Cache - Control directive
*
* @ return bool true if the directive exists , false otherwise
*/
public function hasCacheControlDirective ( $key )
{
2020-01-17 10:58:01 +01:00
return \array_key_exists ( $key , $this -> cacheControl );
2017-07-03 19:04:27 +02:00
}
/**
* Returns a Cache - Control directive value by name .
*
* @ param string $key The directive name
*
* @ return mixed | null The directive value if defined , null otherwise
*/
public function getCacheControlDirective ( $key )
{
2020-01-17 10:58:01 +01:00
return \array_key_exists ( $key , $this -> cacheControl ) ? $this -> cacheControl [ $key ] : null ;
2017-07-03 19:04:27 +02:00
}
/**
* Removes a Cache - Control directive .
*
* @ param string $key The Cache - Control directive
*/
public function removeCacheControlDirective ( $key )
{
unset ( $this -> cacheControl [ $key ]);
$this -> set ( 'Cache-Control' , $this -> getCacheControlHeader ());
}
/**
* Returns an iterator for headers .
*
* @ return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator ()
{
return new \ArrayIterator ( $this -> headers );
}
/**
* Returns the number of headers .
*
* @ return int The number of headers
*/
public function count ()
{
2018-08-07 10:42:11 +02:00
return \count ( $this -> headers );
2017-07-03 19:04:27 +02:00
}
protected function getCacheControlHeader ()
{
ksort ( $this -> cacheControl );
2020-01-17 10:58:01 +01:00
return HeaderUtils :: toString ( $this -> cacheControl , ',' );
2017-07-03 19:04:27 +02:00
}
/**
* Parses a Cache - Control HTTP header .
*
* @ param string $header The value of the Cache - Control HTTP header
*
* @ return array An array representing the attribute values
*/
protected function parseCacheControl ( $header )
{
2020-01-17 10:58:01 +01:00
$parts = HeaderUtils :: split ( $header , ',=' );
2017-07-03 19:04:27 +02:00
2020-01-17 10:58:01 +01:00
return HeaderUtils :: combine ( $parts );
2017-07-03 19:04:27 +02:00
}
}