# 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');
        }
    }