ResponseHeaderBag

class ResponseHeaderBag extends HeaderBag

ResponseHeaderBag is a container for Response HTTP headers.

Constants

COOKIES_FLAT = 'flat';

COOKIES_ARRAY = 'array';

DISPOSITION_ATTACHMENT = 'attachment';

DISPOSITION_INLINE = 'inline';

Properties

protected $headers from HeaderBag
protected $cacheControl from HeaderBag
protected $computedCacheControl
protected $cookies
protected $headerNames

Methods

public __construct(array $headers = array()) No description
public string __toString() Returns the headers as a string. from HeaderBag
public array all() Returns the headers.
public array keys() Returns the parameter keys. from HeaderBag
public replace(array $headers = array()) Replaces the current HTTP headers by a new set.
public add(array $headers) Adds new headers the current HTTP headers set. from HeaderBag
public string|string[] get(string $key, string|string[] $default = null, bool $first = true) Returns a header value by name. from HeaderBag
public set(string $key, string|string[] $values, bool $replace = true) Sets a header by name.
public bool has(string $key) Returns true if the HTTP header is defined. from HeaderBag
public bool contains(string $key, string $value) Returns true if the given HTTP header contains the given value. from HeaderBag
public remove(string $key) Removes a header.
public null|DateTime getDate(string $key, DateTime $default = null) Returns the HTTP header value converted to a date. from HeaderBag
public addCacheControlDirective(string $key, mixed $value = true) Adds a custom Cache-Control directive. from HeaderBag
public bool hasCacheControlDirective(string $key) Returns true if the Cache-Control directive is defined.
public mixed|null getCacheControlDirective(string $key) Returns a Cache-Control directive value by name.
public removeCacheControlDirective(string $key) Removes a Cache-Control directive. from HeaderBag
public ArrayIterator getIterator() Returns an iterator for headers. from HeaderBag
public int count() Returns the number of headers. from HeaderBag
protected getCacheControlHeader() No description from HeaderBag
protected array parseCacheControl(string $header) Parses a Cache-Control HTTP header. from HeaderBag
public array allPreserveCase() Returns the headers, with original capitalizations.
public allPreserveCaseWithoutCookies() No description
public setCookie(Cookie $cookie) No description
public removeCookie(string $name, string $path = '/', string $domain = null) Removes a cookie from the array, but does not unset it in the browser.
public array getCookies(string $format = self::COOKIES_FLAT) Returns an array with all cookies.
public clearCookie(string $name, string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true) Clears a cookie in the browser.
public string makeDisposition(string $disposition, string $filename, string $filenameFallback = '') Generates a HTTP Content-Disposition field-value.
protected string computeCacheControlValue() Returns the calculated value of the cache-control header.

Details

at line 31

__construct()

public __construct(array $headers = array())

Parameters

array $headers An array of HTTP headers
in HeaderBag at line 39

__toString()

public string __toString()

Returns the headers as a string.

Return Value

string The headers
at line 91

all()

public array all()

Returns the headers.

Return Value

array An array of headers
in HeaderBag at line 73

keys()

public array keys()

Returns the parameter keys.

Return Value

array An array of parameter keys
at line 73

replace()

public replace(array $headers = array())

Replaces the current HTTP headers by a new set.

Parameters

array $headers An array of HTTP headers
in HeaderBag at line 94

add()

public add(array $headers)

Adds new headers the current HTTP headers set.

Parameters

array $headers An array of HTTP headers
in HeaderBag at line 110

get()

public string|string[] get(string $key, string|string[] $default = null, bool $first = true)

Returns a header value by name.

Parameters

string $key The header name
string|string[] $default The default value
bool $first Whether to return the first value or all header values

Return Value

string|string[] The first header value or default value if $first is true, an array of values otherwise
at line 104

set()

public set(string $key, string|string[] $values, bool $replace = true)

Sets a header by name.

Parameters

string $key The key
string|string[] $values The value or an array of values
bool $replace Whether to replace the actual value or not (true by default)
in HeaderBag at line 169

has()

public bool has(string $key)

Returns true if the HTTP header is defined.

Parameters

string $key The HTTP header

Return Value

bool true if the parameter exists, false otherwise
in HeaderBag at line 182

contains()

public bool contains(string $key, string $value)

Returns true if the given HTTP header contains the given value.

Parameters

string $key The HTTP header name
string $value The HTTP value

Return Value

bool true if the value is contained in the header, false otherwise
at line 136

remove()

public remove(string $key)

Removes a header.

Parameters

string $key The HTTP header name
in HeaderBag at line 213

getDate()

public null|DateTime getDate(string $key, DateTime $default = null)

Returns the HTTP header value converted to a date.

Parameters

string $key The parameter key
DateTime $default The default value

Return Value

null|DateTime The parsed DateTime or the default value if the header does not exist

Exceptions

RuntimeException When the HTTP header is not parseable
in HeaderBag at line 232

addCacheControlDirective()

public addCacheControlDirective(string $key, mixed $value = true)

Adds a custom Cache-Control directive.

Parameters

string $key The Cache-Control directive name
mixed $value The Cache-Control directive value
at line 161

hasCacheControlDirective()

public bool hasCacheControlDirective(string $key)

Returns true if the Cache-Control directive is defined.

Parameters

string $key The Cache-Control directive

Return Value

bool true if the directive exists, false otherwise
at line 169

getCacheControlDirective()

public mixed|null getCacheControlDirective(string $key)

Returns a Cache-Control directive value by name.

Parameters

string $key The directive name

Return Value

mixed|null The directive value if defined, null otherwise
in HeaderBag at line 268

removeCacheControlDirective()

public removeCacheControlDirective(string $key)

Removes a Cache-Control directive.

Parameters

string $key The Cache-Control directive
in HeaderBag at line 280

getIterator()

public ArrayIterator getIterator()

Returns an iterator for headers.

Return Value

ArrayIterator An \ArrayIterator instance
in HeaderBag at line 290

count()

public int count()

Returns the number of headers.

Return Value

int The number of headers
in HeaderBag at line 295

getCacheControlHeader()

protected getCacheControlHeader()
in HeaderBag at line 321

parseCacheControl()

protected array parseCacheControl(string $header)

Parses a Cache-Control HTTP header.

Parameters

string $header The value of the Cache-Control HTTP header

Return Value

array An array representing the attribute values
at line 50

allPreserveCase()

public array allPreserveCase()

Returns the headers, with original capitalizations.

Return Value

array An array of headers
at line 60

allPreserveCaseWithoutCookies()

public allPreserveCaseWithoutCookies()
at line 174

setCookie()

public setCookie(Cookie $cookie)

Parameters

Cookie $cookie
at line 187

removeCookie()

public removeCookie(string $name, string $path = '/', string $domain = null)

Removes a cookie from the array, but does not unset it in the browser.

Parameters

string $name
string $path
string $domain
at line 217

getCookies()

public array getCookies(string $format = self::COOKIES_FLAT)

Returns an array with all cookies.

Parameters

string $format

Return Value

array

Exceptions

InvalidArgumentException When the $format is invalid
at line 248

clearCookie()

public clearCookie(string $name, string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true)

Clears a cookie in the browser.

Parameters

string $name
string $path
string $domain
bool $secure
bool $httpOnly
at line 268

makeDisposition()

public string makeDisposition(string $disposition, string $filename, string $filenameFallback = '')

Generates a HTTP Content-Disposition field-value.

Parameters

string $disposition One of "inline" or "attachment"
string $filename A unicode string
string $filenameFallback A string containing only ASCII characters that is semantically equivalent to $filename. If the filename is already ASCII, it can be omitted, or just copied from $filename

Return Value

string A string suitable for use as a Content-Disposition field-value

Exceptions

InvalidArgumentException

See also

RFC 6266
at line 310

computeCacheControlValue()

protected string computeCacheControlValue()

Returns the calculated value of the cache-control header.

This considers several other headers and calculates or modifies the cache-control header to a sensible, conservative value.

Return Value

string

Source code

<?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 App\Khan\Component\HttpFoundation;

/**
 * ResponseHeaderBag is a container for Response HTTP headers.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ResponseHeaderBag extends HeaderBag
{
    const COOKIES_FLAT = 'flat';
    const COOKIES_ARRAY = 'array';

    const DISPOSITION_ATTACHMENT = 'attachment';
    const DISPOSITION_INLINE = 'inline';

    protected $computedCacheControl = array();
    protected $cookies = array();
    protected $headerNames = array();

    public function __construct(array $headers = array())
    {
        parent::__construct($headers);

        if (!isset($this->headers['cache-control'])) {
            $this->set('Cache-Control', '');
        }

        /* RFC2616 - 14.18 says all Responses need to have a Date */
        if (!isset($this->headers['date'])) {
            $this->initDate();
        }
    }

    /**
     * Returns the headers, with original capitalizations.
     *
     * @return array An array of headers
     */
    public function allPreserveCase()
    {
        $headers = array();
        foreach ($this->all() as $name => $value) {
            $headers[isset($this->headerNames[$name]) ? $this->headerNames[$name] : $name] = $value;
        }

        return $headers;
    }

    public function allPreserveCaseWithoutCookies()
    {
        $headers = $this->allPreserveCase();
        if (isset($this->headerNames['set-cookie'])) {
            unset($headers[$this->headerNames['set-cookie']]);
        }

        return $headers;
    }

    /**
     * {@inheritdoc}
     */
    public function replace(array $headers = array())
    {
        $this->headerNames = array();

        parent::replace($headers);

        if (!isset($this->headers['cache-control'])) {
            $this->set('Cache-Control', '');
        }

        if (!isset($this->headers['date'])) {
            $this->initDate();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function all()
    {
        $headers = parent::all();
        foreach ($this->getCookies() as $cookie) {
            $headers['set-cookie'][] = (string) $cookie;
        }

        return $headers;
    }

    /**
     * {@inheritdoc}
     */
    public function set($key, $values, $replace = true)
    {
        $uniqueKey = str_replace('_', '-', strtolower($key));

        if ('set-cookie' === $uniqueKey) {
            if ($replace) {
                $this->cookies = array();
            }
            foreach ((array) $values as $cookie) {
                $this->setCookie(Cookie::fromString($cookie));
            }
            $this->headerNames[$uniqueKey] = $key;

            return;
        }

        $this->headerNames[$uniqueKey] = $key;

        parent::set($key, $values, $replace);

        // ensure the cache-control header has sensible defaults
        if (\in_array($uniqueKey, array('cache-control', 'etag', 'last-modified', 'expires'), true)) {
            $computed = $this->computeCacheControlValue();
            $this->headers['cache-control'] = array($computed);
            $this->headerNames['cache-control'] = 'Cache-Control';
            $this->computedCacheControl = $this->parseCacheControl($computed);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function remove($key)
    {
        $uniqueKey = str_replace('_', '-', strtolower($key));
        unset($this->headerNames[$uniqueKey]);

        if ('set-cookie' === $uniqueKey) {
            $this->cookies = array();

            return;
        }

        parent::remove($key);

        if ('cache-control' === $uniqueKey) {
            $this->computedCacheControl = array();
        }

        if ('date' === $uniqueKey) {
            $this->initDate();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function hasCacheControlDirective($key)
    {
        return array_key_exists($key, $this->computedCacheControl);
    }

    /**
     * {@inheritdoc}
     */
    public function getCacheControlDirective($key)
    {
        return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
    }

    public function setCookie(Cookie $cookie)
    {
        $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
        $this->headerNames['set-cookie'] = 'Set-Cookie';
    }

    /**
     * Removes a cookie from the array, but does not unset it in the browser.
     *
     * @param string $name
     * @param string $path
     * @param string $domain
     */
    public function removeCookie($name, $path = '/', $domain = null)
    {
        if (null === $path) {
            $path = '/';
        }

        unset($this->cookies[$domain][$path][$name]);

        if (empty($this->cookies[$domain][$path])) {
            unset($this->cookies[$domain][$path]);

            if (empty($this->cookies[$domain])) {
                unset($this->cookies[$domain]);
            }
        }

        if (empty($this->cookies)) {
            unset($this->headerNames['set-cookie']);
        }
    }

    /**
     * Returns an array with all cookies.
     *
     * @param string $format
     *
     * @return array
     *
     * @throws \InvalidArgumentException When the $format is invalid
     */
    public function getCookies($format = self::COOKIES_FLAT)
    {
        if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
            throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
        }

        if (self::COOKIES_ARRAY === $format) {
            return $this->cookies;
        }

        $flattenedCookies = array();
        foreach ($this->cookies as $path) {
            foreach ($path as $cookies) {
                foreach ($cookies as $cookie) {
                    $flattenedCookies[] = $cookie;
                }
            }
        }

        return $flattenedCookies;
    }

    /**
     * Clears a cookie in the browser.
     *
     * @param string $name
     * @param string $path
     * @param string $domain
     * @param bool   $secure
     * @param bool   $httpOnly
     */
    public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true)
    {
        $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly));
    }

    /**
     * Generates a HTTP Content-Disposition field-value.
     *
     * @param string $disposition      One of "inline" or "attachment"
     * @param string $filename         A unicode string
     * @param string $filenameFallback A string containing only ASCII characters that
     *                                 is semantically equivalent to $filename. If the filename is already ASCII,
     *                                 it can be omitted, or just copied from $filename
     *
     * @return string A string suitable for use as a Content-Disposition field-value
     *
     * @throws \InvalidArgumentException
     *
     * @see RFC 6266
     */
    public function makeDisposition($disposition, $filename, $filenameFallback = '')
    {
        if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
            throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
        }

        if ('' == $filenameFallback) {
            $filenameFallback = $filename;
        }

        // filenameFallback is not ASCII.
        if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
            throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
        }

        // percent characters aren't safe in fallback.
        if (false !== strpos($filenameFallback, '%')) {
            throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
        }

        // path separators aren't allowed in either.
        if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) {
            throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
        }

        $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));

        if ($filename !== $filenameFallback) {
            $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
        }

        return $output;
    }

    /**
     * Returns the calculated value of the cache-control header.
     *
     * This considers several other headers and calculates or modifies the
     * cache-control header to a sensible, conservative value.
     *
     * @return string
     */
    protected function computeCacheControlValue()
    {
        if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) {
            return 'no-cache, private';
        }

        if (!$this->cacheControl) {
            // conservative by default
            return 'private, must-revalidate';
        }

        $header = $this->getCacheControlHeader();
        if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
            return $header;
        }

        // public if s-maxage is defined, private otherwise
        if (!isset($this->cacheControl['s-maxage'])) {
            return $header.', private';
        }

        return $header;
    }

    private function initDate()
    {
        $now = \DateTime::createFromFormat('U', time());
        $now->setTimezone(new \DateTimeZone('UTC'));
        $this->set('Date', $now->format('D, d M Y H:i:s').' GMT');
    }
}