Browse Source

Merge pull request #10505 from cakephp/3next-cookie-check-methods

3.next - Add Cookie->isExpired()
Mark Story 9 years ago
parent
commit
ff2144990b

+ 35 - 17
src/Http/Cookie/Cookie.php

@@ -175,23 +175,6 @@ class Cookie implements CookieInterface
     }
 
     /**
-     * Get the timestamp from the expiration time
-     *
-     * Timestamps are strings as large timestamps can overflow MAX_INT
-     * in 32bit systems.
-     *
-     * @return string|null The expiry time as a string timestamp.
-     */
-    public function getExpiresTimestamp()
-    {
-        if (!$this->expiresAt) {
-            return null;
-        }
-
-        return $this->expiresAt->format('U');
-    }
-
-    /**
      * Returns a header value as string
      *
      * @return string
@@ -478,6 +461,41 @@ class Cookie implements CookieInterface
     }
 
     /**
+     * Get the timestamp from the expiration time
+     *
+     * Timestamps are strings as large timestamps can overflow MAX_INT
+     * in 32bit systems.
+     *
+     * @return string|null The expiry time as a string timestamp.
+     */
+    public function getExpiresTimestamp()
+    {
+        if (!$this->expiresAt) {
+            return null;
+        }
+
+        return $this->expiresAt->format('U');
+    }
+
+    /**
+     * Check if a cookie is expired when compared to $time
+     *
+     * Cookies without an expiration date always return false.
+     *
+     * @param \DatetimeInterface $time The time to test against. Defaults to 'now' in UTC.
+     * @return bool
+     */
+    public function isExpired(DatetimeInterface $time = null)
+    {
+        $time = $time ?: new DateTimeImmutable('now', new DateTimezone('UTC'));
+        if (!$this->expiresAt) {
+            return false;
+        }
+
+        return $this->expiresAt < $time;
+    }
+
+    /**
      * Create a new cookie that will virtually never expire.
      *
      * @return static

+ 7 - 9
src/Http/Cookie/CookieCollection.php

@@ -16,7 +16,8 @@ namespace Cake\Http\Cookie;
 use ArrayIterator;
 use Cake\Http\Client\Response as ClientResponse;
 use Countable;
-use DateTime;
+use DateTimeImmutable;
+use DateTimeZone;
 use InvalidArgumentException;
 use IteratorAggregate;
 use Psr\Http\Message\RequestInterface;
@@ -240,6 +241,7 @@ class CookieCollection implements IteratorAggregate, Countable
     protected function findMatchingCookies($scheme, $host, $path)
     {
         $out = [];
+        $now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
         foreach ($this->cookies as $cookie) {
             if ($scheme === 'http' && $cookie->isSecure()) {
                 continue;
@@ -253,8 +255,7 @@ class CookieCollection implements IteratorAggregate, Countable
                 $domain = ltrim($domain, '.');
             }
 
-            $expires = $cookie->getExpiresTimestamp();
-            if ($expires && time() > $expires) {
+            if ($cookie->isExpired($now)) {
                 continue;
             }
 
@@ -358,8 +359,7 @@ class CookieCollection implements IteratorAggregate, Countable
             }
             $expires = null;
             if ($cookie['expires']) {
-                $expires = new DateTime();
-                $expires->setTimestamp(strtotime($cookie['expires']));
+                $expires = new DateTimeImmutable('@' . strtotime($cookie['expires']));
             }
 
             $cookies[] = new Cookie(
@@ -385,13 +385,11 @@ class CookieCollection implements IteratorAggregate, Countable
      */
     protected function removeExpiredCookies($host, $path)
     {
-        $time = time();
+        $time = new DateTimeImmutable('now', new DateTimeZone('UTC'));
         $hostPattern = '/' . preg_quote($host, '/') . '$/';
 
         foreach ($this->cookies as $i => $cookie) {
-            $expires = $cookie->getExpiresTimestamp();
-            $expired = ($expires > 0 && $expires < $time);
-
+            $expired = $cookie->isExpired($time);
             $pathMatches = strpos($path, $cookie->getPath()) === 0;
             $hostMatches = preg_match($hostPattern, $cookie->getDomain());
             if ($pathMatches && $hostMatches && $expired) {

+ 21 - 0
tests/TestCase/Http/Cookie/CookieTest.php

@@ -376,6 +376,27 @@ class CookieTest extends TestCase
     }
 
     /**
+     * Test the isExpired method
+     *
+     * @return void
+     */
+    public function testIsExpired()
+    {
+        $date = Chronos::now();
+        $cookie = new Cookie('cakephp', 'yay');
+        $this->assertFalse($cookie->isExpired($date));
+
+        $cookie = new Cookie('cakephp', 'yay', $date);
+        $this->assertFalse($cookie->isExpired($date), 'same time, not expired');
+
+        $date = $date->modify('+10 seconds');
+        $this->assertTrue($cookie->isExpired($date), 'future now');
+
+        $date = $date->modify('-1 minute');
+        $this->assertFalse($cookie->isExpired($date), 'expires later');
+    }
+
+    /**
      * Test the withName method
      *
      * @return void