CookieTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Http_Cookie
  17. * @subpackage UnitTests
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. require_once dirname(__FILE__) . '/../../TestHelper.php';
  23. require_once 'Zend/Http/Cookie.php';
  24. /**
  25. * Zend_Http_Cookie unit tests
  26. *
  27. * @category Zend
  28. * @package Zend_Http_Cookie
  29. * @subpackage UnitTests
  30. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. * @group Zend_Http
  33. * @group Zend_Http_Cookie
  34. */
  35. class Zend_Http_CookieTest extends PHPUnit_Framework_TestCase
  36. {
  37. /**
  38. * Cookie creation and data accessors tests
  39. */
  40. /**
  41. * Make sure we can't set invalid names
  42. *
  43. * @dataProvider invalidCookieNameCharProvider
  44. * @expectedException Zend_Http_Exception
  45. */
  46. public function testSetInvalidName($char)
  47. {
  48. $cookie = new Zend_Http_Cookie("cookie_$char", 'foo', 'example.com');
  49. }
  50. /**
  51. * Test we get the cookie name properly
  52. *
  53. * @dataProvider validCookieWithInfoProvider
  54. */
  55. public function testGetName($cStr, $cInfo)
  56. {
  57. $cookie = Zend_Http_Cookie::fromString($cStr);
  58. if (! $cookie instanceof Zend_Http_Cookie) {
  59. $this->fail("Failed creating a cookie object from '$cStr'");
  60. }
  61. if (isset($cInfo['name'])) {
  62. $this->assertEquals($cInfo['name'], $cookie->getName());
  63. }
  64. }
  65. /**
  66. * Make sure we get the correct value if it was set through the constructor
  67. *
  68. * @param string $value
  69. * @dataProvider validCookieValueProvider
  70. */
  71. public function testGetValueConstructor($val)
  72. {
  73. $cookie = new Zend_Http_Cookie('cookie', $val, 'example.com', time(), '/', true);
  74. $this->assertEquals($val, $cookie->getValue());
  75. }
  76. /**
  77. * Make sure we get the correct value if it was set through fromString()
  78. *
  79. * @param string $value
  80. * @dataProvider validCookieValueProvider
  81. */
  82. public function testGetValueFromString($val)
  83. {
  84. $cookie = Zend_Http_Cookie::fromString('cookie=' . urlencode($val) . '; domain=example.com');
  85. $this->assertEquals($val, $cookie->getValue());
  86. }
  87. /**
  88. * Make sure we get the correct domain when it's set in the cookie string
  89. *
  90. * @dataProvider validCookieWithInfoProvider
  91. */
  92. public function testGetDomainInStr($cStr, $cInfo)
  93. {
  94. $cookie = Zend_Http_Cookie::fromString($cStr);
  95. if (! $cookie instanceof Zend_Http_Cookie) {
  96. $this->fail("Failed creating a cookie object from '$cStr'");
  97. }
  98. if (isset($cInfo['domain'])) {
  99. $this->assertEquals($cInfo['domain'], $cookie->getDomain());
  100. }
  101. }
  102. /**
  103. * Make sure we get the correct domain when it's set in a reference URL
  104. *
  105. * @dataProvider refUrlProvider
  106. */
  107. public function testGetDomainInRefUrl(Zend_Uri $uri)
  108. {
  109. $domain = $uri->getHost();
  110. $cookie = Zend_Http_Cookie::fromString('foo=baz; path=/', 'http://' . $domain);
  111. if (! $cookie instanceof Zend_Http_Cookie) {
  112. $this->fail("Failed creating a cookie object with URL '$uri'");
  113. }
  114. $this->assertEquals($domain, $cookie->getDomain());
  115. }
  116. /**
  117. * Make sure we get the correct path when it's set in the cookie string
  118. *
  119. * @dataProvider validCookieWithInfoProvider
  120. */
  121. public function testGetPathInStr($cStr, $cInfo)
  122. {
  123. $cookie = Zend_Http_Cookie::fromString($cStr);
  124. if (! $cookie instanceof Zend_Http_Cookie) {
  125. $this->fail("Failed creating a cookie object from '$cStr'");
  126. }
  127. if (isset($cInfo['path'])) {
  128. $this->assertEquals($cInfo['path'], $cookie->getPath());
  129. }
  130. }
  131. /**
  132. * Make sure we get the correct path when it's set a reference URL
  133. *
  134. * @dataProvider refUrlProvider
  135. */
  136. public function testGetPathInRefUrl(Zend_Uri $uri)
  137. {
  138. $path = $uri->getPath();
  139. if (substr($path, -1, 1) == '/') $path .= 'x';
  140. $path = dirname($path);
  141. if ($path == DIRECTORY_SEPARATOR) {
  142. $path = '/';
  143. }
  144. $cookie = Zend_Http_Cookie::fromString('foo=bar', (string) $uri);
  145. if (! $cookie instanceof Zend_Http_Cookie) {
  146. $this->fail("Failed creating a cookie object with URL '$uri'");
  147. }
  148. $this->assertEquals($path, $cookie->getPath());
  149. }
  150. /**
  151. * Test we get the correct expiry time
  152. *
  153. * @dataProvider validCookieWithInfoProvider
  154. */
  155. public function testGetExpiryTime($cStr, $cInfo)
  156. {
  157. $cookie = Zend_Http_Cookie::fromString($cStr);
  158. if (! $cookie instanceof Zend_Http_Cookie) {
  159. $this->fail("Failed creating a cookie object from '$cStr'");
  160. }
  161. if (isset($cInfo['expires'])) {
  162. $this->assertEquals($cInfo['expires'], $cookie->getExpiryTime());
  163. }
  164. }
  165. /**
  166. * Make sure the "is secure" flag is correctly set
  167. *
  168. * @dataProvider validCookieWithInfoProvider
  169. */
  170. public function testIsSecure($cStr, $cInfo)
  171. {
  172. $cookie = Zend_Http_Cookie::fromString($cStr);
  173. if (! $cookie instanceof Zend_Http_Cookie) {
  174. $this->fail("Failed creating a cookie object from '$cStr'");
  175. }
  176. if (isset($cInfo['secure'])) {
  177. $this->assertEquals($cInfo['secure'], $cookie->isSecure());
  178. }
  179. }
  180. /**
  181. * Cookie expiry time tests
  182. */
  183. /**
  184. * Make sure we get the correct value for 'isExpired'
  185. *
  186. * @dataProvider cookieWithExpiredFlagProvider
  187. */
  188. public function testIsExpired($cStr, $expired)
  189. {
  190. $cookie = Zend_Http_Cookie::fromString($cStr);
  191. if (! $cookie) {
  192. $this->fail("Failed creating a cookie object from '$cStr'");
  193. }
  194. $this->assertEquals($expired, $cookie->isExpired());
  195. }
  196. /**
  197. * Make sure we get the correct value for 'isExpired', when time is manually set
  198. */
  199. public function testIsExpiredDifferentTime()
  200. {
  201. $notexpired = time() + 3600;
  202. $expired = time() - 3600;
  203. $now = time() + 7200;
  204. $cookies = array(
  205. 'cookie=foo; domain=example.com; expires=' . date(DATE_COOKIE, $notexpired),
  206. 'cookie=foo; domain=example.com; expires=' . date(DATE_COOKIE, $expired)
  207. );
  208. // Make sure all cookies are expired
  209. foreach ($cookies as $cstr) {
  210. $cookie = Zend_Http_Cookie::fromString($cstr);
  211. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  212. $this->assertTrue($cookie->isExpired($now), 'Cookie is expected to be expired');
  213. }
  214. // Make sure all cookies are not expired
  215. $now = time() - 7200;
  216. foreach ($cookies as $cstr) {
  217. $cookie = Zend_Http_Cookie::fromString($cstr);
  218. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  219. $this->assertFalse($cookie->isExpired($now), 'Cookie is expected not to be expired');
  220. }
  221. }
  222. /**
  223. * Test we can properly check if a cookie is a session cookie (has no expiry time)
  224. *
  225. * @dataProvider validCookieWithInfoProvider
  226. */
  227. public function testIsSessionCookie($cStr, $cInfo)
  228. {
  229. $cookie = Zend_Http_Cookie::fromString($cStr);
  230. if (! $cookie instanceof Zend_Http_Cookie) {
  231. $this->fail("Failed creating a cookie object from '$cStr'");
  232. }
  233. if (array_key_exists('expires', $cInfo)) {
  234. $this->assertEquals(($cInfo['expires'] === null), $cookie->isSessionCookie());
  235. }
  236. }
  237. /**
  238. * Make sure cookies are properly converted back to strings
  239. *
  240. * @dataProvider validCookieWithInfoProvider
  241. */
  242. public function testToString($cStr, $cInfo)
  243. {
  244. $cookie = Zend_Http_Cookie::fromString($cStr);
  245. if (! $cookie instanceof Zend_Http_Cookie) {
  246. $this->fail("Failed creating a cookie object from '$cStr'");
  247. }
  248. $expected = substr($cStr, 0, strpos($cStr, ';') + 1);
  249. $this->assertEquals($expected, (string) $cookie);
  250. }
  251. public function testGarbageInStrIsIgnored()
  252. {
  253. $cookies = array(
  254. 'name=value; domain=foo.com; silly=place; secure',
  255. 'foo=value; someCrap; secure; domain=foo.com; ',
  256. 'anothercookie=value; secure; has some crap; ignore=me; domain=foo.com; '
  257. );
  258. foreach ($cookies as $cstr) {
  259. $cookie = Zend_Http_Cookie::fromString($cstr);
  260. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  261. $this->assertEquals('value', $cookie->getValue(), 'Value is not as expected');
  262. $this->assertEquals('foo.com', $cookie->getDomain(), 'Domain is not as expected');
  263. $this->assertTrue($cookie->isSecure(), 'Cookie is expected to be secure');
  264. }
  265. }
  266. /**
  267. * Test the match() method against a domain
  268. *
  269. * @dataProvider domainMatchTestProvider
  270. */
  271. public function testMatchDomain($cookieStr, $uri, $match)
  272. {
  273. $cookie = Zend_Http_Cookie::fromString($cookieStr);
  274. $this->assertEquals($match, $cookie->match($uri));
  275. }
  276. static public function domainMatchTestProvider()
  277. {
  278. $uri = Zend_Uri::factory('http://www.foo.com/some/file.txt');
  279. return array(
  280. array('foo=bar; domain=.example.com;', 'http://www.example.com/foo/bar.php', true),
  281. array('foo=bar; domain=.example.com;', 'http://example.com/foo/bar.php', true),
  282. array('foo=bar; domain=.example.com;', 'http://www.somexample.com/foo/bar.php', false),
  283. array('foo=bar; domain=example.com;', 'http://www.somexample.com/foo/bar.php', false),
  284. array('cookie=value; domain=www.foo.com', $uri, true),
  285. array('cookie=value; domain=www.foo.com', 'http://il.www.foo.com', true),
  286. array('cookie=value; domain=www.foo.com', 'http://bar.foo.com', false)
  287. );
  288. }
  289. /**
  290. * Test the match() method against a domain
  291. *
  292. */
  293. public function testMatchPath()
  294. {
  295. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; path=/foo');
  296. $this->assertTrue($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected to match, but didn\'t');
  297. $this->assertFalse($cookie->match('http://www.example.com/bar.php'), 'Cookie expected not to match, but did');
  298. $cookie = Zend_Http_Cookie::fromString('cookie=value; domain=www.foo.com; path=/some/long/path');
  299. $this->assertTrue($cookie->match('http://www.foo.com/some/long/path/file.txt'), 'Cookie expected to match, but didn\'t');
  300. $this->assertTrue($cookie->match('http://www.foo.com/some/long/path/and/even/more'), 'Cookie expected to match, but didn\'t');
  301. $this->assertFalse($cookie->match('http://www.foo.com/some/long/file.txt'), 'Cookie expected not to match, but did');
  302. $this->assertFalse($cookie->match('http://www.foo.com/some/different/path/file.txt'), 'Cookie expected not to match, but did');
  303. }
  304. /**
  305. * Test the match() method against secure / non secure connections
  306. *
  307. */
  308. public function testMatchSecure()
  309. {
  310. // A non secure cookie, should match both
  311. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com;');
  312. $this->assertTrue($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected to match, but didn\'t');
  313. $this->assertTrue($cookie->match('https://www.example.com/bar.php'), 'Cookie expected to match, but didn\'t');
  314. // A secure cookie, should match secure connections only
  315. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; secure');
  316. $this->assertFalse($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected not to match, but it did');
  317. $this->assertTrue($cookie->match('https://www.example.com/bar.php'), 'Cookie expected to match, but didn\'t');
  318. }
  319. /**
  320. * Test the match() method against different expiry times
  321. *
  322. */
  323. public function testMatchExpire()
  324. {
  325. // A session cookie - should always be valid
  326. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com;');
  327. $this->assertTrue($cookie->match('http://www.example.com/'), 'Cookie expected to match, but didn\'t');
  328. $this->assertTrue($cookie->match('http://www.example.com/', true, time() + 3600), 'Cookie expected to match, but didn\'t');
  329. // A session cookie, should not match
  330. $this->assertFalse($cookie->match('https://www.example.com/', false), 'Cookie expected not to match, but it did');
  331. $this->assertFalse($cookie->match('https://www.example.com/', false, time() - 3600), 'Cookie expected not to match, but it did');
  332. // A cookie with expiry time in the future
  333. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; expires=' . date(DATE_COOKIE, time() + 3600));
  334. $this->assertTrue($cookie->match('http://www.example.com/'), 'Cookie expected to match, but didn\'t');
  335. $this->assertFalse($cookie->match('https://www.example.com/', true, time() + 7200), 'Cookie expected not to match, but it did');
  336. // A cookie with expiry time in the past
  337. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; expires=' . date(DATE_COOKIE, time() - 3600));
  338. $this->assertFalse($cookie->match('http://www.example.com/'), 'Cookie expected not to match, but it did');
  339. $this->assertTrue($cookie->match('https://www.example.com/', true, time() - 7200), 'Cookie expected to match, but didn\'t');
  340. }
  341. public function testFromStringFalse()
  342. {
  343. $cookie = Zend_Http_Cookie::fromString('foo; domain=www.exmaple.com');
  344. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  345. $cookie = Zend_Http_Cookie::fromString('=bar; secure; domain=foo.nl');
  346. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  347. $cookie = Zend_Http_Cookie::fromString('fo;o=bar; secure; domain=foo.nl');
  348. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  349. }
  350. /**
  351. * Test that cookies with far future expiry date (beyond the 32 bit unsigned int range) are
  352. * not mistakenly marked as 'expired'
  353. *
  354. * @link http://framework.zend.com/issues/browse/ZF-5690
  355. */
  356. public function testZF5690OverflowingExpiryDate()
  357. {
  358. $expTime = "Sat, 29-Jan-2039 00:54:42 GMT";
  359. $cookie = Zend_Http_Cookie::fromString("foo=bar; domain=.example.com; expires=$expTime");
  360. $this->assertFalse($cookie->isExpired(), 'Expiry: ' . $cookie->getExpiryTime());
  361. }
  362. /**
  363. * Data Providers
  364. */
  365. /**
  366. * Provide characters which are invalid in cookie names
  367. *
  368. * @return array
  369. */
  370. static public function invalidCookieNameCharProvider()
  371. {
  372. return array(
  373. array("="),
  374. array(","),
  375. array(";"),
  376. array("\t"),
  377. array("\r"),
  378. array("\n"),
  379. array("\013"),
  380. array("\014")
  381. );
  382. }
  383. /**
  384. * Provide valid cookie values
  385. *
  386. * @return array
  387. */
  388. static public function validCookieValueProvider()
  389. {
  390. return array(
  391. array('simpleCookie'),
  392. array('space cookie'),
  393. array('!@#$%^*&()* ][{}?;'),
  394. array("line\n\rbreaks"),
  395. // Long cookie value - 2kb
  396. array(str_repeat(md5(time()), 64))
  397. );
  398. }
  399. /**
  400. * Provider of valid reference URLs to be used for creating cookies
  401. *
  402. * @return array
  403. */
  404. static public function refUrlProvider()
  405. {
  406. return array(
  407. array(Zend_Uri::factory('http://example.com/')),
  408. array(Zend_Uri::factory('http://www.example.com/foo/bar/')),
  409. array(Zend_Uri::factory('http://some.really.deep.domain.com')),
  410. array(Zend_Uri::factory('http://localhost/path/to/very/deep/file.php')),
  411. array(Zend_Uri::factory('http://arr.gr/some%20path/text%2Ffile'))
  412. );
  413. }
  414. /**
  415. * Provide valid cookie strings with information about them
  416. *
  417. * @return array
  418. */
  419. static public function validCookieWithInfoProvider()
  420. {
  421. $now = time();
  422. $yesterday = $now - (3600 * 24);
  423. return array(
  424. array(
  425. 'justacookie=foo; domain=example.com',
  426. array(
  427. 'name' => 'justacookie',
  428. 'domain' => 'example.com',
  429. 'path' => '/',
  430. 'expires' => null,
  431. 'secure' => false
  432. )
  433. ),
  434. array(
  435. 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
  436. array(
  437. 'name' => 'expires',
  438. 'domain' => '.example.com',
  439. 'path' => '/Space Out/',
  440. 'expires' => strtotime('Tue, 21-Nov-2006 08:33:44 GMT'),
  441. 'secure' => true
  442. )
  443. ),
  444. array(
  445. 'domain=unittests; expires=' . date(DATE_COOKIE, $now) . '; domain=example.com; path=/some%20value/',
  446. array(
  447. 'name' => 'domain',
  448. 'domain' => 'example.com',
  449. 'path' => '/some%20value/',
  450. 'expires' => $now,
  451. 'secure' => false,
  452. )
  453. ),
  454. array(
  455. 'path=indexAction; path=/; domain=.foo.com; expires=' . date(DATE_COOKIE, $yesterday),
  456. array(
  457. 'name' => 'path',
  458. 'domain' => '.foo.com',
  459. 'path' => '/',
  460. 'expires' => $yesterday,
  461. 'secure' => false
  462. )
  463. ),
  464. array(
  465. 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com',
  466. array(
  467. 'name' => 'secure',
  468. 'domain' => 'some.really.deep.domain.com',
  469. 'path' => '/',
  470. 'expires' => null,
  471. 'secure' => true
  472. )
  473. ),
  474. array(
  475. 'PHPSESSID=123456789+abcd%2Cef; secure; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
  476. array(
  477. 'name' => 'PHPSESSID',
  478. 'domain' => '.localdomain',
  479. 'path' => '/foo/baz',
  480. 'expires' => strtotime('Tue, 21-Nov-2006 08:33:44 GMT'),
  481. 'secure' => true
  482. )
  483. ),
  484. );
  485. }
  486. /**
  487. * Cookie with 'expired' flag, used to test if Cookie->isExpired()
  488. *
  489. * @return array
  490. */
  491. public static function cookieWithExpiredFlagProvider()
  492. {
  493. return array(
  494. array('cookie=foo;domain=example.com;expires=' . date(DATE_COOKIE, time() + 12 * 3600), false),
  495. array('cookie=foo;domain=example.com;expires=' . date(DATE_COOKIE, time() - 15), true),
  496. array('cookie=foo;domain=example.com;', false),
  497. array('cookie=foo;domain=example.com;expires=Fri, 01-Mar-2109 00:19:21 GMT', false),
  498. array('cookie=foo;domain=example.com;expires=Fri, 06-Jun-1966 00:19:21 GMT', true),
  499. );
  500. }
  501. }