Skip to content

Instantly share code, notes, and snippets.

@slattery
Forked from chrisguitarguy/cookies.php
Created October 8, 2013 21:27
Show Gist options
  • Save slattery/6892029 to your computer and use it in GitHub Desktop.
Save slattery/6892029 to your computer and use it in GitHub Desktop.
<?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