Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

better support for cookie handling, use native PHP function to set co…

…okies
  • Loading branch information...
commit 98b52b607cbfe67697b36aa426dfacc126be817e 1 parent 102491b
@schmittjoh schmittjoh authored fabpot committed
View
88 src/Symfony/Component/HttpFoundation/Cookie.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Symfony\Component\HttpFoundation;
+
+/**
+ * Represents a cookie
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class Cookie
+{
+ protected $name;
+ protected $value;
+ protected $domain;
+ protected $expire;
+ protected $path;
+ protected $secure;
+ protected $httponly;
+
+ public function __construct($name, $value = null, $expire = 0, $path = null, $domain = null, $secure = false, $httponly = true)
+ {
+ // from PHP source code
+ if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
+ throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
+ }
+
+ if (preg_match("/[,; \t\r\n\013\014]/", $value)) {
+ throw new \InvalidArgumentException(sprintf('The cookie value "%s" contains invalid characters.', $name));
+ }
+
+ if (empty($name)) {
+ throw new \InvalidArgumentException('The cookie name cannot be empty');
+ }
+
+ $this->name = $name;
+ $this->value = $value;
+ $this->domain = $domain;
+ $this->expire = (integer) $expire;
+ $this->path = $path;
+ $this->secure = (Boolean) $secure;
+ $this->httponly = (Boolean) $httponly;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ public function getDomain()
+ {
+ return $this->domain;
+ }
+
+ public function getExpire()
+ {
+ return $this->expire;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ public function isSecure()
+ {
+ return $this->secure;
+ }
+
+ public function isHttponly()
+ {
+ return $this->httponly;
+ }
+
+ /**
+ * Whether this cookie is about to be cleared
+ *
+ * @return Boolean
+ */
+ public function isCleared()
+ {
+ return $this->expire < time();
+ }
+}
View
79 src/Symfony/Component/HttpFoundation/HeaderBag.php
@@ -19,6 +19,7 @@
class HeaderBag
{
protected $headers;
+ protected $cookies;
protected $cacheControl;
/**
@@ -29,6 +30,7 @@ class HeaderBag
public function __construct(array $headers = array())
{
$this->cacheControl = array();
+ $this->cookies = array();
$this->replace($headers);
}
@@ -163,21 +165,62 @@ public function remove($key)
/**
* Sets a cookie.
*
- * @param string $name The cookie name
- * @param string $value The value of the cookie
- * @param string $domain The domain that the cookie is available
- * @param string $expire The time the cookie expires
- * @param string $path The path on the server in which the cookie will be available on
- * @param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client
- * @param bool $httponly When TRUE the cookie will not be made accessible to JavaScript, preventing XSS attacks from stealing cookies
+ * @param Cookie $cookie
*
* @throws \InvalidArgumentException When the cookie expire parameter is not valid
+ *
+ * @return void
+ */
+ public function setCookie(Cookie $cookie)
+ {
+ $this->cookies[$cookie->getName()] = $cookie;
+ }
+
+ /**
+ * Removes a cookie from the array, but does not unset it in the browser
+ *
+ * @param string $name
+ * @return void
+ */
+ public function removeCookie($name)
+ {
+ unset($this->cookies[$name]);
+ }
+
+ /**
+ * Whether the array contains any cookie with this name
+ *
+ * @param string $name
+ * @return Boolean
+ */
+ public function hasCookie($name)
+ {
+ return isset($this->cookies[$name]);
+ }
+
+ /**
+ * Returns a cookie
+ *
+ * @param string $name
+ * @return Cookie
*/
- public function setCookie($name, $value, $domain = null, $expires = null, $path = '/', $secure = false, $httponly = true)
+ public function getCookie($name)
{
- $this->validateCookie($name, $value);
+ if (!$this->hasCookie($name)) {
+ throw new \InvalidArgumentException(sprintf('There is no cookie with name "%s".', $name));
+ }
+
+ return $this->cookies[$name];
+ }
- return $this->set('Cookie', sprintf('%s=%s', $name, urlencode($value)));
+ /**
+ * Returns an array with all cookies
+ *
+ * @return array
+ */
+ public function getCookies()
+ {
+ return $this->cookies;
}
/**
@@ -261,20 +304,4 @@ protected function parseCacheControl($header)
return $cacheControl;
}
-
- protected function validateCookie($name, $value)
- {
- // from PHP source code
- if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
- throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
- }
-
- if (preg_match("/[,; \t\r\n\013\014]/", $value)) {
- throw new \InvalidArgumentException(sprintf('The cookie value "%s" contains invalid characters.', $name));
- }
-
- if (!$name) {
- throw new \InvalidArgumentException('The cookie name cannot be empty');
- }
- }
}
View
5 src/Symfony/Component/HttpFoundation/Response.php
@@ -141,6 +141,11 @@ public function sendHeaders()
header($name.': '.$value);
}
}
+
+ // cookies
+ foreach ($this->headers->getCookies() as $cookie) {
+ setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpire(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
+ }
}
/**
View
50 src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
@@ -62,58 +62,28 @@ public function remove($key)
/**
* {@inheritdoc}
*/
- public function setCookie($name, $value, $domain = null, $expires = null, $path = '/', $secure = false, $httponly = true)
+ public function hasCacheControlDirective($key)
{
- $this->validateCookie($name, $value);
-
- $cookie = sprintf('%s=%s', $name, urlencode($value));
-
- if (null !== $expires) {
- if (is_numeric($expires)) {
- $expires = (int) $expires;
- } elseif ($expires instanceof \DateTime) {
- $expires = $expires->getTimestamp();
- } else {
- $expires = strtotime($expires);
- if (false === $expires || -1 == $expires) {
- throw new \InvalidArgumentException(sprintf('The "expires" cookie parameter is not valid.', $expires));
- }
- }
-
- $cookie .= '; expires='.substr(\DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'), 0, -5);
- }
-
- if ($domain) {
- $cookie .= '; domain='.$domain;
- }
-
- $cookie .= '; path='.$path;
-
- if ($secure) {
- $cookie .= '; secure';
- }
-
- if ($httponly) {
- $cookie .= '; httponly';
- }
-
- $this->set('Set-Cookie', $cookie, false);
+ return array_key_exists($key, $this->computedCacheControl);
}
/**
* {@inheritdoc}
*/
- public function hasCacheControlDirective($key)
+ public function getCacheControlDirective($key)
{
- return array_key_exists($key, $this->computedCacheControl);
+ return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
}
/**
- * {@inheritdoc}
+ * Clears a cookie in the browser
+ *
+ * @param string $name
+ * @return void
*/
- public function getCacheControlDirective($key)
+ public function clearCookie($name)
{
- return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
+ $this->setCookie(new Cookie($name, null, time() - 86400));
}
/**
View
14 src/Symfony/Component/HttpKernel/Security/Logout/CookieClearingLogoutHandler.php
@@ -17,13 +17,13 @@
/**
* This handler cleares the passed cookies when a user logs out.
- *
+ *
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class CookieClearingLogoutHandler implements LogoutHandlerInterface
{
protected $cookieNames;
-
+
/**
* Constructor
* @param array $cookieNames An array of cookie names to unset
@@ -32,7 +32,7 @@ public function __construct(array $cookieNames)
{
$this->cookieNames = $cookieNames;
}
-
+
/**
* Returns the names of the cookies to unset
* @return array
@@ -41,10 +41,10 @@ public function getCookieNames()
{
return $this->cookieNames;
}
-
+
/**
* Implementation for the LogoutHandlerInterface. Deletes all requested cookies.
- *
+ *
* @param Request $request
* @param Response $response
* @param TokenInterface $token
@@ -52,10 +52,8 @@ public function getCookieNames()
*/
public function logout(Request $request, Response $response, TokenInterface $token)
{
- $expires = time() - 86400;
-
foreach ($this->cookieNames as $cookieName) {
- $response->headers->setCookie($cookieName, '', null, $expires);
+ $response->headers->clearCookie($cookieName);
}
}
}
View
33 tests/Symfony/Tests/Component/HttpKernel/Security/Logout/CookieClearingLogoutHandlerTest.php
@@ -11,32 +11,33 @@ class CookieClearingLogoutHandlerTest extends \PHPUnit_Framework_TestCase
public function testConstructor()
{
$cookieNames = array('foo', 'foo2', 'foo3');
-
+
$handler = new CookieClearingLogoutHandler($cookieNames);
-
+
$this->assertEquals($cookieNames, $handler->getCookieNames());
}
-
+
public function testLogout()
{
$request = new Request();
$response = new Response();
$token = $this->getMock('Symfony\Component\Security\Authentication\Token\TokenInterface');
-
+
$handler = new CookieClearingLogoutHandler(array('foo', 'foo2'));
-
- $this->assertFalse($response->headers->has('Set-Cookie'));
-
+
+ $this->assertFalse($response->headers->hasCookie('foo'));
+
$handler->logout($request, $response, $token);
-
- $headers = $response->headers->all();
- $cookies = $headers['set-cookie'];
+
+ $cookies = $response->headers->getCookies();
$this->assertEquals(2, count($cookies));
-
- $cookie = $cookies[0];
- $this->assertStringStartsWith('foo=;', $cookie);
-
- $cookie = $cookies[1];
- $this->assertStringStartsWith('foo2=;', $cookie);
+
+ $cookie = $cookies['foo'];
+ $this->assertEquals('foo', $cookie->getName());
+ $this->assertTrue($cookie->isCleared());
+
+ $cookie = $cookies['foo2'];
+ $this->assertStringStartsWith('foo2', $cookie->getName());
+ $this->assertTrue($cookie->isCleared());
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.