/src/Symfony/Component/HttpFoundation/HeaderBag.php

https://github.com/sebio/symfony · PHP · 317 lines · 156 code · 40 blank · 121 comment · 18 complexity · d570c40aa863c504dc6123b91b72143b MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpFoundation;
  11. /**
  12. * HeaderBag is a container for HTTP headers.
  13. *
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. */
  16. class HeaderBag
  17. {
  18. protected $headers;
  19. protected $cookies;
  20. protected $cacheControl;
  21. /**
  22. * Constructor.
  23. *
  24. * @param array $headers An array of HTTP headers
  25. */
  26. public function __construct(array $headers = array())
  27. {
  28. $this->cacheControl = array();
  29. $this->cookies = array();
  30. $this->replace($headers);
  31. }
  32. /**
  33. * Returns the headers.
  34. *
  35. * @return array An array of headers
  36. */
  37. public function all()
  38. {
  39. return $this->headers;
  40. }
  41. /**
  42. * Returns the parameter keys.
  43. *
  44. * @return array An array of parameter keys
  45. */
  46. public function keys()
  47. {
  48. return array_keys($this->headers);
  49. }
  50. /**
  51. * Replaces the current HTTP headers by a new set.
  52. *
  53. * @param array $headers An array of HTTP headers
  54. */
  55. public function replace(array $headers = array())
  56. {
  57. $this->headers = array();
  58. $this->add($headers);
  59. }
  60. /**
  61. * Adds new headers the current HTTP headers set.
  62. *
  63. * @param array $headers An array of HTTP headers
  64. */
  65. public function add(array $headers)
  66. {
  67. foreach ($headers as $key => $values) {
  68. $this->set($key, $values);
  69. }
  70. }
  71. /**
  72. * Returns a header value by name.
  73. *
  74. * @param string $key The header name
  75. * @param mixed $default The default value
  76. * @param Boolean $first Whether to return the first value or all header values
  77. *
  78. * @return string|array The first header value if $first is true, an array of values otherwise
  79. */
  80. public function get($key, $default = null, $first = true)
  81. {
  82. $key = strtr(strtolower($key), '_', '-');
  83. if (!array_key_exists($key, $this->headers)) {
  84. if (null === $default) {
  85. return $first ? null : array();
  86. } else {
  87. return $first ? $default : array($default);
  88. }
  89. }
  90. if ($first) {
  91. return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
  92. } else {
  93. return $this->headers[$key];
  94. }
  95. }
  96. /**
  97. * Sets a header by name.
  98. *
  99. * @param string $key The key
  100. * @param string|array $values The value or an array of values
  101. * @param Boolean $replace Whether to replace the actual value of not (true by default)
  102. */
  103. public function set($key, $values, $replace = true)
  104. {
  105. $key = strtr(strtolower($key), '_', '-');
  106. if (!is_array($values)) {
  107. $values = array($values);
  108. }
  109. if (true === $replace || !isset($this->headers[$key])) {
  110. $this->headers[$key] = $values;
  111. } else {
  112. $this->headers[$key] = array_merge($this->headers[$key], $values);
  113. }
  114. if ('cache-control' === $key) {
  115. $this->cacheControl = $this->parseCacheControl($values[0]);
  116. }
  117. }
  118. /**
  119. * Returns true if the HTTP header is defined.
  120. *
  121. * @param string $key The HTTP header
  122. *
  123. * @return Boolean true if the parameter exists, false otherwise
  124. */
  125. public function has($key)
  126. {
  127. return array_key_exists(strtr(strtolower($key), '_', '-'), $this->headers);
  128. }
  129. /**
  130. * Returns true if the given HTTP header contains the given value.
  131. *
  132. * @param string $key The HTTP header name
  133. * @param string $value The HTTP value
  134. *
  135. * @return Boolean true if the value is contained in the header, false otherwise
  136. */
  137. public function contains($key, $value)
  138. {
  139. return in_array($value, $this->get($key, null, false));
  140. }
  141. /**
  142. * Removes a header.
  143. *
  144. * @param string $key The HTTP header name
  145. */
  146. public function remove($key)
  147. {
  148. $key = strtr(strtolower($key), '_', '-');
  149. unset($this->headers[$key]);
  150. if ('cache-control' === $key) {
  151. $this->cacheControl = array();
  152. }
  153. }
  154. /**
  155. * Sets a cookie.
  156. *
  157. * @param Cookie $cookie
  158. *
  159. * @throws \InvalidArgumentException When the cookie expire parameter is not valid
  160. *
  161. * @return void
  162. */
  163. public function setCookie(Cookie $cookie)
  164. {
  165. $this->cookies[$cookie->getName()] = $cookie;
  166. }
  167. /**
  168. * Removes a cookie from the array, but does not unset it in the browser
  169. *
  170. * @param string $name
  171. * @return void
  172. */
  173. public function removeCookie($name)
  174. {
  175. unset($this->cookies[$name]);
  176. }
  177. /**
  178. * Whether the array contains any cookie with this name
  179. *
  180. * @param string $name
  181. * @return Boolean
  182. */
  183. public function hasCookie($name)
  184. {
  185. return isset($this->cookies[$name]);
  186. }
  187. /**
  188. * Returns a cookie
  189. *
  190. * @param string $name
  191. * @return Cookie
  192. */
  193. public function getCookie($name)
  194. {
  195. if (!$this->hasCookie($name)) {
  196. throw new \InvalidArgumentException(sprintf('There is no cookie with name "%s".', $name));
  197. }
  198. return $this->cookies[$name];
  199. }
  200. /**
  201. * Returns an array with all cookies
  202. *
  203. * @return array
  204. */
  205. public function getCookies()
  206. {
  207. return $this->cookies;
  208. }
  209. /**
  210. * Returns the HTTP header value converted to a date.
  211. *
  212. * @param string $key The parameter key
  213. * @param \DateTime $default The default value
  214. *
  215. * @return \DateTime The filtered value
  216. */
  217. public function getDate($key, \DateTime $default = null)
  218. {
  219. if (null === $value = $this->get($key)) {
  220. return $default;
  221. }
  222. if (false === $date = \DateTime::createFromFormat(DATE_RFC2822, $value)) {
  223. throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).', $key, $value));
  224. }
  225. return $date;
  226. }
  227. public function addCacheControlDirective($key, $value = true)
  228. {
  229. $this->cacheControl[$key] = $value;
  230. $this->set('Cache-Control', $this->getCacheControlHeader());
  231. }
  232. public function hasCacheControlDirective($key)
  233. {
  234. return array_key_exists($key, $this->cacheControl);
  235. }
  236. public function getCacheControlDirective($key)
  237. {
  238. return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null;
  239. }
  240. public function removeCacheControlDirective($key)
  241. {
  242. unset($this->cacheControl[$key]);
  243. $this->set('Cache-Control', $this->getCacheControlHeader());
  244. }
  245. protected function getCacheControlHeader()
  246. {
  247. $parts = array();
  248. ksort($this->cacheControl);
  249. foreach ($this->cacheControl as $key => $value) {
  250. if (true === $value) {
  251. $parts[] = $key;
  252. } else {
  253. if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
  254. $value = '"'.$value.'"';
  255. }
  256. $parts[] = "$key=$value";
  257. }
  258. }
  259. return implode(', ', $parts);
  260. }
  261. /**
  262. * Parses a Cache-Control HTTP header.
  263. *
  264. * @param string $header The value of the Cache-Control HTTP header
  265. *
  266. * @return array An array representing the attribute values
  267. */
  268. protected function parseCacheControl($header)
  269. {
  270. $cacheControl = array();
  271. preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
  272. foreach ($matches as $match) {
  273. $cacheControl[strtolower($match[1])] = isset($match[2]) && $match[2] ? $match[2] : (isset($match[3]) ? $match[3] : true);
  274. }
  275. return $cacheControl;
  276. }
  277. }