|
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 * ResponseHeaderBag is a container for Response HTTP headers. |
|
16 * |
|
17 * @author Fabien Potencier <fabien@symfony.com> |
|
18 * |
|
19 * @api |
|
20 */ |
|
21 class ResponseHeaderBag extends HeaderBag |
|
22 { |
|
23 const COOKIES_FLAT = 'flat'; |
|
24 const COOKIES_ARRAY = 'array'; |
|
25 |
|
26 protected $computedCacheControl = array(); |
|
27 protected $cookies = array(); |
|
28 |
|
29 /** |
|
30 * Constructor. |
|
31 * |
|
32 * @param array $headers An array of HTTP headers |
|
33 * |
|
34 * @api |
|
35 */ |
|
36 public function __construct(array $headers = array()) |
|
37 { |
|
38 parent::__construct($headers); |
|
39 |
|
40 if (!isset($this->headers['cache-control'])) { |
|
41 $this->set('cache-control', ''); |
|
42 } |
|
43 } |
|
44 |
|
45 /** |
|
46 * {@inheritdoc} |
|
47 */ |
|
48 public function __toString() |
|
49 { |
|
50 $cookies = ''; |
|
51 foreach ($this->getCookies() as $cookie) { |
|
52 $cookies .= 'Set-Cookie: '.$cookie."\r\n"; |
|
53 } |
|
54 |
|
55 return parent::__toString().$cookies; |
|
56 } |
|
57 |
|
58 /** |
|
59 * {@inheritdoc} |
|
60 * |
|
61 * @api |
|
62 */ |
|
63 public function replace(array $headers = array()) |
|
64 { |
|
65 parent::replace($headers); |
|
66 |
|
67 if (!isset($this->headers['cache-control'])) { |
|
68 $this->set('cache-control', ''); |
|
69 } |
|
70 } |
|
71 |
|
72 /** |
|
73 * {@inheritdoc} |
|
74 * |
|
75 * @api |
|
76 */ |
|
77 public function set($key, $values, $replace = true) |
|
78 { |
|
79 parent::set($key, $values, $replace); |
|
80 |
|
81 // ensure the cache-control header has sensible defaults |
|
82 if (in_array(strtr(strtolower($key), '_', '-'), array('cache-control', 'etag', 'last-modified', 'expires'))) { |
|
83 $computed = $this->computeCacheControlValue(); |
|
84 $this->headers['cache-control'] = array($computed); |
|
85 $this->computedCacheControl = $this->parseCacheControl($computed); |
|
86 } |
|
87 } |
|
88 |
|
89 /** |
|
90 * {@inheritdoc} |
|
91 * |
|
92 * @api |
|
93 */ |
|
94 public function remove($key) |
|
95 { |
|
96 parent::remove($key); |
|
97 |
|
98 if ('cache-control' === strtr(strtolower($key), '_', '-')) { |
|
99 $this->computedCacheControl = array(); |
|
100 } |
|
101 } |
|
102 |
|
103 /** |
|
104 * {@inheritdoc} |
|
105 */ |
|
106 public function hasCacheControlDirective($key) |
|
107 { |
|
108 return array_key_exists($key, $this->computedCacheControl); |
|
109 } |
|
110 |
|
111 /** |
|
112 * {@inheritdoc} |
|
113 */ |
|
114 public function getCacheControlDirective($key) |
|
115 { |
|
116 return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null; |
|
117 } |
|
118 |
|
119 /** |
|
120 * Sets a cookie. |
|
121 * |
|
122 * @param Cookie $cookie |
|
123 * @return void |
|
124 * |
|
125 * @api |
|
126 */ |
|
127 public function setCookie(Cookie $cookie) |
|
128 { |
|
129 $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; |
|
130 } |
|
131 |
|
132 /** |
|
133 * Removes a cookie from the array, but does not unset it in the browser |
|
134 * |
|
135 * @param string $name |
|
136 * @param string $path |
|
137 * @param string $domain |
|
138 * @return void |
|
139 * |
|
140 * @api |
|
141 */ |
|
142 public function removeCookie($name, $path = null, $domain = null) |
|
143 { |
|
144 unset($this->cookies[$domain][$path][$name]); |
|
145 |
|
146 if (empty($this->cookies[$domain][$path])) { |
|
147 unset($this->cookies[$domain][$path]); |
|
148 |
|
149 if (empty($this->cookies[$domain])) { |
|
150 unset($this->cookies[$domain]); |
|
151 } |
|
152 } |
|
153 } |
|
154 |
|
155 /** |
|
156 * Returns an array with all cookies |
|
157 * |
|
158 * @param string $format |
|
159 * |
|
160 * @throws \InvalidArgumentException When the $format is invalid |
|
161 * |
|
162 * @return array |
|
163 * |
|
164 * @api |
|
165 */ |
|
166 public function getCookies($format = self::COOKIES_FLAT) |
|
167 { |
|
168 if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) { |
|
169 throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY)))); |
|
170 } |
|
171 |
|
172 if (self::COOKIES_ARRAY === $format) { |
|
173 return $this->cookies; |
|
174 } |
|
175 |
|
176 $flattenedCookies = array(); |
|
177 foreach ($this->cookies as $path) { |
|
178 foreach ($path as $cookies) { |
|
179 foreach ($cookies as $cookie) { |
|
180 $flattenedCookies[] = $cookie; |
|
181 } |
|
182 } |
|
183 } |
|
184 |
|
185 return $flattenedCookies; |
|
186 } |
|
187 |
|
188 /** |
|
189 * Clears a cookie in the browser |
|
190 * |
|
191 * @param string $name |
|
192 * @param string $path |
|
193 * @param string $domain |
|
194 * @return void |
|
195 * |
|
196 * @api |
|
197 */ |
|
198 public function clearCookie($name, $path = null, $domain = null) |
|
199 { |
|
200 $this->setCookie(new Cookie($name, null, 1, $path, $domain)); |
|
201 } |
|
202 |
|
203 /** |
|
204 * Returns the calculated value of the cache-control header. |
|
205 * |
|
206 * This considers several other headers and calculates or modifies the |
|
207 * cache-control header to a sensible, conservative value. |
|
208 * |
|
209 * @return string |
|
210 */ |
|
211 protected function computeCacheControlValue() |
|
212 { |
|
213 if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) { |
|
214 return 'no-cache'; |
|
215 } |
|
216 |
|
217 if (!$this->cacheControl) { |
|
218 // conservative by default |
|
219 return 'private, must-revalidate'; |
|
220 } |
|
221 |
|
222 $header = $this->getCacheControlHeader(); |
|
223 if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) { |
|
224 return $header; |
|
225 } |
|
226 |
|
227 // public if s-maxage is defined, private otherwise |
|
228 if (!isset($this->cacheControl['s-maxage'])) { |
|
229 return $header.', private'; |
|
230 } |
|
231 |
|
232 return $header; |
|
233 } |
|
234 } |