Updated the Session class so that if a database is being used, any custom data is stored to the DB rather then the cookie.
diff --git a/system/libraries/Session.php b/system/libraries/Session.php
index 31a162e..9907ade 100644
--- a/system/libraries/Session.php
+++ b/system/libraries/Session.php
@@ -26,17 +26,24 @@
  */

 class CI_Session {

 

+	var $sess_encrypt_cookie		= FALSE;

+	var $sess_use_database			= FALSE;

+	var $sess_table_name			= '';

+	var $sess_expiration			= 7200;

+	var $sess_match_ip				= FALSE;

+	var $sess_match_useragent		= TRUE;

+	var $sess_cookie_name			= 'ci_session';

+	var $cookie_prefix				= '';

+	var $cookie_path				= '';

+	var $cookie_domain				= '';

+	var $sess_time_to_update		= 300;

+	var $encryption_key				= '';

+	var $flashdata_key 				= 'flash';

+	var $time_reference				= 'time';

+	var $gc_probability				= 5;

+	var $userdata					= array();

 	var $CI;

 	var $now;

-	var $encryption		= TRUE;

-	var $use_database	= FALSE;

-	var $session_table	= FALSE;

-	var $sess_length	= 7200;

-	var $sess_cookie	= 'ci_session';

-	var $userdata		= array();

-	var $gc_probability	= 5;

-	var $flashdata_key 	= 'flash';

-	var $time_to_update	= 300;

 

 	/**

 	 * Session Constructor

@@ -44,132 +51,70 @@
 	 * The constructor runs the session routines automatically

 	 * whenever the class is instantiated.

 	 */		

-	function CI_Session()

+	function CI_Session($params = array())

 	{

-		$this->CI =& get_instance();

-

 		log_message('debug', "Session Class Initialized");

-		$this->sess_run();

-	}

-	

-	// --------------------------------------------------------------------

-	

-	/**

-	 * Run the session routines

-	 *

-	 * @access	public

-	 * @return	void

-	 */		

-	function sess_run()

-	{

-		/*

-		 *  Set the "now" time

-		 *

-		 * It can either set to GMT or time(). The pref

-		 * is set in the config file.  If the developer

-		 * is doing any sort of time localization they

-		 * might want to set the session time to GMT so

-		 * they can offset the "last_activity" time

-		 * based on each user's locale.

-		 *

-		 */

 

-		if (is_numeric($this->CI->config->item('sess_time_to_update')))

+		// Set the super object to a local variable for use throughout the class

+		$this->CI =& get_instance();

+		

+		// Set all the session preferences, which can either be set 

+		// manually via the $params array above or via the config file

+		foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)

 		{

-			$this->time_to_update = $this->CI->config->item('sess_time_to_update');

-		}

+			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);

+		}		

+	

+		// Load the string helper so we can use the strip_slashes() function

+		$this->CI->load->helper('string');

 

-		if (strtolower($this->CI->config->item('time_reference')) == 'gmt')

-		{

-			$now = time();

-			$this->now = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));

-	

-			if (strlen($this->now) < 10)

-			{

-				$this->now = time();

-				log_message('error', 'The session class could not set a proper GMT timestamp so the local time() value was used.');

-			}

-		}

-		else

-		{

-			$this->now = time();

-		}

-		

-		/*

-		 *  Set the session length

-		 *

-		 * If the session expiration is set to zero in

-		 * the config file we'll set the expiration

-		 * two years from now.

-		 *

-		 */

-		$expiration = $this->CI->config->item('sess_expiration');

-		

-		if (is_numeric($expiration))

-		{

-			if ($expiration > 0)

-			{

-				$this->sess_length = $this->CI->config->item('sess_expiration');

-			}

-			else

-			{

-				$this->sess_length = (60*60*24*365*2);

-			}

-		}

-		

-		// Do we need encryption?

-		$this->encryption = $this->CI->config->item('sess_encrypt_cookie');

-	

-		if ($this->encryption == TRUE)	

+		// Do we need encryption? If so, load the encryption class

+		if ($this->sess_encrypt_cookie == TRUE)	

 		{

 			$this->CI->load->library('encrypt');

 		}		

 

-		// Are we using a database?

-		if ($this->CI->config->item('sess_use_database') === TRUE AND $this->CI->config->item('sess_table_name') != '')

+		// Are we using a database?  If so, load it

+		if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')

 		{

-			$this->use_database = TRUE;

-			$this->session_table = $this->CI->config->item('sess_table_name');

 			$this->CI->load->database();

 		}

-		

-		// Set the cookie name

-		if ($this->CI->config->item('sess_cookie_name') != FALSE)

+

+		// Set the "now" time.  Can either be GMT or server time, based on the

+		// config prefs.  We use this to set the "last activity" time

+		$this->now = $this->_get_time();

+

+		// Set the session length. If the session expiration is

+		// set to zero we'll set the expiration two years from now.

+		if ($this->sess_expiration == 0)

 		{

-			$this->sess_cookie = $this->CI->config->item('cookie_prefix').$this->CI->config->item('sess_cookie_name');

+			$this->sess_expiration = (60*60*24*365*2);

 		}

+		 				

+		// Set the cookie name

+		$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;

 	

-		/*

-		 *  Fetch the current session

-		 *

-		 * If a session doesn't exist we'll create

-		 * a new one.  If it does, we'll update it.

-		 *

-		 */

+		// Run the Session routine. If a session doesn't exist we'll 

+		// create a new one.  If it does, we'll update it.

 		if ( ! $this->sess_read())

 		{

 			$this->sess_create();

 		}

 		else

 		{	

-			// We only update the session every five minutes

-			if (($this->userdata['last_activity'] + $this->time_to_update) < $this->now)

-			{

-				$this->sess_update();

-			}

+			$this->sess_update();

 		}

 		

-		// Delete expired sessions if necessary

-		if ($this->use_database === TRUE)

-		{		

-			$this->sess_gc();

-		}

-

 		// 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 sessions if necessary

+		$this->_sess_gc();

+

+		log_message('debug', "Session routines successfully run");

 	}

 	

 	// --------------------------------------------------------------------

@@ -183,28 +128,28 @@
 	function sess_read()

 	{	

 		// Fetch the cookie

-		$session = $this->CI->input->cookie($this->sess_cookie);

+		$session = $this->CI->input->cookie($this->sess_cookie_name);

 		

+		// No cookie?  Goodbye cruel world!...

 		if ($session === FALSE)

 		{

 			log_message('debug', 'A session cookie was not found.');

 			return FALSE;

 		}

 		

-		// Decrypt and unserialize the data

-		if ($this->encryption == TRUE)

+		// Decrypt the cookie data

+		if ($this->sess_encrypt_cookie == TRUE)

 		{

 			$session = $this->CI->encrypt->decode($session);

 		}

 		else

 		{	

 			// encryption was not used, so we need to check the md5 hash

-			$hash = substr($session, strlen($session)-32); // get last 32 chars

+			$hash	 = substr($session, strlen($session)-32); // get last 32 chars

 			$session = substr($session, 0, strlen($session)-32);

 

-			// Does the md5 hash match?  This is to prevent manipulation of session data

-			// in userspace

-			if ($hash !==  md5($session.$this->CI->config->item('encryption_key')))

+			// Does the md5 hash match?  This is to prevent manipulation of session data in userspace

+			if ($hash !==  md5($session.$this->encryption_key))

 			{

 				log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');

 				$this->sess_destroy();

@@ -212,68 +157,75 @@
 			}

 		}

 		

-		$session = @unserialize($this->strip_slashes($session));

+		// Unserialize the session array

+		$session = @unserialize(strip_slashes($session));

 		

-		if ( ! is_array($session) OR ! isset($session['last_activity']))

+		// Is the session data we unserialized and array with the correct format?

+		if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))

 		{

-			log_message('error', 'The session cookie data did not contain a valid array. This could be a possible hacking attempt.');

+			$this->sess_destroy();

 			return FALSE;

 		}

 		

 		// Is the session current?

-		if (($session['last_activity'] + $this->sess_length) < $this->now)

+		if (($session['last_activity'] + $this->sess_expiration) < $this->now)

 		{

 			$this->sess_destroy();

 			return FALSE;

 		}

 

 		// Does the IP Match?

-		if ($this->CI->config->item('sess_match_ip') == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())

+		if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())

 		{

 			$this->sess_destroy();

 			return FALSE;

 		}

 		

 		// Does the User Agent Match?

-		if ($this->CI->config->item('sess_match_useragent') == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))

+		if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))

 		{

 			$this->sess_destroy();

 			return FALSE;

 		}

 		

 		// Is there a corresponding session in the DB?

-		if ($this->use_database === TRUE)

+		if ($this->sess_use_database === TRUE)

 		{

 			$this->CI->db->where('session_id', $session['session_id']);

 					

-			if ($this->CI->config->item('sess_match_ip') == TRUE)

+			if ($this->sess_match_ip == TRUE)

 			{

 				$this->CI->db->where('ip_address', $session['ip_address']);

 			}

 

-			if ($this->CI->config->item('sess_match_useragent') == TRUE)

+			if ($this->sess_match_useragent == TRUE)

 			{

 				$this->CI->db->where('user_agent', $session['user_agent']);

 			}

 			

-			$query = $this->CI->db->get($this->session_table);

+			$query = $this->CI->db->get($this->sess_table_name);

 

+			// No result?  Kill it!

 			if ($query->num_rows() == 0)

 			{

 				$this->sess_destroy();

 				return FALSE;

 			}

-			else

+

+			// Is there custom data?  If so, add it to the main session array

+			$row = $query->row();

+			if (isset($row->user_data) AND $row->user_data != '')

 			{

-				$row = $query->row();

-				if (($row->last_activity + $this->sess_length) < $this->now)

+				$custom_data = @unserialize(strip_slashes($row->user_data));

+

+				if (is_array($custom_data))

 				{

-					$this->CI->db->where('session_id', $session['session_id']);

-					$this->CI->db->delete($this->session_table);

-					$this->sess_destroy();

-					return FALSE;

+					foreach ($custom_data as $key => $val)

+					{

+						$session[$key] = $val;

+					}

 				}

-			}

+			}				

 		}

 	

 		// Session is valid!

@@ -286,35 +238,61 @@
 	// --------------------------------------------------------------------

 	

 	/**

-	 * Write the session cookie

+	 * Write the session data

 	 *

 	 * @access	public

 	 * @return	void

 	 */

 	function sess_write()

-	{								

-		$cookie_data = serialize($this->userdata);

-		

-		if ($this->encryption == TRUE)

+	{

+		// Are we saving custom data to the DB?  If not, all we do is update the cookie

+		if ($this->sess_use_database === FALSE)

 		{

-			$cookie_data = $this->CI->encrypt->encode($cookie_data);

+			$this->_set_cookie();

+			return;

+		}

+

+		// We need two copies of the session data array.  One will contain any custom data

+		// that might have been set.  The other will contain the data that will be saved to the cookie

+		$cookie_userdata = $this->userdata;

+		$custom_userdata = $this->userdata;

+

+		// Before continuing, we need to determine if there is any custom data to deal with.

+		// Let's determine this by removing the default indexes to see if there's anything left in the array

+		foreach (array('session_id','ip_address','user_agent','last_activity') as $val)

+		{

+			unset($custom_userdata[$val]);

+		}

+		

+		// Did we find any custom data?  If not, we turn the empty array into a string

+		// since there's no reason to serialize and store an empty array in the DB

+		if (count($custom_userdata) === 0)

+		{

+			$custom_userdata = '';

 		}

 		else

 		{

-			// if encryption is not used, we provide an md5 hash to prevent userside tampering

-			$cookie_data = $cookie_data . md5($cookie_data.$this->CI->config->item('encryption_key'));

+			// Before we serialize the custom data array, let's remove that data from the

+			// main session array since we do not want to save that info to the cookie

+			foreach (array_keys($custom_userdata) as $val)

+			{

+				unset($cookie_userdata[$val]);

+			}

+		

+			// Serialize the custom data array so we can store it

+			$custom_userdata = serialize($custom_userdata);

 		}

+		

+		// Run the update query

+		$this->CI->db->where('session_id', $this->userdata['session_id']);

+		$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));

 

-		setcookie(

-					$this->sess_cookie,

-					$cookie_data,

-					$this->sess_length + time(),

-					$this->CI->config->item('cookie_path'),

-					$this->CI->config->item('cookie_domain'),

-					0

-				);

+		// Write the cookie.  Notice that we manually pass the cookie data array to the

+		// _set_cookie() function. Normally that function will store $this->userdata, but 

+		// in this case that array contains custom data, which we do not want in the cookie.

+		$this->_set_cookie($cookie_userdata);

 	}

-	

+

 	// --------------------------------------------------------------------

 	

 	/**

@@ -330,6 +308,9 @@
 		{

 			$sessid .= mt_rand(0, mt_getrandmax());

 		}

+		

+		// To make the session ID even more secure we'll combine it with the user's IP

+		$sessid .= $this->CI->input->ip_address();

 	

 		$this->userdata = array(

 							'session_id' 	=> md5(uniqid($sessid, TRUE)),

@@ -339,14 +320,14 @@
 							);

 		

 		

-		// Save the session in the DB if needed

-		if ($this->use_database === TRUE)

+		// Save the data to the DB if needed

+		if ($this->sess_use_database === TRUE)

 		{

-			$this->CI->db->query($this->CI->db->insert_string($this->session_table, $this->userdata));

+			$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));

 		}

 			

 		// Write the cookie

-		$this->sess_write();

+		$this->_set_cookie();

 	}

 	

 	// --------------------------------------------------------------------

@@ -358,7 +339,13 @@
 	 * @return	void

 	 */

 	function sess_update()

-	{	

+	{

+		// We only update the session every five minutes by default

+		if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)

+		{

+			return;

+		}

+	

 		// Save the old session id so we know which record to 

 		// update in the database if we need it

 		$old_sessid = $this->userdata['session_id'];

@@ -367,20 +354,25 @@
 		{

 			$new_sessid .= mt_rand(0, mt_getrandmax());

 		}

+		

+		// To make the session ID even more secure we'll combine it with the user's IP

+		$new_sessid .= $this->CI->input->ip_address();

+		

+		// Turn it into a hash

 		$new_sessid = md5(uniqid($new_sessid, TRUE));

 		

         // Update the session data in the session data array

 		$this->userdata['session_id'] = $new_sessid;

 		$this->userdata['last_activity'] = $this->now;

 		

-		// Update the session in the DB if needed

-		if ($this->use_database === TRUE)

-		{		

-			$this->CI->db->query($this->CI->db->update_string($this->session_table, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));

+		// Update the session ID and last_activity field in the DB if needed

+		if ($this->sess_use_database === TRUE)

+		{

+			$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));

 		}

 		

 		// Write the cookie

-		$this->sess_write();

+		$this->_set_cookie();

 	}

 	

 	// --------------------------------------------------------------------

@@ -392,13 +384,21 @@
 	 * @return	void

 	 */

 	function sess_destroy()

-	{

+	{	

+		// Kill the session DB row

+		if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id']))

+		{

+			$this->CI->db->where('session_id', $this->userdata['session_id']);

+			$this->CI->db->delete($this->sess_table_name);

+		}

+	

+		// Kill the cookie

 		setcookie(

-					$this->sess_cookie,

+					$this->sess_cookie_name,

 					addslashes(serialize(array())),

 					($this->now - 31500000),

-					$this->CI->config->item('cookie_path'),

-					$this->CI->config->item('cookie_domain'),

+					$this->cookie_path,

+					$this->cookie_domain,

 					0

 				);

 	}

@@ -406,31 +406,6 @@
 	// --------------------------------------------------------------------

 	

 	/**

-	 * Garbage collection

-	 *

-	 * This deletes expired session rows from database

-	 * if the probability percentage is met

-	 *

-	 * @access	public

-	 * @return	void

-	 */

-	function sess_gc()

-	{

-		srand(time());

-		if ((rand() % 100) < $this->gc_probability)

-		{

-			$expire = $this->now - $this->sess_length;

-			

-			$this->CI->db->where("last_activity < {$expire}");

-			$this->CI->db->delete($this->session_table);

-

-			log_message('debug', 'Session garbage collection performed.');

-		}

-	}

-	

-	// --------------------------------------------------------------------

-	

-	/**

 	 * Fetch a specific item from the session array

 	 *

 	 * @access	public

@@ -509,33 +484,6 @@
 		$this->sess_write();

 	}

 	

-	// --------------------------------------------------------------------

-	

-	/**

-	 * Strip slashes

-	 *

-	 * @access	public

-	 * @param	mixed

-	 * @return	mixed

-	 */

-	function strip_slashes($vals)

-	{

-		if (is_array($vals))

-	 	{	

-	 		foreach ($vals as $key=>$val)

-	 		{

-	 			$vals[$key] = $this->strip_slashes($val);

-	 		}

-	 	}

-	 	else

-	 	{

-	 		$vals = stripslashes($vals);

-	 	}

-	 	

-	 	return $vals;

-	}

-

-	

     // ------------------------------------------------------------------------

 

     /**

@@ -646,6 +594,99 @@
         }

 

     }

+

+	// --------------------------------------------------------------------

+	

+	/**

+	 * Get the "now" time

+	 *

+	 * @access	private

+	 * @return	string

+	 */

+	function _get_time()

+	{

+		if (strtolower($this->time_reference) == 'gmt')

+		{

+			$now = time();

+			$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));

+		}

+		else

+		{

+			$time = time();

+		}

+	

+		return $time;

+	}

+

+	// --------------------------------------------------------------------

+	

+	/**

+	 * Write the session cookie

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function _set_cookie($cookie_data = NULL)

+	{

+		if (is_null($cookie_data))

+		{

+			$cookie_data = $this->userdata;

+		}

+	

+		// Serialize the userdata for the cookie

+		$cookie_data = serialize($cookie_data);

+		

+		if ($this->sess_encrypt_cookie == TRUE)

+		{

+			$cookie_data = $this->CI->encrypt->encode($cookie_data);

+		}

+		else

+		{

+			// if encryption is not used, we provide an md5 hash to prevent userside tampering

+			$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);

+		}

+		

+		// Set the cookie

+		setcookie(

+					$this->sess_cookie_name,

+					$cookie_data,

+					$this->sess_expiration + time(),

+					$this->cookie_path,

+					$this->cookie_domain,

+					0

+				);

+	}

+

+	// --------------------------------------------------------------------

+	

+	/**

+	 * Garbage collection

+	 *

+	 * This deletes expired session rows from database

+	 * if the probability percentage is met

+	 *

+	 * @access	public

+	 * @return	void

+	 */

+	function _sess_gc()

+	{

+		if ($this->sess_use_database != TRUE)

+		{

+			return;

+		}

+		

+		srand(time());

+		if ((rand() % 100) < $this->gc_probability)

+		{

+			$expire = $this->now - $this->sess_expiration;

+			

+			$this->CI->db->where("last_activity < {$expire}");

+			$this->CI->db->delete($this->sess_table_name);

+

+			log_message('debug', 'Session garbage collection performed.');

+		}

+	}

+

 	

 }

 // END Session Class