2015-08-17 17:00:26 -07: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
{
protected $headers = array ();
protected $cacheControl = array ();
/**
* Constructor .
*
* @ param array $headers An array of HTTP headers
*/
public function __construct ( array $headers = array ())
{
foreach ( $headers as $key => $values ) {
$this -> set ( $key , $values );
}
}
/**
* Returns the headers as a string .
*
* @ return string The headers
*/
public function __toString ()
{
if ( ! $this -> headers ) {
return '' ;
}
$max = max ( array_map ( 'strlen' , array_keys ( $this -> headers ))) + 1 ;
$content = '' ;
ksort ( $this -> headers );
foreach ( $this -> headers as $name => $values ) {
$name = implode ( '-' , array_map ( 'ucfirst' , explode ( '-' , $name )));
foreach ( $values as $value ) {
$content .= sprintf ( " %- { $max } s %s \r \n " , $name . ':' , $value );
}
}
return $content ;
}
/**
* Returns the headers .
*
* @ return array An array of headers
*/
public function all ()
{
return $this -> headers ;
}
/**
* Returns the parameter keys .
*
* @ return array An array of parameter keys
*/
public function keys ()
{
return array_keys ( $this -> headers );
}
/**
* Replaces the current HTTP headers by a new set .
*
* @ param array $headers An array of HTTP headers
*/
public function replace ( array $headers = array ())
{
$this -> headers = array ();
$this -> add ( $headers );
}
/**
* Adds new headers the current HTTP headers set .
*
* @ param array $headers An array of HTTP headers
*/
public function add ( array $headers )
{
foreach ( $headers as $key => $values ) {
$this -> set ( $key , $values );
}
}
/**
* Returns a header value by name .
*
* @ param string $key The header name
* @ param mixed $default The default value
* @ param bool $first Whether to return the first value or all header values
*
* @ return string | array The first header value if $first is true , an array of values otherwise
*/
public function get ( $key , $default = null , $first = true )
{
2016-04-20 09:56:34 -07:00
$key = str_replace ( '_' , '-' , strtolower ( $key ));
2015-08-17 17:00:26 -07:00
if ( ! array_key_exists ( $key , $this -> headers )) {
if ( null === $default ) {
return $first ? null : array ();
}
return $first ? $default : array ( $default );
}
if ( $first ) {
return count ( $this -> headers [ $key ]) ? $this -> headers [ $key ][ 0 ] : $default ;
}
return $this -> headers [ $key ];
}
/**
* Sets a header by name .
*
* @ param string $key The key
* @ param string | array $values The value or an array of values
* @ param bool $replace Whether to replace the actual value or not ( true by default )
*/
public function set ( $key , $values , $replace = true )
{
2016-04-20 09:56:34 -07:00
$key = str_replace ( '_' , '-' , strtolower ( $key ));
2015-08-17 17:00:26 -07:00
$values = array_values (( array ) $values );
if ( true === $replace || ! isset ( $this -> headers [ $key ])) {
$this -> headers [ $key ] = $values ;
} else {
$this -> headers [ $key ] = array_merge ( $this -> headers [ $key ], $values );
}
if ( 'cache-control' === $key ) {
$this -> cacheControl = $this -> parseCacheControl ( $values [ 0 ]);
}
}
/**
* 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 )
{
2016-04-20 09:56:34 -07:00
return array_key_exists ( str_replace ( '_' , '-' , strtolower ( $key )), $this -> headers );
2015-08-17 17:00:26 -07: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 )
{
return in_array ( $value , $this -> get ( $key , null , false ));
}
/**
* Removes a header .
*
* @ param string $key The HTTP header name
*/
public function remove ( $key )
{
2016-04-20 09:56:34 -07:00
$key = str_replace ( '_' , '-' , strtolower ( $key ));
2015-08-17 17:00:26 -07:00
unset ( $this -> headers [ $key ]);
if ( 'cache-control' === $key ) {
$this -> cacheControl = array ();
}
}
/**
* Returns the HTTP header value converted to a date .
*
* @ param string $key The parameter key
* @ param \DateTime $default The default value
*
* @ return null | \DateTime The parsed DateTime or the default value if the header does not exist
*
* @ 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 )
{
return array_key_exists ( $key , $this -> cacheControl );
}
/**
* 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 )
{
return array_key_exists ( $key , $this -> cacheControl ) ? $this -> cacheControl [ $key ] : null ;
}
/**
* 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 ()
{
return count ( $this -> headers );
}
protected function getCacheControlHeader ()
{
$parts = array ();
ksort ( $this -> cacheControl );
foreach ( $this -> cacheControl as $key => $value ) {
if ( true === $value ) {
$parts [] = $key ;
} else {
if ( preg_match ( '#[^a-zA-Z0-9._-]#' , $value )) {
$value = '"' . $value . '"' ;
}
$parts [] = " $key = $value " ;
}
}
return implode ( ', ' , $parts );
}
/**
* 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 )
{
$cacheControl = array ();
preg_match_all ( '#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#' , $header , $matches , PREG_SET_ORDER );
foreach ( $matches as $match ) {
$cacheControl [ strtolower ( $match [ 1 ])] = isset ( $match [ 3 ]) ? $match [ 3 ] : ( isset ( $match [ 2 ]) ? $match [ 2 ] : true );
}
return $cacheControl ;
}
}