Fix bug in style changes for the Use cases on the live site.
[yaffs-website] / vendor / symfony / http-foundation / HeaderBag.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation;
13
14 /**
15  * HeaderBag is a container for HTTP headers.
16  *
17  * @author Fabien Potencier <fabien@symfony.com>
18  */
19 class HeaderBag implements \IteratorAggregate, \Countable
20 {
21     protected $headers = array();
22     protected $cacheControl = array();
23
24     /**
25      * Constructor.
26      *
27      * @param array $headers An array of HTTP headers
28      */
29     public function __construct(array $headers = array())
30     {
31         foreach ($headers as $key => $values) {
32             $this->set($key, $values);
33         }
34     }
35
36     /**
37      * Returns the headers as a string.
38      *
39      * @return string The headers
40      */
41     public function __toString()
42     {
43         if (!$this->headers) {
44             return '';
45         }
46
47         $max = max(array_map('strlen', array_keys($this->headers))) + 1;
48         $content = '';
49         ksort($this->headers);
50         foreach ($this->headers as $name => $values) {
51             $name = implode('-', array_map('ucfirst', explode('-', $name)));
52             foreach ($values as $value) {
53                 $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
54             }
55         }
56
57         return $content;
58     }
59
60     /**
61      * Returns the headers.
62      *
63      * @return array An array of headers
64      */
65     public function all()
66     {
67         return $this->headers;
68     }
69
70     /**
71      * Returns the parameter keys.
72      *
73      * @return array An array of parameter keys
74      */
75     public function keys()
76     {
77         return array_keys($this->headers);
78     }
79
80     /**
81      * Replaces the current HTTP headers by a new set.
82      *
83      * @param array $headers An array of HTTP headers
84      */
85     public function replace(array $headers = array())
86     {
87         $this->headers = array();
88         $this->add($headers);
89     }
90
91     /**
92      * Adds new headers the current HTTP headers set.
93      *
94      * @param array $headers An array of HTTP headers
95      */
96     public function add(array $headers)
97     {
98         foreach ($headers as $key => $values) {
99             $this->set($key, $values);
100         }
101     }
102
103     /**
104      * Returns a header value by name.
105      *
106      * @param string $key     The header name
107      * @param mixed  $default The default value
108      * @param bool   $first   Whether to return the first value or all header values
109      *
110      * @return string|array The first header value if $first is true, an array of values otherwise
111      */
112     public function get($key, $default = null, $first = true)
113     {
114         $key = str_replace('_', '-', strtolower($key));
115
116         if (!array_key_exists($key, $this->headers)) {
117             if (null === $default) {
118                 return $first ? null : array();
119             }
120
121             return $first ? $default : array($default);
122         }
123
124         if ($first) {
125             return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
126         }
127
128         return $this->headers[$key];
129     }
130
131     /**
132      * Sets a header by name.
133      *
134      * @param string       $key     The key
135      * @param string|array $values  The value or an array of values
136      * @param bool         $replace Whether to replace the actual value or not (true by default)
137      */
138     public function set($key, $values, $replace = true)
139     {
140         $key = str_replace('_', '-', strtolower($key));
141
142         $values = array_values((array) $values);
143
144         if (true === $replace || !isset($this->headers[$key])) {
145             $this->headers[$key] = $values;
146         } else {
147             $this->headers[$key] = array_merge($this->headers[$key], $values);
148         }
149
150         if ('cache-control' === $key) {
151             $this->cacheControl = $this->parseCacheControl($values[0]);
152         }
153     }
154
155     /**
156      * Returns true if the HTTP header is defined.
157      *
158      * @param string $key The HTTP header
159      *
160      * @return bool true if the parameter exists, false otherwise
161      */
162     public function has($key)
163     {
164         return array_key_exists(str_replace('_', '-', strtolower($key)), $this->headers);
165     }
166
167     /**
168      * Returns true if the given HTTP header contains the given value.
169      *
170      * @param string $key   The HTTP header name
171      * @param string $value The HTTP value
172      *
173      * @return bool true if the value is contained in the header, false otherwise
174      */
175     public function contains($key, $value)
176     {
177         return in_array($value, $this->get($key, null, false));
178     }
179
180     /**
181      * Removes a header.
182      *
183      * @param string $key The HTTP header name
184      */
185     public function remove($key)
186     {
187         $key = str_replace('_', '-', strtolower($key));
188
189         unset($this->headers[$key]);
190
191         if ('cache-control' === $key) {
192             $this->cacheControl = array();
193         }
194     }
195
196     /**
197      * Returns the HTTP header value converted to a date.
198      *
199      * @param string    $key     The parameter key
200      * @param \DateTime $default The default value
201      *
202      * @return null|\DateTime The parsed DateTime or the default value if the header does not exist
203      *
204      * @throws \RuntimeException When the HTTP header is not parseable
205      */
206     public function getDate($key, \DateTime $default = null)
207     {
208         if (null === $value = $this->get($key)) {
209             return $default;
210         }
211
212         if (false === $date = \DateTime::createFromFormat(DATE_RFC2822, $value)) {
213             throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).', $key, $value));
214         }
215
216         return $date;
217     }
218
219     /**
220      * Adds a custom Cache-Control directive.
221      *
222      * @param string $key   The Cache-Control directive name
223      * @param mixed  $value The Cache-Control directive value
224      */
225     public function addCacheControlDirective($key, $value = true)
226     {
227         $this->cacheControl[$key] = $value;
228
229         $this->set('Cache-Control', $this->getCacheControlHeader());
230     }
231
232     /**
233      * Returns true if the Cache-Control directive is defined.
234      *
235      * @param string $key The Cache-Control directive
236      *
237      * @return bool true if the directive exists, false otherwise
238      */
239     public function hasCacheControlDirective($key)
240     {
241         return array_key_exists($key, $this->cacheControl);
242     }
243
244     /**
245      * Returns a Cache-Control directive value by name.
246      *
247      * @param string $key The directive name
248      *
249      * @return mixed|null The directive value if defined, null otherwise
250      */
251     public function getCacheControlDirective($key)
252     {
253         return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null;
254     }
255
256     /**
257      * Removes a Cache-Control directive.
258      *
259      * @param string $key The Cache-Control directive
260      */
261     public function removeCacheControlDirective($key)
262     {
263         unset($this->cacheControl[$key]);
264
265         $this->set('Cache-Control', $this->getCacheControlHeader());
266     }
267
268     /**
269      * Returns an iterator for headers.
270      *
271      * @return \ArrayIterator An \ArrayIterator instance
272      */
273     public function getIterator()
274     {
275         return new \ArrayIterator($this->headers);
276     }
277
278     /**
279      * Returns the number of headers.
280      *
281      * @return int The number of headers
282      */
283     public function count()
284     {
285         return count($this->headers);
286     }
287
288     protected function getCacheControlHeader()
289     {
290         $parts = array();
291         ksort($this->cacheControl);
292         foreach ($this->cacheControl as $key => $value) {
293             if (true === $value) {
294                 $parts[] = $key;
295             } else {
296                 if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
297                     $value = '"'.$value.'"';
298                 }
299
300                 $parts[] = "$key=$value";
301             }
302         }
303
304         return implode(', ', $parts);
305     }
306
307     /**
308      * Parses a Cache-Control HTTP header.
309      *
310      * @param string $header The value of the Cache-Control HTTP header
311      *
312      * @return array An array representing the attribute values
313      */
314     protected function parseCacheControl($header)
315     {
316         $cacheControl = array();
317         preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
318         foreach ($matches as $match) {
319             $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
320         }
321
322         return $cacheControl;
323     }
324 }