2
0

CookieTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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-2009 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-2009 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. $cookie = Zend_Http_Cookie::fromString('foo=bar', (string) $uri);
  142. if (! $cookie instanceof Zend_Http_Cookie) {
  143. $this->fail("Failed creating a cookie object with URL '$uri'");
  144. }
  145. $this->assertEquals($path, $cookie->getPath());
  146. }
  147. /**
  148. * Test we get the correct expiry time
  149. *
  150. * @dataProvider validCookieWithInfoProvider
  151. */
  152. public function testGetExpiryTime($cStr, $cInfo)
  153. {
  154. $cookie = Zend_Http_Cookie::fromString($cStr);
  155. if (! $cookie instanceof Zend_Http_Cookie) {
  156. $this->fail("Failed creating a cookie object from '$cStr'");
  157. }
  158. if (isset($cInfo['expires'])) {
  159. $this->assertEquals($cInfo['expires'], $cookie->getExpiryTime());
  160. }
  161. }
  162. /**
  163. * Make sure the "is secure" flag is correctly set
  164. *
  165. * @dataProvider validCookieWithInfoProvider
  166. */
  167. public function testIsSecure($cStr, $cInfo)
  168. {
  169. $cookie = Zend_Http_Cookie::fromString($cStr);
  170. if (! $cookie instanceof Zend_Http_Cookie) {
  171. $this->fail("Failed creating a cookie object from '$cStr'");
  172. }
  173. if (isset($cInfo['secure'])) {
  174. $this->assertEquals($cInfo['secure'], $cookie->isSecure());
  175. }
  176. }
  177. /**
  178. * Cookie expiry time tests
  179. */
  180. /**
  181. * Make sure we get the correct value for 'isExpired'
  182. *
  183. * @dataProvider cookieWithExpiredFlagProvider
  184. */
  185. public function testIsExpired($cStr, $expired)
  186. {
  187. $cookie = Zend_Http_Cookie::fromString($cStr);
  188. if (! $cookie) {
  189. $this->fail("Failed creating a cookie object from '$cStr'");
  190. }
  191. $this->assertEquals($expired, $cookie->isExpired());
  192. }
  193. /**
  194. * Make sure we get the correct value for 'isExpired', when time is manually set
  195. */
  196. public function testIsExpiredDifferentTime()
  197. {
  198. $notexpired = time() + 3600;
  199. $expired = time() - 3600;
  200. $now = time() + 7200;
  201. $cookies = array(
  202. 'cookie=foo; domain=example.com; expires=' . date(DATE_COOKIE, $notexpired),
  203. 'cookie=foo; domain=example.com; expires=' . date(DATE_COOKIE, $expired)
  204. );
  205. // Make sure all cookies are expired
  206. foreach ($cookies as $cstr) {
  207. $cookie = Zend_Http_Cookie::fromString($cstr);
  208. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  209. $this->assertTrue($cookie->isExpired($now), 'Cookie is expected to be expired');
  210. }
  211. // Make sure all cookies are not expired
  212. $now = time() - 7200;
  213. foreach ($cookies as $cstr) {
  214. $cookie = Zend_Http_Cookie::fromString($cstr);
  215. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  216. $this->assertFalse($cookie->isExpired($now), 'Cookie is expected not to be expired');
  217. }
  218. }
  219. /**
  220. * Test we can properly check if a cookie is a session cookie (has no expiry time)
  221. *
  222. * @dataProvider validCookieWithInfoProvider
  223. */
  224. public function testIsSessionCookie($cStr, $cInfo)
  225. {
  226. $cookie = Zend_Http_Cookie::fromString($cStr);
  227. if (! $cookie instanceof Zend_Http_Cookie) {
  228. $this->fail("Failed creating a cookie object from '$cStr'");
  229. }
  230. if (array_key_exists('expires', $cInfo)) {
  231. $this->assertEquals(($cInfo['expires'] === null), $cookie->isSessionCookie());
  232. }
  233. }
  234. /**
  235. * Make sure cookies are properly converted back to strings
  236. *
  237. * @dataProvider validCookieWithInfoProvider
  238. */
  239. public function testToString($cStr, $cInfo)
  240. {
  241. $cookie = Zend_Http_Cookie::fromString($cStr);
  242. if (! $cookie instanceof Zend_Http_Cookie) {
  243. $this->fail("Failed creating a cookie object from '$cStr'");
  244. }
  245. $expected = substr($cStr, 0, strpos($cStr, ';') + 1);
  246. $this->assertEquals($expected, (string) $cookie);
  247. }
  248. public function testGarbageInStrIsIgnored()
  249. {
  250. $cookies = array(
  251. 'name=value; domain=foo.com; silly=place; secure',
  252. 'foo=value; someCrap; secure; domain=foo.com; ',
  253. 'anothercookie=value; secure; has some crap; ignore=me; domain=foo.com; '
  254. );
  255. foreach ($cookies as $cstr) {
  256. $cookie = Zend_Http_Cookie::fromString($cstr);
  257. if (! $cookie) $this->fail('Got no cookie object from a valid cookie string');
  258. $this->assertEquals('value', $cookie->getValue(), 'Value is not as expected');
  259. $this->assertEquals('foo.com', $cookie->getDomain(), 'Domain is not as expected');
  260. $this->assertTrue($cookie->isSecure(), 'Cookie is expected to be secure');
  261. }
  262. }
  263. /**
  264. * Test the match() method against a domain
  265. *
  266. * @dataProvider domainMatchTestProvider
  267. */
  268. public function testMatchDomain($cookieStr, $uri, $match)
  269. {
  270. $cookie = Zend_Http_Cookie::fromString($cookieStr);
  271. $this->assertEquals($match, $cookie->match($uri));
  272. }
  273. static public function domainMatchTestProvider()
  274. {
  275. $uri = Zend_Uri::factory('http://www.foo.com/some/file.txt');
  276. return array(
  277. array('foo=bar; domain=.example.com;', 'http://www.example.com/foo/bar.php', true),
  278. array('foo=bar; domain=.example.com;', 'http://example.com/foo/bar.php', true),
  279. array('foo=bar; domain=.example.com;', 'http://www.somexample.com/foo/bar.php', false),
  280. array('foo=bar; domain=example.com;', 'http://www.somexample.com/foo/bar.php', false),
  281. array('cookie=value; domain=www.foo.com', $uri, true),
  282. array('cookie=value; domain=www.foo.com', 'http://il.www.foo.com', true),
  283. array('cookie=value; domain=www.foo.com', 'http://bar.foo.com', false)
  284. );
  285. }
  286. /**
  287. * Test the match() method against a domain
  288. *
  289. */
  290. public function testMatchPath()
  291. {
  292. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; path=/foo');
  293. $this->assertTrue($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected to match, but didn\'t');
  294. $this->assertFalse($cookie->match('http://www.example.com/bar.php'), 'Cookie expected not to match, but did');
  295. $cookie = Zend_Http_Cookie::fromString('cookie=value; domain=www.foo.com; path=/some/long/path');
  296. $this->assertTrue($cookie->match('http://www.foo.com/some/long/path/file.txt'), 'Cookie expected to match, but didn\'t');
  297. $this->assertTrue($cookie->match('http://www.foo.com/some/long/path/and/even/more'), 'Cookie expected to match, but didn\'t');
  298. $this->assertFalse($cookie->match('http://www.foo.com/some/long/file.txt'), 'Cookie expected not to match, but did');
  299. $this->assertFalse($cookie->match('http://www.foo.com/some/different/path/file.txt'), 'Cookie expected not to match, but did');
  300. }
  301. /**
  302. * Test the match() method against secure / non secure connections
  303. *
  304. */
  305. public function testMatchSecure()
  306. {
  307. // A non secure cookie, should match both
  308. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com;');
  309. $this->assertTrue($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected to match, but didn\'t');
  310. $this->assertTrue($cookie->match('https://www.example.com/bar.php'), 'Cookie expected to match, but didn\'t');
  311. // A secure cookie, should match secure connections only
  312. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; secure');
  313. $this->assertFalse($cookie->match('http://www.example.com/foo/bar.php'), 'Cookie expected not to match, but it did');
  314. $this->assertTrue($cookie->match('https://www.example.com/bar.php'), 'Cookie expected to match, but didn\'t');
  315. }
  316. /**
  317. * Test the match() method against different expiry times
  318. *
  319. */
  320. public function testMatchExpire()
  321. {
  322. // A session cookie - should always be valid
  323. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com;');
  324. $this->assertTrue($cookie->match('http://www.example.com/'), 'Cookie expected to match, but didn\'t');
  325. $this->assertTrue($cookie->match('http://www.example.com/', true, time() + 3600), 'Cookie expected to match, but didn\'t');
  326. // A session cookie, should not match
  327. $this->assertFalse($cookie->match('https://www.example.com/', false), 'Cookie expected not to match, but it did');
  328. $this->assertFalse($cookie->match('https://www.example.com/', false, time() - 3600), 'Cookie expected not to match, but it did');
  329. // A cookie with expiry time in the future
  330. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; expires=' . date(DATE_COOKIE, time() + 3600));
  331. $this->assertTrue($cookie->match('http://www.example.com/'), 'Cookie expected to match, but didn\'t');
  332. $this->assertFalse($cookie->match('https://www.example.com/', true, time() + 7200), 'Cookie expected not to match, but it did');
  333. // A cookie with expiry time in the past
  334. $cookie = Zend_Http_Cookie::fromString('foo=bar; domain=.example.com; expires=' . date(DATE_COOKIE, time() - 3600));
  335. $this->assertFalse($cookie->match('http://www.example.com/'), 'Cookie expected not to match, but it did');
  336. $this->assertTrue($cookie->match('https://www.example.com/', true, time() - 7200), 'Cookie expected to match, but didn\'t');
  337. }
  338. public function testFromStringFalse()
  339. {
  340. $cookie = Zend_Http_Cookie::fromString('foo; domain=www.exmaple.com');
  341. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  342. $cookie = Zend_Http_Cookie::fromString('=bar; secure; domain=foo.nl');
  343. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  344. $cookie = Zend_Http_Cookie::fromString('fo;o=bar; secure; domain=foo.nl');
  345. $this->assertEquals(false, $cookie, 'fromString was expected to fail and return false');
  346. }
  347. /**
  348. * Test that cookies with far future expiry date (beyond the 32 bit unsigned int range) are
  349. * not mistakenly marked as 'expired'
  350. *
  351. * @link http://framework.zend.com/issues/browse/ZF-5690
  352. */
  353. public function testZF5690OverflowingExpiryDate()
  354. {
  355. $expTime = "Sat, 29-Jan-2039 00:54:42 GMT";
  356. $cookie = Zend_Http_Cookie::fromString("foo=bar; domain=.example.com; expires=$expTime");
  357. $this->assertFalse($cookie->isExpired(), 'Expiry: ' . $cookie->getExpiryTime());
  358. }
  359. /**
  360. * Data Providers
  361. */
  362. /**
  363. * Provide characters which are invalid in cookie names
  364. *
  365. * @return array
  366. */
  367. static public function invalidCookieNameCharProvider()
  368. {
  369. return array(
  370. array("="),
  371. array(","),
  372. array(";"),
  373. array("\t"),
  374. array("\r"),
  375. array("\n"),
  376. array("\013"),
  377. array("\014")
  378. );
  379. }
  380. /**
  381. * Provide valid cookie values
  382. *
  383. * @return array
  384. */
  385. static public function validCookieValueProvider()
  386. {
  387. return array(
  388. array('simpleCookie'),
  389. array('space cookie'),
  390. array('!@#$%^*&()* ][{}?;'),
  391. array("line\n\rbreaks"),
  392. // Long cookie value - 2kb
  393. array(str_repeat(md5(time()), 64))
  394. );
  395. }
  396. /**
  397. * Provider of valid reference URLs to be used for creating cookies
  398. *
  399. * @return array
  400. */
  401. static public function refUrlProvider()
  402. {
  403. return array(
  404. array(Zend_Uri::factory('http://example.com/')),
  405. array(Zend_Uri::factory('http://www.example.com/foo/bar/')),
  406. array(Zend_Uri::factory('http://some.really.deep.domain.com')),
  407. array(Zend_Uri::factory('http://localhost/path/to/very/deep/file.php')),
  408. array(Zend_Uri::factory('http://arr.gr/some%20path/text%2Ffile'))
  409. );
  410. }
  411. /**
  412. * Provide valid cookie strings with information about them
  413. *
  414. * @return array
  415. */
  416. static public function validCookieWithInfoProvider()
  417. {
  418. $now = time();
  419. $yesterday = $now - (3600 * 24);
  420. return array(
  421. array(
  422. 'justacookie=foo; domain=example.com',
  423. array(
  424. 'name' => 'justacookie',
  425. 'domain' => 'example.com',
  426. 'path' => '/',
  427. 'expires' => null,
  428. 'secure' => false
  429. )
  430. ),
  431. array(
  432. 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
  433. array(
  434. 'name' => 'expires',
  435. 'domain' => '.example.com',
  436. 'path' => '/Space Out/',
  437. 'expires' => strtotime('Tue, 21-Nov-2006 08:33:44 GMT'),
  438. 'secure' => true
  439. )
  440. ),
  441. array(
  442. 'domain=unittests; expires=' . date(DATE_COOKIE, $now) . '; domain=example.com; path=/some%20value/',
  443. array(
  444. 'name' => 'domain',
  445. 'domain' => 'example.com',
  446. 'path' => '/some%20value/',
  447. 'expires' => $now,
  448. 'secure' => false,
  449. )
  450. ),
  451. array(
  452. 'path=indexAction; path=/; domain=.foo.com; expires=' . date(DATE_COOKIE, $yesterday),
  453. array(
  454. 'name' => 'path',
  455. 'domain' => '.foo.com',
  456. 'path' => '/',
  457. 'expires' => $yesterday,
  458. 'secure' => false
  459. )
  460. ),
  461. array(
  462. 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com',
  463. array(
  464. 'name' => 'secure',
  465. 'domain' => 'some.really.deep.domain.com',
  466. 'path' => '/',
  467. 'expires' => null,
  468. 'secure' => true
  469. )
  470. ),
  471. array(
  472. 'PHPSESSID=123456789+abcd%2Cef; secure; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
  473. array(
  474. 'name' => 'PHPSESSID',
  475. 'domain' => '.localdomain',
  476. 'path' => '/foo/baz',
  477. 'expires' => strtotime('Tue, 21-Nov-2006 08:33:44 GMT'),
  478. 'secure' => true
  479. )
  480. ),
  481. );
  482. }
  483. /**
  484. * Cookie with 'expired' flag, used to test if Cookie->isExpired()
  485. *
  486. * @return array
  487. */
  488. public static function cookieWithExpiredFlagProvider()
  489. {
  490. return array(
  491. array('cookie=foo;domain=example.com;expires=' . date(DATE_COOKIE, time() + 12 * 3600), false),
  492. array('cookie=foo;domain=example.com;expires=' . date(DATE_COOKIE, time() - 15), true),
  493. array('cookie=foo;domain=example.com;', false),
  494. array('cookie=foo;domain=example.com;expires=Fri, 01-Mar-2109 00:19:21 GMT', false),
  495. array('cookie=foo;domain=example.com;expires=Fri, 06-Jun-1966 00:19:21 GMT', true),
  496. );
  497. }
  498. }