blob: 89e81386f68ec448cec97be391e7a02e2ddd4494 [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 *
31 * This is the CI_Session functionality, as written by EllisLab, abstracted out to a driver.
32 * I have done a little updating for PHP5, and made minor changes to extract this functionality from
33 * the public interface (now in the Session Library), but effectively this code is unchanged.
34 *
35 * @package CodeIgniter
36 * @subpackage Libraries
37 * @category Sessions
Derek Jonesf4a4bd82011-10-20 12:18:42 -050038 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000039 * @link http://codeigniter.com/user_guide/libraries/sessions.html
Darren Hillc4e266b2011-08-30 15:40:27 -040040 */
Darren Hill5073a372011-08-31 13:54:19 -040041class CI_Session_cookie extends CI_Session_driver {
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 /**
162 * Reference to CodeIgniter instance
163 *
164 * @var object
165 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200166 public $CI;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200167
Timothy Warren68f09812012-04-27 10:38:32 -0400168 /**
169 * Current time
170 *
171 * @var int
172 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200173 public $now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400174
175 /**
176 * Initialize session driver object
177 *
178 * @access protected
179 * @return void
180 */
181 protected function initialize()
182 {
183 // Set the super object to a local variable for use throughout the class
184 $this->CI =& get_instance();
185
186 // Set all the session preferences, which can either be set
dchill4242b77a92012-07-23 11:28:42 -0400187 // manually via the $params array or via the config file
dchill4226429202012-07-31 10:55:07 -0400188 $prefs = array(
189 'sess_encrypt_cookie',
190 'sess_use_database',
191 'sess_table_name',
192 'sess_expiration',
193 'sess_expire_on_close',
194 'sess_match_ip',
195 'sess_match_useragent',
196 'sess_cookie_name',
197 'cookie_path',
198 'cookie_domain',
199 'cookie_secure',
200 'cookie_httponly',
201 'sess_time_to_update',
202 'time_reference',
203 'cookie_prefix',
204 'encryption_key'
205 );
206 foreach ($prefs as $key)
Darren Hillc4e266b2011-08-30 15:40:27 -0400207 {
dchill42c5872252012-07-30 14:53:11 -0400208 $this->$key = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] :
dchill42c5079de2012-07-23 10:53:47 -0400209 $this->CI->config->item($key);
Darren Hillc4e266b2011-08-30 15:40:27 -0400210 }
211
Alex Bilbied261b1e2012-06-02 11:12:16 +0100212 if ($this->encryption_key === '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400213 {
dchill42c5872252012-07-30 14:53:11 -0400214 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 -0400215 'in your config file.');
216 }
217
218 // Load the string helper so we can use the strip_slashes() function
219 $this->CI->load->helper('string');
220
221 // Do we need encryption? If so, load the encryption class
Alex Bilbied261b1e2012-06-02 11:12:16 +0100222 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400223 {
224 $this->CI->load->library('encrypt');
225 }
226
227 // Are we using a database? If so, load it
Alex Bilbied261b1e2012-06-02 11:12:16 +0100228 if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400229 {
230 $this->CI->load->database();
231 }
232
233 // Set the "now" time. Can either be GMT or server time, based on the config prefs.
234 // We use this to set the "last activity" time
235 $this->now = $this->_get_time();
236
237 // Set the session length. If the session expiration is
238 // set to zero we'll set the expiration two years from now.
Alex Bilbied261b1e2012-06-02 11:12:16 +0100239 if ($this->sess_expiration === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400240 {
241 $this->sess_expiration = (60*60*24*365*2);
242 }
243
244 // Set the cookie name
245 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
246
247 // Run the Session routine. If a session doesn't exist we'll
248 // create a new one. If it does, we'll update it.
249 if ( ! $this->_sess_read())
250 {
251 $this->_sess_create();
252 }
253 else
254 {
255 $this->_sess_update();
256 }
257
258 // Delete expired sessions if necessary
259 $this->_sess_gc();
260 }
261
262 /**
263 * Write the session data
264 *
265 * @return void
266 */
267 public function sess_save()
268 {
269 // Are we saving custom data to the DB? If not, all we do is update the cookie
270 if ($this->sess_use_database === FALSE)
271 {
272 $this->_set_cookie();
273 return;
274 }
275
276 // set the custom userdata, the session data we will set in a second
277 $custom_userdata = $this->all_userdata();
278 $cookie_userdata = array();
279
280 // Before continuing, we need to determine if there is any custom data to deal with.
281 // Let's determine this by removing the default indexes to see if there's anything left in the array
282 // and set the session data while we're at it
dchill4226429202012-07-31 10:55:07 -0400283 $defaults = array(
284 'session_id',
285 'ip_address',
286 'user_agent',
287 'last_activity'
288 );
289 foreach ($defaults as $val)
Darren Hillc4e266b2011-08-30 15:40:27 -0400290 {
291 unset($custom_userdata[$val]);
dchill42c5079de2012-07-23 10:53:47 -0400292 $cookie_userdata[$val] = $this->userdata[$val];
Darren Hillc4e266b2011-08-30 15:40:27 -0400293 }
294
295 // Did we find any custom data? If not, we turn the empty array into a string
296 // since there's no reason to serialize and store an empty array in the DB
297 if (count($custom_userdata) === 0)
298 {
299 $custom_userdata = '';
300 }
301 else
302 {
303 // Serialize the custom data array so we can store it
304 $custom_userdata = $this->_serialize($custom_userdata);
305 }
306
307 // Run the update query
dchill42c5079de2012-07-23 10:53:47 -0400308 $this->CI->db->where('session_id', $this->userdata['session_id']);
dchill4226429202012-07-31 10:55:07 -0400309 $this->CI->db->update($this->sess_table_name, array(
310 'last_activity' => $this->userdata['last_activity'],
311 'user_data' => $custom_userdata
312 ));
Darren Hillc4e266b2011-08-30 15:40:27 -0400313
314 // Write the cookie. Notice that we manually pass the cookie data array to the
315 // _set_cookie() function. Normally that function will store $this->userdata, but
316 // in this case that array contains custom data, which we do not want in the cookie.
317 $this->_set_cookie($cookie_userdata);
318 }
319
320 /**
321 * Destroy the current session
322 *
323 * @return void
324 */
325 public function sess_destroy()
326 {
327 // Kill the session DB row
dchill42aee92652012-08-26 21:45:35 -0400328 if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400329 {
330 $this->CI->db->where('session_id', $this->userdata['session_id']);
331 $this->CI->db->delete($this->sess_table_name);
332 }
333
334 // Kill the cookie
dchill42c5872252012-07-30 14:53:11 -0400335 $this->_setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
Darren Hillc4e266b2011-08-30 15:40:27 -0400336 $this->cookie_path, $this->cookie_domain, 0);
dchill42c5079de2012-07-23 10:53:47 -0400337
338 // Kill session data
339 $this->userdata = array();
Darren Hillc4e266b2011-08-30 15:40:27 -0400340 }
341
342 /**
343 * Regenerate the current session
344 *
345 * Regenerate the session id
346 *
347 * @param boolean Destroy session data flag (default: false)
348 * @return void
349 */
350 public function sess_regenerate($destroy = false)
351 {
352 // Check destroy flag
353 if ($destroy)
354 {
355 // Destroy old session and create new one
356 $this->sess_destroy();
357 $this->_sess_create();
358 }
359 else
360 {
361 // Just force an update to recreate the id
362 $this->_sess_update(true);
363 }
364 }
365
366 /**
367 * Get a reference to user data array
368 *
369 * @return array - Reference to userdata
370 */
371 public function &get_userdata()
372 {
373 // Return reference to array
374 return $this->userdata;
375 }
376
377 /**
378 * Fetch the current session data if it exists
379 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400380 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400381 * @return bool
382 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400383 protected function _sess_read()
Darren Hillc4e266b2011-08-30 15:40:27 -0400384 {
385 // Fetch the cookie
386 $session = $this->CI->input->cookie($this->sess_cookie_name);
387
388 // No cookie? Goodbye cruel world!...
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100389 if ($session === NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400390 {
391 log_message('debug', 'A session cookie was not found.');
392 return FALSE;
393 }
394
395 // Decrypt the cookie data
Alex Bilbied261b1e2012-06-02 11:12:16 +0100396 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400397 {
398 $session = $this->CI->encrypt->decode($session);
399 }
400 else
401 {
402 // encryption was not used, so we need to check the md5 hash
Derek Allard2067d1a2008-11-13 22:59:24 +0000403 $hash = substr($session, strlen($session)-32); // get last 32 chars
Darren Hillc4e266b2011-08-30 15:40:27 -0400404 $session = substr($session, 0, strlen($session)-32);
405
406 // Does the md5 hash match? This is to prevent manipulation of session data in userspace
407 if ($hash !== md5($session.$this->encryption_key))
408 {
409 log_message('error', 'The session cookie data did not match what was expected. '.
410 'This could be a possible hacking attempt.');
411 $this->sess_destroy();
412 return FALSE;
413 }
414 }
415
416 // Unserialize the session array
417 $session = $this->_unserialize($session);
418
419 // Is the session data we unserialized an array with the correct format?
dchill42c5079de2012-07-23 10:53:47 -0400420 if ( ! is_array($session) || ! isset($session['session_id'], $session['ip_address'], $session['user_agent'],
421 $session['last_activity']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400422 {
423 $this->sess_destroy();
424 return FALSE;
425 }
426
427 // Is the session current?
Andrey Andreev7e087f52012-01-20 11:46:27 +0200428 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400429 {
430 $this->sess_destroy();
431 return FALSE;
432 }
433
Andrey Andreev7e087f52012-01-20 11:46:27 +0200434 // Does the IP match?
Alex Bilbied261b1e2012-06-02 11:12:16 +0100435 if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
Darren Hillc4e266b2011-08-30 15:40:27 -0400436 {
437 $this->sess_destroy();
438 return FALSE;
439 }
440
441 // Does the User Agent Match?
dchill42c5079de2012-07-23 10:53:47 -0400442 if ($this->sess_match_useragent === TRUE &&
443 trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
Darren Hillc4e266b2011-08-30 15:40:27 -0400444 {
445 $this->sess_destroy();
446 return FALSE;
447 }
448
449 // Is there a corresponding session in the DB?
450 if ($this->sess_use_database === TRUE)
451 {
452 $this->CI->db->where('session_id', $session['session_id']);
453
Alex Bilbied261b1e2012-06-02 11:12:16 +0100454 if ($this->sess_match_ip === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400455 {
456 $this->CI->db->where('ip_address', $session['ip_address']);
457 }
458
Alex Bilbied261b1e2012-06-02 11:12:16 +0100459 if ($this->sess_match_useragent === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400460 {
461 $this->CI->db->where('user_agent', $session['user_agent']);
462 }
463
Timothy Warrenf1421922012-03-02 11:51:42 -0500464 $query = $this->CI->db->limit(1)->get($this->sess_table_name);
Darren Hillc4e266b2011-08-30 15:40:27 -0400465
466 // No result? Kill it!
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200467 if ($query->num_rows() === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400468 {
469 $this->sess_destroy();
470 return FALSE;
471 }
472
473 // Is there custom data? If so, add it to the main session array
474 $row = $query->row();
Andrey Andreev5036c9c2012-06-04 15:34:56 +0300475 if ( ! empty($row->user_data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400476 {
477 $custom_data = $this->_unserialize($row->user_data);
478
479 if (is_array($custom_data))
480 {
481 foreach ($custom_data as $key => $val)
482 {
483 $session[$key] = $val;
484 }
485 }
486 }
487 }
488
489 // Session is valid!
490 $this->userdata = $session;
491 unset($session);
492
493 return TRUE;
494 }
495
496 /**
497 * Create a new session
498 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400499 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400500 * @return void
501 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400502 protected function _sess_create()
Darren Hillc4e266b2011-08-30 15:40:27 -0400503 {
504 $sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200505 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400506 {
507 $sessid .= mt_rand(0, mt_getrandmax());
508 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200509 while (strlen($sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400510
511 // To make the session ID even more secure we'll combine it with the user's IP
512 $sessid .= $this->CI->input->ip_address();
513
Derek Allard2067d1a2008-11-13 22:59:24 +0000514 $this->userdata = array(
dchill42c5079de2012-07-23 10:53:47 -0400515 'session_id' => md5(uniqid($sessid, TRUE)),
516 'ip_address' => $this->CI->input->ip_address(),
517 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
518 'last_activity' => $this->now,
519 'user_data' => ''
520 );
Darren Hillc4e266b2011-08-30 15:40:27 -0400521
522 // Save the data to the DB if needed
523 if ($this->sess_use_database === TRUE)
524 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000525 $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
Darren Hillc4e266b2011-08-30 15:40:27 -0400526 }
527
528 // Write the cookie
529 $this->_set_cookie();
530 }
531
532 /**
533 * Update an existing session
534 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400535 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400536 * @param boolean Force update flag (default: false)
537 * @return void
538 */
dchill42c5079de2012-07-23 10:53:47 -0400539 protected function _sess_update($force = FALSE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400540 {
541 // We only update the session every five minutes by default (unless forced)
dchill4277ee3fd2012-07-24 11:50:01 -0400542 if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400543 {
544 return;
545 }
546
Andrey Andreev9c622f32012-01-19 14:12:54 +0200547 // _set_cookie() will handle this for us if we aren't using database sessions
548 // by pushing all userdata to the cookie.
549 $cookie_data = NULL;
550
dchill4242b77a92012-07-23 11:28:42 -0400551 // Changing the session ID during an AJAX call causes problems, so we'll only update our last_activity
Andrey Andreev9c622f32012-01-19 14:12:54 +0200552 if ($this->CI->input->is_ajax_request())
553 {
554 $this->userdata['last_activity'] = $this->now;
555
556 // Update the session ID and last_activity field in the DB if needed
557 if ($this->sess_use_database === TRUE)
558 {
559 // set cookie explicitly to only have our session data
560 $cookie_data = array();
dchill4226429202012-07-31 10:55:07 -0400561 $defaults = array(
562 'session_id',
563 'ip_address',
564 'user_agent',
565 'last_activity'
566 );
567 foreach ($defaults as $val)
Andrey Andreev9c622f32012-01-19 14:12:54 +0200568 {
569 $cookie_data[$val] = $this->userdata[$val];
570 }
571
572 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
573 array('last_activity' => $this->userdata['last_activity']),
574 array('session_id' => $this->userdata['session_id'])));
575 }
576
577 return $this->_set_cookie($cookie_data);
578 }
579
Darren Hillc4e266b2011-08-30 15:40:27 -0400580 // Save the old session id so we know which record to
581 // update in the database if we need it
582 $old_sessid = $this->userdata['session_id'];
583 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200584 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400585 {
586 $new_sessid .= mt_rand(0, mt_getrandmax());
587 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200588 while (strlen($new_sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400589
590 // To make the session ID even more secure we'll combine it with the user's IP
591 $new_sessid .= $this->CI->input->ip_address();
592
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200593 // Turn it into a hash and update the session data array
594 $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
Derek Allard2067d1a2008-11-13 22:59:24 +0000595 $this->userdata['last_activity'] = $this->now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400596
597 // Update the session ID and last_activity field in the DB if needed
598 if ($this->sess_use_database === TRUE)
599 {
600 // set cookie explicitly to only have our session data
601 $cookie_data = array();
dchill4226429202012-07-31 10:55:07 -0400602 $defaults = array(
603 'session_id',
604 'ip_address',
605 'user_agent',
606 'last_activity'
607 );
608 foreach ($defaults as $val)
Darren Hillc4e266b2011-08-30 15:40:27 -0400609 {
610 $cookie_data[$val] = $this->userdata[$val];
611 }
612
613 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
dchill42c5079de2012-07-23 10:53:47 -0400614 array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
Darren Hillc4e266b2011-08-30 15:40:27 -0400615 }
616
617 // Write the cookie
618 $this->_set_cookie($cookie_data);
619 }
620
621 /**
622 * Get the "now" time
623 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400624 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400625 * @return int Time
Darren Hillc4e266b2011-08-30 15:40:27 -0400626 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400627 protected function _get_time()
Darren Hillc4e266b2011-08-30 15:40:27 -0400628 {
dchill42c5079de2012-07-23 10:53:47 -0400629 if ($this->time_reference === 'local' || $this->time_reference === date_default_timezone_get())
Darren Hillc4e266b2011-08-30 15:40:27 -0400630 {
Iban Eguiafeb14da2012-06-12 16:09:36 +0200631 return time();
Darren Hillc4e266b2011-08-30 15:40:27 -0400632 }
633
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300634 $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
Iban Eguiafeb14da2012-06-12 16:09:36 +0200635 sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
636
637 return mktime($hour, $minute, $second, $month, $day, $year);
Darren Hillc4e266b2011-08-30 15:40:27 -0400638 }
639
640 /**
641 * Write the session cookie
642 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400643 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400644 * @param array Cookie name/value pairs
645 * @return void
646 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400647 protected function _set_cookie(array $cookie_data = NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400648 {
649 if (is_null($cookie_data))
650 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000651 $cookie_data = $this->userdata;
Darren Hillc4e266b2011-08-30 15:40:27 -0400652 }
653
654 // Serialize the userdata for the cookie
655 $cookie_data = $this->_serialize($cookie_data);
656
Alex Bilbied261b1e2012-06-02 11:12:16 +0100657 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400658 {
659 $cookie_data = $this->CI->encrypt->encode($cookie_data);
660 }
661 else
662 {
663 // if encryption is not used, we provide an md5 hash to prevent userside tampering
664 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
665 }
666
667 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
668
669 // Set the cookie
dchill42c5872252012-07-30 14:53:11 -0400670 $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
dchill42c5079de2012-07-23 10:53:47 -0400671 $this->cookie_secure, $this->cookie_httponly);
Darren Hillc4e266b2011-08-30 15:40:27 -0400672 }
673
674 /**
dchill42c5872252012-07-30 14:53:11 -0400675 * Set a cookie with the system
676 *
677 * This abstraction of the setcookie call allows overriding for unit testing
678 *
679 * @access protected
680 * @param string Cookie name
681 * @param string Cookie value
682 * @param int Expiration time
683 * @param string Cookie path
684 * @param string Cookie domain
685 * @param bool Secure connection flag
686 * @param bool HTTP protocol only flag
687 * @return void
688 */
689 protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = false,
690 $httponly = false)
691 {
692 // Set the cookie
693 setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
694 }
695
696 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400697 * Serialize an array
698 *
699 * This function first converts any slashes found in the array to a temporary
700 * marker, so when it gets unserialized the slashes will be preserved
701 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400702 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400703 * @param mixed Data to serialize
dchill42c5079de2012-07-23 10:53:47 -0400704 * @return string Serialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400705 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400706 protected function _serialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400707 {
708 if (is_array($data))
709 {
Chris Muench95933492011-10-16 14:14:04 -0400710 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400711 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200712 elseif (is_string($data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400713 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200714 $data = str_replace('\\', '{{slash}}', $data);
Darren Hillc4e266b2011-08-30 15:40:27 -0400715 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400716 return serialize($data);
717 }
718
719 /**
Chris Muench95933492011-10-16 14:14:04 -0400720 * Escape slashes
721 *
722 * This function converts any slashes found into a temporary marker
723 *
dchill42c5079de2012-07-23 10:53:47 -0400724 * @access protected
725 * @param string Value
726 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200727 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400728 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200729 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400730 {
731 if (is_string($val))
732 {
733 $val = str_replace('\\', '{{slash}}', $val);
734 }
735 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000736
Derek Allard2067d1a2008-11-13 22:59:24 +0000737 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400738 * Unserialize
739 *
740 * This function unserializes a data string, then converts any
741 * temporary slash markers back to actual slashes
742 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400743 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400744 * @param mixed Data to unserialize
745 * @return mixed Unserialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400746 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400747 protected function _unserialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400748 {
Andrey Andreev6b831232012-03-06 11:16:57 +0200749 $data = @unserialize(strip_slashes(trim($data)));
Darren Hillc4e266b2011-08-30 15:40:27 -0400750
751 if (is_array($data))
752 {
Chris Muench95933492011-10-16 14:14:04 -0400753 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400754 return $data;
755 }
756
Andrey Andreev6b831232012-03-06 11:16:57 +0200757 return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000758 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200759
Chris Muench95933492011-10-16 14:14:04 -0400760 /**
761 * Unescape slashes
762 *
763 * This function converts any slash markers back into actual slashes
764 *
dchill42c5079de2012-07-23 10:53:47 -0400765 * @access protected
766 * @param string Value
767 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200768 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400769 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200770 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400771 {
Chris Muench3e414f92011-10-16 23:03:55 -0400772 if (is_string($val))
773 {
774 $val= str_replace('{{slash}}', '\\', $val);
775 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400776 }
777
778 /**
779 * Garbage collection
780 *
781 * This deletes expired session rows from database
782 * if the probability percentage is met
783 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400784 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400785 * @return void
786 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400787 protected function _sess_gc()
Darren Hillc4e266b2011-08-30 15:40:27 -0400788 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100789 if ($this->sess_use_database !== TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400790 {
791 return;
792 }
793
Christopher Guiney7a142862012-06-29 20:34:28 -0700794 $probability = ini_get('session.gc_probability');
795 $divisor = ini_get('session.gc_divisor');
796
Darren Hillc4e266b2011-08-30 15:40:27 -0400797 srand(time());
Christopher Guiney7a142862012-06-29 20:34:28 -0700798 if ((mt_rand(0, $divisor) / $divisor) < $probability)
Darren Hillc4e266b2011-08-30 15:40:27 -0400799 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000800 $expire = $this->now - $this->sess_expiration;
Darren Hillc4e266b2011-08-30 15:40:27 -0400801
802 $this->CI->db->where('last_activity < '.$expire);
803 $this->CI->db->delete($this->sess_table_name);
804
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 */