This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/HttpFoundation/HeaderBag.php

326 lines
8.0 KiB
PHP
Raw Normal View History

<?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;
/**
2010-06-23 15:24:24 +01:00
* HeaderBag is a container for HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
2011-07-20 09:06:02 +01:00
*
* @api
*/
class HeaderBag implements \IteratorAggregate, \Countable
{
2010-06-23 15:24:24 +01:00
protected $headers;
protected $cacheControl;
/**
* Constructor.
*
* @param array $headers An array of HTTP headers
2011-07-20 09:06:02 +01:00
*
* @api
*/
public function __construct(array $headers = array())
{
$this->cacheControl = array();
$this->headers = array();
foreach ($headers as $key => $values) {
$this->set($key, $values);
}
}
/**
* Returns the headers as a string.
*
* @return string The headers
*/
public function __toString()
{
2011-05-15 18:44:22 +01:00
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;
}
2010-06-23 15:24:24 +01:00
/**
* Returns the headers.
*
* @return array An array of headers
2011-07-20 09:06:02 +01:00
*
* @api
2010-06-23 15:24:24 +01:00
*/
public function all()
{
return $this->headers;
}
/**
* Returns the parameter keys.
*
* @return array An array of parameter keys
2011-07-20 09:06:02 +01:00
*
* @api
*/
public function keys()
{
return array_keys($this->headers);
}
/**
* Replaces the current HTTP headers by a new set.
*
2012-05-15 21:19:31 +01:00
* @param array $headers An array of HTTP headers
2011-07-20 09:06:02 +01:00
*
* @api
*/
2010-06-23 15:24:24 +01:00
public function replace(array $headers = array())
{
2010-06-23 15:24:24 +01:00
$this->headers = array();
$this->add($headers);
}
/**
* Adds new headers the current HTTP headers set.
*
2012-05-15 21:19:31 +01:00
* @param array $headers An array of HTTP headers
2011-07-20 09:06:02 +01:00
*
* @api
*/
public function add(array $headers)
{
2010-06-23 15:24:24 +01:00
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 Boolean $first Whether to return the first value or all header values
2010-06-23 15:24:24 +01:00
*
* @return string|array The first header value if $first is true, an array of values otherwise
2011-07-20 09:06:02 +01:00
*
* @api
*/
public function get($key, $default = null, $first = true)
{
$key = strtr(strtolower($key), '_', '-');
2010-06-23 15:24:24 +01:00
if (!array_key_exists($key, $this->headers)) {
if (null === $default) {
return $first ? null : array();
}
2011-02-27 17:28:11 +00:00
return $first ? $default : array($default);
2010-06-23 15:24:24 +01:00
}
if ($first) {
return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
2010-06-23 15:24:24 +01:00
}
2011-02-27 17:28:11 +00:00
return $this->headers[$key];
}
/**
* Sets a header by name.
*
2010-06-23 15:24:24 +01:00
* @param string $key The key
* @param string|array $values The value or an array of values
2013-03-31 19:13:07 +01:00
* @param Boolean $replace Whether to replace the actual value or not (true by default)
2011-07-20 09:06:02 +01:00
*
* @api
*/
2010-06-23 15:24:24 +01:00
public function set($key, $values, $replace = true)
{
$key = strtr(strtolower($key), '_', '-');
$values = array_values((array) $values);
2010-06-23 15:24:24 +01:00
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 Boolean true if the parameter exists, false otherwise
2011-07-20 09:06:02 +01:00
*
* @api
*/
public function has($key)
2010-05-03 17:10:24 +01:00
{
2010-06-23 15:24:24 +01:00
return array_key_exists(strtr(strtolower($key), '_', '-'), $this->headers);
2010-05-03 17:10:24 +01:00
}
[HttpKernel] removed Response assertions They are too magic and they don't really add value: $this->assertResponseStatusCodeEmpty($client); $this->assertTrue($client->getResponse()->isEmpty()); $this->assertResponseStatusCodeNotFound($client); $this->assertTrue($client->getResponse()->isNotFound()); $this->assertResponseStatusCodeForbidden($client); $this->assertTrue($client->getResponse()->isForbidden()); $this->assertResponseStatusCodeOk($client); $this->assertTrue($client->getResponse()->isOk()); $this->assertResponseStatusCodeServerError($client); $this->assertTrue($client->getResponse()->isServerError()); $this->assertResponseStatusCodeClientError($client); $this->assertTrue($client->getResponse()->isClientError()); $this->assertResponseStatusCodeRedirection($client); $this->assertTrue($client->getResponse()->isRedirection()); $this->assertResponseStatusCodeSuccessful($client); $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertResponseStatusCodeInformational($client); $this->assertTrue($client->getResponse()->isInformational()); $this->assertResponseStatusCode(200, $client); $this->assertEquals(200, $client->getResponse()->getStatusCode()); $this->assertResponseStatusCodeRedirect('google.com', $client); $this->assertTrue($client->getResponse()->isRedirected('google.com')); $this->assertResponseNotRegExp('/foo/', $client); $this->assertNotRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseRegExp('/foo/', $client); $this->assertRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseNotSelectExists('h1', $client); $this->assertTrue($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectExists('h1', $client); $this->assertFalse($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectCount(3, 'h1', $client); $this->assertEquals(3, $crawler->filter('h1')->count()); $this->assertResponseSelectEquals($expected, $selector, $arguments, $client); $this->assertEquals($expected, $crawler->filter($selector)->extract($arguments)); $this->assertResponseHeaderEquals($value, $key, $client); $this->assertTrue($client->getResponse()->headers->contains($key, $value)); $this->assertResponseNotHeaderEquals($value, $key, $client); $this->assertFalse($client->getResponse()->headers->contains($key, $value)); $this->assertResponseHeaderRegExp($regex, $key, $client); $this->assertRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseNotHeaderRegExp($regex, $key, $client); $this->assertNotRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseCookie($value, $attributes, $name, $client); $this->assertTrue($client->getResponse()->hasCookie($name));
2010-06-23 09:39:33 +01: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 Boolean true if the value is contained in the header, false otherwise
2011-07-20 09:06:02 +01:00
*
* @api
[HttpKernel] removed Response assertions They are too magic and they don't really add value: $this->assertResponseStatusCodeEmpty($client); $this->assertTrue($client->getResponse()->isEmpty()); $this->assertResponseStatusCodeNotFound($client); $this->assertTrue($client->getResponse()->isNotFound()); $this->assertResponseStatusCodeForbidden($client); $this->assertTrue($client->getResponse()->isForbidden()); $this->assertResponseStatusCodeOk($client); $this->assertTrue($client->getResponse()->isOk()); $this->assertResponseStatusCodeServerError($client); $this->assertTrue($client->getResponse()->isServerError()); $this->assertResponseStatusCodeClientError($client); $this->assertTrue($client->getResponse()->isClientError()); $this->assertResponseStatusCodeRedirection($client); $this->assertTrue($client->getResponse()->isRedirection()); $this->assertResponseStatusCodeSuccessful($client); $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertResponseStatusCodeInformational($client); $this->assertTrue($client->getResponse()->isInformational()); $this->assertResponseStatusCode(200, $client); $this->assertEquals(200, $client->getResponse()->getStatusCode()); $this->assertResponseStatusCodeRedirect('google.com', $client); $this->assertTrue($client->getResponse()->isRedirected('google.com')); $this->assertResponseNotRegExp('/foo/', $client); $this->assertNotRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseRegExp('/foo/', $client); $this->assertRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseNotSelectExists('h1', $client); $this->assertTrue($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectExists('h1', $client); $this->assertFalse($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectCount(3, 'h1', $client); $this->assertEquals(3, $crawler->filter('h1')->count()); $this->assertResponseSelectEquals($expected, $selector, $arguments, $client); $this->assertEquals($expected, $crawler->filter($selector)->extract($arguments)); $this->assertResponseHeaderEquals($value, $key, $client); $this->assertTrue($client->getResponse()->headers->contains($key, $value)); $this->assertResponseNotHeaderEquals($value, $key, $client); $this->assertFalse($client->getResponse()->headers->contains($key, $value)); $this->assertResponseHeaderRegExp($regex, $key, $client); $this->assertRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseNotHeaderRegExp($regex, $key, $client); $this->assertNotRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseCookie($value, $attributes, $name, $client); $this->assertTrue($client->getResponse()->hasCookie($name));
2010-06-23 09:39:33 +01:00
*/
public function contains($key, $value)
{
return in_array($value, $this->get($key, null, false));
[HttpKernel] removed Response assertions They are too magic and they don't really add value: $this->assertResponseStatusCodeEmpty($client); $this->assertTrue($client->getResponse()->isEmpty()); $this->assertResponseStatusCodeNotFound($client); $this->assertTrue($client->getResponse()->isNotFound()); $this->assertResponseStatusCodeForbidden($client); $this->assertTrue($client->getResponse()->isForbidden()); $this->assertResponseStatusCodeOk($client); $this->assertTrue($client->getResponse()->isOk()); $this->assertResponseStatusCodeServerError($client); $this->assertTrue($client->getResponse()->isServerError()); $this->assertResponseStatusCodeClientError($client); $this->assertTrue($client->getResponse()->isClientError()); $this->assertResponseStatusCodeRedirection($client); $this->assertTrue($client->getResponse()->isRedirection()); $this->assertResponseStatusCodeSuccessful($client); $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertResponseStatusCodeInformational($client); $this->assertTrue($client->getResponse()->isInformational()); $this->assertResponseStatusCode(200, $client); $this->assertEquals(200, $client->getResponse()->getStatusCode()); $this->assertResponseStatusCodeRedirect('google.com', $client); $this->assertTrue($client->getResponse()->isRedirected('google.com')); $this->assertResponseNotRegExp('/foo/', $client); $this->assertNotRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseRegExp('/foo/', $client); $this->assertRegExp('/foo', $client->getResponse()->getContent()); $this->assertResponseNotSelectExists('h1', $client); $this->assertTrue($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectExists('h1', $client); $this->assertFalse($crawler->filter('h1')->isEmpty()); $this->assertResponseSelectCount(3, 'h1', $client); $this->assertEquals(3, $crawler->filter('h1')->count()); $this->assertResponseSelectEquals($expected, $selector, $arguments, $client); $this->assertEquals($expected, $crawler->filter($selector)->extract($arguments)); $this->assertResponseHeaderEquals($value, $key, $client); $this->assertTrue($client->getResponse()->headers->contains($key, $value)); $this->assertResponseNotHeaderEquals($value, $key, $client); $this->assertFalse($client->getResponse()->headers->contains($key, $value)); $this->assertResponseHeaderRegExp($regex, $key, $client); $this->assertRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseNotHeaderRegExp($regex, $key, $client); $this->assertNotRegExp($regex, $client->getResponse()->headers->get($key)); $this->assertResponseCookie($value, $attributes, $name, $client); $this->assertTrue($client->getResponse()->hasCookie($name));
2010-06-23 09:39:33 +01:00
}
/**
made some method name changes to have a better coherence throughout the framework When an object has a "main" many relation with related "things" (objects, parameters, ...), the method names are normalized: * get() * set() * all() * replace() * remove() * clear() * isEmpty() * add() * register() * count() * keys() The classes below follow this method naming convention: * BrowserKit\CookieJar -> Cookie * BrowserKit\History -> Request * Console\Application -> Command * Console\Application\Helper\HelperSet -> HelperInterface * DependencyInjection\Container -> services * DependencyInjection\ContainerBuilder -> services * DependencyInjection\ParameterBag\ParameterBag -> parameters * DependencyInjection\ParameterBag\FrozenParameterBag -> parameters * DomCrawler\Form -> FormField * EventDispatcher\Event -> parameters * Form\FieldGroup -> Field * HttpFoundation\HeaderBag -> headers * HttpFoundation\ParameterBag -> parameters * HttpFoundation\Session -> attributes * HttpKernel\Profiler\Profiler -> DataCollectorInterface * Routing\RouteCollection -> Route * Security\Authentication\AuthenticationProviderManager -> AuthenticationProviderInterface * Templating\Engine -> HelperInterface * Translation\MessageCatalogue -> messages The usage of these methods are only allowed when it is clear that there is a main relation: * a CookieJar has many Cookies; * a Container has many services and many parameters (as services is the main relation, we use the naming convention for this relation); * a Console Input has many arguments and many options. There is no "main" relation, and so the naming convention does not apply. For many relations where the convention does not apply, the following methods must be used instead (where XXX is the name of the related thing): * get() -> getXXX() * set() -> setXXX() * all() -> getXXXs() * replace() -> setXXXs() * remove() -> removeXXX() * clear() -> clearXXX() * isEmpty() -> isEmptyXXX() * add() -> addXXX() * register() -> registerXXX() * count() -> countXXX() * keys()
2010-11-23 08:42:19 +00:00
* Removes a header.
*
* @param string $key The HTTP header name
2011-07-20 09:06:02 +01:00
*
* @api
*/
made some method name changes to have a better coherence throughout the framework When an object has a "main" many relation with related "things" (objects, parameters, ...), the method names are normalized: * get() * set() * all() * replace() * remove() * clear() * isEmpty() * add() * register() * count() * keys() The classes below follow this method naming convention: * BrowserKit\CookieJar -> Cookie * BrowserKit\History -> Request * Console\Application -> Command * Console\Application\Helper\HelperSet -> HelperInterface * DependencyInjection\Container -> services * DependencyInjection\ContainerBuilder -> services * DependencyInjection\ParameterBag\ParameterBag -> parameters * DependencyInjection\ParameterBag\FrozenParameterBag -> parameters * DomCrawler\Form -> FormField * EventDispatcher\Event -> parameters * Form\FieldGroup -> Field * HttpFoundation\HeaderBag -> headers * HttpFoundation\ParameterBag -> parameters * HttpFoundation\Session -> attributes * HttpKernel\Profiler\Profiler -> DataCollectorInterface * Routing\RouteCollection -> Route * Security\Authentication\AuthenticationProviderManager -> AuthenticationProviderInterface * Templating\Engine -> HelperInterface * Translation\MessageCatalogue -> messages The usage of these methods are only allowed when it is clear that there is a main relation: * a CookieJar has many Cookies; * a Container has many services and many parameters (as services is the main relation, we use the naming convention for this relation); * a Console Input has many arguments and many options. There is no "main" relation, and so the naming convention does not apply. For many relations where the convention does not apply, the following methods must be used instead (where XXX is the name of the related thing): * get() -> getXXX() * set() -> setXXX() * all() -> getXXXs() * replace() -> setXXXs() * remove() -> removeXXX() * clear() -> clearXXX() * isEmpty() -> isEmptyXXX() * add() -> addXXX() * register() -> registerXXX() * count() -> countXXX() * keys()
2010-11-23 08:42:19 +00:00
public function remove($key)
{
$key = strtr(strtolower($key), '_', '-');
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
2011-07-20 09:06:02 +01:00
*
* @api
*/
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;
}
public function addCacheControlDirective($key, $value = true)
{
$this->cacheControl[$key] = $value;
$this->set('Cache-Control', $this->getCacheControlHeader());
}
public function hasCacheControlDirective($key)
{
return array_key_exists($key, $this->cacheControl);
}
public function getCacheControlDirective($key)
{
return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null;
}
public function removeCacheControlDirective($key)
{
unset($this->cacheControl[$key]);
$this->set('Cache-Control', $this->getCacheControlHeader());
}
/**
2012-03-23 12:49:00 +00:00
* Returns an iterator for headers.
*
2012-03-23 12:49:00 +00:00
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->headers);
}
/**
2012-03-23 12:49:00 +00:00
* Returns the number of headers.
*
2012-03-23 12:49:00 +00:00
* @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;
}
}