summaryrefslogtreecommitdiffstats
path: root/system
diff options
context:
space:
mode:
Diffstat (limited to 'system')
-rw-r--r--system/core/Loader.php53
-rw-r--r--system/database/DB_driver.php3
-rw-r--r--system/database/drivers/mysql/mysql_driver.php18
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php22
-rw-r--r--system/helpers/captcha_helper.php3
-rw-r--r--system/helpers/text_helper.php3
-rw-r--r--system/language/english/date_lang.php28
-rw-r--r--system/libraries/Driver.php22
-rwxr-xr-xsystem/libraries/Session/Session.php689
-rwxr-xr-x[-rw-r--r--]system/libraries/Session/drivers/Session_cookie.php (renamed from system/libraries/Session.php)721
-rwxr-xr-xsystem/libraries/Session/drivers/Session_native.php232
-rw-r--r--system/libraries/Xmlrpc.php2
12 files changed, 1327 insertions, 469 deletions
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 0bc6e844a..89b2028bf 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -409,8 +409,8 @@ class CI_Loader {
* 1. The name of the "view" file to be included.
* 2. An associative array of data to be extracted for use in the view.
* 3. TRUE/FALSE - whether to return the data or load it. In
- * some cases it's advantageous to be able to return data so that
- * a developer can process it in some way.
+ * some cases it's advantageous to be able to return data so that
+ * a developer can process it in some way.
*
* @param string
* @param array
@@ -633,13 +633,7 @@ class CI_Loader {
{
$this->driver($driver);
}
- return FALSE;
- }
-
- if ( ! class_exists('CI_Driver_Library'))
- {
- // we aren't instantiating an object here, that'll be done by the Library itself
- require BASEPATH.'libraries/Driver.php';
+ return;
}
if ($library === '')
@@ -785,11 +779,11 @@ class CI_Loader {
$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
$_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
- foreach ($this->_ci_view_paths as $view_file => $cascade)
+ foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
{
- if (file_exists($view_file.$_ci_file))
+ if (file_exists($_ci_view_file.$_ci_file))
{
- $_ci_path = $view_file.$_ci_file;
+ $_ci_path = $_ci_view_file.$_ci_file;
$file_exists = TRUE;
break;
}
@@ -837,10 +831,10 @@ class CI_Loader {
* We buffer the output for two reasons:
* 1. Speed. You get a significant speed boost.
* 2. So that the final rendered template can be post-processed by
- * the output class. Why do we need post processing? For one thing,
- * in order to show the elapsed page load time. Unless we can
- * intercept the content right before it's sent to the browser and
- * then stop the timer it won't be accurate.
+ * the output class. Why do we need post processing? For one thing,
+ * in order to show the elapsed page load time. Unless we can
+ * intercept the content right before it's sent to the browser and
+ * then stop the timer it won't be accurate.
*/
ob_start();
@@ -915,6 +909,13 @@ class CI_Loader {
// Get the filename from the path
$class = substr($class, $last_slash);
+
+ // Check for match and driver base class
+ if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library'))
+ {
+ // We aren't instantiating an object here, just making the base class available
+ require BASEPATH.'libraries/Driver.php';
+ }
}
// We'll test for both lowercase and capitalized versions of the file name
@@ -996,14 +997,19 @@ class CI_Loader {
$this->_ci_loaded_files[] = $filepath;
return $this->_ci_init_class($class, '', $params, $object_name);
}
-
} // END FOREACH
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
if ($subdir === '')
{
$path = strtolower($class).'/'.$class;
- return $this->_ci_load_class($path, $params);
+ return $this->_ci_load_class($path, $params, $object_name);
+ }
+ else if (ucfirst($subdir) != $subdir)
+ {
+ // Lowercase subdir failed - retry capitalized
+ $path = ucfirst($subdir).$class;
+ return $this->_ci_load_class($path, $params, $object_name);
}
// If we got this far we were unable to find the requested class.
@@ -1193,6 +1199,15 @@ class CI_Loader {
}
}
+ // Autoload drivers
+ if (isset($autoload['drivers']))
+ {
+ foreach ($autoload['drivers'] as $item)
+ {
+ $this->driver($item);
+ }
+ }
+
// Autoload models
if (isset($autoload['model']))
{
@@ -1260,4 +1275,4 @@ class CI_Loader {
}
/* End of file Loader.php */
-/* Location: ./system/core/Loader.php */ \ No newline at end of file
+/* Location: ./system/core/Loader.php */
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index d63a1d955..9628e9a9e 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -51,6 +51,7 @@ abstract class CI_DB_driver {
public $char_set = 'utf8';
public $dbcollat = 'utf8_general_ci';
public $autoinit = TRUE; // Whether to automatically initialize the DB
+ public $compress = TRUE;
public $swap_pre = '';
public $port = '';
public $pconnect = FALSE;
@@ -1352,7 +1353,7 @@ abstract class CI_DB_driver {
$trace = debug_backtrace();
foreach ($trace as $call)
{
- if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
+ if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE && isset($call['class']) && strpos($call['class'], 'Loader') !== FALSE)
{
// Found it - use a relative path for safety
$message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 29db90408..35473016f 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -83,7 +83,14 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_connect()
{
- return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ if ($this->compress === TRUE)
+ {
+ return @mysql_connect($this->hostname, $this->username, $this->password, TRUE, MYSQL_CLIENT_COMPRESS);
+ }
+ else
+ {
+ return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ }
}
// --------------------------------------------------------------------
@@ -95,7 +102,14 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ if ($this->compress === TRUE)
+ {
+ return @mysql_pconnect($this->hostname, $this->username, $this->password, MYSQL_CLIENT_COMPRESS);
+ }
+ else
+ {
+ return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ }
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index be61aab20..9558dfd86 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -65,6 +65,17 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function db_connect()
{
+ // Use MySQL client compression?
+ if ($this->compress === TRUE)
+ {
+ $port = empty($this->port) ? NULL : $this->port;
+
+ $mysqli = mysqli_init();
+ $mysqli->real_connect($this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
+
+ return $mysqli;
+ }
+
return empty($this->port)
? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
: @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
@@ -85,6 +96,17 @@ class CI_DB_mysqli_driver extends CI_DB {
return $this->db_connect();
}
+ // Use MySQL client compression?
+ if ($this->compress === TRUE)
+ {
+ $port = empty($this->port) ? NULL : $this->port;
+
+ $mysqli = mysqli_init();
+ $mysqli->real_connect('p:'.$this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
+
+ return $mysqli;
+ }
+
return empty($this->port)
? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
: @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index a4383c9d3..3aac14db8 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -80,8 +80,7 @@ if ( ! function_exists('create_captcha'))
$current_dir = @opendir($img_path);
while ($filename = @readdir($current_dir))
{
- if ($filename !== '.' && $filename !== '..' && $filename !== 'index.html'
- && (str_replace('.jpg', '', $filename) + $expiration) < $now)
+ if (substr($filename, -4) === '.jpg' && (str_replace('.jpg', '', $filename) + $expiration) < $now)
{
@unlink($img_path.$filename);
}
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 8a1f01b51..b592f3cc0 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -89,7 +89,8 @@ if ( ! function_exists('character_limiter'))
return $str;
}
- $str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+ // a bit complicated, but faster than preg_replace with \s+
+ $str = preg_replace('/ {2,}/', ' ', str_replace(array("\r", "\n", "\t", "\x0B", "\x0C"), ' ', $str));
if (strlen($str) <= $n)
{
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index 229d33d2e..6683e4c69 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -25,20 +25,20 @@
* @filesource
*/
-$lang['date_year'] = "Year";
-$lang['date_years'] = "Years";
-$lang['date_month'] = "Month";
-$lang['date_months'] = "Months";
-$lang['date_week'] = "Week";
-$lang['date_weeks'] = "Weeks";
-$lang['date_day'] = "Day";
-$lang['date_days'] = "Days";
-$lang['date_hour'] = "Hour";
-$lang['date_hours'] = "Hours";
-$lang['date_minute'] = "Minute";
-$lang['date_minutes'] = "Minutes";
-$lang['date_second'] = "Second";
-$lang['date_seconds'] = "Seconds";
+$lang['date_year'] = 'Year';
+$lang['date_years'] = 'Years';
+$lang['date_month'] = 'Month';
+$lang['date_months'] = 'Months';
+$lang['date_week'] = 'Week';
+$lang['date_weeks'] = 'Weeks';
+$lang['date_day'] = 'Day';
+$lang['date_days'] = 'Days';
+$lang['date_hour'] = 'Hour';
+$lang['date_hours'] = 'Hours';
+$lang['date_minute'] = 'Minute';
+$lang['date_minutes'] = 'Minutes';
+$lang['date_second'] = 'Second';
+$lang['date_seconds'] = 'Seconds';
$lang['UM12'] = '(UTC -12:00) Baker/Howland Island';
$lang['UM11'] = '(UTC -11:00) Niue';
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index d67ee2549..1d084c8e4 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -54,13 +54,29 @@ class CI_Driver_Library {
protected $lib_name;
/**
+ * Get magic method
+ *
* The first time a child is used it won't exist, so we instantiate it
* subsequents calls will go straight to the proper child.
*
- * @param mixed $child
- * @return mixed
+ * @param string Child class name
+ * @return object Child class
*/
public function __get($child)
+ {
+ // Try to load the driver
+ return $this->load_driver($child);
+ }
+
+ /**
+ * Load driver
+ *
+ * Separate load_driver call to support explicit driver load by library or user
+ *
+ * @param string Child class name
+ * @return object Child class
+ */
+ public function load_driver($child)
{
if ( ! isset($this->lib_name))
{
@@ -268,4 +284,4 @@ class CI_Driver {
}
/* End of file Driver.php */
-/* Location: ./system/libraries/Driver.php */ \ No newline at end of file
+/* Location: ./system/libraries/Driver.php */
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
new file mode 100755
index 000000000..e6f6050c0
--- /dev/null
+++ b/system/libraries/Session/Session.php
@@ -0,0 +1,689 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc.
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.0
+ * @filesource
+ */
+
+/**
+ * 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
+ * @link http://codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session extends CI_Driver_Library {
+
+ public $params = array();
+ protected $current = NULL;
+ 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;
+
+ /**
+ * CI_Session 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
+ */
+ public function __construct(array $params = array())
+ {
+ log_message('debug', 'CI_Session Class Initialized');
+
+ // Get valid drivers list
+ $CI =& get_instance();
+ $this->valid_drivers = array(
+ 'Session_native',
+ 'Session_cookie'
+ );
+ $key = 'sess_valid_drivers';
+ $drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ($drivers)
+ {
+ is_array($drivers) OR $drivers = array($drivers);
+
+ // Add driver names to valid list
+ foreach ($drivers as $driver)
+ {
+ if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = $driver;
+ }
+ }
+ }
+
+ // Get driver to load
+ $key = 'sess_driver';
+ $driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ( ! $driver)
+ {
+ $driver = 'cookie';
+ }
+
+ if ( ! in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = 'Session_'.$driver;
+ }
+
+ // 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 classname
+ * @return void
+ */
+ public function select_driver($driver)
+ {
+ // Validate driver name
+ $lowername = strtolower(str_replace('CI_', '', $driver));
+ if (in_array($lowername, array_map('strtolower', $this->valid_drivers)))
+ {
+ // See if driver is loaded
+ $child = str_replace($this->lib_name.'_', '', $driver);
+ if (isset($this->$child))
+ {
+ // 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();
+ }
+ }
+ else
+ {
+ // Load new driver
+ $this->load_driver($child);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Just call destroy on driver
+ $this->current->sess_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @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();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific item from the session array
+ *
+ * @param string Item key
+ * @return string Item value or NULL if not found
+ */
+ public function userdata($item)
+ {
+ return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all session data
+ *
+ * @return array User data array
+ */
+ public function all_userdata()
+ {
+ return isset($this->userdata) ? $this->userdata : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all flashdata
+ *
+ * @return array Flash data array
+ */
+ public function all_flashdata()
+ {
+ $out = array();
+
+ // loop through all userdata
+ foreach ($this->all_userdata() as $key => $val)
+ {
+ // if it contains flashdata, add it
+ if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE)
+ {
+ $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key);
+ $out[$key] = $val;
+ }
+ }
+ return $out;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * 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 = array(), $newval = '')
+ {
+ // Wrap params as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Set each name/value pair
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $this->userdata[$key] = $val;
+ }
+ }
+
+ // Tell driver data changed
+ $this->current->sess_save();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_userdata($newdata = array())
+ {
+ // Wrap single name as array
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => '');
+ }
+
+ // Unset each item name
+ if (count($newdata) > 0)
+ {
+ foreach (array_keys($newdata) as $key)
+ {
+ 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 = array(), $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 string Item key
+ * @return void
+ */
+ public function keep_flashdata($key)
+ {
+ // '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);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific flashdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function flashdata($key)
+ {
+ // Prepend key and retrieve value
+ $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
+ return $this->userdata($flashdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change tempdata, only available until expiration
+ *
+ * @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
+ * @return void
+ */
+ public function set_tempdata($newdata = array(), $newval = '', $expire = 0)
+ {
+ // 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);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a temporary session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_tempdata($newdata = array())
+ {
+ // 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);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific tempdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function tempdata($key)
+ {
+ // Prepend key and return value
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ return $this->userdata($tempdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Identifies flashdata as 'old' for removal
+ * when _flashdata_sweep() runs.
+ *
+ * @return void
+ */
+ protected function _flashdata_mark()
+ {
+ foreach ($this->all_userdata() as $name => $value)
+ {
+ $parts = explode(self::FLASHDATA_NEW, $name);
+ if (is_array($parts) && count($parts) === 2)
+ {
+ $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1];
+ $this->set_userdata($new_name, $value);
+ $this->unset_userdata($name);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Removes all flashdata marked as 'old'
+ *
+ * @return void
+ */
+ protected function _flashdata_sweep()
+ {
+ $userdata = $this->all_userdata();
+ foreach (array_keys($userdata) as $key)
+ {
+ if (strpos($key, self::FLASHDATA_OLD))
+ {
+ $this->unset_userdata($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->all_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 {
+
+ /**
+ * 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 */
+/* Location: ./system/libraries/Session/Session.php */ \ No newline at end of file
diff --git a/system/libraries/Session.php b/system/libraries/Session/drivers/Session_cookie.php
index af38dc366..4f415cc0d 100644..100755
--- a/system/libraries/Session.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -9,7 +9,7 @@
* Licensed under the Open Software License version 3.0
*
* This source file is subject to the Open Software License (OSL 3.0) that is
- * bundled with this package in the files license.txt / license.rst. It is
+ * bundled with this package in the files license.txt / license.rst. It is
* also available through the world wide web at this URL:
* http://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to obtain it
@@ -26,7 +26,9 @@
*/
/**
- * Session Class
+ * Cookie-based session management driver
+ *
+ * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver.
*
* @package CodeIgniter
* @subpackage Libraries
@@ -34,7 +36,7 @@
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/sessions.html
*/
-class CI_Session {
+class CI_Session_cookie extends CI_Session_driver {
/**
* Whether to encrypt the session cookie
@@ -69,7 +71,7 @@ class CI_Session {
*
* @var bool
*/
- public $sess_expire_on_close = FALSE;
+ public $sess_expire_on_close = FALSE;
/**
* Whether to match session on ip address
@@ -83,7 +85,7 @@ class CI_Session {
*
* @var bool
*/
- public $sess_match_useragent = TRUE;
+ public $sess_match_useragent = TRUE;
/**
* Name of session cookie
@@ -104,7 +106,7 @@ class CI_Session {
*
* @var string
*/
- public $cookie_path = '';
+ public $cookie_path = '';
/**
* Session cookie domain
@@ -142,26 +144,18 @@ class CI_Session {
public $encryption_key = '';
/**
- * String to indicate flash data cookies
- *
- * @var string
- */
- public $flashdata_key = 'flash';
-
- /**
* Timezone to use for the current time
*
* @var string
*/
public $time_reference = 'local';
-
/**
* Session data
*
* @var array
*/
- public $userdata = array();
+ public $userdata = array();
/**
* Reference to CodeIgniter instance
@@ -178,31 +172,65 @@ class CI_Session {
public $now;
/**
- * Session Constructor
+ * Default userdata keys
*
- * The constructor runs the session routines automatically
- * whenever the class is instantiated.
+ * @var array
+ */
+ protected $defaults = array(
+ 'session_id' => NULL,
+ 'ip_address' => NULL,
+ 'user_agent' => NULL,
+ 'last_activity' => NULL
+ );
+
+ /**
+ * Data needs DB update flag
+ *
+ * @var bool
+ */
+ protected $data_dirty = FALSE;
+
+ /**
+ * Initialize session driver object
*
- * @param array
* @return void
*/
- public function __construct($params = array())
+ protected function initialize()
{
- log_message('debug', 'Session Class Initialized');
-
// 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_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
+ // manually via the $params array or via the config file
+ $prefs = array(
+ 'sess_encrypt_cookie',
+ 'sess_use_database',
+ 'sess_table_name',
+ 'sess_expiration',
+ 'sess_expire_on_close',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_cookie_name',
+ 'cookie_path',
+ 'cookie_domain',
+ 'cookie_secure',
+ 'cookie_httponly',
+ 'sess_time_to_update',
+ 'time_reference',
+ 'cookie_prefix',
+ 'encryption_key'
+ );
+
+ foreach ($prefs as $key)
{
- $this->$key = isset($params[$key]) ? $params[$key] : $this->CI->config->item($key);
+ $this->$key = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $this->CI->config->item($key);
}
if ($this->encryption_key === '')
{
- show_error('In order to use the Session class you are required to set an encryption key in your config file.');
+ show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.');
}
// Load the string helper so we can use the strip_slashes() function
@@ -214,14 +242,18 @@ class CI_Session {
$this->CI->load->library('encrypt');
}
- // Are we using a database? If so, load it
+ // Check for database
if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
{
+ // Load database driver
$this->CI->load->database();
+
+ // Register shutdown function
+ register_shutdown_function(array($this, '_update_db'));
}
- // 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
+ // 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
@@ -236,59 +268,135 @@ class CI_Session {
// 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())
+ if ( ! $this->_sess_read())
{
- $this->sess_create();
+ $this->_sess_create();
}
else
{
- $this->sess_update();
+ $this->_sess_update();
}
- // 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();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Write the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Check for database
+ if ($this->sess_use_database === TRUE)
+ {
+ // Mark custom data as dirty so we know to update the DB
+ $this->data_dirty = TRUE;
+ }
+
+ // Write the cookie
+ $this->_set_cookie();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Kill the session DB row
+ if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
+ {
+ $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id']));
+ $this->data_dirty = FALSE;
+ }
+
+ // Kill the cookie
+ $this->_setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
+ $this->cookie_path, $this->cookie_domain, 0);
+
+ // Kill session data
+ $this->userdata = array();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Check destroy flag
+ if ($destroy)
+ {
+ // Destroy old session and create new one
+ $this->sess_destroy();
+ $this->_sess_create();
+ }
+ else
+ {
+ // Just force an update to recreate the id
+ $this->_sess_update(TRUE);
+ }
+ }
- log_message('debug', 'Session routines successfully run');
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ return $this->userdata;
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Fetch the current session data if it exists
*
* @return bool
*/
- public function sess_read()
+ protected function _sess_read()
{
// Fetch the cookie
$session = $this->CI->input->cookie($this->sess_cookie_name);
- // No cookie? Goodbye cruel world!...
+ // No cookie? Goodbye cruel world!...
if ($session === NULL)
{
log_message('debug', 'A session cookie was not found.');
return FALSE;
}
- // Decrypt the cookie data
+ // Check for encryption
if ($this->sess_encrypt_cookie === TRUE)
{
+ // Decrypt the cookie data
$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
- $session = substr($session, 0, strlen($session)-32);
+ // Encryption was not used, so we need to check the md5 hash in the last 32 chars
+ $len = strlen($session)-32;
+ $hash = substr($session, $len);
+ $session = substr($session, 0, $len);
// Does the md5 hash match? This is to prevent manipulation of session data in userspace
- if ($hash !== md5($session.$this->encryption_key))
+ 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();
@@ -321,7 +429,8 @@ class CI_Session {
}
// Does the User Agent Match?
- if ($this->sess_match_useragent === TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
+ if ($this->sess_match_useragent === TRUE &&
+ trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
{
$this->sess_destroy();
return FALSE;
@@ -342,8 +451,19 @@ class CI_Session {
$this->CI->db->where('user_agent', $session['user_agent']);
}
+ // Is caching in effect? Turn it off
+ $db_cache = $this->CI->db->cache_on;
+ $this->CI->db->cache_off();
+
$query = $this->CI->db->limit(1)->get($this->sess_table_name);
+ // Was caching in effect?
+ if ($db_cache)
+ {
+ // Turn it back on
+ $this->CI->db->cache_on();
+ }
+
// No result? Kill it!
if ($query->num_rows() === 0)
{
@@ -351,7 +471,7 @@ class CI_Session {
return FALSE;
}
- // Is there custom data? If so, add it to the main session array
+ // Is there custom data? If so, add it to the main session array
$row = $query->row();
if ( ! empty($row->user_data))
{
@@ -359,424 +479,164 @@ class CI_Session {
if (is_array($custom_data))
{
- foreach ($custom_data as $key => $val)
- {
- $session[$key] = $val;
- }
+ $session = $session + $custom_data;
}
}
}
// Session is valid!
$this->userdata = $session;
- unset($session);
-
return TRUE;
}
- // --------------------------------------------------------------------
-
- /**
- * Write the session data
- *
- * @return void
- */
- public function sess_write()
- {
- // Are we saving custom data to the DB? If not, all we do is update the cookie
- if ($this->sess_use_database === FALSE)
- {
- $this->_set_cookie();
- return;
- }
-
- // set the custom userdata, the session data we will set in a second
- $custom_userdata = $this->userdata;
- $cookie_userdata = array();
-
- // 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
- // and set the session data while we're at it
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- unset($custom_userdata[$val]);
- $cookie_userdata[$val] = $this->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
- {
- // Serialize the custom data array so we can store it
- $custom_userdata = $this->_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));
-
- // 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);
- }
-
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Create a new session
*
* @return void
*/
- public function sess_create()
+ protected function _sess_create()
{
- $sessid = '';
- do
- {
- $sessid .= mt_rand(0, mt_getrandmax());
- }
- while (strlen($sessid) < 32);
-
- // To make the session ID even more secure we'll combine it with the user's IP
- $sessid .= $this->CI->input->ip_address();
-
+ // Initialize userdata
$this->userdata = array(
- 'session_id' => md5(uniqid($sessid, TRUE)),
- 'ip_address' => $this->CI->input->ip_address(),
- 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
- 'last_activity' => $this->now,
- 'user_data' => ''
- );
-
- // Save the data to the DB if needed
+ 'session_id' => $this->_make_sess_id(),
+ 'ip_address' => $this->CI->input->ip_address(),
+ 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
+ 'last_activity' => $this->now,
+ );
+
+ // Check for database
if ($this->sess_use_database === TRUE)
{
- $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
+ // Add empty user_data field and save the data to the DB
+ $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata);
}
// Write the cookie
$this->_set_cookie();
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Update an existing session
*
+ * @param bool Force update flag (default: false)
* @return void
*/
- public function sess_update()
+ protected function _sess_update($force = FALSE)
{
- // We only update the session every five minutes by default
- if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
+ // We only update the session every five minutes by default (unless forced)
+ if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
- // _set_cookie() will handle this for us if we aren't using database sessions
- // by pushing all userdata to the cookie.
- $cookie_data = NULL;
-
- /* Changing the session ID during an AJAX call causes problems,
- * so we'll only update our last_activity
- */
- if ($this->CI->input->is_ajax_request())
- {
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
- if ($this->sess_use_database === TRUE)
- {
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
- array('last_activity' => $this->userdata['last_activity']),
- array('session_id' => $this->userdata['session_id'])));
- }
-
- return $this->_set_cookie($cookie_data);
- }
+ // Update last activity to now
+ $this->userdata['last_activity'] = $this->now;
- // Save the old session id so we know which record to
- // update in the database if we need it
+ // Save the old session id so we know which DB record to update
$old_sessid = $this->userdata['session_id'];
- $new_sessid = '';
- do
+
+ // Changing the session ID during an AJAX call causes problems
+ if ( ! $this->CI->input->is_ajax_request())
{
- $new_sessid .= mt_rand(0, mt_getrandmax());
+ // Get new id
+ $this->userdata['session_id'] = $this->_make_sess_id();
}
- while (strlen($new_sessid) < 32);
-
- // 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 and update the session data array
- $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
+ // Check for database
if ($this->sess_use_database === TRUE)
{
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $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)));
+ // Update the session ID and last_activity field in the DB
+ $this->CI->db->update($this->sess_table_name, array(
+ 'last_activity' => $this->now,
+ 'session_id' => $this->userdata['session_id']
+ ), array('session_id' => $old_sessid));
}
// Write the cookie
- $this->_set_cookie($cookie_data);
+ $this->_set_cookie();
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
- * Destroy the current session
+ * Update database with current data
+ *
+ * This gets called from the shutdown function and also
+ * registered with PHP to run at the end of the request
+ * so it's guaranteed to update even when a fatal error
+ * occurs. The first call makes the update and clears the
+ * dirty flag so it won't happen twice.
*
* @return void
*/
- public function sess_destroy()
+ public function _update_db()
{
- // Kill the session DB row
- if ($this->sess_use_database === TRUE && 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_name,
- addslashes(serialize(array())),
- ($this->now - 31500000),
- $this->cookie_path,
- $this->cookie_domain,
- 0
+ // Check for database and dirty flag and unsaved
+ if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE)
+ {
+ // Set up activity and data fields to be set
+ // If we don't find custom data, user_data will remain an empty string
+ $set = array(
+ 'last_activity' => $this->userdata['last_activity'],
+ 'user_data' => ''
);
- // Kill session data
- $this->userdata = array();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch a specific item from the session array
- *
- * @param string
- * @return string
- */
- public function userdata($item)
- {
- return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
- }
+ // Get the custom userdata, leaving out the defaults
+ // (which get stored in the cookie)
+ $userdata = array_diff_key($this->userdata, $this->defaults);
- // --------------------------------------------------------------------
-
- /**
- * Fetch all session data
- *
- * @return array
- */
- public function all_userdata()
- {
- return $this->userdata;
- }
-
- // --------------------------------------------------------------------------
-
- /**
- * Fetch all flashdata
- *
- * @return array
- */
- public function all_flashdata()
- {
- $out = array();
-
- // loop through all userdata
- foreach ($this->all_userdata() as $key => $val)
- {
- // if it contains flashdata, add it
- if (strpos($key, 'flash:old:') !== FALSE)
+ // Did we find any custom data?
+ if ( ! empty($userdata))
{
- $out[$key] = $val;
+ // Serialize the custom data array so we can store it
+ $set['user_data'] = $this->_serialize($userdata);
}
- }
- return $out;
- }
- // --------------------------------------------------------------------
+ // Run the update query
+ // Any time we change the session id, it gets updated immediately,
+ // so our where clause below is always safe
+ $this->CI->db->update($this->sess_table_name, $set, array('session_id' => $this->userdata['session_id']));
- /**
- * Add or change data in the "userdata" array
- *
- * @param mixed
- * @param string
- * @return void
- */
- public function set_userdata($newdata = array(), $newval = '')
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- $this->userdata[$key] = $val;
- }
- }
-
- $this->sess_write();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Delete a session variable from the "userdata" array
- *
- * @param array
- * @return void
- */
- public function unset_userdata($newdata = array())
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => '');
- }
+ // Clear dirty flag to prevent double updates
+ $this->data_dirty = FALSE;
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- unset($this->userdata[$key]);
- }
+ log_message('debug', 'CI_Session Data Saved To DB');
}
-
- $this->sess_write();
}
// ------------------------------------------------------------------------
/**
- * Add or change flashdata, only available
- * until the next request
+ * Generate a new session id
*
- * @param mixed
- * @param string
- * @return void
+ * @return string Hashed session id
*/
- public function set_flashdata($newdata = array(), $newval = '')
+ protected function _make_sess_id()
{
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
+ $new_sessid = '';
+ do
{
- foreach ($newdata as $key => $val)
- {
- $this->set_userdata($this->flashdata_key.':new:'.$key, $val);
- }
+ $new_sessid .= mt_rand(0, mt_getrandmax());
}
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Keeps existing flashdata available to next request.
- *
- * @param string
- * @return void
- */
- public function keep_flashdata($key)
- {
- // '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
- $value = $this->userdata($this->flashdata_key.':old:'.$key);
-
- $this->set_userdata($this->flashdata_key.':new:'.$key, $value);
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Fetch a specific flashdata item from the session array
- *
- * @param string
- * @return string
- */
- public function flashdata($key)
- {
- return $this->userdata($this->flashdata_key.':old:'.$key);
- }
+ while (strlen($new_sessid) < 32);
- // ------------------------------------------------------------------------
+ // To make the session ID even more secure we'll combine it with the user's IP
+ $new_sessid .= $this->CI->input->ip_address();
- /**
- * Identifies flashdata as 'old' for removal
- * when _flashdata_sweep() runs.
- *
- * @return void
- */
- protected function _flashdata_mark()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $name => $value)
- {
- $parts = explode(':new:', $name);
- if (is_array($parts) && count($parts) === 2)
- {
- $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value);
- $this->unset_userdata($name);
- }
- }
+ // Turn it into a hash and return
+ return md5(uniqid($new_sessid, TRUE));
}
// ------------------------------------------------------------------------
/**
- * Removes all flashdata marked as 'old'
- *
- * @return void
- */
- protected function _flashdata_sweep()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $key => $value)
- {
- if (strpos($key, ':old:'))
- {
- $this->unset_userdata($key);
- }
- }
-
- }
-
- // --------------------------------------------------------------------
-
- /**
* Get the "now" time
*
- * @return string
+ * @return int Time
*/
protected function _get_time()
{
@@ -791,49 +651,57 @@ class CI_Session {
return mktime($hour, $minute, $second, $month, $day, $year);
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Write the session cookie
*
- * @param mixed
* @return void
*/
- protected function _set_cookie($cookie_data = NULL)
+ protected function _set_cookie()
{
- if (is_null($cookie_data))
- {
- $cookie_data = $this->userdata;
- }
+ // Get userdata (only defaults if database)
+ $cookie_data = ($this->sess_use_database === TRUE)
+ ? array_intersect_key($this->userdata, $this->defaults)
+ : $this->userdata;
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
- if ($this->sess_encrypt_cookie === TRUE)
- {
- $cookie_data = $this->CI->encrypt->encode($cookie_data);
- }
- else
- {
+ $cookie_data = ($this->sess_encrypt_cookie === TRUE)
+ ? $this->CI->encrypt->encode($cookie_data)
// if encryption is not used, we provide an md5 hash to prevent userside tampering
- $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
- }
+ : $cookie_data.md5($cookie_data.$this->encryption_key);
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
// Set the cookie
- setcookie(
- $this->sess_cookie_name,
- $cookie_data,
- $expire,
- $this->cookie_path,
- $this->cookie_domain,
- $this->cookie_secure,
- $this->cookie_httponly
- );
+ $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
+ $this->cookie_secure, $this->cookie_httponly);
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set a cookie with the system
+ *
+ * This abstraction of the setcookie call allows overriding for unit testing
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param int Expiration time
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param bool Secure connection flag
+ * @param bool HTTP protocol only flag
+ * @return void
+ */
+ protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE)
+ {
+ setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
+ }
+
+ // ------------------------------------------------------------------------
/**
* Serialize an array
@@ -841,8 +709,8 @@ class CI_Session {
* This function first converts any slashes found in the array to a temporary
* marker, so when it gets unserialized the slashes will be preserved
*
- * @param array
- * @return string
+ * @param mixed Data to serialize
+ * @return string Serialized data
*/
protected function _serialize($data)
{
@@ -854,16 +722,19 @@ class CI_Session {
{
$data = str_replace('\\', '{{slash}}', $data);
}
+
return serialize($data);
}
+ // ------------------------------------------------------------------------
+
/**
* Escape slashes
*
* This function converts any slashes found into a temporary marker
*
- * @param string
- * @param string
+ * @param string Value
+ * @param string Key
* @return void
*/
protected function _escape_slashes(&$val, $key)
@@ -874,7 +745,7 @@ class CI_Session {
}
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Unserialize
@@ -882,8 +753,8 @@ class CI_Session {
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
- * @param array
- * @return string
+ * @param mixed Data to unserialize
+ * @return mixed Unserialized data
*/
protected function _unserialize($data)
{
@@ -898,15 +769,15 @@ class CI_Session {
return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Unescape slashes
*
* This function converts any slash markers back into actual slashes
*
- * @param string
- * @param string
+ * @param string Value
+ * @param string Key
* @return void
*/
protected function _unescape_slashes(&$val, $key)
@@ -917,7 +788,7 @@ class CI_Session {
}
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Garbage collection
@@ -941,9 +812,7 @@ class CI_Session {
if ((mt_rand(0, $divisor) / $divisor) < $probability)
{
$expire = $this->now - $this->sess_expiration;
-
- $this->CI->db->where('last_activity < '.$expire);
- $this->CI->db->delete($this->sess_table_name);
+ $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
log_message('debug', 'Session garbage collection performed.');
}
@@ -951,5 +820,5 @@ class CI_Session {
}
-/* End of file Session.php */
-/* Location: ./system/libraries/Session.php */ \ No newline at end of file
+/* End of file Session_cookie.php */
+/* Location: ./system/libraries/Session/drivers/Session_cookie.php */ \ No newline at end of file
diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php
new file mode 100755
index 000000000..c97e15356
--- /dev/null
+++ b/system/libraries/Session/drivers/Session_native.php
@@ -0,0 +1,232 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 1.0
+ * @filesource
+ */
+
+/**
+ * Native PHP session management driver
+ *
+ * This is the driver that uses the native PHP $_SESSION array through the Session driver library.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ */
+class CI_Session_native extends CI_Session_driver {
+
+ /**
+ * Initialize session driver object
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Get config parameters
+ $config = array();
+ $CI =& get_instance();
+ $prefs = array(
+ 'sess_cookie_name',
+ 'sess_expire_on_close',
+ 'sess_expiration',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_time_to_update',
+ 'cookie_prefix',
+ 'cookie_path',
+ 'cookie_domain'
+ );
+
+ foreach ($prefs as $key)
+ {
+ $config[$key] = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $CI->config->item($key);
+ }
+
+ // Set session name, if specified
+ if ($config['sess_cookie_name'])
+ {
+ // Differentiate name from cookie driver with '_id' suffix
+ $name = $config['sess_cookie_name'].'_id';
+ if ($config['cookie_prefix'])
+ {
+ // Prepend cookie prefix
+ $name = $config['cookie_prefix'].$name;
+ }
+ session_name($name);
+ }
+
+ // Set expiration, path, and domain
+ $expire = 7200;
+ $path = '/';
+ $domain = '';
+ if ($config['sess_expiration'] !== FALSE)
+ {
+ // Default to 2 years if expiration is "0"
+ $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration'];
+ }
+
+ if ($config['cookie_path'])
+ {
+ // Use specified path
+ $path = $config['cookie_path'];
+ }
+
+ if ($config['cookie_domain'])
+ {
+ // Use specified domain
+ $domain = $config['cookie_domain'];
+ }
+ session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain);
+
+ // Start session
+ session_start();
+
+ // Check session expiration, ip, and agent
+ $now = time();
+ $destroy = FALSE;
+ if (isset($_SESSION['last_activity']) && ($_SESSION['last_activity'] + $expire) < $now)
+ {
+ // Expired - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_ip'] === TRUE && isset($_SESSION['ip_address'])
+ && $_SESSION['ip_address'] !== $CI->input->ip_address())
+ {
+ // IP doesn't match - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_useragent'] === TRUE && isset($_SESSION['user_agent'])
+ && $_SESSION['user_agent'] !== trim(substr($CI->input->user_agent(), 0, 50)))
+ {
+ // Agent doesn't match - destroy
+ $destroy = TRUE;
+ }
+
+ // Destroy expired or invalid session
+ if ($destroy)
+ {
+ // Clear old session and start new
+ $this->sess_destroy();
+ session_start();
+ }
+
+ // Check for update time
+ if ($config['sess_time_to_update'] && isset($_SESSION['last_activity'])
+ && ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now)
+ {
+ // Regenerate ID, but don't destroy session
+ $this->sess_regenerate(FALSE);
+ }
+
+ // Set activity time
+ $_SESSION['last_activity'] = $now;
+
+ // Set matching values as required
+ if ($config['sess_match_ip'] === TRUE && ! isset($_SESSION['ip_address']))
+ {
+ // Store user IP address
+ $_SESSION['ip_address'] = $CI->input->ip_address();
+ }
+
+ if ($config['sess_match_useragent'] === TRUE && ! isset($_SESSION['user_agent']))
+ {
+ // Store user agent string
+ $_SESSION['user_agent'] = trim(substr($CI->input->user_agent(), 0, 50));
+ }
+
+ // Make session ID available
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Save the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Nothing to do - changes to $_SESSION are automatically saved
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Cleanup session
+ $_SESSION = array();
+ $name = session_name();
+ if (isset($_COOKIE[$name]))
+ {
+ // Clear session cookie
+ $params = session_get_cookie_params();
+ setcookie($name, '', time() - 42000, $params['path'], $params['domain']);
+ unset($_COOKIE[$name]);
+ }
+ session_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: FALSE)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Just regenerate id, passing destroy flag
+ session_regenerate_id($destroy);
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ // Just return reference to $_SESSION
+ return $_SESSION;
+ }
+
+}
+
+/* End of file Session_native.php */
+/* Location: ./system/libraries/Session/drivers/Session_native.php */ \ No newline at end of file
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index cbb91c40a..a8aaa2088 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -1359,7 +1359,7 @@ class XML_RPC_Values extends CI_Xmlrpc
if ($type === $this->xmlrpcBoolean)
{
- $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
+ $val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
}
if ($this->mytype === 2)