PageRenderTime 40ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Http/Header/SetCookie.php

https://bitbucket.org/aboozar/zf2
PHP | 520 lines | 279 code | 72 blank | 169 comment | 48 complexity | 7e8e8dc3127f446fbd66e16d4d0512d7 MD5 | raw file
Possible License(s): BSD-3-Clause
  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-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. * @package Zend_Http
  9. */
  10. namespace Zend\Http\Header;
  11. /**
  12. * @throws Exception\InvalidArgumentException
  13. * @see http://www.ietf.org/rfc/rfc2109.txt
  14. * @see http://www.w3.org/Protocols/rfc2109/rfc2109
  15. */
  16. class SetCookie implements MultipleHeaderInterface
  17. {
  18. /**
  19. * Cookie name
  20. *
  21. * @var string
  22. */
  23. protected $name = null;
  24. /**
  25. * Cookie value
  26. *
  27. * @var string
  28. */
  29. protected $value = null;
  30. /**
  31. * Version
  32. *
  33. * @var integer
  34. */
  35. protected $version = null;
  36. /**
  37. * Max Age
  38. *
  39. * @var integer
  40. */
  41. protected $maxAge = null;
  42. /**
  43. * Cookie expiry date
  44. *
  45. * @var int
  46. */
  47. protected $expires = null;
  48. /**
  49. * Cookie domain
  50. *
  51. * @var string
  52. */
  53. protected $domain = null;
  54. /**
  55. * Cookie path
  56. *
  57. * @var string
  58. */
  59. protected $path = null;
  60. /**
  61. * Whether the cookie is secure or not
  62. *
  63. * @var boolean
  64. */
  65. protected $secure = null;
  66. /**
  67. * @var true
  68. */
  69. protected $httponly = null;
  70. /**
  71. * @static
  72. * @throws Exception\InvalidArgumentException
  73. * @param $headerLine
  74. * @param bool $bypassHeaderFieldName
  75. * @return array|SetCookie
  76. */
  77. public static function fromString($headerLine, $bypassHeaderFieldName = false)
  78. {
  79. /* @var $setCookieProcessor Closure */
  80. static $setCookieProcessor = null;
  81. if ($setCookieProcessor === null) {
  82. $setCookieClass = get_called_class();
  83. $setCookieProcessor = function($headerLine) use ($setCookieClass) {
  84. $header = new $setCookieClass;
  85. $keyValuePairs = preg_split('#;\s*#', $headerLine);
  86. foreach ($keyValuePairs as $keyValue) {
  87. if (strpos($keyValue, '=')) {
  88. list($headerKey, $headerValue) = preg_split('#=\s*#', $keyValue, 2);
  89. } else {
  90. $headerKey = $keyValue;
  91. $headerValue = null;
  92. }
  93. // First K=V pair is always the cookie name and value
  94. if ($header->getName() === NULL) {
  95. $header->setName($headerKey);
  96. $header->setValue($headerValue);
  97. continue;
  98. }
  99. // Process the remanining elements
  100. switch (str_replace(array('-', '_'), '', strtolower($headerKey))) {
  101. case 'expires' : $header->setExpires($headerValue); break;
  102. case 'domain' : $header->setDomain($headerValue); break;
  103. case 'path' : $header->setPath($headerValue); break;
  104. case 'secure' : $header->setSecure(true); break;
  105. case 'httponly': $header->setHttponly(true); break;
  106. case 'version' : $header->setVersion((int) $headerValue); break;
  107. case 'maxage' : $header->setMaxAge((int) $headerValue); break;
  108. default:
  109. // Intentionally omitted
  110. }
  111. }
  112. return $header;
  113. };
  114. }
  115. list($name, $value) = explode(': ', $headerLine, 2);
  116. // check to ensure proper header type for this factory
  117. if (strtolower($name) !== 'set-cookie') {
  118. throw new Exception\InvalidArgumentException('Invalid header line for Set-Cookie string: "' . $name . '"');
  119. }
  120. $multipleHeaders = preg_split('#(?<!Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s*#', $value);
  121. if (count($multipleHeaders) <= 1) {
  122. return $setCookieProcessor(array_pop($multipleHeaders));
  123. } else {
  124. $headers = array();
  125. foreach ($multipleHeaders as $headerLine) {
  126. $headers[] = $setCookieProcessor($headerLine);
  127. }
  128. return $headers;
  129. }
  130. }
  131. /**
  132. * Cookie object constructor
  133. *
  134. * @todo Add validation of each one of the parameters (legal domain, etc.)
  135. *
  136. * @param string $name
  137. * @param string $value
  138. * @param int $expires
  139. * @param string $path
  140. * @param string $domain
  141. * @param bool $secure
  142. * @param bool $httponly
  143. * @param string $maxAge
  144. * @param int $version
  145. * @return SetCookie
  146. */
  147. public function __construct($name = null, $value = null, $expires = null, $path = null, $domain = null, $secure = false, $httponly = false, $maxAge = null, $version = null)
  148. {
  149. $this->type = 'Cookie';
  150. if ($name) {
  151. $this->setName($name);
  152. }
  153. if ($value) {
  154. $this->setValue($value); // in parent
  155. }
  156. if ($version!==null) {
  157. $this->setVersion($version);
  158. }
  159. if ($maxAge!==null) {
  160. $this->setMaxAge($maxAge);
  161. }
  162. if ($domain) {
  163. $this->setDomain($domain);
  164. }
  165. if ($expires) {
  166. $this->setExpires($expires);
  167. }
  168. if ($path) {
  169. $this->setPath($path);
  170. }
  171. if ($secure) {
  172. $this->setSecure($secure);
  173. }
  174. if ($httponly) {
  175. $this->setHttpOnly($httponly);
  176. }
  177. }
  178. /**
  179. * @return string 'Set-Cookie'
  180. */
  181. public function getFieldName()
  182. {
  183. return 'Set-Cookie';
  184. }
  185. /**
  186. * @throws Exception\RuntimeException
  187. * @return string
  188. */
  189. public function getFieldValue()
  190. {
  191. if ($this->getName() == '') {
  192. throw new Exception\RuntimeException('A cookie name is required to generate a field value for this cookie');
  193. }
  194. $value = $this->getValue();
  195. if (strpos($value, '"')!==false) {
  196. $value = '"'.urlencode(str_replace('"', '', $value)).'"';
  197. } else {
  198. $value = urlencode($value);
  199. }
  200. $fieldValue = $this->getName() . '=' . $value;
  201. $version = $this->getVersion();
  202. if ($version!==null) {
  203. $fieldValue .= '; Version=' . $version;
  204. }
  205. $maxAge = $this->getMaxAge();
  206. if ($maxAge!==null) {
  207. $fieldValue .= '; Max-Age=' . $maxAge;
  208. }
  209. $expires = $this->getExpires();
  210. if ($expires) {
  211. $fieldValue .= '; Expires=' . $expires;
  212. }
  213. $domain = $this->getDomain();
  214. if ($domain) {
  215. $fieldValue .= '; Domain=' . $domain;
  216. }
  217. $path = $this->getPath();
  218. if ($path) {
  219. $fieldValue .= '; Path=' . $path;
  220. }
  221. if ($this->isSecure()) {
  222. $fieldValue .= '; Secure';
  223. }
  224. if ($this->isHttponly()) {
  225. $fieldValue .= '; HttpOnly';
  226. }
  227. return $fieldValue;
  228. }
  229. /**
  230. * @param string $name
  231. * @return SetCookie
  232. */
  233. public function setName($name)
  234. {
  235. if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
  236. throw new Exception\InvalidArgumentException("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})");
  237. }
  238. $this->name = $name;
  239. return $this;
  240. }
  241. /**
  242. * @return string
  243. */
  244. public function getName()
  245. {
  246. return $this->name;
  247. }
  248. /**
  249. * @param string $value
  250. */
  251. public function setValue($value)
  252. {
  253. $this->value = $value;
  254. }
  255. /**
  256. * @return string
  257. */
  258. public function getValue()
  259. {
  260. return $this->value;
  261. }
  262. /**
  263. * Set version
  264. *
  265. * @param integer $version
  266. */
  267. public function setVersion($version)
  268. {
  269. if (!is_int($version)) {
  270. throw new Exception\InvalidArgumentException('Invalid Version number specified');
  271. }
  272. $this->version = $version;
  273. }
  274. /**
  275. * Get version
  276. *
  277. * @return integer
  278. */
  279. public function getVersion()
  280. {
  281. return $this->version;
  282. }
  283. /**
  284. * Set Max-Age
  285. *
  286. * @param integer $maxAge
  287. */
  288. public function setMaxAge($maxAge)
  289. {
  290. if (!is_int($maxAge) || ($maxAge<0)) {
  291. throw new Exception\InvalidArgumentException('Invalid Max-Age number specified');
  292. }
  293. $this->maxAge = $maxAge;
  294. }
  295. /**
  296. * Get Max-Age
  297. *
  298. * @return integer
  299. */
  300. public function getMaxAge()
  301. {
  302. return $this->maxAge;
  303. }
  304. /**
  305. * @param int $expires
  306. * @return SetCookie
  307. */
  308. public function setExpires($expires)
  309. {
  310. if (!empty($expires)) {
  311. if (is_string($expires)) {
  312. $expires = strtotime($expires);
  313. } elseif (!is_int($expires)) {
  314. throw new Exception\InvalidArgumentException('Invalid expires time specified');
  315. }
  316. $this->expires = (int) $expires;
  317. }
  318. return $this;
  319. }
  320. /**
  321. * @return int
  322. */
  323. public function getExpires($inSeconds = false)
  324. {
  325. if ($this->expires == null) {
  326. return;
  327. }
  328. if ($inSeconds) {
  329. return $this->expires;
  330. }
  331. return gmdate('D, d-M-Y H:i:s', $this->expires) . ' GMT';
  332. }
  333. /**
  334. * @param string $domain
  335. */
  336. public function setDomain($domain)
  337. {
  338. $this->domain = $domain;
  339. }
  340. /**
  341. * @return string
  342. */
  343. public function getDomain()
  344. {
  345. return $this->domain;
  346. }
  347. /**
  348. * @param string $path
  349. */
  350. public function setPath($path)
  351. {
  352. $this->path = $path;
  353. }
  354. /**
  355. * @return string
  356. */
  357. public function getPath()
  358. {
  359. return $this->path;
  360. }
  361. /**
  362. * @param boolean $secure
  363. */
  364. public function setSecure($secure)
  365. {
  366. $this->secure = $secure;
  367. }
  368. /**
  369. * @return boolean
  370. */
  371. public function isSecure()
  372. {
  373. return $this->secure;
  374. }
  375. /**
  376. * @param \Zend\Http\Header\true $httponly
  377. */
  378. public function setHttponly($httponly)
  379. {
  380. $this->httponly = $httponly;
  381. }
  382. /**
  383. * @return \Zend\Http\Header\true
  384. */
  385. public function isHttponly()
  386. {
  387. return $this->httponly;
  388. }
  389. /**
  390. * Check whether the cookie has expired
  391. *
  392. * Always returns false if the cookie is a session cookie (has no expiry time)
  393. *
  394. * @param int $now Timestamp to consider as "now"
  395. * @return boolean
  396. */
  397. public function isExpired($now = null)
  398. {
  399. if ($now === null) {
  400. $now = time();
  401. }
  402. if (is_int($this->expires) && $this->expires < $now) {
  403. return true;
  404. } else {
  405. return false;
  406. }
  407. }
  408. /**
  409. * Check whether the cookie is a session cookie (has no expiry time set)
  410. *
  411. * @return boolean
  412. */
  413. public function isSessionCookie()
  414. {
  415. return ($this->expires === null);
  416. }
  417. public function isValidForRequest($requestDomain, $path, $isSecure = false)
  418. {
  419. if ($this->getDomain() && (strrpos($requestDomain, $this->getDomain()) !== false)) {
  420. return false;
  421. }
  422. if ($this->getPath() && (strpos($path, $this->getPath()) !== 0)) {
  423. return false;
  424. }
  425. if ($this->secure && $this->isSecure()!==$isSecure) {
  426. return false;
  427. }
  428. return true;
  429. }
  430. public function toString()
  431. {
  432. return 'Set-Cookie: ' . $this->getFieldValue();
  433. }
  434. public function toStringMultipleHeaders(array $headers)
  435. {
  436. $headerLine = $this->toString();
  437. /* @var $header SetCookie */
  438. foreach ($headers as $header) {
  439. if (!$header instanceof SetCookie) {
  440. throw new Exception\RuntimeException(
  441. 'The SetCookie multiple header implementation can only accept an array of SetCookie headers'
  442. );
  443. }
  444. $headerLine .= ', ' . $header->getFieldValue();
  445. }
  446. return $headerLine;
  447. }
  448. }