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