blob: 057e5a1d1c520816475882d13f39f1fcf100e9c9 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
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
Andrey Andreevc5536aa2012-11-01 17:33:58 +020012 * 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
Andrey Andreev80500af2013-01-01 08:16:53 +020021 * @copyright Copyright (c) 2008 - 2013, 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 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Darren Hillc4e266b2011-08-30 15:40:27 -040028
Darren Hillc4e266b2011-08-30 15:40:27 -040029/**
30 * Cookie-based session management driver
31 *
dchill423cecd822012-08-28 21:37:27 -040032 * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver.
Darren Hillc4e266b2011-08-30 15:40:27 -040033 *
34 * @package CodeIgniter
35 * @subpackage Libraries
36 * @category Sessions
Derek Jonesf4a4bd82011-10-20 12:18:42 -050037 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000038 * @link http://codeigniter.com/user_guide/libraries/sessions.html
Darren Hillc4e266b2011-08-30 15:40:27 -040039 */
Darren Hill5073a372011-08-31 13:54:19 -040040class CI_Session_cookie extends CI_Session_driver {
Andrey Andreev9ffcee62012-09-05 16:25:16 +030041
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020042 /**
Timothy Warren68f09812012-04-27 10:38:32 -040043 * Whether to encrypt the session cookie
44 *
45 * @var bool
46 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020047 public $sess_encrypt_cookie = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020048
Timothy Warren68f09812012-04-27 10:38:32 -040049 /**
50 * Whether to use to the database for session storage
51 *
52 * @var bool
53 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020054 public $sess_use_database = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020055
Timothy Warren68f09812012-04-27 10:38:32 -040056 /**
57 * Name of the database table in which to store sessions
58 *
59 * @var string
60 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020061 public $sess_table_name = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020062
Timothy Warren68f09812012-04-27 10:38:32 -040063 /**
64 * Length of time (in seconds) for sessions to expire
65 *
66 * @var int
67 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020068 public $sess_expiration = 7200;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020069
Timothy Warren68f09812012-04-27 10:38:32 -040070 /**
71 * Whether to kill session on close of browser window
72 *
73 * @var bool
74 */
dchill4226429202012-07-31 10:55:07 -040075 public $sess_expire_on_close = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020076
Timothy Warren68f09812012-04-27 10:38:32 -040077 /**
78 * Whether to match session on ip address
79 *
80 * @var bool
81 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020082 public $sess_match_ip = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020083
Timothy Warren68f09812012-04-27 10:38:32 -040084 /**
85 * Whether to match session on user-agent
86 *
87 * @var bool
88 */
dchill4226429202012-07-31 10:55:07 -040089 public $sess_match_useragent = TRUE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020090
Timothy Warren68f09812012-04-27 10:38:32 -040091 /**
92 * Name of session cookie
93 *
94 * @var string
95 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020096 public $sess_cookie_name = 'ci_session';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020097
Timothy Warren68f09812012-04-27 10:38:32 -040098 /**
99 * Session cookie prefix
100 *
101 * @var string
102 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200103 public $cookie_prefix = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200104
Timothy Warren68f09812012-04-27 10:38:32 -0400105 /**
106 * Session cookie path
107 *
108 * @var string
109 */
dchill4226429202012-07-31 10:55:07 -0400110 public $cookie_path = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200111
Timothy Warren68f09812012-04-27 10:38:32 -0400112 /**
113 * Session cookie domain
114 *
115 * @var string
116 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200117 public $cookie_domain = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200118
Timothy Warren68f09812012-04-27 10:38:32 -0400119 /**
120 * Whether to set the cookie only on HTTPS connections
121 *
122 * @var bool
123 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200124 public $cookie_secure = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200125
Timothy Warren68f09812012-04-27 10:38:32 -0400126 /**
127 * Whether cookie should be allowed only to be sent by the server
128 *
129 * @var bool
130 */
freewil4ad0fd82012-03-13 22:37:42 -0400131 public $cookie_httponly = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200132
Timothy Warren68f09812012-04-27 10:38:32 -0400133 /**
134 * Interval at which to update session
135 *
136 * @var int
137 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200138 public $sess_time_to_update = 300;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200139
Timothy Warren68f09812012-04-27 10:38:32 -0400140 /**
141 * Key with which to encrypt the session cookie
142 *
143 * @var string
144 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200145 public $encryption_key = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200146
Timothy Warren68f09812012-04-27 10:38:32 -0400147 /**
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300148 * Timezone to use for the current time
Timothy Warren68f09812012-04-27 10:38:32 -0400149 *
150 * @var string
151 */
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300152 public $time_reference = 'local';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200153
Timothy Warren68f09812012-04-27 10:38:32 -0400154 /**
155 * Session data
156 *
157 * @var array
158 */
dchill4226429202012-07-31 10:55:07 -0400159 public $userdata = array();
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200160
Timothy Warren68f09812012-04-27 10:38:32 -0400161 /**
Timothy Warren68f09812012-04-27 10:38:32 -0400162 * Current time
163 *
164 * @var int
165 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200166 public $now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400167
168 /**
dchill423cecd822012-08-28 21:37:27 -0400169 * Default userdata keys
170 *
171 * @var array
172 */
173 protected $defaults = array(
dchill4288b636b2012-08-29 08:47:05 -0400174 'session_id' => NULL,
175 'ip_address' => NULL,
176 'user_agent' => NULL,
177 'last_activity' => NULL
dchill423cecd822012-08-28 21:37:27 -0400178 );
179
180 /**
181 * Data needs DB update flag
182 *
183 * @var bool
184 */
185 protected $data_dirty = FALSE;
186
187 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400188 * Initialize session driver object
189 *
Darren Hillc4e266b2011-08-30 15:40:27 -0400190 * @return void
191 */
192 protected function initialize()
193 {
Darren Hillc4e266b2011-08-30 15:40:27 -0400194 // Set all the session preferences, which can either be set
dchill4242b77a92012-07-23 11:28:42 -0400195 // manually via the $params array or via the config file
dchill4226429202012-07-31 10:55:07 -0400196 $prefs = array(
197 'sess_encrypt_cookie',
198 'sess_use_database',
199 'sess_table_name',
200 'sess_expiration',
201 'sess_expire_on_close',
202 'sess_match_ip',
203 'sess_match_useragent',
204 'sess_cookie_name',
205 'cookie_path',
206 'cookie_domain',
207 'cookie_secure',
208 'cookie_httponly',
209 'sess_time_to_update',
210 'time_reference',
211 'cookie_prefix',
212 'encryption_key'
213 );
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300214
dchill4226429202012-07-31 10:55:07 -0400215 foreach ($prefs as $key)
Darren Hillc4e266b2011-08-30 15:40:27 -0400216 {
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300217 $this->$key = isset($this->_parent->params[$key])
218 ? $this->_parent->params[$key]
219 : $this->CI->config->item($key);
Darren Hillc4e266b2011-08-30 15:40:27 -0400220 }
221
Andrey Andreev4abd0942012-11-26 12:13:59 +0200222 if (empty($this->encryption_key))
Darren Hillc4e266b2011-08-30 15:40:27 -0400223 {
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300224 show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.');
Darren Hillc4e266b2011-08-30 15:40:27 -0400225 }
226
Darren Hillc4e266b2011-08-30 15:40:27 -0400227 // Do we need encryption? If so, load the encryption class
Alex Bilbied261b1e2012-06-02 11:12:16 +0100228 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400229 {
230 $this->CI->load->library('encrypt');
231 }
232
dchill423cecd822012-08-28 21:37:27 -0400233 // Check for database
Alex Bilbied261b1e2012-06-02 11:12:16 +0100234 if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400235 {
dchill423cecd822012-08-28 21:37:27 -0400236 // Load database driver
Darren Hillc4e266b2011-08-30 15:40:27 -0400237 $this->CI->load->database();
dchill423cecd822012-08-28 21:37:27 -0400238
239 // Register shutdown function
240 register_shutdown_function(array($this, '_update_db'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400241 }
242
243 // Set the "now" time. Can either be GMT or server time, based on the config prefs.
244 // We use this to set the "last activity" time
245 $this->now = $this->_get_time();
246
247 // Set the session length. If the session expiration is
248 // set to zero we'll set the expiration two years from now.
Alex Bilbied261b1e2012-06-02 11:12:16 +0100249 if ($this->sess_expiration === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400250 {
251 $this->sess_expiration = (60*60*24*365*2);
252 }
253
254 // Set the cookie name
255 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
256
257 // Run the Session routine. If a session doesn't exist we'll
258 // create a new one. If it does, we'll update it.
259 if ( ! $this->_sess_read())
260 {
261 $this->_sess_create();
262 }
263 else
264 {
265 $this->_sess_update();
266 }
267
268 // Delete expired sessions if necessary
269 $this->_sess_gc();
270 }
271
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300272 // ------------------------------------------------------------------------
273
Darren Hillc4e266b2011-08-30 15:40:27 -0400274 /**
275 * Write the session data
276 *
277 * @return void
278 */
279 public function sess_save()
280 {
dchill423cecd822012-08-28 21:37:27 -0400281 // Check for database
dchill4288b636b2012-08-29 08:47:05 -0400282 if ($this->sess_use_database === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400283 {
dchill423cecd822012-08-28 21:37:27 -0400284 // Mark custom data as dirty so we know to update the DB
285 $this->data_dirty = TRUE;
Darren Hillc4e266b2011-08-30 15:40:27 -0400286 }
287
dchill423cecd822012-08-28 21:37:27 -0400288 // Write the cookie
289 $this->_set_cookie();
Darren Hillc4e266b2011-08-30 15:40:27 -0400290 }
291
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300292 // ------------------------------------------------------------------------
293
Darren Hillc4e266b2011-08-30 15:40:27 -0400294 /**
295 * Destroy the current session
296 *
297 * @return void
298 */
299 public function sess_destroy()
300 {
301 // Kill the session DB row
dchill42aee92652012-08-26 21:45:35 -0400302 if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400303 {
dchill423cecd822012-08-28 21:37:27 -0400304 $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id']));
dchill4297b0d832012-09-04 10:09:00 -0400305 $this->data_dirty = FALSE;
Darren Hillc4e266b2011-08-30 15:40:27 -0400306 }
307
308 // Kill the cookie
Andrey Andreevcf264e02012-10-18 16:14:51 +0300309 $this->_setcookie($this->sess_cookie_name, '', ($this->now - 31500000),
Darren Hillc4e266b2011-08-30 15:40:27 -0400310 $this->cookie_path, $this->cookie_domain, 0);
dchill42c5079de2012-07-23 10:53:47 -0400311
312 // Kill session data
313 $this->userdata = array();
Darren Hillc4e266b2011-08-30 15:40:27 -0400314 }
315
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300316 // ------------------------------------------------------------------------
317
Darren Hillc4e266b2011-08-30 15:40:27 -0400318 /**
319 * Regenerate the current session
320 *
321 * Regenerate the session id
322 *
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300323 * @param bool Destroy session data flag (default: false)
Darren Hillc4e266b2011-08-30 15:40:27 -0400324 * @return void
325 */
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300326 public function sess_regenerate($destroy = FALSE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400327 {
328 // Check destroy flag
329 if ($destroy)
330 {
331 // Destroy old session and create new one
332 $this->sess_destroy();
333 $this->_sess_create();
334 }
335 else
336 {
337 // Just force an update to recreate the id
Andrey Andreev3f3f1352012-09-05 16:39:28 +0300338 $this->_sess_update(TRUE);
Darren Hillc4e266b2011-08-30 15:40:27 -0400339 }
340 }
341
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300342 // ------------------------------------------------------------------------
343
Darren Hillc4e266b2011-08-30 15:40:27 -0400344 /**
345 * Get a reference to user data array
346 *
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300347 * @return array Reference to userdata
Darren Hillc4e266b2011-08-30 15:40:27 -0400348 */
349 public function &get_userdata()
350 {
Darren Hillc4e266b2011-08-30 15:40:27 -0400351 return $this->userdata;
352 }
353
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300354 // ------------------------------------------------------------------------
355
Darren Hillc4e266b2011-08-30 15:40:27 -0400356 /**
357 * Fetch the current session data if it exists
358 *
Darren Hillc4e266b2011-08-30 15:40:27 -0400359 * @return bool
360 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400361 protected function _sess_read()
Darren Hillc4e266b2011-08-30 15:40:27 -0400362 {
363 // Fetch the cookie
364 $session = $this->CI->input->cookie($this->sess_cookie_name);
365
366 // No cookie? Goodbye cruel world!...
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100367 if ($session === NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400368 {
369 log_message('debug', 'A session cookie was not found.');
370 return FALSE;
371 }
372
Pascal Krietef69f0e82012-10-16 11:54:49 -0400373 $len = strlen($session) - 40;
374
375 if ($len < 0)
376 {
377 log_message('debug', 'The session cookie was not signed.');
378 return FALSE;
379 }
380
381 // Check cookie authentication
382 $hmac = substr($session, $len);
383 $session = substr($session, 0, $len);
384
385 if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key))
386 {
Pascal Kriete28dc2022012-10-17 11:27:29 -0400387 log_message('error', 'The session cookie data did not match what was expected.');
Pascal Krietef69f0e82012-10-16 11:54:49 -0400388 $this->sess_destroy();
389 return FALSE;
390 }
391
dchill423cecd822012-08-28 21:37:27 -0400392 // Check for encryption
Alex Bilbied261b1e2012-06-02 11:12:16 +0100393 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400394 {
dchill423cecd822012-08-28 21:37:27 -0400395 // Decrypt the cookie data
Darren Hillc4e266b2011-08-30 15:40:27 -0400396 $session = $this->CI->encrypt->decode($session);
397 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400398
399 // Unserialize the session array
400 $session = $this->_unserialize($session);
401
402 // Is the session data we unserialized an array with the correct format?
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300403 if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400404 {
405 $this->sess_destroy();
406 return FALSE;
407 }
408
409 // Is the session current?
Andrey Andreev02117682012-10-15 11:12:37 +0300410 if (($session['last_activity'] + $this->sess_expiration) < $this->now OR $session['last_activity'] > $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400411 {
412 $this->sess_destroy();
413 return FALSE;
414 }
415
Andrey Andreev7e087f52012-01-20 11:46:27 +0200416 // Does the IP match?
Alex Bilbied261b1e2012-06-02 11:12:16 +0100417 if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
Darren Hillc4e266b2011-08-30 15:40:27 -0400418 {
419 $this->sess_destroy();
420 return FALSE;
421 }
422
423 // Does the User Agent Match?
dchill42c5079de2012-07-23 10:53:47 -0400424 if ($this->sess_match_useragent === TRUE &&
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300425 trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
Darren Hillc4e266b2011-08-30 15:40:27 -0400426 {
427 $this->sess_destroy();
428 return FALSE;
429 }
430
431 // Is there a corresponding session in the DB?
432 if ($this->sess_use_database === TRUE)
433 {
434 $this->CI->db->where('session_id', $session['session_id']);
435
Alex Bilbied261b1e2012-06-02 11:12:16 +0100436 if ($this->sess_match_ip === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400437 {
438 $this->CI->db->where('ip_address', $session['ip_address']);
439 }
440
Alex Bilbied261b1e2012-06-02 11:12:16 +0100441 if ($this->sess_match_useragent === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400442 {
443 $this->CI->db->where('user_agent', $session['user_agent']);
444 }
445
dchill42cd436e92012-09-04 10:15:14 -0400446 // Is caching in effect? Turn it off
447 $db_cache = $this->CI->db->cache_on;
448 $this->CI->db->cache_off();
449
Timothy Warrenf1421922012-03-02 11:51:42 -0500450 $query = $this->CI->db->limit(1)->get($this->sess_table_name);
Darren Hillc4e266b2011-08-30 15:40:27 -0400451
dchill42cd436e92012-09-04 10:15:14 -0400452 // Was caching in effect?
453 if ($db_cache)
454 {
455 // Turn it back on
456 $this->CI->db->cache_on();
457 }
458
Darren Hillc4e266b2011-08-30 15:40:27 -0400459 // No result? Kill it!
Andrey Andreeva8e34ac2012-12-17 10:39:32 +0200460 if (empty($query) OR $query->num_rows() === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400461 {
462 $this->sess_destroy();
463 return FALSE;
464 }
465
466 // Is there custom data? If so, add it to the main session array
467 $row = $query->row();
Andrey Andreev5036c9c2012-06-04 15:34:56 +0300468 if ( ! empty($row->user_data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400469 {
470 $custom_data = $this->_unserialize($row->user_data);
471
472 if (is_array($custom_data))
473 {
dchill423cecd822012-08-28 21:37:27 -0400474 $session = $session + $custom_data;
Darren Hillc4e266b2011-08-30 15:40:27 -0400475 }
476 }
477 }
478
479 // Session is valid!
480 $this->userdata = $session;
Darren Hillc4e266b2011-08-30 15:40:27 -0400481 return TRUE;
482 }
483
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300484 // ------------------------------------------------------------------------
485
Darren Hillc4e266b2011-08-30 15:40:27 -0400486 /**
487 * Create a new session
488 *
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
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300512 // ------------------------------------------------------------------------
513
Darren Hillc4e266b2011-08-30 15:40:27 -0400514 /**
515 * Update an existing session
516 *
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300517 * @param bool Force update flag (default: false)
Darren Hillc4e266b2011-08-30 15:40:27 -0400518 * @return void
519 */
dchill42c5079de2012-07-23 10:53:47 -0400520 protected function _sess_update($force = FALSE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400521 {
522 // We only update the session every five minutes by default (unless forced)
dchill4277ee3fd2012-07-24 11:50:01 -0400523 if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400524 {
525 return;
526 }
527
dchill423cecd822012-08-28 21:37:27 -0400528 // Update last activity to now
529 $this->userdata['last_activity'] = $this->now;
Andrey Andreev9c622f32012-01-19 14:12:54 +0200530
dchill423cecd822012-08-28 21:37:27 -0400531 // Save the old session id so we know which DB record to update
532 $old_sessid = $this->userdata['session_id'];
533
534 // Changing the session ID during an AJAX call causes problems
535 if ( ! $this->CI->input->is_ajax_request())
Andrey Andreev9c622f32012-01-19 14:12:54 +0200536 {
dchill423cecd822012-08-28 21:37:27 -0400537 // Get new id
538 $this->userdata['session_id'] = $this->_make_sess_id();
Andrey Andreev9c622f32012-01-19 14:12:54 +0200539 }
540
dchill423cecd822012-08-28 21:37:27 -0400541 // Check for database
542 if ($this->sess_use_database === TRUE)
543 {
Andrey Andreeve2afc882012-11-01 01:35:34 +0200544 $this->CI->db->where('session_id', $old_sessid);
545
546 if ($this->sess_match_ip === TRUE)
547 {
548 $this->CI->db->where('ip_address', $this->CI->input->ip_address());
549 }
550
551 if ($this->sess_match_useragent === TRUE)
552 {
553 $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120)));
554 }
555
dchill423cecd822012-08-28 21:37:27 -0400556 // Update the session ID and last_activity field in the DB
Andrey Andreeve2afc882012-11-01 01:35:34 +0200557 $this->CI->db->update($this->sess_table_name,
558 array(
559 'last_activity' => $this->now,
560 'session_id' => $this->userdata['session_id']
561 )
562 );
dchill423cecd822012-08-28 21:37:27 -0400563 }
564
565 // Write the cookie
566 $this->_set_cookie();
567 }
568
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300569 // ------------------------------------------------------------------------
570
dchill423cecd822012-08-28 21:37:27 -0400571 /**
572 * Update database with current data
573 *
574 * This gets called from the shutdown function and also
575 * registered with PHP to run at the end of the request
576 * so it's guaranteed to update even when a fatal error
577 * occurs. The first call makes the update and clears the
578 * dirty flag so it won't happen twice.
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300579 *
580 * @return void
dchill423cecd822012-08-28 21:37:27 -0400581 */
582 public function _update_db()
583 {
584 // Check for database and dirty flag and unsaved
585 if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE)
586 {
587 // Set up activity and data fields to be set
588 // If we don't find custom data, user_data will remain an empty string
589 $set = array(
590 'last_activity' => $this->userdata['last_activity'],
591 'user_data' => ''
592 );
593
594 // Get the custom userdata, leaving out the defaults
595 // (which get stored in the cookie)
596 $userdata = array_diff_key($this->userdata, $this->defaults);
597
598 // Did we find any custom data?
599 if ( ! empty($userdata))
600 {
601 // Serialize the custom data array so we can store it
602 $set['user_data'] = $this->_serialize($userdata);
603 }
604
Dionysis Arvanitisf8e2d0e2013-02-19 23:27:16 +0200605 // Reset query builder values.
606 $this->CI->db->reset_query();
607
dchill423cecd822012-08-28 21:37:27 -0400608 // Run the update query
609 // Any time we change the session id, it gets updated immediately,
610 // so our where clause below is always safe
Andrey Andreeve2afc882012-11-01 01:35:34 +0200611 $this->CI->db->where('session_id', $this->userdata['session_id']);
612
613 if ($this->sess_match_ip === TRUE)
614 {
615 $this->CI->db->where('ip_address', $this->CI->input->ip_address());
616 }
617
618 if ($this->sess_match_useragent === TRUE)
619 {
620 $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120)));
621 }
622
623 $this->CI->db->update($this->sess_table_name, $set);
dchill423cecd822012-08-28 21:37:27 -0400624
625 // Clear dirty flag to prevent double updates
626 $this->data_dirty = FALSE;
627
628 log_message('debug', 'CI_Session Data Saved To DB');
629 }
630 }
631
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300632 // ------------------------------------------------------------------------
633
dchill423cecd822012-08-28 21:37:27 -0400634 /**
635 * Generate a new session id
636 *
637 * @return string Hashed session id
638 */
639 protected function _make_sess_id()
640 {
Darren Hillc4e266b2011-08-30 15:40:27 -0400641 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200642 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400643 {
644 $new_sessid .= mt_rand(0, mt_getrandmax());
645 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200646 while (strlen($new_sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400647
648 // To make the session ID even more secure we'll combine it with the user's IP
649 $new_sessid .= $this->CI->input->ip_address();
650
dchill423cecd822012-08-28 21:37:27 -0400651 // Turn it into a hash and return
652 return md5(uniqid($new_sessid, TRUE));
Darren Hillc4e266b2011-08-30 15:40:27 -0400653 }
654
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300655 // ------------------------------------------------------------------------
656
Darren Hillc4e266b2011-08-30 15:40:27 -0400657 /**
658 * Get the "now" time
659 *
dchill42c5079de2012-07-23 10:53:47 -0400660 * @return int Time
Darren Hillc4e266b2011-08-30 15:40:27 -0400661 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400662 protected function _get_time()
Darren Hillc4e266b2011-08-30 15:40:27 -0400663 {
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300664 if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get())
Darren Hillc4e266b2011-08-30 15:40:27 -0400665 {
Iban Eguiafeb14da2012-06-12 16:09:36 +0200666 return time();
Darren Hillc4e266b2011-08-30 15:40:27 -0400667 }
668
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300669 $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
Iban Eguiafeb14da2012-06-12 16:09:36 +0200670 sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
671
672 return mktime($hour, $minute, $second, $month, $day, $year);
Darren Hillc4e266b2011-08-30 15:40:27 -0400673 }
674
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300675 // ------------------------------------------------------------------------
676
Darren Hillc4e266b2011-08-30 15:40:27 -0400677 /**
678 * Write the session cookie
679 *
Darren Hillc4e266b2011-08-30 15:40:27 -0400680 * @return void
681 */
dchill423cecd822012-08-28 21:37:27 -0400682 protected function _set_cookie()
Darren Hillc4e266b2011-08-30 15:40:27 -0400683 {
dchill423cecd822012-08-28 21:37:27 -0400684 // Get userdata (only defaults if database)
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300685 $cookie_data = ($this->sess_use_database === TRUE)
686 ? array_intersect_key($this->userdata, $this->defaults)
687 : $this->userdata;
Darren Hillc4e266b2011-08-30 15:40:27 -0400688
689 // Serialize the userdata for the cookie
690 $cookie_data = $this->_serialize($cookie_data);
691
Pascal Krietef69f0e82012-10-16 11:54:49 -0400692 if ($this->sess_encrypt_cookie === TRUE)
693 {
Andrey Andreevcf264e02012-10-18 16:14:51 +0300694 $cookie_data = $this->CI->encrypt->encode($cookie_data);
Pascal Krietef69f0e82012-10-16 11:54:49 -0400695 }
696
697 // Require message authentication
698 $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key);
Darren Hillc4e266b2011-08-30 15:40:27 -0400699
700 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
701
702 // Set the cookie
dchill42c5872252012-07-30 14:53:11 -0400703 $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
dchill42c5079de2012-07-23 10:53:47 -0400704 $this->cookie_secure, $this->cookie_httponly);
Darren Hillc4e266b2011-08-30 15:40:27 -0400705 }
706
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300707 // ------------------------------------------------------------------------
708
Darren Hillc4e266b2011-08-30 15:40:27 -0400709 /**
dchill42c5872252012-07-30 14:53:11 -0400710 * Set a cookie with the system
711 *
712 * This abstraction of the setcookie call allows overriding for unit testing
713 *
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300714 * @param string Cookie name
715 * @param string Cookie value
716 * @param int Expiration time
717 * @param string Cookie path
718 * @param string Cookie domain
719 * @param bool Secure connection flag
720 * @param bool HTTP protocol only flag
721 * @return void
dchill42c5872252012-07-30 14:53:11 -0400722 */
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300723 protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE)
dchill42c5872252012-07-30 14:53:11 -0400724 {
dchill42c5872252012-07-30 14:53:11 -0400725 setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
726 }
727
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300728 // ------------------------------------------------------------------------
729
dchill42c5872252012-07-30 14:53:11 -0400730 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400731 * Serialize an array
732 *
733 * This function first converts any slashes found in the array to a temporary
734 * marker, so when it gets unserialized the slashes will be preserved
735 *
Darren Hillc4e266b2011-08-30 15:40:27 -0400736 * @param mixed Data to serialize
dchill42c5079de2012-07-23 10:53:47 -0400737 * @return string Serialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400738 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400739 protected function _serialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400740 {
741 if (is_array($data))
742 {
Chris Muench95933492011-10-16 14:14:04 -0400743 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400744 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200745 elseif (is_string($data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400746 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200747 $data = str_replace('\\', '{{slash}}', $data);
Darren Hillc4e266b2011-08-30 15:40:27 -0400748 }
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300749
Darren Hillc4e266b2011-08-30 15:40:27 -0400750 return serialize($data);
751 }
752
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300753 // ------------------------------------------------------------------------
754
Darren Hillc4e266b2011-08-30 15:40:27 -0400755 /**
Chris Muench95933492011-10-16 14:14:04 -0400756 * Escape slashes
757 *
758 * This function converts any slashes found into a temporary marker
759 *
dchill42c5079de2012-07-23 10:53:47 -0400760 * @param string Value
761 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200762 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400763 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200764 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400765 {
766 if (is_string($val))
767 {
768 $val = str_replace('\\', '{{slash}}', $val);
769 }
770 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000771
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300772 // ------------------------------------------------------------------------
773
Derek Allard2067d1a2008-11-13 22:59:24 +0000774 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400775 * Unserialize
776 *
777 * This function unserializes a data string, then converts any
778 * temporary slash markers back to actual slashes
779 *
dchill42c5079de2012-07-23 10:53:47 -0400780 * @param mixed Data to unserialize
781 * @return mixed Unserialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400782 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400783 protected function _unserialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400784 {
Andrey Andreevca20d842012-10-27 03:02:38 +0300785 $data = @unserialize(trim($data));
Darren Hillc4e266b2011-08-30 15:40:27 -0400786
787 if (is_array($data))
788 {
Chris Muench95933492011-10-16 14:14:04 -0400789 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400790 return $data;
791 }
792
Andrey Andreev6b831232012-03-06 11:16:57 +0200793 return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000794 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200795
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300796 // ------------------------------------------------------------------------
797
Chris Muench95933492011-10-16 14:14:04 -0400798 /**
799 * Unescape slashes
800 *
801 * This function converts any slash markers back into actual slashes
802 *
dchill42c5079de2012-07-23 10:53:47 -0400803 * @param string Value
804 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200805 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400806 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200807 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400808 {
Chris Muench3e414f92011-10-16 23:03:55 -0400809 if (is_string($val))
810 {
Andrey Andreevcc221dc2013-02-08 21:57:42 +0200811 $val = str_replace('{{slash}}', '\\', $val);
Chris Muench3e414f92011-10-16 23:03:55 -0400812 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400813 }
814
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300815 // ------------------------------------------------------------------------
816
Darren Hillc4e266b2011-08-30 15:40:27 -0400817 /**
818 * Garbage collection
819 *
820 * This deletes expired session rows from database
821 * if the probability percentage is met
822 *
Darren Hillc4e266b2011-08-30 15:40:27 -0400823 * @return void
824 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400825 protected function _sess_gc()
Darren Hillc4e266b2011-08-30 15:40:27 -0400826 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100827 if ($this->sess_use_database !== TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400828 {
829 return;
830 }
831
Christopher Guiney7a142862012-06-29 20:34:28 -0700832 $probability = ini_get('session.gc_probability');
833 $divisor = ini_get('session.gc_divisor');
834
Darren Hillc4e266b2011-08-30 15:40:27 -0400835 srand(time());
Christopher Guiney7a142862012-06-29 20:34:28 -0700836 if ((mt_rand(0, $divisor) / $divisor) < $probability)
Darren Hillc4e266b2011-08-30 15:40:27 -0400837 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000838 $expire = $this->now - $this->sess_expiration;
dchill423cecd822012-08-28 21:37:27 -0400839 $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
Darren Hillc4e266b2011-08-30 15:40:27 -0400840
841 log_message('debug', 'Session garbage collection performed.');
842 }
843 }
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300844
Darren Hillc4e266b2011-08-30 15:40:27 -0400845}
Darren Hillc4e266b2011-08-30 15:40:27 -0400846
847/* End of file Session_cookie.php */
Andrey Andreev9ffcee62012-09-05 16:25:16 +0300848/* Location: ./system/libraries/Session/drivers/Session_cookie.php */