blob: 52eeddbc441753d4103c8107ad741790eb27f112 [file] [log] [blame]
Andrey Andreev57ffbbb2011-12-25 04:48:47 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Darren Hillc4e266b2011-08-30 15:40:27 -04002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev57ffbbb2011-12-25 04:48:47 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
dchill42c5079de2012-07-23 10:53:47 -040012 * bundled with this package in the files license.txt / license.rst. It is
Derek Jonesf4a4bd82011-10-20 12:18:42 -050013 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
Darren Hillc4e266b2011-08-30 15:40:27 -040018 *
19 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Darren Hillc4e266b2011-08-30 15:40:27 -040023 * @link http://codeigniter.com
Derek Allard2067d1a2008-11-13 22:59:24 +000024 * @since Version 1.0
Darren Hillc4e266b2011-08-30 15:40:27 -040025 * @filesource
26 */
27
Darren Hillc4e266b2011-08-30 15:40:27 -040028/**
29 * Cookie-based session management driver
30 *
dchill423cecd822012-08-28 21:37:27 -040031 * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver.
Darren Hillc4e266b2011-08-30 15:40:27 -040032 *
33 * @package CodeIgniter
34 * @subpackage Libraries
35 * @category Sessions
Derek Jonesf4a4bd82011-10-20 12:18:42 -050036 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000037 * @link http://codeigniter.com/user_guide/libraries/sessions.html
Darren Hillc4e266b2011-08-30 15:40:27 -040038 */
Darren Hill5073a372011-08-31 13:54:19 -040039class CI_Session_cookie extends CI_Session_driver {
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020040 /**
Timothy Warren68f09812012-04-27 10:38:32 -040041 * Whether to encrypt the session cookie
42 *
43 * @var bool
44 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020045 public $sess_encrypt_cookie = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020046
Timothy Warren68f09812012-04-27 10:38:32 -040047 /**
48 * Whether to use to the database for session storage
49 *
50 * @var bool
51 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020052 public $sess_use_database = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020053
Timothy Warren68f09812012-04-27 10:38:32 -040054 /**
55 * Name of the database table in which to store sessions
56 *
57 * @var string
58 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020059 public $sess_table_name = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020060
Timothy Warren68f09812012-04-27 10:38:32 -040061 /**
62 * Length of time (in seconds) for sessions to expire
63 *
64 * @var int
65 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020066 public $sess_expiration = 7200;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020067
Timothy Warren68f09812012-04-27 10:38:32 -040068 /**
69 * Whether to kill session on close of browser window
70 *
71 * @var bool
72 */
dchill4226429202012-07-31 10:55:07 -040073 public $sess_expire_on_close = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020074
Timothy Warren68f09812012-04-27 10:38:32 -040075 /**
76 * Whether to match session on ip address
77 *
78 * @var bool
79 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020080 public $sess_match_ip = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020081
Timothy Warren68f09812012-04-27 10:38:32 -040082 /**
83 * Whether to match session on user-agent
84 *
85 * @var bool
86 */
dchill4226429202012-07-31 10:55:07 -040087 public $sess_match_useragent = TRUE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020088
Timothy Warren68f09812012-04-27 10:38:32 -040089 /**
90 * Name of session cookie
91 *
92 * @var string
93 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020094 public $sess_cookie_name = 'ci_session';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020095
Timothy Warren68f09812012-04-27 10:38:32 -040096 /**
97 * Session cookie prefix
98 *
99 * @var string
100 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200101 public $cookie_prefix = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200102
Timothy Warren68f09812012-04-27 10:38:32 -0400103 /**
104 * Session cookie path
105 *
106 * @var string
107 */
dchill4226429202012-07-31 10:55:07 -0400108 public $cookie_path = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200109
Timothy Warren68f09812012-04-27 10:38:32 -0400110 /**
111 * Session cookie domain
112 *
113 * @var string
114 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200115 public $cookie_domain = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200116
Timothy Warren68f09812012-04-27 10:38:32 -0400117 /**
118 * Whether to set the cookie only on HTTPS connections
119 *
120 * @var bool
121 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200122 public $cookie_secure = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200123
Timothy Warren68f09812012-04-27 10:38:32 -0400124 /**
125 * Whether cookie should be allowed only to be sent by the server
126 *
127 * @var bool
128 */
freewil4ad0fd82012-03-13 22:37:42 -0400129 public $cookie_httponly = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200130
Timothy Warren68f09812012-04-27 10:38:32 -0400131 /**
132 * Interval at which to update session
133 *
134 * @var int
135 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200136 public $sess_time_to_update = 300;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200137
Timothy Warren68f09812012-04-27 10:38:32 -0400138 /**
139 * Key with which to encrypt the session cookie
140 *
141 * @var string
142 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200143 public $encryption_key = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200144
Timothy Warren68f09812012-04-27 10:38:32 -0400145 /**
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300146 * Timezone to use for the current time
Timothy Warren68f09812012-04-27 10:38:32 -0400147 *
148 * @var string
149 */
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300150 public $time_reference = 'local';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200151
Timothy Warren68f09812012-04-27 10:38:32 -0400152 /**
153 * Session data
154 *
155 * @var array
156 */
dchill4226429202012-07-31 10:55:07 -0400157 public $userdata = array();
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200158
Timothy Warren68f09812012-04-27 10:38:32 -0400159 /**
160 * Reference to CodeIgniter instance
161 *
162 * @var object
163 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200164 public $CI;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200165
Timothy Warren68f09812012-04-27 10:38:32 -0400166 /**
167 * Current time
168 *
169 * @var int
170 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200171 public $now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400172
173 /**
dchill423cecd822012-08-28 21:37:27 -0400174 * Default userdata keys
175 *
176 * @var array
177 */
178 protected $defaults = array(
dchill4288b636b2012-08-29 08:47:05 -0400179 'session_id' => NULL,
180 'ip_address' => NULL,
181 'user_agent' => NULL,
182 'last_activity' => NULL
dchill423cecd822012-08-28 21:37:27 -0400183 );
184
185 /**
186 * Data needs DB update flag
187 *
188 * @var bool
189 */
190 protected $data_dirty = FALSE;
191
192 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400193 * Initialize session driver object
194 *
195 * @access protected
196 * @return void
197 */
198 protected function initialize()
199 {
200 // Set the super object to a local variable for use throughout the class
201 $this->CI =& get_instance();
202
203 // Set all the session preferences, which can either be set
dchill4242b77a92012-07-23 11:28:42 -0400204 // manually via the $params array or via the config file
dchill4226429202012-07-31 10:55:07 -0400205 $prefs = array(
206 'sess_encrypt_cookie',
207 'sess_use_database',
208 'sess_table_name',
209 'sess_expiration',
210 'sess_expire_on_close',
211 'sess_match_ip',
212 'sess_match_useragent',
213 'sess_cookie_name',
214 'cookie_path',
215 'cookie_domain',
216 'cookie_secure',
217 'cookie_httponly',
218 'sess_time_to_update',
219 'time_reference',
220 'cookie_prefix',
221 'encryption_key'
222 );
223 foreach ($prefs as $key)
Darren Hillc4e266b2011-08-30 15:40:27 -0400224 {
dchill42c5872252012-07-30 14:53:11 -0400225 $this->$key = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] :
dchill42c5079de2012-07-23 10:53:47 -0400226 $this->CI->config->item($key);
Darren Hillc4e266b2011-08-30 15:40:27 -0400227 }
228
Alex Bilbied261b1e2012-06-02 11:12:16 +0100229 if ($this->encryption_key === '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400230 {
dchill42c5872252012-07-30 14:53:11 -0400231 show_error('In order to use the Cookie Session driver you are required to set an encryption key '.
Darren Hillc4e266b2011-08-30 15:40:27 -0400232 'in your config file.');
233 }
234
235 // Load the string helper so we can use the strip_slashes() function
236 $this->CI->load->helper('string');
237
238 // Do we need encryption? If so, load the encryption class
Alex Bilbied261b1e2012-06-02 11:12:16 +0100239 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400240 {
241 $this->CI->load->library('encrypt');
242 }
243
dchill423cecd822012-08-28 21:37:27 -0400244 // Check for database
Alex Bilbied261b1e2012-06-02 11:12:16 +0100245 if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400246 {
dchill423cecd822012-08-28 21:37:27 -0400247 // Load database driver
Darren Hillc4e266b2011-08-30 15:40:27 -0400248 $this->CI->load->database();
dchill423cecd822012-08-28 21:37:27 -0400249
250 // Register shutdown function
251 register_shutdown_function(array($this, '_update_db'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400252 }
253
254 // Set the "now" time. Can either be GMT or server time, based on the config prefs.
255 // We use this to set the "last activity" time
256 $this->now = $this->_get_time();
257
258 // Set the session length. If the session expiration is
259 // set to zero we'll set the expiration two years from now.
Alex Bilbied261b1e2012-06-02 11:12:16 +0100260 if ($this->sess_expiration === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400261 {
262 $this->sess_expiration = (60*60*24*365*2);
263 }
264
265 // Set the cookie name
266 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
267
268 // Run the Session routine. If a session doesn't exist we'll
269 // create a new one. If it does, we'll update it.
270 if ( ! $this->_sess_read())
271 {
272 $this->_sess_create();
273 }
274 else
275 {
276 $this->_sess_update();
277 }
278
279 // Delete expired sessions if necessary
280 $this->_sess_gc();
281 }
282
283 /**
284 * Write the session data
285 *
286 * @return void
287 */
288 public function sess_save()
289 {
dchill423cecd822012-08-28 21:37:27 -0400290 // Check for database
dchill4288b636b2012-08-29 08:47:05 -0400291 if ($this->sess_use_database === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400292 {
dchill423cecd822012-08-28 21:37:27 -0400293 // Mark custom data as dirty so we know to update the DB
294 $this->data_dirty = TRUE;
Darren Hillc4e266b2011-08-30 15:40:27 -0400295 }
296
dchill423cecd822012-08-28 21:37:27 -0400297 // Write the cookie
298 $this->_set_cookie();
Darren Hillc4e266b2011-08-30 15:40:27 -0400299 }
300
301 /**
302 * Destroy the current session
303 *
304 * @return void
305 */
306 public function sess_destroy()
307 {
308 // Kill the session DB row
dchill42aee92652012-08-26 21:45:35 -0400309 if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400310 {
dchill423cecd822012-08-28 21:37:27 -0400311 $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id']));
dchill4297b0d832012-09-04 10:09:00 -0400312 $this->data_dirty = FALSE;
Darren Hillc4e266b2011-08-30 15:40:27 -0400313 }
314
315 // Kill the cookie
dchill42c5872252012-07-30 14:53:11 -0400316 $this->_setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
Darren Hillc4e266b2011-08-30 15:40:27 -0400317 $this->cookie_path, $this->cookie_domain, 0);
dchill42c5079de2012-07-23 10:53:47 -0400318
319 // Kill session data
320 $this->userdata = array();
Darren Hillc4e266b2011-08-30 15:40:27 -0400321 }
322
323 /**
324 * Regenerate the current session
325 *
326 * Regenerate the session id
327 *
328 * @param boolean Destroy session data flag (default: false)
329 * @return void
330 */
331 public function sess_regenerate($destroy = false)
332 {
333 // Check destroy flag
334 if ($destroy)
335 {
336 // Destroy old session and create new one
337 $this->sess_destroy();
338 $this->_sess_create();
339 }
340 else
341 {
342 // Just force an update to recreate the id
343 $this->_sess_update(true);
344 }
345 }
346
347 /**
348 * Get a reference to user data array
349 *
350 * @return array - Reference to userdata
351 */
352 public function &get_userdata()
353 {
354 // Return reference to array
355 return $this->userdata;
356 }
357
358 /**
359 * Fetch the current session data if it exists
360 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400361 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400362 * @return bool
363 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400364 protected function _sess_read()
Darren Hillc4e266b2011-08-30 15:40:27 -0400365 {
366 // Fetch the cookie
367 $session = $this->CI->input->cookie($this->sess_cookie_name);
368
369 // No cookie? Goodbye cruel world!...
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100370 if ($session === NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400371 {
372 log_message('debug', 'A session cookie was not found.');
373 return FALSE;
374 }
375
dchill423cecd822012-08-28 21:37:27 -0400376 // Check for encryption
Alex Bilbied261b1e2012-06-02 11:12:16 +0100377 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400378 {
dchill423cecd822012-08-28 21:37:27 -0400379 // Decrypt the cookie data
Darren Hillc4e266b2011-08-30 15:40:27 -0400380 $session = $this->CI->encrypt->decode($session);
381 }
382 else
383 {
dchill423cecd822012-08-28 21:37:27 -0400384 // Encryption was not used, so we need to check the md5 hash in the last 32 chars
385 $len = strlen($session)-32;
386 $hash = substr($session, $len);
387 $session = substr($session, 0, $len);
Darren Hillc4e266b2011-08-30 15:40:27 -0400388
389 // Does the md5 hash match? This is to prevent manipulation of session data in userspace
390 if ($hash !== md5($session.$this->encryption_key))
391 {
392 log_message('error', 'The session cookie data did not match what was expected. '.
393 'This could be a possible hacking attempt.');
394 $this->sess_destroy();
395 return FALSE;
396 }
397 }
398
399 // Unserialize the session array
400 $session = $this->_unserialize($session);
401
402 // Is the session data we unserialized an array with the correct format?
dchill42c5079de2012-07-23 10:53:47 -0400403 if ( ! is_array($session) || ! isset($session['session_id'], $session['ip_address'], $session['user_agent'],
404 $session['last_activity']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400405 {
406 $this->sess_destroy();
407 return FALSE;
408 }
409
410 // Is the session current?
Andrey Andreev7e087f52012-01-20 11:46:27 +0200411 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400412 {
413 $this->sess_destroy();
414 return FALSE;
415 }
416
Andrey Andreev7e087f52012-01-20 11:46:27 +0200417 // Does the IP match?
Alex Bilbied261b1e2012-06-02 11:12:16 +0100418 if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
Darren Hillc4e266b2011-08-30 15:40:27 -0400419 {
420 $this->sess_destroy();
421 return FALSE;
422 }
423
424 // Does the User Agent Match?
dchill42c5079de2012-07-23 10:53:47 -0400425 if ($this->sess_match_useragent === TRUE &&
426 trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
Darren Hillc4e266b2011-08-30 15:40:27 -0400427 {
428 $this->sess_destroy();
429 return FALSE;
430 }
431
432 // Is there a corresponding session in the DB?
433 if ($this->sess_use_database === TRUE)
434 {
435 $this->CI->db->where('session_id', $session['session_id']);
436
Alex Bilbied261b1e2012-06-02 11:12:16 +0100437 if ($this->sess_match_ip === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400438 {
439 $this->CI->db->where('ip_address', $session['ip_address']);
440 }
441
Alex Bilbied261b1e2012-06-02 11:12:16 +0100442 if ($this->sess_match_useragent === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400443 {
444 $this->CI->db->where('user_agent', $session['user_agent']);
445 }
446
dchill42cd436e92012-09-04 10:15:14 -0400447 // Is caching in effect? Turn it off
448 $db_cache = $this->CI->db->cache_on;
449 $this->CI->db->cache_off();
450
Timothy Warrenf1421922012-03-02 11:51:42 -0500451 $query = $this->CI->db->limit(1)->get($this->sess_table_name);
Darren Hillc4e266b2011-08-30 15:40:27 -0400452
dchill42cd436e92012-09-04 10:15:14 -0400453 // Was caching in effect?
454 if ($db_cache)
455 {
456 // Turn it back on
457 $this->CI->db->cache_on();
458 }
459
Darren Hillc4e266b2011-08-30 15:40:27 -0400460 // No result? Kill it!
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200461 if ($query->num_rows() === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400462 {
463 $this->sess_destroy();
464 return FALSE;
465 }
466
467 // Is there custom data? If so, add it to the main session array
468 $row = $query->row();
Andrey Andreev5036c9c2012-06-04 15:34:56 +0300469 if ( ! empty($row->user_data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400470 {
471 $custom_data = $this->_unserialize($row->user_data);
472
473 if (is_array($custom_data))
474 {
dchill423cecd822012-08-28 21:37:27 -0400475 $session = $session + $custom_data;
Darren Hillc4e266b2011-08-30 15:40:27 -0400476 }
477 }
478 }
479
480 // Session is valid!
481 $this->userdata = $session;
Darren Hillc4e266b2011-08-30 15:40:27 -0400482 return TRUE;
483 }
484
485 /**
486 * Create a new session
487 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400488 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400489 * @return void
490 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400491 protected function _sess_create()
Darren Hillc4e266b2011-08-30 15:40:27 -0400492 {
dchill423cecd822012-08-28 21:37:27 -0400493 // Initialize userdata
Derek Allard2067d1a2008-11-13 22:59:24 +0000494 $this->userdata = array(
dchill423cecd822012-08-28 21:37:27 -0400495 'session_id' => $this->_make_sess_id(),
dchill42c5079de2012-07-23 10:53:47 -0400496 'ip_address' => $this->CI->input->ip_address(),
497 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
498 'last_activity' => $this->now,
dchill42c5079de2012-07-23 10:53:47 -0400499 );
Darren Hillc4e266b2011-08-30 15:40:27 -0400500
dchill423cecd822012-08-28 21:37:27 -0400501 // Check for database
Darren Hillc4e266b2011-08-30 15:40:27 -0400502 if ($this->sess_use_database === TRUE)
503 {
dchill423cecd822012-08-28 21:37:27 -0400504 // Add empty user_data field and save the data to the DB
505 $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata);
Darren Hillc4e266b2011-08-30 15:40:27 -0400506 }
507
508 // Write the cookie
509 $this->_set_cookie();
510 }
511
512 /**
513 * Update an existing session
514 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400515 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400516 * @param boolean Force update flag (default: false)
517 * @return void
518 */
dchill42c5079de2012-07-23 10:53:47 -0400519 protected function _sess_update($force = FALSE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400520 {
521 // We only update the session every five minutes by default (unless forced)
dchill4277ee3fd2012-07-24 11:50:01 -0400522 if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400523 {
524 return;
525 }
526
dchill423cecd822012-08-28 21:37:27 -0400527 // Update last activity to now
528 $this->userdata['last_activity'] = $this->now;
Andrey Andreev9c622f32012-01-19 14:12:54 +0200529
dchill423cecd822012-08-28 21:37:27 -0400530 // Save the old session id so we know which DB record to update
531 $old_sessid = $this->userdata['session_id'];
532
533 // Changing the session ID during an AJAX call causes problems
534 if ( ! $this->CI->input->is_ajax_request())
Andrey Andreev9c622f32012-01-19 14:12:54 +0200535 {
dchill423cecd822012-08-28 21:37:27 -0400536 // Get new id
537 $this->userdata['session_id'] = $this->_make_sess_id();
Andrey Andreev9c622f32012-01-19 14:12:54 +0200538 }
539
dchill423cecd822012-08-28 21:37:27 -0400540 // Check for database
541 if ($this->sess_use_database === TRUE)
542 {
543 // Update the session ID and last_activity field in the DB
544 $this->CI->db->update($this->sess_table_name, array(
545 'last_activity' => $this->now,
546 'session_id' => $this->userdata['session_id']
547 ), array('session_id' => $old_sessid));
548 }
549
550 // Write the cookie
551 $this->_set_cookie();
552 }
553
554 /**
555 * Update database with current data
556 *
557 * This gets called from the shutdown function and also
558 * registered with PHP to run at the end of the request
559 * so it's guaranteed to update even when a fatal error
560 * occurs. The first call makes the update and clears the
561 * dirty flag so it won't happen twice.
562 */
563 public function _update_db()
564 {
565 // Check for database and dirty flag and unsaved
566 if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE)
567 {
568 // Set up activity and data fields to be set
569 // If we don't find custom data, user_data will remain an empty string
570 $set = array(
571 'last_activity' => $this->userdata['last_activity'],
572 'user_data' => ''
573 );
574
575 // Get the custom userdata, leaving out the defaults
576 // (which get stored in the cookie)
577 $userdata = array_diff_key($this->userdata, $this->defaults);
578
579 // Did we find any custom data?
580 if ( ! empty($userdata))
581 {
582 // Serialize the custom data array so we can store it
583 $set['user_data'] = $this->_serialize($userdata);
584 }
585
586 // Run the update query
587 // Any time we change the session id, it gets updated immediately,
588 // so our where clause below is always safe
589 $this->CI->db->update($this->sess_table_name, $set, array('session_id' => $this->userdata['session_id']));
590
591 // Clear dirty flag to prevent double updates
592 $this->data_dirty = FALSE;
593
594 log_message('debug', 'CI_Session Data Saved To DB');
595 }
596 }
597
598 /**
599 * Generate a new session id
600 *
601 * @return string Hashed session id
602 */
603 protected function _make_sess_id()
604 {
Darren Hillc4e266b2011-08-30 15:40:27 -0400605 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200606 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400607 {
608 $new_sessid .= mt_rand(0, mt_getrandmax());
609 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200610 while (strlen($new_sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400611
612 // To make the session ID even more secure we'll combine it with the user's IP
613 $new_sessid .= $this->CI->input->ip_address();
614
dchill423cecd822012-08-28 21:37:27 -0400615 // Turn it into a hash and return
616 return md5(uniqid($new_sessid, TRUE));
Darren Hillc4e266b2011-08-30 15:40:27 -0400617 }
618
619 /**
620 * Get the "now" time
621 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400622 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400623 * @return int Time
Darren Hillc4e266b2011-08-30 15:40:27 -0400624 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400625 protected function _get_time()
Darren Hillc4e266b2011-08-30 15:40:27 -0400626 {
dchill42c5079de2012-07-23 10:53:47 -0400627 if ($this->time_reference === 'local' || $this->time_reference === date_default_timezone_get())
Darren Hillc4e266b2011-08-30 15:40:27 -0400628 {
Iban Eguiafeb14da2012-06-12 16:09:36 +0200629 return time();
Darren Hillc4e266b2011-08-30 15:40:27 -0400630 }
631
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300632 $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
Iban Eguiafeb14da2012-06-12 16:09:36 +0200633 sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
634
635 return mktime($hour, $minute, $second, $month, $day, $year);
Darren Hillc4e266b2011-08-30 15:40:27 -0400636 }
637
638 /**
639 * Write the session cookie
640 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400641 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400642 * @return void
643 */
dchill423cecd822012-08-28 21:37:27 -0400644 protected function _set_cookie()
Darren Hillc4e266b2011-08-30 15:40:27 -0400645 {
dchill423cecd822012-08-28 21:37:27 -0400646 // Get userdata (only defaults if database)
647 if ($this->sess_use_database === TRUE)
648 {
649 $cookie_data = array_intersect_key($this->userdata, $this->defaults);
650 }
651 else
Darren Hillc4e266b2011-08-30 15:40:27 -0400652 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 $cookie_data = $this->userdata;
Darren Hillc4e266b2011-08-30 15:40:27 -0400654 }
655
656 // Serialize the userdata for the cookie
657 $cookie_data = $this->_serialize($cookie_data);
658
Alex Bilbied261b1e2012-06-02 11:12:16 +0100659 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400660 {
661 $cookie_data = $this->CI->encrypt->encode($cookie_data);
662 }
663 else
664 {
665 // if encryption is not used, we provide an md5 hash to prevent userside tampering
666 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
667 }
668
669 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
670
671 // Set the cookie
dchill42c5872252012-07-30 14:53:11 -0400672 $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
dchill42c5079de2012-07-23 10:53:47 -0400673 $this->cookie_secure, $this->cookie_httponly);
Darren Hillc4e266b2011-08-30 15:40:27 -0400674 }
675
676 /**
dchill42c5872252012-07-30 14:53:11 -0400677 * Set a cookie with the system
678 *
679 * This abstraction of the setcookie call allows overriding for unit testing
680 *
681 * @access protected
682 * @param string Cookie name
683 * @param string Cookie value
684 * @param int Expiration time
685 * @param string Cookie path
686 * @param string Cookie domain
687 * @param bool Secure connection flag
688 * @param bool HTTP protocol only flag
689 * @return void
690 */
691 protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = false,
692 $httponly = false)
693 {
694 // Set the cookie
695 setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
696 }
697
698 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400699 * Serialize an array
700 *
701 * This function first converts any slashes found in the array to a temporary
702 * marker, so when it gets unserialized the slashes will be preserved
703 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400704 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400705 * @param mixed Data to serialize
dchill42c5079de2012-07-23 10:53:47 -0400706 * @return string Serialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400707 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400708 protected function _serialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400709 {
710 if (is_array($data))
711 {
Chris Muench95933492011-10-16 14:14:04 -0400712 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400713 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200714 elseif (is_string($data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400715 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200716 $data = str_replace('\\', '{{slash}}', $data);
Darren Hillc4e266b2011-08-30 15:40:27 -0400717 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400718 return serialize($data);
719 }
720
721 /**
Chris Muench95933492011-10-16 14:14:04 -0400722 * Escape slashes
723 *
724 * This function converts any slashes found into a temporary marker
725 *
dchill42c5079de2012-07-23 10:53:47 -0400726 * @access protected
727 * @param string Value
728 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200729 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400730 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200731 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400732 {
733 if (is_string($val))
734 {
735 $val = str_replace('\\', '{{slash}}', $val);
736 }
737 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000738
Derek Allard2067d1a2008-11-13 22:59:24 +0000739 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400740 * Unserialize
741 *
742 * This function unserializes a data string, then converts any
743 * temporary slash markers back to actual slashes
744 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400745 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400746 * @param mixed Data to unserialize
747 * @return mixed Unserialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400748 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400749 protected function _unserialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400750 {
Andrey Andreev6b831232012-03-06 11:16:57 +0200751 $data = @unserialize(strip_slashes(trim($data)));
Darren Hillc4e266b2011-08-30 15:40:27 -0400752
753 if (is_array($data))
754 {
Chris Muench95933492011-10-16 14:14:04 -0400755 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400756 return $data;
757 }
758
Andrey Andreev6b831232012-03-06 11:16:57 +0200759 return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000760 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200761
Chris Muench95933492011-10-16 14:14:04 -0400762 /**
763 * Unescape slashes
764 *
765 * This function converts any slash markers back into actual slashes
766 *
dchill42c5079de2012-07-23 10:53:47 -0400767 * @access protected
768 * @param string Value
769 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200770 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400771 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200772 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400773 {
Chris Muench3e414f92011-10-16 23:03:55 -0400774 if (is_string($val))
775 {
776 $val= str_replace('{{slash}}', '\\', $val);
777 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400778 }
779
780 /**
781 * Garbage collection
782 *
783 * This deletes expired session rows from database
784 * if the probability percentage is met
785 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400786 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400787 * @return void
788 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400789 protected function _sess_gc()
Darren Hillc4e266b2011-08-30 15:40:27 -0400790 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100791 if ($this->sess_use_database !== TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400792 {
793 return;
794 }
795
Christopher Guiney7a142862012-06-29 20:34:28 -0700796 $probability = ini_get('session.gc_probability');
797 $divisor = ini_get('session.gc_divisor');
798
Darren Hillc4e266b2011-08-30 15:40:27 -0400799 srand(time());
Christopher Guiney7a142862012-06-29 20:34:28 -0700800 if ((mt_rand(0, $divisor) / $divisor) < $probability)
Darren Hillc4e266b2011-08-30 15:40:27 -0400801 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000802 $expire = $this->now - $this->sess_expiration;
dchill423cecd822012-08-28 21:37:27 -0400803 $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
Darren Hillc4e266b2011-08-30 15:40:27 -0400804
805 log_message('debug', 'Session garbage collection performed.');
806 }
807 }
808}
Darren Hillc4e266b2011-08-30 15:40:27 -0400809
810/* End of file Session_cookie.php */
Darren Hill5073a372011-08-31 13:54:19 -0400811/* Location: ./system/libraries/Session/drivers/Session_cookie.php */