|  | @@ -1,7 +1,9 @@
 | 
	
		
			
				|  |  | -<?php namespace Laravel\Session;
 | 
	
		
			
				|  |  | +<?php namespace Laravel\Session\Drivers;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +use Closure;
 | 
	
		
			
				|  |  |  use Laravel\Str;
 | 
	
		
			
				|  |  |  use Laravel\Input;
 | 
	
		
			
				|  |  | +use Laravel\Config;
 | 
	
		
			
				|  |  |  use Laravel\Cookie;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  abstract class Driver {
 | 
	
	
		
			
				|  | @@ -14,38 +16,54 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	public $session = array();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  | -	 * The application session configuration.
 | 
	
		
			
				|  |  | +	 * The configuration manager instance.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * @var array
 | 
	
		
			
				|  |  | +	 * @var Config
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public $config = array();
 | 
	
		
			
				|  |  | +	protected $config;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Load the session for a given session ID.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * The session will be checked for validity and necessary data. For example, if the session
 | 
	
		
			
				|  |  | -	 * does not have a CSRF token, a token will be generated for the session.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * If the session has expired, a new, empty session will be generated.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | +	 * @param  Config  $config
 | 
	
		
			
				|  |  |  	 * @param  string  $id
 | 
	
		
			
				|  |  | -	 * @param  array   $config
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function start($id, $config)
 | 
	
		
			
				|  |  | +	public final function start(Config $config, $id)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		$this->config = $config;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		$this->session = ( ! is_null($id)) ? $this->load($id) : null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		if (is_null($this->session) or (time() - $this->session['last_activity']) > ($this->config['lifetime'] * 60))
 | 
	
		
			
				|  |  | +		// If the session is expired, a new session will be generated and all of the data from
 | 
	
		
			
				|  |  | +		// the previous session will be lost. The new session will be assigned a random, long
 | 
	
		
			
				|  |  | +		// string ID to uniquely identify it among the application's current users.
 | 
	
		
			
				|  |  | +		if (is_null($this->session) or $this->expired())
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			$this->session = array('id' => Str::random(40), 'data' => array());
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		if ( ! $this->has('csrf_token')) $this->put('csrf_token', Str::random(16));
 | 
	
		
			
				|  |  | +		// If a CSRF token is not present in the session, we will generate one. These tokens
 | 
	
		
			
				|  |  | +		// are generated per session to protect against Cross-Site Request Forgery attacks on
 | 
	
		
			
				|  |  | +		// the application. It is up to the developer to take advantage of them using the token
 | 
	
		
			
				|  |  | +		// methods on the Form class and the "csrf" route filter.
 | 
	
		
			
				|  |  | +		if ( ! $this->has('csrf_token'))
 | 
	
		
			
				|  |  | +		{
 | 
	
		
			
				|  |  | +			$this->put('csrf_token', Str::random(16));
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		$this->session['last_activity'] = time();
 | 
	
		
			
				|  |  | +	/**
 | 
	
		
			
				|  |  | +	 * Deteremine if the session is expired based on the last activity timestamp
 | 
	
		
			
				|  |  | +	 * and the session lifetime set in the configuration file.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * @return bool
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	private function expired()
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		return (time() - $this->session['last_activity']) > ($this->config->get('session.lifetime') * 60);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
	
		
			
				|  | @@ -86,41 +104,28 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  |  	 * A default value may also be specified, and will be returned in the item doesn't exist.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * <code>
 | 
	
		
			
				|  |  | -	 *		// Get an item from the session
 | 
	
		
			
				|  |  | -	 *		$name = Session::get('name');
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 *		// Get an item from the session and return a default value if it doesn't exist
 | 
	
		
			
				|  |  | -	 *		$name = Session::get('name', 'Fred');
 | 
	
		
			
				|  |  | -	 * </code>
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * @param  string  $key
 | 
	
		
			
				|  |  |  	 * @param  mixed   $default
 | 
	
		
			
				|  |  |  	 * @return mixed
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function get($key, $default = null)
 | 
	
		
			
				|  |  | +	public final function get($key, $default = null)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		foreach (array($key, ':old:'.$key, ':new:'.$key) as $possibility)
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			if (array_key_exists($possibility, $this->session['data'])) return $this->session['data'][$possibility];
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		return ($default instanceof \Closure) ? call_user_func($default) : $default;
 | 
	
		
			
				|  |  | +		return ($default instanceof Closure) ? call_user_func($default) : $default;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Write an item to the session.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * <code>
 | 
	
		
			
				|  |  | -	 *		// Store an item in the session
 | 
	
		
			
				|  |  | -	 *		Session::put('name', 'Fred');
 | 
	
		
			
				|  |  | -	 * </code>
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * @param  string  $key
 | 
	
		
			
				|  |  |  	 * @param  mixed   $value
 | 
	
		
			
				|  |  |  	 * @return Driver
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function put($key, $value)
 | 
	
		
			
				|  |  | +	public final function put($key, $value)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		$this->session['data'][$key] = $value;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -133,29 +138,52 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	 * Flash data only exists for the next request. After that, it will be removed from
 | 
	
		
			
				|  |  |  	 * the session. Flash data is useful for temporary status or welcome messages.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * <code>
 | 
	
		
			
				|  |  | -	 *		// Store an item in the session flash data
 | 
	
		
			
				|  |  | -	 *		Session::flash('name', 'Fred');
 | 
	
		
			
				|  |  | -	 * </code>
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * @param  string  $key
 | 
	
		
			
				|  |  |  	 * @param  mixed   $value
 | 
	
		
			
				|  |  |  	 * @return Driver
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function flash($key, $value)
 | 
	
		
			
				|  |  | +	public final function flash($key, $value)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		$this->put(':new:'.$key, $value);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		return $this;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/**
 | 
	
		
			
				|  |  | +	 * Keep all of the session flash data from expiring at the end of the request.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * @return void
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	public final function reflash()
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		$this->readdress(':old:', ':new:', array_keys($this->session['data']));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/**
 | 
	
		
			
				|  |  | +	 * Keep a session flash item from expiring at the end of the request.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * If a string is passed to the method, only that item will be kept. An array may also
 | 
	
		
			
				|  |  | +	 * be passed to the method, in which case all items in the array will be kept.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * @param  string|array  $key
 | 
	
		
			
				|  |  | +	 * @return void
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	public final function keep($key)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		if (is_array($key)) return array_map(array($this, 'keep'), $key);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		$this->flash($key, $this->get($key));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		$this->forget(':old:'.$key);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Remove an item from the session.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  |  	 * @param  string  $key
 | 
	
		
			
				|  |  |  	 * @return Driver
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function forget($key)
 | 
	
		
			
				|  |  | +	public final function forget($key)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		unset($this->session['data'][$key]);
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -165,7 +193,7 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function flush()
 | 
	
		
			
				|  |  | +	public final function flush()
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		$this->session['data'] = array();
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -175,7 +203,7 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	public function regenerate()
 | 
	
		
			
				|  |  | +	public final function regenerate()
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		$this->delete();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -183,25 +211,28 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  | -	 * Close the session.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * The session will be stored in persistant storage and the session cookie will be
 | 
	
		
			
				|  |  | -	 * session cookie will be sent to the browser.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * The input of the current request will also be flashed to the session so it is
 | 
	
		
			
				|  |  | -	 * available for the next request via the "old" method on the input class.
 | 
	
		
			
				|  |  | +	 * Close the session and store the session payload in persistant storage.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  |  	 * @param  Laravel\Input  $input
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  |  	public function close(Input $input)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  | +		// The input for the current request will be flashed to the session for
 | 
	
		
			
				|  |  | +		// convenient access through the "old" method of the input class. This
 | 
	
		
			
				|  |  | +		// allows the easy repopulation of forms.
 | 
	
		
			
				|  |  |  		$this->flash('laravel_old_input', $input->get())->age();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +		$this->session['last_activity'] = time();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		$this->save();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		$this->write_cookie($input->cookies, $this->config);
 | 
	
		
			
				|  |  | +		$this->cookie($input->cookies);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +		// Some session drivers implement the "Sweeper" interface, which specifies
 | 
	
		
			
				|  |  | +		// that the driver needs to manually clean up its expired sessions. If the
 | 
	
		
			
				|  |  | +		// driver does in fact implement this interface, we will randomly call the
 | 
	
		
			
				|  |  | +		// sweep method on the driver.
 | 
	
		
			
				|  |  |  		if ($this instanceof Sweeper and mt_rand(1, 100) <= 2)
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			$this->sweep(time() - ($this->config['lifetime'] * 60));
 | 
	
	
		
			
				|  | @@ -211,56 +242,56 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Age the session flash data.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * To age the data, we will forget all of the old keys and then rewrite the newly
 | 
	
		
			
				|  |  | -	 * flashed items to have old keys, which will be available for the next request.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	protected function age()
 | 
	
		
			
				|  |  | +	private function age()
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  | +		// To age the data, we will forget all of the old keys and then rewrite the newly
 | 
	
		
			
				|  |  | +		// flashed items to have old keys, which will be available for the next request.
 | 
	
		
			
				|  |  |  		foreach ($this->session['data'] as $key => $value)
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			if (strpos($key, ':old:') === 0) $this->forget($key);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		$session = $this->session['data'];
 | 
	
		
			
				|  |  | +		$this->readdress(':new:', ':old:', array_keys($this->session['data']));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		$this->session['data'] = array_combine(str_replace(':new:', ':old:', array_keys($session)), array_values($session));
 | 
	
		
			
				|  |  | +	/**
 | 
	
		
			
				|  |  | +	 * Readdress the session data by performing a string replacement on the keys.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * @param  string  $search
 | 
	
		
			
				|  |  | +	 * @param  string  $replace
 | 
	
		
			
				|  |  | +	 * @param  array   $keys
 | 
	
		
			
				|  |  | +	 * @return void
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	private function readdress($search, $replace, $keys)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +		$this->session['data'] = array_combine(str_replace($search, $replace, $keys), array_values($this->session['data']));
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Write the session cookie.
 | 
	
		
			
				|  |  |  	 *
 | 
	
		
			
				|  |  | -	 * All of the session cookie configuration options are stored in the session
 | 
	
		
			
				|  |  | -	 * configuration file. The cookie will only be written if the headers have not
 | 
	
		
			
				|  |  | -	 * already been sent to the browser.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  |  	 * @param  Laravel\Cookie  $cookie
 | 
	
		
			
				|  |  |  	 * @param  array           $config
 | 
	
		
			
				|  |  |  	 * @return void
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  | -	protected function write_cookie(Cookie $cookies, $config)
 | 
	
		
			
				|  |  | +	private function cookie(Cookie $cookies)
 | 
	
		
			
				|  |  |  	{
 | 
	
		
			
				|  |  |  		if ( ! headers_sent())
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  | +			$config = $this->config->get('session');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  			extract($config);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			$minutes = ($expire_on_close) ? 0 : $lifetime;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			$cookies->put('laravel_session', $this->session['id'], $minutes, $path, $domain, $https, $http_only);
 | 
	
		
			
				|  |  | +			$cookies->put('laravel_session', $this->session['id'], $minutes, $path, $domain);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Magic Method for retrieving items from the session.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * This method is particularly helpful in controllers where access to the IoC container
 | 
	
		
			
				|  |  | -	 * is provided through the controller's magic __get method.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * <code>
 | 
	
		
			
				|  |  | -	 *		// Retrieve an item from the session from a controller method
 | 
	
		
			
				|  |  | -	 *		$name = $this->session->name;
 | 
	
		
			
				|  |  | -	 * </code>
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  |  	public function __get($key)
 | 
	
		
			
				|  |  |  	{
 | 
	
	
		
			
				|  | @@ -269,14 +300,6 @@ abstract class Driver {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/**
 | 
	
		
			
				|  |  |  	 * Magic Method for writings items to the session.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * This method is particularly helpful in controllers where access to the IoC container
 | 
	
		
			
				|  |  | -	 * is provided through the controller's magic __get method.
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * <code>
 | 
	
		
			
				|  |  | -	 *		// Set an item in the session from a controller method
 | 
	
		
			
				|  |  | -	 *		$this->session->name = 'Fred';
 | 
	
		
			
				|  |  | -	 * </code>
 | 
	
		
			
				|  |  |  	 */
 | 
	
		
			
				|  |  |  	public function __set($key, $value)
 | 
	
		
			
				|  |  |  	{
 |