Instantly share code, notes, and snippets.
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save slattery/6892029 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Classes related to cookies | |
* | |
* @author Christopher Davis | |
* @copyright 2012 Christopher Davis | |
* @license ISC | |
*/ | |
/** | |
* Base class for cookies. Could be used to make setting and removing cookies | |
* more like an array | |
*/ | |
class CookieStorage implements ArrayAccess | |
{ | |
/** | |
* the domain where cookies are available | |
* | |
* @access protected | |
*/ | |
protected $domain; | |
/** | |
* Path where these cookies are avilable | |
* | |
* @access protected | |
*/ | |
protected $path = '/'; | |
/** | |
* Default expire time offset from time(). Defaults to 30 days | |
* | |
* @access protected | |
*/ | |
protected $expire; | |
/** | |
* Constructor | |
* | |
* @param string $domain Domain for this cookie storage | |
* @param string $path Path for the cookies | |
* @param string $expire When the cookie will expire. Defaults to 30 days | |
*/ | |
public function __construct($domain, $path = '/', $expire = null) | |
{ | |
$this->domain = $domain; | |
$this->path = $path; | |
$this->expire = is_null($expire) ? 60*60*24*30 : $expire; | |
} | |
/** | |
* Handles setting values. eg. $some_cookie_storate['blah'] = 'foo' | |
* | |
* @access public | |
*/ | |
public function offsetSet($offset, $value) | |
{ | |
if(is_null($offset)) | |
{ | |
throw new CookieError('You must set a cookie name'); | |
} | |
$this->set( | |
$offset, | |
$value, | |
$this->expire, | |
$this->path, | |
$this->domain | |
); | |
} | |
/** | |
* Handles isset calls to this object | |
* | |
* @access public | |
*/ | |
public function offsetExists($offset) | |
{ | |
return isset($_COOKIE[$offset]); | |
} | |
/** | |
* Handles unset calls on this object. Forces a cookie to expire by setting | |
* the expiration in the past | |
* | |
* @access public | |
*/ | |
public function offsetUnset($offset) | |
{ | |
return setcookie($offset, '', 1); | |
} | |
/** | |
* Handles getting values from the array | |
* | |
* @access public | |
*/ | |
public function offsetGet($offset) | |
{ | |
return $this->get($offset); | |
} | |
/* | |
* Get the cookie value. First checks to see if it's been tampered | |
* with | |
* | |
* @access protected | |
*/ | |
protected function get($offset) | |
{ | |
return $this->offsetExists($offset) ? $_COOKIE[$offset] : false; | |
} | |
/** | |
* Sets the cookie value. Thin wrapper around setcookie | |
* | |
* @access public | |
*/ | |
public function set($name, $value, $expire, $path, $domain) | |
{ | |
return setcookie( | |
$name, | |
$value, | |
time() + $expire, | |
$path, | |
$domain, | |
isset($_SERVER['HTTPS']), | |
true | |
); | |
} | |
} // end class CookieStorage | |
/** | |
* Wrapper around signed cookie storage. | |
*/ | |
class SignedCookieStorage extends CookieStorage | |
{ | |
/** | |
* The secret key used to sign cookies | |
* | |
* @access protected | |
*/ | |
protected $secret = null; | |
/** | |
* Algo used for hashing cookies | |
* | |
* @access protected | |
*/ | |
protected $algo = 'sha1'; | |
/** | |
* constructor | |
* | |
* @access public | |
* @param string $secret The secret key | |
* @param string $domain The cookie domain | |
* @param string $path The cookie path | |
* @param int $expire When the cookies expire | |
* @param string $algo The hashing algorithm to use | |
*/ | |
public function __construct($secret, $domain, $path = '/', $expire = null, $algo = 'sha1') | |
{ | |
$this->secret = $secret; | |
$this->algo = $algo; | |
parent::__construct($domain, $path, $expire); | |
} | |
/** | |
* Set a cookie with a value and signed hash | |
* | |
* @access public | |
*/ | |
public function set($name, $value, $expire, $path, $domain) | |
{ | |
$cookie = $this->hash_cookie($name, $value); | |
return parent::set($name, $cookie, $expire, $path, $domain); | |
} | |
/* | |
* Get the cookie value. First checks to see if it's been tampered | |
* with | |
* | |
* @access protected | |
* @return see SignedCookieStorage::validate_cookie | |
*/ | |
protected function get($offset) | |
{ | |
$cookie = $this->offsetExists($offset) ? $_COOKIE[$offset] : false; | |
return $this->validate_cookie($offset, $cookie); | |
} | |
/** | |
* Validate a cookie | |
* | |
* @access protected | |
* @param string $cookie The cookie to validate | |
* @return string|bool False if the hash doesn't valid, the cookie value otherwise | |
*/ | |
protected function validate_cookie($key, $cookie) | |
{ | |
if(!$cookie) return false; | |
$rv = false; | |
if(substr_count($cookie, '$') == 1) | |
{ | |
list($value, $hash) = explode('$', $cookie); | |
$hash_cmp = $this->get_hash($key, $value); | |
if(strcmp($hash, $hash_cmp) == 0) | |
{ | |
$rv = $value; | |
} | |
} | |
return $rv; | |
} | |
/** | |
* Hash a cookie and return the value and hash separated by a dollar sign | |
* | |
* @access protected | |
* @param string $name The cookie name | |
* @param string $value The cookie value | |
*/ | |
function hash_cookie($name, $value) | |
{ | |
$hash = $this->get_hash($name, $value); | |
return sprintf('%s$%s', $value, $hash); | |
} | |
/** | |
* Get the hash for a $name and $value | |
* | |
* @access protected | |
* @param string $name The cookie name | |
* @param string $value the Cookie value | |
* @return string | |
*/ | |
protected function get_hash($name, $value) | |
{ | |
return hash_hmac( | |
$this->algo, | |
$name . $value, | |
$this->secret | |
); | |
} | |
} // end class SignedCookieStorage | |
/** | |
* Exception class throw for certain errors that happen in this library. | |
* | |
* @author Christopher Davis <http://christopherdavis.me> | |
*/ | |
class CookieError extends Exception | |
{ | |
function __toString() | |
{ | |
return sprintf('Cookie Error: %s', $this->message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment