/vendor/zendframework/zend-http/src/Header/CacheControl.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 252 lines · 124 code · 31 blank · 97 comment · 11 complexity · d57f3c724d48068a89ee3d3ee3b61478 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Http\Header;
  10. /**
  11. * @throws Exception\InvalidArgumentException
  12. * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
  13. */
  14. class CacheControl implements HeaderInterface
  15. {
  16. /**
  17. * @var string
  18. */
  19. protected $value;
  20. /**
  21. * Array of Cache-Control directives
  22. *
  23. * @var array
  24. */
  25. protected $directives = array();
  26. /**
  27. * Creates a CacheControl object from a headerLine
  28. *
  29. * @param string $headerLine
  30. * @throws Exception\InvalidArgumentException
  31. * @return CacheControl
  32. */
  33. public static function fromString($headerLine)
  34. {
  35. list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
  36. // check to ensure proper header type for this factory
  37. if (strtolower($name) !== 'cache-control') {
  38. throw new Exception\InvalidArgumentException(sprintf(
  39. 'Invalid header line for Cache-Control string: ""',
  40. $name
  41. ));
  42. }
  43. HeaderValue::assertValid($value);
  44. $directives = static::parseValue($value);
  45. // @todo implementation details
  46. $header = new static();
  47. foreach ($directives as $key => $value) {
  48. $header->addDirective($key, $value);
  49. }
  50. return $header;
  51. }
  52. /**
  53. * Required from HeaderDescription interface
  54. *
  55. * @return string
  56. */
  57. public function getFieldName()
  58. {
  59. return 'Cache-Control';
  60. }
  61. /**
  62. * Checks if the internal directives array is empty
  63. *
  64. * @return bool
  65. */
  66. public function isEmpty()
  67. {
  68. return empty($this->directives);
  69. }
  70. /**
  71. * Add a directive
  72. * For directives like 'max-age=60', $value = '60'
  73. * For directives like 'private', use the default $value = true
  74. *
  75. * @param string $key
  76. * @param string|bool $value
  77. * @return CacheControl - provides the fluent interface
  78. */
  79. public function addDirective($key, $value = true)
  80. {
  81. HeaderValue::assertValid($key);
  82. if (! is_bool($value)) {
  83. HeaderValue::assertValid($value);
  84. }
  85. $this->directives[$key] = $value;
  86. return $this;
  87. }
  88. /**
  89. * Check the internal directives array for a directive
  90. *
  91. * @param string $key
  92. * @return bool
  93. */
  94. public function hasDirective($key)
  95. {
  96. return array_key_exists($key, $this->directives);
  97. }
  98. /**
  99. * Fetch the value of a directive from the internal directive array
  100. *
  101. * @param string $key
  102. * @return string|null
  103. */
  104. public function getDirective($key)
  105. {
  106. return array_key_exists($key, $this->directives) ? $this->directives[$key] : null;
  107. }
  108. /**
  109. * Remove a directive
  110. *
  111. * @param string $key
  112. * @return CacheControl - provides the fluent interface
  113. */
  114. public function removeDirective($key)
  115. {
  116. unset($this->directives[$key]);
  117. return $this;
  118. }
  119. /**
  120. * Assembles the directives into a comma-delimited string
  121. *
  122. * @return string
  123. */
  124. public function getFieldValue()
  125. {
  126. $parts = array();
  127. ksort($this->directives);
  128. foreach ($this->directives as $key => $value) {
  129. if (true === $value) {
  130. $parts[] = $key;
  131. } else {
  132. if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
  133. $value = '"' . $value.'"';
  134. }
  135. $parts[] = "$key=$value";
  136. }
  137. }
  138. return implode(', ', $parts);
  139. }
  140. /**
  141. * Returns a string representation of the HTTP Cache-Control header
  142. *
  143. * @return string
  144. */
  145. public function toString()
  146. {
  147. return 'Cache-Control: ' . $this->getFieldValue();
  148. }
  149. /**
  150. * Internal function for parsing the value part of a
  151. * HTTP Cache-Control header
  152. *
  153. * @param string $value
  154. * @throws Exception\InvalidArgumentException
  155. * @return array
  156. */
  157. protected static function parseValue($value)
  158. {
  159. $value = trim($value);
  160. $directives = array();
  161. // handle empty string early so we don't need a separate start state
  162. if ($value == '') {
  163. return $directives;
  164. }
  165. $lastMatch = null;
  166. state_directive:
  167. switch (static::match(array('[a-zA-Z][a-zA-Z_-]*'), $value, $lastMatch)) {
  168. case 0:
  169. $directive = $lastMatch;
  170. goto state_value;
  171. // intentional fall-through
  172. default:
  173. throw new Exception\InvalidArgumentException('expected DIRECTIVE');
  174. }
  175. state_value:
  176. switch (static::match(array('="[^"]*"', '=[^",\s;]*'), $value, $lastMatch)) {
  177. case 0:
  178. $directives[$directive] = substr($lastMatch, 2, -1);
  179. goto state_separator;
  180. // intentional fall-through
  181. case 1:
  182. $directives[$directive] = rtrim(substr($lastMatch, 1));
  183. goto state_separator;
  184. // intentional fall-through
  185. default:
  186. $directives[$directive] = true;
  187. goto state_separator;
  188. }
  189. state_separator:
  190. switch (static::match(array('\s*,\s*', '$'), $value, $lastMatch)) {
  191. case 0:
  192. goto state_directive;
  193. // intentional fall-through
  194. case 1:
  195. return $directives;
  196. default:
  197. throw new Exception\InvalidArgumentException('expected SEPARATOR or END');
  198. }
  199. }
  200. /**
  201. * Internal function used by parseValue to match tokens
  202. *
  203. * @param array $tokens
  204. * @param string $string
  205. * @param string $lastMatch
  206. * @return int
  207. */
  208. protected static function match($tokens, &$string, &$lastMatch)
  209. {
  210. // Ensure we have a string
  211. $value = (string) $string;
  212. foreach ($tokens as $i => $token) {
  213. if (preg_match('/^' . $token . '/', $value, $matches)) {
  214. $lastMatch = $matches[0];
  215. $string = substr($value, strlen($matches[0]));
  216. return $i;
  217. }
  218. }
  219. return -1;
  220. }
  221. }