blob: 0dc109bd13ce401d9769a7b9c6e1d0f1e90fbab2 [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 {
Darren Hillc4e266b2011-08-30 15:40:27 -040042
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020043 /**
Timothy Warren68f09812012-04-27 10:38:32 -040044 * Whether to encrypt the session cookie
45 *
46 * @var bool
47 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020048 public $sess_encrypt_cookie = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020049
Timothy Warren68f09812012-04-27 10:38:32 -040050 /**
51 * Whether to use to the database for session storage
52 *
53 * @var bool
54 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020055 public $sess_use_database = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020056
Timothy Warren68f09812012-04-27 10:38:32 -040057 /**
58 * Name of the database table in which to store sessions
59 *
60 * @var string
61 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020062 public $sess_table_name = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020063
Timothy Warren68f09812012-04-27 10:38:32 -040064 /**
65 * Length of time (in seconds) for sessions to expire
66 *
67 * @var int
68 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020069 public $sess_expiration = 7200;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020070
Timothy Warren68f09812012-04-27 10:38:32 -040071 /**
72 * Whether to kill session on close of browser window
73 *
74 * @var bool
75 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020076 public $sess_expire_on_close = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020077
Timothy Warren68f09812012-04-27 10:38:32 -040078 /**
79 * Whether to match session on ip address
80 *
81 * @var bool
82 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020083 public $sess_match_ip = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020084
Timothy Warren68f09812012-04-27 10:38:32 -040085 /**
86 * Whether to match session on user-agent
87 *
88 * @var bool
89 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020090 public $sess_match_useragent = TRUE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020091
Timothy Warren68f09812012-04-27 10:38:32 -040092 /**
93 * Name of session cookie
94 *
95 * @var string
96 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020097 public $sess_cookie_name = 'ci_session';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +020098
Timothy Warren68f09812012-04-27 10:38:32 -040099 /**
100 * Session cookie prefix
101 *
102 * @var string
103 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200104 public $cookie_prefix = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200105
Timothy Warren68f09812012-04-27 10:38:32 -0400106 /**
107 * Session cookie path
108 *
109 * @var string
110 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200111 public $cookie_path = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200112
Timothy Warren68f09812012-04-27 10:38:32 -0400113 /**
114 * Session cookie domain
115 *
116 * @var string
117 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200118 public $cookie_domain = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200119
Timothy Warren68f09812012-04-27 10:38:32 -0400120 /**
121 * Whether to set the cookie only on HTTPS connections
122 *
123 * @var bool
124 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200125 public $cookie_secure = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200126
Timothy Warren68f09812012-04-27 10:38:32 -0400127 /**
128 * Whether cookie should be allowed only to be sent by the server
129 *
130 * @var bool
131 */
freewil4ad0fd82012-03-13 22:37:42 -0400132 public $cookie_httponly = FALSE;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200133
Timothy Warren68f09812012-04-27 10:38:32 -0400134 /**
135 * Interval at which to update session
136 *
137 * @var int
138 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200139 public $sess_time_to_update = 300;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200140
Timothy Warren68f09812012-04-27 10:38:32 -0400141 /**
142 * Key with which to encrypt the session cookie
143 *
144 * @var string
145 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200146 public $encryption_key = '';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200147
Timothy Warren68f09812012-04-27 10:38:32 -0400148 /**
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300149 * Timezone to use for the current time
Timothy Warren68f09812012-04-27 10:38:32 -0400150 *
151 * @var string
152 */
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300153 public $time_reference = 'local';
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200154
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200155
Timothy Warren68f09812012-04-27 10:38:32 -0400156 /**
157 * Session data
158 *
159 * @var array
160 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200161 public $userdata = array();
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200162
Timothy Warren68f09812012-04-27 10:38:32 -0400163 /**
164 * Reference to CodeIgniter instance
165 *
166 * @var object
167 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200168 public $CI;
Michiel Vugteveen4c316b62012-05-04 11:32:48 +0200169
Timothy Warren68f09812012-04-27 10:38:32 -0400170 /**
171 * Current time
172 *
173 * @var int
174 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200175 public $now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400176
177 /**
178 * Initialize session driver object
179 *
180 * @access protected
181 * @return void
182 */
183 protected function initialize()
184 {
185 // Set the super object to a local variable for use throughout the class
186 $this->CI =& get_instance();
187
188 // Set all the session preferences, which can either be set
189 // manually via the $params array above or via the config file
190 foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration',
191 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path',
dchill42c5079de2012-07-23 10:53:47 -0400192 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix',
193 'encryption_key') as $key)
Darren Hillc4e266b2011-08-30 15:40:27 -0400194 {
dchill42c5079de2012-07-23 10:53:47 -0400195 $this->$key = isset($this->parent->params[$key]) ? $this->parent->params[$key] :
196 $this->CI->config->item($key);
Darren Hillc4e266b2011-08-30 15:40:27 -0400197 }
198
Alex Bilbied261b1e2012-06-02 11:12:16 +0100199 if ($this->encryption_key === '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400200 {
dchill42c5079de2012-07-23 10:53:47 -0400201 show_error('In order to use the Session Cookie driver you are required to set an encryption key '.
Darren Hillc4e266b2011-08-30 15:40:27 -0400202 'in your config file.');
203 }
204
205 // Load the string helper so we can use the strip_slashes() function
206 $this->CI->load->helper('string');
207
208 // Do we need encryption? If so, load the encryption class
Alex Bilbied261b1e2012-06-02 11:12:16 +0100209 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400210 {
211 $this->CI->load->library('encrypt');
212 }
213
214 // Are we using a database? If so, load it
Alex Bilbied261b1e2012-06-02 11:12:16 +0100215 if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
Darren Hillc4e266b2011-08-30 15:40:27 -0400216 {
217 $this->CI->load->database();
218 }
219
220 // Set the "now" time. Can either be GMT or server time, based on the config prefs.
221 // We use this to set the "last activity" time
222 $this->now = $this->_get_time();
223
224 // Set the session length. If the session expiration is
225 // set to zero we'll set the expiration two years from now.
Alex Bilbied261b1e2012-06-02 11:12:16 +0100226 if ($this->sess_expiration === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400227 {
228 $this->sess_expiration = (60*60*24*365*2);
229 }
230
231 // Set the cookie name
232 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
233
234 // Run the Session routine. If a session doesn't exist we'll
235 // create a new one. If it does, we'll update it.
236 if ( ! $this->_sess_read())
237 {
238 $this->_sess_create();
239 }
240 else
241 {
242 $this->_sess_update();
243 }
244
245 // Delete expired sessions if necessary
246 $this->_sess_gc();
247 }
248
249 /**
250 * Write the session data
251 *
252 * @return void
253 */
254 public function sess_save()
255 {
256 // Are we saving custom data to the DB? If not, all we do is update the cookie
257 if ($this->sess_use_database === FALSE)
258 {
259 $this->_set_cookie();
260 return;
261 }
262
263 // set the custom userdata, the session data we will set in a second
264 $custom_userdata = $this->all_userdata();
265 $cookie_userdata = array();
266
267 // Before continuing, we need to determine if there is any custom data to deal with.
268 // Let's determine this by removing the default indexes to see if there's anything left in the array
269 // and set the session data while we're at it
270 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
271 {
272 unset($custom_userdata[$val]);
dchill42c5079de2012-07-23 10:53:47 -0400273 $cookie_userdata[$val] = $this->userdata[$val];
Darren Hillc4e266b2011-08-30 15:40:27 -0400274 }
275
276 // Did we find any custom data? If not, we turn the empty array into a string
277 // since there's no reason to serialize and store an empty array in the DB
278 if (count($custom_userdata) === 0)
279 {
280 $custom_userdata = '';
281 }
282 else
283 {
284 // Serialize the custom data array so we can store it
285 $custom_userdata = $this->_serialize($custom_userdata);
286 }
287
288 // Run the update query
dchill42c5079de2012-07-23 10:53:47 -0400289 $this->CI->db->where('session_id', $this->userdata['session_id']);
Darren Hillc4e266b2011-08-30 15:40:27 -0400290 $this->CI->db->update($this->sess_table_name,
dchill42c5079de2012-07-23 10:53:47 -0400291 array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
Darren Hillc4e266b2011-08-30 15:40:27 -0400292
293 // Write the cookie. Notice that we manually pass the cookie data array to the
294 // _set_cookie() function. Normally that function will store $this->userdata, but
295 // in this case that array contains custom data, which we do not want in the cookie.
296 $this->_set_cookie($cookie_userdata);
297 }
298
299 /**
300 * Destroy the current session
301 *
302 * @return void
303 */
304 public function sess_destroy()
305 {
306 // Kill the session DB row
307 if ($this->sess_use_database === TRUE && $this->has_userdata('session_id'))
308 {
309 $this->CI->db->where('session_id', $this->userdata['session_id']);
310 $this->CI->db->delete($this->sess_table_name);
311 }
312
313 // Kill the cookie
314 setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
315 $this->cookie_path, $this->cookie_domain, 0);
dchill42c5079de2012-07-23 10:53:47 -0400316
317 // Kill session data
318 $this->userdata = array();
Darren Hillc4e266b2011-08-30 15:40:27 -0400319 }
320
321 /**
322 * Regenerate the current session
323 *
324 * Regenerate the session id
325 *
326 * @param boolean Destroy session data flag (default: false)
327 * @return void
328 */
329 public function sess_regenerate($destroy = false)
330 {
331 // Check destroy flag
332 if ($destroy)
333 {
334 // Destroy old session and create new one
335 $this->sess_destroy();
336 $this->_sess_create();
337 }
338 else
339 {
340 // Just force an update to recreate the id
341 $this->_sess_update(true);
342 }
343 }
344
345 /**
346 * Get a reference to user data array
347 *
348 * @return array - Reference to userdata
349 */
350 public function &get_userdata()
351 {
352 // Return reference to array
353 return $this->userdata;
354 }
355
356 /**
357 * Fetch the current session data if it exists
358 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400359 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400360 * @return bool
361 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400362 protected function _sess_read()
Darren Hillc4e266b2011-08-30 15:40:27 -0400363 {
364 // Fetch the cookie
365 $session = $this->CI->input->cookie($this->sess_cookie_name);
366
367 // No cookie? Goodbye cruel world!...
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100368 if ($session === NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400369 {
370 log_message('debug', 'A session cookie was not found.');
371 return FALSE;
372 }
373
374 // Decrypt the cookie data
Alex Bilbied261b1e2012-06-02 11:12:16 +0100375 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400376 {
377 $session = $this->CI->encrypt->decode($session);
378 }
379 else
380 {
381 // encryption was not used, so we need to check the md5 hash
Derek Allard2067d1a2008-11-13 22:59:24 +0000382 $hash = substr($session, strlen($session)-32); // get last 32 chars
Darren Hillc4e266b2011-08-30 15:40:27 -0400383 $session = substr($session, 0, strlen($session)-32);
384
385 // Does the md5 hash match? This is to prevent manipulation of session data in userspace
386 if ($hash !== md5($session.$this->encryption_key))
387 {
388 log_message('error', 'The session cookie data did not match what was expected. '.
389 'This could be a possible hacking attempt.');
390 $this->sess_destroy();
391 return FALSE;
392 }
393 }
394
395 // Unserialize the session array
396 $session = $this->_unserialize($session);
397
398 // Is the session data we unserialized an array with the correct format?
dchill42c5079de2012-07-23 10:53:47 -0400399 if ( ! is_array($session) || ! isset($session['session_id'], $session['ip_address'], $session['user_agent'],
400 $session['last_activity']))
Darren Hillc4e266b2011-08-30 15:40:27 -0400401 {
402 $this->sess_destroy();
403 return FALSE;
404 }
405
406 // Is the session current?
Andrey Andreev7e087f52012-01-20 11:46:27 +0200407 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400408 {
409 $this->sess_destroy();
410 return FALSE;
411 }
412
Andrey Andreev7e087f52012-01-20 11:46:27 +0200413 // Does the IP match?
Alex Bilbied261b1e2012-06-02 11:12:16 +0100414 if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
Darren Hillc4e266b2011-08-30 15:40:27 -0400415 {
416 $this->sess_destroy();
417 return FALSE;
418 }
419
420 // Does the User Agent Match?
dchill42c5079de2012-07-23 10:53:47 -0400421 if ($this->sess_match_useragent === TRUE &&
422 trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
Darren Hillc4e266b2011-08-30 15:40:27 -0400423 {
424 $this->sess_destroy();
425 return FALSE;
426 }
427
428 // Is there a corresponding session in the DB?
429 if ($this->sess_use_database === TRUE)
430 {
431 $this->CI->db->where('session_id', $session['session_id']);
432
Alex Bilbied261b1e2012-06-02 11:12:16 +0100433 if ($this->sess_match_ip === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400434 {
435 $this->CI->db->where('ip_address', $session['ip_address']);
436 }
437
Alex Bilbied261b1e2012-06-02 11:12:16 +0100438 if ($this->sess_match_useragent === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400439 {
440 $this->CI->db->where('user_agent', $session['user_agent']);
441 }
442
Timothy Warrenf1421922012-03-02 11:51:42 -0500443 $query = $this->CI->db->limit(1)->get($this->sess_table_name);
Darren Hillc4e266b2011-08-30 15:40:27 -0400444
445 // No result? Kill it!
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200446 if ($query->num_rows() === 0)
Darren Hillc4e266b2011-08-30 15:40:27 -0400447 {
448 $this->sess_destroy();
449 return FALSE;
450 }
451
452 // Is there custom data? If so, add it to the main session array
453 $row = $query->row();
Andrey Andreev5036c9c2012-06-04 15:34:56 +0300454 if ( ! empty($row->user_data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400455 {
456 $custom_data = $this->_unserialize($row->user_data);
457
458 if (is_array($custom_data))
459 {
460 foreach ($custom_data as $key => $val)
461 {
462 $session[$key] = $val;
463 }
464 }
465 }
466 }
467
468 // Session is valid!
469 $this->userdata = $session;
470 unset($session);
471
472 return TRUE;
473 }
474
475 /**
476 * Create a new session
477 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400478 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400479 * @return void
480 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400481 protected function _sess_create()
Darren Hillc4e266b2011-08-30 15:40:27 -0400482 {
483 $sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200484 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400485 {
486 $sessid .= mt_rand(0, mt_getrandmax());
487 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200488 while (strlen($sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400489
490 // To make the session ID even more secure we'll combine it with the user's IP
491 $sessid .= $this->CI->input->ip_address();
492
Derek Allard2067d1a2008-11-13 22:59:24 +0000493 $this->userdata = array(
dchill42c5079de2012-07-23 10:53:47 -0400494 'session_id' => md5(uniqid($sessid, TRUE)),
495 'ip_address' => $this->CI->input->ip_address(),
496 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
497 'last_activity' => $this->now,
498 'user_data' => ''
499 );
Darren Hillc4e266b2011-08-30 15:40:27 -0400500
501 // Save the data to the DB if needed
502 if ($this->sess_use_database === TRUE)
503 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000504 $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
Darren Hillc4e266b2011-08-30 15:40:27 -0400505 }
506
507 // Write the cookie
508 $this->_set_cookie();
509 }
510
511 /**
512 * Update an existing session
513 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400514 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400515 * @param boolean Force update flag (default: false)
516 * @return void
517 */
dchill42c5079de2012-07-23 10:53:47 -0400518 protected function _sess_update($force = FALSE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400519 {
520 // We only update the session every five minutes by default (unless forced)
dchill42c5079de2012-07-23 10:53:47 -0400521 if (!$force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Darren Hillc4e266b2011-08-30 15:40:27 -0400522 {
523 return;
524 }
525
Andrey Andreev9c622f32012-01-19 14:12:54 +0200526 // _set_cookie() will handle this for us if we aren't using database sessions
527 // by pushing all userdata to the cookie.
528 $cookie_data = NULL;
529
530 /* Changing the session ID during an AJAX call causes problems,
531 * so we'll only update our last_activity
532 */
533 if ($this->CI->input->is_ajax_request())
534 {
535 $this->userdata['last_activity'] = $this->now;
536
537 // Update the session ID and last_activity field in the DB if needed
538 if ($this->sess_use_database === TRUE)
539 {
540 // set cookie explicitly to only have our session data
541 $cookie_data = array();
542 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
543 {
544 $cookie_data[$val] = $this->userdata[$val];
545 }
546
547 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
548 array('last_activity' => $this->userdata['last_activity']),
549 array('session_id' => $this->userdata['session_id'])));
550 }
551
552 return $this->_set_cookie($cookie_data);
553 }
554
Darren Hillc4e266b2011-08-30 15:40:27 -0400555 // Save the old session id so we know which record to
556 // update in the database if we need it
557 $old_sessid = $this->userdata['session_id'];
558 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200559 do
Darren Hillc4e266b2011-08-30 15:40:27 -0400560 {
561 $new_sessid .= mt_rand(0, mt_getrandmax());
562 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200563 while (strlen($new_sessid) < 32);
Darren Hillc4e266b2011-08-30 15:40:27 -0400564
565 // To make the session ID even more secure we'll combine it with the user's IP
566 $new_sessid .= $this->CI->input->ip_address();
567
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200568 // Turn it into a hash and update the session data array
569 $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
Derek Allard2067d1a2008-11-13 22:59:24 +0000570 $this->userdata['last_activity'] = $this->now;
Darren Hillc4e266b2011-08-30 15:40:27 -0400571
572 // Update the session ID and last_activity field in the DB if needed
573 if ($this->sess_use_database === TRUE)
574 {
575 // set cookie explicitly to only have our session data
576 $cookie_data = array();
577 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
578 {
579 $cookie_data[$val] = $this->userdata[$val];
580 }
581
582 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
dchill42c5079de2012-07-23 10:53:47 -0400583 array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
Darren Hillc4e266b2011-08-30 15:40:27 -0400584 }
585
586 // Write the cookie
587 $this->_set_cookie($cookie_data);
588 }
589
590 /**
591 * Get the "now" time
592 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400593 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400594 * @return int Time
Darren Hillc4e266b2011-08-30 15:40:27 -0400595 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400596 protected function _get_time()
Darren Hillc4e266b2011-08-30 15:40:27 -0400597 {
dchill42c5079de2012-07-23 10:53:47 -0400598 if ($this->time_reference === 'local' || $this->time_reference === date_default_timezone_get())
Darren Hillc4e266b2011-08-30 15:40:27 -0400599 {
Iban Eguiafeb14da2012-06-12 16:09:36 +0200600 return time();
Darren Hillc4e266b2011-08-30 15:40:27 -0400601 }
602
Andrey Andreevd163e0b2012-06-14 03:09:53 +0300603 $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
Iban Eguiafeb14da2012-06-12 16:09:36 +0200604 sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
605
606 return mktime($hour, $minute, $second, $month, $day, $year);
Darren Hillc4e266b2011-08-30 15:40:27 -0400607 }
608
609 /**
610 * Write the session cookie
611 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400612 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400613 * @param array Cookie name/value pairs
614 * @return void
615 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400616 protected function _set_cookie(array $cookie_data = NULL)
Darren Hillc4e266b2011-08-30 15:40:27 -0400617 {
618 if (is_null($cookie_data))
619 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000620 $cookie_data = $this->userdata;
Darren Hillc4e266b2011-08-30 15:40:27 -0400621 }
622
623 // Serialize the userdata for the cookie
624 $cookie_data = $this->_serialize($cookie_data);
625
Alex Bilbied261b1e2012-06-02 11:12:16 +0100626 if ($this->sess_encrypt_cookie === TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400627 {
628 $cookie_data = $this->CI->encrypt->encode($cookie_data);
629 }
630 else
631 {
632 // if encryption is not used, we provide an md5 hash to prevent userside tampering
633 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
634 }
635
636 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
637
638 // Set the cookie
Darren Hill00fcb542011-09-12 07:57:04 -0400639 setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
dchill42c5079de2012-07-23 10:53:47 -0400640 $this->cookie_secure, $this->cookie_httponly);
Darren Hillc4e266b2011-08-30 15:40:27 -0400641 }
642
643 /**
644 * Serialize an array
645 *
646 * This function first converts any slashes found in the array to a temporary
647 * marker, so when it gets unserialized the slashes will be preserved
648 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400649 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400650 * @param mixed Data to serialize
dchill42c5079de2012-07-23 10:53:47 -0400651 * @return string Serialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400652 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400653 protected function _serialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400654 {
655 if (is_array($data))
656 {
Chris Muench95933492011-10-16 14:14:04 -0400657 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400658 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200659 elseif (is_string($data))
Darren Hillc4e266b2011-08-30 15:40:27 -0400660 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200661 $data = str_replace('\\', '{{slash}}', $data);
Darren Hillc4e266b2011-08-30 15:40:27 -0400662 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400663 return serialize($data);
664 }
665
666 /**
Chris Muench95933492011-10-16 14:14:04 -0400667 * Escape slashes
668 *
669 * This function converts any slashes found into a temporary marker
670 *
dchill42c5079de2012-07-23 10:53:47 -0400671 * @access protected
672 * @param string Value
673 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200674 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400675 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200676 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400677 {
678 if (is_string($val))
679 {
680 $val = str_replace('\\', '{{slash}}', $val);
681 }
682 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000683
Derek Allard2067d1a2008-11-13 22:59:24 +0000684 /**
Darren Hillc4e266b2011-08-30 15:40:27 -0400685 * Unserialize
686 *
687 * This function unserializes a data string, then converts any
688 * temporary slash markers back to actual slashes
689 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400690 * @access protected
dchill42c5079de2012-07-23 10:53:47 -0400691 * @param mixed Data to unserialize
692 * @return mixed Unserialized data
Darren Hillc4e266b2011-08-30 15:40:27 -0400693 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400694 protected function _unserialize($data)
Darren Hillc4e266b2011-08-30 15:40:27 -0400695 {
Andrey Andreev6b831232012-03-06 11:16:57 +0200696 $data = @unserialize(strip_slashes(trim($data)));
Darren Hillc4e266b2011-08-30 15:40:27 -0400697
698 if (is_array($data))
699 {
Chris Muench95933492011-10-16 14:14:04 -0400700 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Darren Hillc4e266b2011-08-30 15:40:27 -0400701 return $data;
702 }
703
Andrey Andreev6b831232012-03-06 11:16:57 +0200704 return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000705 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200706
Chris Muench95933492011-10-16 14:14:04 -0400707 /**
708 * Unescape slashes
709 *
710 * This function converts any slash markers back into actual slashes
711 *
dchill42c5079de2012-07-23 10:53:47 -0400712 * @access protected
713 * @param string Value
714 * @param string Key
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200715 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400716 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200717 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400718 {
Chris Muench3e414f92011-10-16 23:03:55 -0400719 if (is_string($val))
720 {
721 $val= str_replace('{{slash}}', '\\', $val);
722 }
Darren Hillc4e266b2011-08-30 15:40:27 -0400723 }
724
725 /**
726 * Garbage collection
727 *
728 * This deletes expired session rows from database
729 * if the probability percentage is met
730 *
Darren Hilla2ae6572011-09-01 07:36:26 -0400731 * @access protected
Darren Hillc4e266b2011-08-30 15:40:27 -0400732 * @return void
733 */
Darren Hilla2ae6572011-09-01 07:36:26 -0400734 protected function _sess_gc()
Darren Hillc4e266b2011-08-30 15:40:27 -0400735 {
Alex Bilbied261b1e2012-06-02 11:12:16 +0100736 if ($this->sess_use_database !== TRUE)
Darren Hillc4e266b2011-08-30 15:40:27 -0400737 {
738 return;
739 }
740
Christopher Guiney7a142862012-06-29 20:34:28 -0700741 $probability = ini_get('session.gc_probability');
742 $divisor = ini_get('session.gc_divisor');
743
Darren Hillc4e266b2011-08-30 15:40:27 -0400744 srand(time());
Christopher Guiney7a142862012-06-29 20:34:28 -0700745 if ((mt_rand(0, $divisor) / $divisor) < $probability)
Darren Hillc4e266b2011-08-30 15:40:27 -0400746 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000747 $expire = $this->now - $this->sess_expiration;
Darren Hillc4e266b2011-08-30 15:40:27 -0400748
749 $this->CI->db->where('last_activity < '.$expire);
750 $this->CI->db->delete($this->sess_table_name);
751
752 log_message('debug', 'Session garbage collection performed.');
753 }
754 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000755
Darren Hillc4e266b2011-08-30 15:40:27 -0400756}
Darren Hillc4e266b2011-08-30 15:40:27 -0400757
758/* End of file Session_cookie.php */
Darren Hill5073a372011-08-31 13:54:19 -0400759/* Location: ./system/libraries/Session/drivers/Session_cookie.php */