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 extends HeaderBag
22: {
23: const COOKIES_FLAT = 'flat';
24: const COOKIES_ARRAY = 'array';
25:
26: const DISPOSITION_ATTACHMENT = 'attachment';
27: const DISPOSITION_INLINE = 'inline';
28:
29: 30: 31:
32: protected $computedCacheControl = array();
33:
34: 35: 36:
37: protected $cookies = array();
38:
39: 40: 41:
42: protected = array();
43:
44: 45: 46: 47: 48: 49: 50:
51: public function __construct(array $headers = array())
52: {
53: parent::__construct($headers);
54:
55: if (!isset($this->headers['cache-control'])) {
56: $this->set('Cache-Control', '');
57: }
58: }
59:
60: 61: 62:
63: public function __toString()
64: {
65: $cookies = '';
66: foreach ($this->getCookies() as $cookie) {
67: $cookies .= 'Set-Cookie: '.$cookie."\r\n";
68: }
69:
70: ksort($this->headerNames);
71:
72: return parent::__toString().$cookies;
73: }
74:
75: 76: 77: 78: 79:
80: public function allPreserveCase()
81: {
82: return array_combine($this->headerNames, $this->headers);
83: }
84:
85: 86: 87: 88: 89:
90: public function replace(array $headers = array())
91: {
92: $this->headerNames = array();
93:
94: parent::replace($headers);
95:
96: if (!isset($this->headers['cache-control'])) {
97: $this->set('Cache-Control', '');
98: }
99: }
100:
101: 102: 103: 104: 105:
106: public function set($key, $values, $replace = true)
107: {
108: parent::set($key, $values, $replace);
109:
110: $uniqueKey = strtr(strtolower($key), '_', '-');
111: $this->headerNames[$uniqueKey] = $key;
112:
113:
114: if (in_array($uniqueKey, array('cache-control', 'etag', 'last-modified', 'expires'))) {
115: $computed = $this->computeCacheControlValue();
116: $this->headers['cache-control'] = array($computed);
117: $this->headerNames['cache-control'] = 'Cache-Control';
118: $this->computedCacheControl = $this->parseCacheControl($computed);
119: }
120: }
121:
122: 123: 124: 125: 126:
127: public function remove($key)
128: {
129: parent::remove($key);
130:
131: $uniqueKey = strtr(strtolower($key), '_', '-');
132: unset($this->headerNames[$uniqueKey]);
133:
134: if ('cache-control' === $uniqueKey) {
135: $this->computedCacheControl = array();
136: }
137: }
138:
139: 140: 141:
142: public function hasCacheControlDirective($key)
143: {
144: return array_key_exists($key, $this->computedCacheControl);
145: }
146:
147: 148: 149:
150: public function getCacheControlDirective($key)
151: {
152: return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
153: }
154:
155: 156: 157: 158: 159: 160: 161:
162: public function setCookie(Cookie $cookie)
163: {
164: $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
165: }
166:
167: 168: 169: 170: 171: 172: 173: 174: 175:
176: public function removeCookie($name, $path = '/', $domain = null)
177: {
178: if (null === $path) {
179: $path = '/';
180: }
181:
182: unset($this->cookies[$domain][$path][$name]);
183:
184: if (empty($this->cookies[$domain][$path])) {
185: unset($this->cookies[$domain][$path]);
186:
187: if (empty($this->cookies[$domain])) {
188: unset($this->cookies[$domain]);
189: }
190: }
191: }
192:
193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203:
204: public function getCookies($format = self::COOKIES_FLAT)
205: {
206: if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
207: throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
208: }
209:
210: if (self::COOKIES_ARRAY === $format) {
211: return $this->cookies;
212: }
213:
214: $flattenedCookies = array();
215: foreach ($this->cookies as $path) {
216: foreach ($path as $cookies) {
217: foreach ($cookies as $cookie) {
218: $flattenedCookies[] = $cookie;
219: }
220: }
221: }
222:
223: return $flattenedCookies;
224: }
225:
226: 227: 228: 229: 230: 231: 232: 233: 234:
235: public function clearCookie($name, $path = '/', $domain = null)
236: {
237: $this->setCookie(new Cookie($name, null, 1, $path, $domain));
238: }
239:
240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253:
254: public function makeDisposition($disposition, $filename, $filenameFallback = '')
255: {
256: if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
257: throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
258: }
259:
260: if ('' == $filenameFallback) {
261: $filenameFallback = $filename;
262: }
263:
264:
265: if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
266: throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
267: }
268:
269:
270: if (false !== strpos($filenameFallback, '%')) {
271: throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
272: }
273:
274:
275: if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) {
276: throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
277: }
278:
279: $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
280:
281: if ($filename !== $filenameFallback) {
282: $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
283: }
284:
285: return $output;
286: }
287:
288: 289: 290: 291: 292: 293: 294: 295:
296: protected function computeCacheControlValue()
297: {
298: if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) {
299: return 'no-cache';
300: }
301:
302: if (!$this->cacheControl) {
303:
304: return 'private, must-revalidate';
305: }
306:
307: $header = $this->getCacheControlHeader();
308: if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
309: return $header;
310: }
311:
312:
313: if (!isset($this->cacheControl['s-maxage'])) {
314: return $header.', private';
315: }
316:
317: return $header;
318: }
319: }
320: