CookieTest.php 19 KB

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