Initial version of new Session library
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index 905352b..0d444e8 100644
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -29,175 +29,169 @@
 /**
  * CodeIgniter Session Class
  *
- * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms.
- * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be
- * used to specify the 'native' driver, or any other you might create.
- * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the
- * 'session' member of the global controller framework (e.g.: $CI->session or $this->session).
- * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing.
- * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods.
- * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods
- * called through the specific driver will switch the "current" driver to itself before invoking the library method
- * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be
- * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar');
- * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous
- * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for
- * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value.
- *
  * @package		CodeIgniter
  * @subpackage	Libraries
  * @category	Sessions
- * @author		EllisLab Dev Team
+ * @author		Andrey Andreev
  * @link		http://codeigniter.com/user_guide/libraries/sessions.html
  */
-class CI_Session extends CI_Driver_Library {
+class CI_Session {
 
-	/**
-	 * Initialization parameters
-	 *
-	 * @var	array
-	 */
-	public $params = array();
-
-	/**
-	 * Valid drivers list
-	 *
-	 * @var	array
-	 */
-	public $valid_drivers = array('native',	'cookie');
-
-	/**
-	 * Current driver in use
-	 *
-	 * @var	string
-	 */
-	public $current = NULL;
-
-	/**
-	 * User data
-	 *
-	 * @var	array
-	 */
-	protected $userdata = array();
-
-	// ------------------------------------------------------------------------
-
-	const FLASHDATA_KEY = 'flash';
-	const FLASHDATA_NEW = ':new:';
-	const FLASHDATA_OLD = ':old:';
-	const FLASHDATA_EXP = ':exp:';
-	const EXPIRATION_KEY = '__expirations';
-	const TEMP_EXP_DEF = 300;
+	protected $_driver = 'files';
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * CI_Session constructor
+	 * Class constructor
 	 *
-	 * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running
-	 * routines in its constructor, and manages flashdata aging.
-	 *
-	 * @param	array	Configuration parameters
+	 * @param	array	$params	Configuration parameters
 	 * @return	void
 	 */
 	public function __construct(array $params = array())
 	{
-		$_config =& get_instance()->config;
 
 		// No sessions under CLI
 		if (is_cli())
 		{
+			log_message('debug', 'Session: Initialization under CLI aborted.');
+			return;
+		}
+		elseif ((bool) ini_get('session.auto_start'))
+		{
+			log_message('error', 'Session: session.auto_start is enabled in php.ini. Aborting.');
+			return;
+		}
+		elseif ( ! empty($params['driver']))
+		{
+			$this->_driver = $params['driver'];
+			unset($params['driver']);
+		}
+
+		if (($class = $this->_ci_load_classes($this->_driver)) === FALSE)
+		{
 			return;
 		}
 
-		log_message('debug', 'CI_Session Class Initialized');
-
-		// Add possible extra entries to our valid drivers list
-		$drivers = isset($params['sess_valid_drivers']) ? $params['sess_valid_drivers'] : $_config->item('sess_valid_drivers');
-		if ( ! empty($drivers))
+		$class = new $class($params);
+		if ($class instanceof SessionHandlerInterface)
 		{
-			$drivers = array_map('strtolower', (array) $drivers);
-			$this->valid_drivers = array_merge($this->valid_drivers, array_diff($drivers, $this->valid_drivers));
-		}
-
-		// Get driver to load
-		$driver = isset($params['sess_driver']) ? $params['sess_driver'] : $_config->item('sess_driver');
-		if ( ! $driver)
-		{
-			log_message('debug', "Session: No driver name is configured, defaulting to 'cookie'.");
-			$driver = 'cookie';
-		}
-
-		if ( ! in_array($driver, $this->valid_drivers))
-		{
-			log_message('error', 'Session: Configured driver name is not valid, aborting.');
-			return;
-		}
-
-		// Save a copy of parameters in case drivers need access
-		$this->params = $params;
-
-		// Load driver and get array reference
-		$this->load_driver($driver);
-
-		// Delete 'old' flashdata (from last request)
-		$this->_flashdata_sweep();
-
-		// Mark all new flashdata as old (data will be deleted before next request)
-		$this->_flashdata_mark();
-
-		// Delete expired tempdata
-		$this->_tempdata_sweep();
-
-		log_message('debug', 'CI_Session routines successfully run');
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Loads session storage driver
-	 *
-	 * @param	string	Driver classname
-	 * @return	object	Loaded driver object
-	 */
-	public function load_driver($driver)
-	{
-		// Save reference to most recently loaded driver as library default and sync userdata
-		$this->current = parent::load_driver($driver);
-		$this->userdata =& $this->current->get_userdata();
-		return $this->current;
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Select default session storage driver
-	 *
-	 * @param	string	Driver name
-	 * @return	void
-	 */
-	public function select_driver($driver)
-	{
-		// Validate driver name
-		$prefix = (string) get_instance()->config->item('subclass_prefix');
-		$child = strtolower(str_replace(array('CI_', $prefix, $this->lib_name.'_'), '', $driver));
-		if (in_array($child, array_map('strtolower', $this->valid_drivers)))
-		{
-			// See if driver is loaded
-			if (isset($this->$child))
+			if (is_php('5.4'))
 			{
-				// See if driver is already current
-				if ($this->$child !== $this->current)
-				{
-					// Make driver current and sync userdata
-					$this->current = $this->$child;
-					$this->userdata =& $this->current->get_userdata();
-				}
+				session_set_save_handler($class, TRUE);
 			}
 			else
 			{
-				// Load new driver
-				$this->load_driver($child);
+				session_set_save_handler(
+					array($class, 'open'),
+					array($class, 'close'),
+					array($class, 'read'),
+					array($class, 'write'),
+					array($class, 'destroy'),
+					array($class, 'gc')
+				);
+
+				register_shutdown_function('session_write_close');
+			}
+		}
+		else
+		{
+			log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting.");
+			return;
+		}
+
+		session_start();
+		$this->_ci_init_vars();
+
+		log_message('debug', "Session: Class initialized using '".$this->_driver."' driver.");
+	}
+
+	// ------------------------------------------------------------------------
+
+	protected function _ci_load_classes($driver)
+	{
+		// PHP 5.4 compatibility
+		interface_exists('SessionHandlerInterface', FALSE) OR require_once(BASEPATH.'libraries/Session/SessionHandlerInterface.php');
+
+		$prefix = config_item('subclass_prefix');
+
+		if ( ! class_exists('CI_Session_driver', FALSE))
+		{
+			if (file_exists($file_path = APPPATH.'libraries/Session/Session_driver.php') OR file_exists($file_path = BASEPATH.'libraries/Session/Session_driver.php'))
+			{
+				require_once($file_path);
+			}
+
+			if (file_exists($file_path = APPPATH.'libraries/Session/'.$prefix.'Session_driver.php'))
+			{
+				require_once($file_path);
+			}
+		}
+
+		$class = 'Session_'.$driver.'_driver';
+
+		if ( ! class_exists('CI_'.$class, FALSE))
+		{
+			if (file_exists($file_path = APPPATH.'libraries/Session/drivers/'.$class.'.php') OR file_exists($file_path = BASEPATH.'libraries/Session/drivers/'.$class.'.php'))
+			{
+				require_once($file_path);
+			}
+
+			if ( ! class_exists('CI_'.$class, FALSE))
+			{
+				log_message('error', "Session: Configured driver '".$driver."' was not found. Aborting.");
+				return FALSE;
+			}
+		}
+
+		if ( ! class_exists($prefix.$class) && file_exists($file_path = APPPATH.'libraries/Session/drivers/'.$prefix.$class.'.php'))
+		{
+			require_once($file_path);
+			if (class_exists($prefix.$class, FALSE))
+			{
+				return $prefix.$class;
+			}
+			else
+			{
+				log_message('debug', 'Session: '.$prefix.$class.".php found but it doesn't declare class ".$prefix.$class.'.');
+			}
+		}
+
+		return 'CI_'.$class;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Handle temporary variables
+	 *
+	 * Clears old "flash" data, marks the new one for deletion and handles
+	 * "temp" data deletion.
+	 *
+	 * @return	void
+	 */
+	protected function _ci_init_vars()
+	{
+		if ( ! empty($_SESSION['__ci_vars']))
+		{
+			$current_time = time();
+
+			foreach ($_SESSION['__ci_vars'] as $key => &$value)
+			{
+				if ($value === 'new')
+				{
+					$_SESSION['__ci_vars'][$key] = 'old';
+				}
+				// Hacky, but 'old' will (implicitly) always be less than time() ;)
+				// DO NOT move this above the 'new' check!
+				elseif ($value < $current_time)
+				{
+					unset($_SESSION[$key], $_SESSION['__ci_vars'][$key]);
+				}
+			}
+
+			if (empty($_SESSION['__ci_vars']))
+			{
+				unset($_SESSION['__ci_vars']);
 			}
 		}
 	}
@@ -205,554 +199,532 @@
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Destroy the current session
+	 * Mark as flash
+	 *
+	 * @param	mixed	$key	Session data key(s)
+	 * @return	bool
+	 */
+	public function mark_as_flash($key)
+	{
+		if (is_array($key))
+		{
+			for ($i = 0, $c = count($key); $i < $c; $i++)
+			{
+				if ( ! isset($_SESSION[$key[$i]]))
+				{
+					return FALSE;
+				}
+			}
+
+			$new = array_fill_keys($key, 'new');
+
+			$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars'])
+				? array_merge($_SESSION['__ci_vars'], $new)
+				: $new;
+
+			return TRUE;
+		}
+
+		if ( ! isset($_SESSION[$key]))
+		{
+			return FALSE;
+		}
+
+		$_SESSION['__ci_vars'][$key] = 'new';
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get flash keys
+	 *
+	 * @return	array
+	 */
+	public function get_flash_keys()
+	{
+		if ( ! isset($_SESSION['__ci_vars']))
+		{
+			return array();
+		}
+
+		$keys = array();
+		foreach (array_keys($_SESSION['__ci_vars']) as $key)
+		{
+			is_int($_SESSION['__ci_vars'][$key]) OR $keys[] = $key;
+		}
+
+		return $keys;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Unmark flash
+	 *
+	 * @param	mixed	$key	Session data key(s)
+	 * @return	void
+	 */
+	public function unmark_flash($key)
+	{
+		if (empty($_SESSION['__ci_vars']))
+		{
+			return;
+		}
+
+		is_array($key) OR $key = array($key);
+
+		foreach ($key as $k)
+		{
+			if (isset($_SESSION['__ci_vars'][$k]) && ! is_int($_SESSION['__ci_vars'][$k]))
+			{
+				unset($_SESSION['__ci_vars'][$k]);
+			}
+		}
+
+		if (empty($_SESSION['__ci_vars']))
+		{
+			unset($_SESSION['__ci_vars']);
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Mark as temp
+	 *
+	 * @param	mixed	$key	Session data key(s)
+	 * @param	int	$ttl	Time-to-live in seconds
+	 * @return	bool
+	 */
+	public function mark_as_temp($key, $ttl = 300)
+	{
+		$ttl += time();
+
+		if (is_array($key))
+		{
+			$temp = array();
+
+			foreach ($key as $k => $v)
+			{
+				// Do we have a key => ttl pair, or just a key?
+				if (is_int($k))
+				{
+					$k = $v;
+					$v = $ttl;
+				}
+				else
+				{
+					$v += time();
+				}
+
+				if ( ! isset($_SESSION[$k]))
+				{
+					return FALSE;
+				}
+
+				$temp[$k] = $ts;
+			}
+
+			$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars'])
+				? array_merge($_SESSION['__ci_vars'], $temp)
+				: $temp;
+
+			return TRUE;
+		}
+
+		if ( ! isset($_SESSION[$key]))
+		{
+			return FALSE;
+		}
+
+		$_SESSION['__ci_vars'][$key] = $ttl;
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Get temp keys
+	 *
+	 * @return	array
+	 */
+	public function get_temp_keys()
+	{
+		if ( ! isset($_SESSION['__ci_vars']))
+		{
+			return array();
+		}
+
+		$keys = array();
+		foreach (array_keys($_SESSION['__ci_vars']) as $key)
+		{
+			is_int($_SESSION['__ci_vars'][$key]) && $keys[] = $key;
+		}
+
+		return $keys;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Unmark flash
+	 *
+	 * @param	mixed	$key	Session data key(s)
+	 * @return	void
+	 */
+	public function unmark_temp($key)
+	{
+		if (empty($_SESSION['__ci_vars']))
+		{
+			return;
+		}
+
+		is_array($key) OR $key = array($key);
+
+		foreach ($key as $k)
+		{
+			if (isset($_SESSION['__ci_vars'][$k]) && is_int($_SESSION['__ci_vars'][$k]))
+			{
+				unset($_SESSION['__ci_vars'][$k]);
+			}
+		}
+
+		if (empty($_SESSION['__ci_vars']))
+		{
+			unset($_SESSION['__ci_vars']);
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * __get()
+	 *
+	 * @param	string	$key	'session_id' or a session data key
+	 * @return	mixed
+	 */
+	public function __get($key)
+	{
+		// Note: Keep this order the same, just in case somebody wants to
+		//       use 'session_id' as a session data key, for whatever reason
+		if (isset($_SESSION[$key]))
+		{
+			return $_SESSION[$key];
+		}
+		elseif ($key === 'session_id')
+		{
+			return session_id();
+		}
+
+		return NULL;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * __set()
+	 *
+	 * @param	string	$key	Session data key
+	 * @param	mixed	$value	Session data value
+	 * @return	void
+	 */
+	public function __set($key, $value)
+	{
+		$_SESSION[$key] = $value;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Session destroy
+	 *
+	 * Legacy CI_Session compatibility method
 	 *
 	 * @return	void
 	 */
 	public function sess_destroy()
 	{
-		// Just call destroy on driver
-		$this->current->sess_destroy();
+		session_destroy();
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Regenerate the current session
+	 * Session regenerate
 	 *
-	 * @param	bool	Destroy session data flag (default: false)
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	bool	$destroy	Destroy old session data flag
 	 * @return	void
 	 */
 	public function sess_regenerate($destroy = FALSE)
 	{
-		// Call regenerate on driver and resync userdata
-		$this->current->sess_regenerate($destroy);
-		$this->userdata =& $this->current->get_userdata();
+		session_regenerate_id($destroy);
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Fetch a specific item from the session array
+	 * Get userdata reference
 	 *
-	 * @param	string	Item key
-	 * @return	string	Item value or NULL if not found
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @returns	array
 	 */
-	public function userdata($item = NULL)
+	public function &get_userdata()
 	{
-		if (isset($item))
+		return $_SESSION;
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Userdata (fetch)
+	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	string	$key	Session data key
+	 * @return	mixed	Session data value or NULL if not found
+	 */
+	public function userdata($key = NULL)
+	{
+		if (isset($key))
 		{
-			return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
+			return isset($_SESSION[$key]) ? $_SESSION[$key] : NULL;
+		}
+		elseif (empty($_SESSION))
+		{
+			return array();
 		}
 
-		return isset($this->userdata) ? $this->userdata : array();
-	}
+		$userdata = array();
+		$_exclude = array_merge(
+			array('__ci_f', '__ci_t'),
+			$this->get_flash_keys(),
+			$this->get_temp_keys()
+		);
 
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Fetch all session data
-	 *
-	 * @deprecated	3.0.0	Use userdata() with no parameters instead
-	 * @return	array	User data array
-	 */
-	public function all_userdata()
-	{
-		return isset($this->userdata) ? $this->userdata : array();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Add or change data in the "userdata" array
-	 *
-	 * @param	mixed	Item name or array of items
-	 * @param	string	Item value or empty string
-	 * @return	void
-	 */
-	public function set_userdata($newdata, $newval = '')
-	{
-		// Wrap params as array if singular
-		if (is_string($newdata))
+		foreach (array_keys($_SESSION) as $key)
 		{
-			$newdata = array($newdata => $newval);
-		}
-
-		// Set each name/value pair
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
+			if ( ! in_array($key, $_exclude, TRUE))
 			{
-				$this->userdata[$key] = $val;
+				$userdata[$key] = $_SESSION[$key];
 			}
 		}
 
-		// Tell driver data changed
-		$this->current->sess_save();
+		return $userdata;
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Delete a session variable from the "userdata" array
+	 * Set userdata
 	 *
-	 * @param	mixed	Item name or array of item names
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	mixed	$data	Session data key or an associative array
+	 * @param	mixed	$value	Value to store
 	 * @return	void
 	 */
-	public function unset_userdata($newdata)
+	public function set_userdata($data, $value = NULL)
 	{
-		// Wrap single name as array
-		if (is_string($newdata))
+		if (is_array($data))
 		{
-			$newdata = array($newdata => '');
-		}
-
-		// Unset each item name
-		if (count($newdata) > 0)
-		{
-			foreach (array_keys($newdata) as $key)
+			foreach ($data as $key => &$value)
 			{
-				unset($this->userdata[$key]);
-			}
-		}
-
-		// Tell driver data changed
-		$this->current->sess_save();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Determine if an item exists
-	 *
-	 * @param	string	Item name
-	 * @return	bool
-	 */
-	public function has_userdata($item)
-	{
-		return isset($this->userdata[$item]);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Add or change flashdata, only available until the next request
-	 *
-	 * @param	mixed	Item name or array of items
-	 * @param	string	Item value or empty string
-	 * @return	void
-	 */
-	public function set_flashdata($newdata, $newval = '')
-	{
-		// Wrap item as array if singular
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => $newval);
-		}
-
-		// Prepend each key name and set value
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
-			{
-				$flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
-				$this->set_userdata($flashdata_key, $val);
-			}
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Keeps existing flashdata available to next request.
-	 *
-	 * @param	mixed	Item key(s)
-	 * @return	void
-	 */
-	public function keep_flashdata($key)
-	{
-
-		if (is_array($key))
-		{
-			foreach ($key as $k)
-			{
-				$this->keep_flashdata($k);
+				$_SESSION[$key] = $value;
 			}
 
 			return;
 		}
 
-		// 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep()
-		// Note the function will return NULL if the $key provided cannot be found
-		$old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
-		$value = $this->userdata($old_flashdata_key);
-
-		$new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
-		$this->set_userdata($new_flashdata_key, $value);
+		$_SESSION[$data] = $value;
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Fetch a specific flashdata item from the session array
+	 * Unset userdata
 	 *
-	 * @param	string	Item key
-	 * @return	string
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	mixed	$data	Session data key(s)
+	 * @return	void
+	 */
+	public function unset_userdata($key)
+	{
+		if (is_array($key))
+		{
+			foreach ($key as $k)
+			{
+				unset($_SESSION[$key]);
+			}
+
+			return;
+		}
+
+		unset($_SESSION[$key]);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * All userdata (fetch)
+	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @return	array	$_SESSION, excluding flash data items
+	 */
+	public function all_userdata()
+	{
+		return $this->userdata();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Has userdata
+	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	string	$key	Session data key
+	 * @return	bool
+	 */
+	public function has_userdata($key)
+	{
+		return isset($_SESSION[$key]);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Flashdata (fetch)
+	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	string	$key	Session data key
+	 * @return	mixed	Session data value or NULL if not found
 	 */
 	public function flashdata($key = NULL)
 	{
 		if (isset($key))
 		{
-			return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key);
+			return isset($_SESSION['__ci_f'], $_SESSION['__ci_f'][$key], $_SESSION[$key])
+				? $_SESSION[$key]
+				: NULL;
 		}
 
-		// Get our flashdata items from userdata
-		$out = array();
-		foreach ($this->userdata() as $key => $val)
+		$flashdata = array();
+
+		if ( ! empty($_SESSION['__ci_f']))
 		{
-			if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE)
+			foreach (array_keys($_SESSION['__ci_f']) as $key)
 			{
-				$key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key);
-				$out[$key] = $val;
+				$flashdata[$key] = $_SESSION[$key];
 			}
 		}
 
-		return $out;
+		return $flashdata;
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Add or change tempdata, only available until expiration
+	 * Set flashdata
 	 *
-	 * @param	mixed	Item name or array of items
-	 * @param	string	Item value or empty string
-	 * @param	int	Item lifetime in seconds or 0 for default
+	 * Legacy CI_Session compatibiliy method
+	 *
+	 * @param	mixed	$data	Session data key or an associative array
+	 * @param	mixed	$value	Value to store
 	 * @return	void
 	 */
-	public function set_tempdata($newdata, $newval = '', $expire = 0)
+	public function set_flashdata($data, $value = NULL)
 	{
-		// Set expiration time
-		$expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF);
-
-		// Wrap item as array if singular
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => $newval);
-		}
-
-		// Get or create expiration list
-		$expirations = $this->userdata(self::EXPIRATION_KEY);
-		if ( ! $expirations)
-		{
-			$expirations = array();
-		}
-
-		// Prepend each key name and set value
-		if (count($newdata) > 0)
-		{
-			foreach ($newdata as $key => $val)
-			{
-				$tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
-				$expirations[$tempdata_key] = $expire;
-				$this->set_userdata($tempdata_key, $val);
-			}
-		}
-
-		// Update expiration list
-		$this->set_userdata(self::EXPIRATION_KEY, $expirations);
+		$this->set_userdata($data, $value);
+		$this->mark_as_flash($data);
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Delete a temporary session variable from the "userdata" array
+	 * Keep flashdata
 	 *
-	 * @param	mixed	Item name or array of item names
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	mixed	$key	Session data key(s)
 	 * @return	void
 	 */
-	public function unset_tempdata($newdata)
+	public function keep_flashdata($key)
 	{
-		// Get expirations list
-		$expirations = $this->userdata(self::EXPIRATION_KEY);
-		if (empty($expirations))
-		{
-			// Nothing to do
-			return;
-		}
-
-		// Wrap single name as array
-		if (is_string($newdata))
-		{
-			$newdata = array($newdata => '');
-		}
-
-		// Prepend each item name and unset
-		if (count($newdata) > 0)
-		{
-			foreach (array_keys($newdata) as $key)
-			{
-				$tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
-				unset($expirations[$tempdata_key]);
-				$this->unset_userdata($tempdata_key);
-			}
-		}
-
-		// Update expiration list
-		$this->set_userdata(self::EXPIRATION_KEY, $expirations);
+		$this->mark_as_flash($key);
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Fetch a specific tempdata item from the session array
+	 * Temp data (fetch)
 	 *
-	 * @param	string	Item key
-	 * @return	string
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	string	$key	Session data key
+	 * @return	mixed	Session data value or NULL if not found
 	 */
 	public function tempdata($key = NULL)
 	{
 		if (isset($key))
 		{
-			return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key);
+			return isset($_SESSION['__ci_t'], $_SESSION['__ci_t'][$key], $_SESSION[$key])
+				? $_SESSION[$key]
+				: NULL;
 		}
 
-		// Get our tempdata items from userdata
-		$out = array();
-		foreach ($this->userdata() as $key => $val)
+		$tempdata = array();
+
+		if ( ! empty($_SESSION['__ci_t']))
 		{
-			if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_EXP) !== FALSE)
+			foreach (array_keys($_SESSION['__ci_t']) as $key)
 			{
-				$key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_EXP, '', $key);
-				$out[$key] = $val;
+				$tempdata[$key] = $_SESSION[$key];
 			}
 		}
 
-		return $out;
+		return $tempdata;
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Identifies flashdata as 'old' for removal
-	 * when _flashdata_sweep() runs.
+	 * Set tempdata
 	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	mixed	$data	Session data key or an associative array of items
+	 * @param	mixed	$value	Value to store
+	 * @param	int	$ttl	Time-to-live in seconds
 	 * @return	void
 	 */
-	protected function _flashdata_mark()
+	public function set_tempdata($data, $value = NULL, $ttl = 300)
 	{
-		foreach ($this->userdata() as $name => $value)
-		{
-			$parts = explode(self::FLASHDATA_NEW, $name);
-			if (count($parts) === 2)
-			{
-				$this->set_userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1], $value);
-				$this->unset_userdata($name);
-			}
-		}
+		$this->set_userdata($data, $value);
+		$this->mark_as_temp($data, $ttl);
 	}
 
 	// ------------------------------------------------------------------------
 
 	/**
-	 * Removes all flashdata marked as 'old'
+	 * Unset tempdata
 	 *
+	 * Legacy CI_Session compatibility method
+	 *
+	 * @param	mixed	$data	Session data key(s)
 	 * @return	void
 	 */
-	protected function _flashdata_sweep()
+	public function unset_tempdata($key)
 	{
-		$userdata = $this->userdata();
-		foreach (array_keys($userdata) as $key)
-		{
-			if (strpos($key, self::FLASHDATA_OLD))
-			{
-				$this->unset_userdata($key);
-			}
-		}
+		$this->unmark_temp($key);
 	}
 
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Removes all expired tempdata
-	 *
-	 * @return	void
-	 */
-	protected function _tempdata_sweep()
-	{
-		// Get expirations list
-		$expirations = $this->userdata(self::EXPIRATION_KEY);
-		if (empty($expirations))
-		{
-			// Nothing to do
-			return;
-		}
-
-		// Unset expired elements
-		$now = time();
-		$userdata = $this->userdata();
-		foreach (array_keys($userdata) as $key)
-		{
-			if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now)
-			{
-				unset($expirations[$key]);
-				$this->unset_userdata($key);
-			}
-		}
-
-		// Update expiration list
-		$this->set_userdata(self::EXPIRATION_KEY, $expirations);
-	}
-
-}
-
-// ------------------------------------------------------------------------
-
-/**
- * CI_Session_driver Class
- *
- * Extend this class to make a new CI_Session driver.
- * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism.
- * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create
- * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler
- * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata).
- * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the
- * application directory, the system directory, or any path you add with $CI->load->add_package_path().
- * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php,
- * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php)
- * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session
- * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); )
- * Already provided are the Native driver, which manages the native PHP $_SESSION array, and
- * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table.
- *
- * @package		CodeIgniter
- * @subpackage	Libraries
- * @category	Sessions
- * @author		EllisLab Dev Team
- */
-abstract class CI_Session_driver extends CI_Driver {
-
-	/**
-	 * CI Singleton
-	 *
-	 * @see	get_instance()
-	 * @var	object
-	 */
-	protected $CI;
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Constructor
-	 *
-	 * Gets the CI singleton, so that individual drivers
-	 * don't have to do it separately.
-	 *
-	 * @return	void
-	 */
-	public function __construct()
-	{
-		$this->CI =& get_instance();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Decorate
-	 *
-	 * Decorates the child with the parent driver lib's methods and properties
-	 *
-	 * @param	object	Parent library object
-	 * @return	void
-	 */
-	public function decorate($parent)
-	{
-		// Call base class decorate first
-		parent::decorate($parent);
-
-		// Call initialize method now that driver has access to $this->_parent
-		$this->initialize();
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * __call magic method
-	 *
-	 * Handles access to the parent driver library's methods
-	 *
-	 * @param	string	Library method name
-	 * @param	array	Method arguments (default: none)
-	 * @return	mixed
-	 */
-	public function __call($method, $args = array())
-	{
-		// Make sure the parent library uses this driver
-		$this->_parent->select_driver(get_class($this));
-		return parent::__call($method, $args);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Initialize driver
-	 *
-	 * @return	void
-	 */
-	protected function initialize()
-	{
-		// Overload this method to implement initialization
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Save the session data
-	 *
-	 * Data in the array has changed - perform any storage synchronization
-	 * necessary. The child class MUST implement this abstract method!
-	 *
-	 * @return	void
-	 */
-	abstract public function sess_save();
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Destroy the current session
-	 *
-	 * Clean up storage for this session - it has been terminated.
-	 * The child class MUST implement this abstract method!
-	 *
-	 * @return	void
-	 */
-	abstract public function sess_destroy();
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Regenerate the current session
-	 *
-	 * Regenerate the session ID.
-	 * The child class MUST implement this abstract method!
-	 *
-	 * @param	bool	Destroy session data flag (default: false)
-	 * @return	void
-	 */
-	abstract public function sess_regenerate($destroy = FALSE);
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Get a reference to user data array
-	 *
-	 * Give array access to the main CI_Session object.
-	 * The child class MUST implement this abstract method!
-	 *
-	 * @return	array	Reference to userdata
-	 */
-	abstract public function &get_userdata();
-
 }
 
 /* End of file Session.php */