blob: c14b11fa3f9a5dac446c8294ff847cc7f325a6ba [file] [log] [blame]
Andrey Andreev57ffbbb2011-12-25 04:48:47 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Greg Aker741de1c2010-11-10 14:52:57 -06005 * An open source application development framework for PHP 5.1.6 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 Andreevf863a022012-01-24 15:31:54 +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.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @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)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * Session Class
30 *
31 * @package CodeIgniter
32 * @subpackage Libraries
33 * @category Sessions
Derek Jonesf4a4bd82011-10-20 12:18:42 -050034 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000035 * @link http://codeigniter.com/user_guide/libraries/sessions.html
36 */
37class CI_Session {
38
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020039 public $sess_encrypt_cookie = FALSE;
40 public $sess_use_database = FALSE;
41 public $sess_table_name = '';
42 public $sess_expiration = 7200;
43 public $sess_expire_on_close = FALSE;
44 public $sess_match_ip = FALSE;
45 public $sess_match_useragent = TRUE;
46 public $sess_cookie_name = 'ci_session';
47 public $cookie_prefix = '';
48 public $cookie_path = '';
49 public $cookie_domain = '';
50 public $cookie_secure = FALSE;
51 public $sess_time_to_update = 300;
52 public $encryption_key = '';
53 public $flashdata_key = 'flash';
54 public $time_reference = 'time';
55 public $gc_probability = 5;
56 public $userdata = array();
57 public $CI;
58 public $now;
Derek Allard2067d1a2008-11-13 22:59:24 +000059
60 /**
61 * Session Constructor
62 *
63 * The constructor runs the session routines automatically
64 * whenever the class is instantiated.
65 */
Greg Akera9263282010-11-10 15:26:43 -060066 public function __construct($params = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000067 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +020068 log_message('debug', 'Session Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000069
70 // Set the super object to a local variable for use throughout the class
71 $this->CI =& get_instance();
72
73 // Set all the session preferences, which can either be set
74 // manually via the $params array above or via the config file
tobiasbgba6432c2011-02-18 21:58:48 +010075 foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
Derek Allard2067d1a2008-11-13 22:59:24 +000076 {
77 $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
78 }
79
Derek Jones5485db52010-08-30 21:31:08 -050080 if ($this->encryption_key == '')
81 {
82 show_error('In order to use the Session class you are required to set an encryption key in your config file.');
83 }
84
Derek Allard2067d1a2008-11-13 22:59:24 +000085 // Load the string helper so we can use the strip_slashes() function
86 $this->CI->load->helper('string');
87
88 // Do we need encryption? If so, load the encryption class
89 if ($this->sess_encrypt_cookie == TRUE)
90 {
91 $this->CI->load->library('encrypt');
92 }
93
Andrey Andreeveea2ff52012-01-19 13:21:53 +020094 // Are we using a database? If so, load it
Andrey Andreevf8868182012-01-20 13:14:53 +020095 if ($this->sess_use_database === TRUE && $this->sess_table_name != '')
Derek Allard2067d1a2008-11-13 22:59:24 +000096 {
97 $this->CI->load->database();
98 }
99
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200100 // Set the "now" time. Can either be GMT or server time, based on the
101 // config prefs. We use this to set the "last activity" time
Derek Allard2067d1a2008-11-13 22:59:24 +0000102 $this->now = $this->_get_time();
103
104 // Set the session length. If the session expiration is
105 // set to zero we'll set the expiration two years from now.
106 if ($this->sess_expiration == 0)
107 {
108 $this->sess_expiration = (60*60*24*365*2);
109 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200110
Derek Allard2067d1a2008-11-13 22:59:24 +0000111 // Set the cookie name
112 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
113
114 // Run the Session routine. If a session doesn't exist we'll
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200115 // create a new one. If it does, we'll update it.
Derek Allard2067d1a2008-11-13 22:59:24 +0000116 if ( ! $this->sess_read())
117 {
118 $this->sess_create();
119 }
120 else
121 {
122 $this->sess_update();
123 }
124
125 // Delete 'old' flashdata (from last request)
Barry Mienydd671972010-10-04 16:33:58 +0200126 $this->_flashdata_sweep();
Derek Allard2067d1a2008-11-13 22:59:24 +0000127
128 // Mark all new flashdata as old (data will be deleted before next request)
Barry Mienydd671972010-10-04 16:33:58 +0200129 $this->_flashdata_mark();
Derek Allard2067d1a2008-11-13 22:59:24 +0000130
131 // Delete expired sessions if necessary
132 $this->_sess_gc();
133
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200134 log_message('debug', 'Session routines successfully run');
Derek Allard2067d1a2008-11-13 22:59:24 +0000135 }
136
137 // --------------------------------------------------------------------
138
139 /**
140 * Fetch the current session data if it exists
141 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000142 * @return bool
143 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200144 public function sess_read()
Derek Allard2067d1a2008-11-13 22:59:24 +0000145 {
146 // Fetch the cookie
147 $session = $this->CI->input->cookie($this->sess_cookie_name);
148
Derek Jones4b9c6292011-07-01 17:40:48 -0500149 // No cookie? Goodbye cruel world!...
Derek Allard2067d1a2008-11-13 22:59:24 +0000150 if ($session === FALSE)
151 {
152 log_message('debug', 'A session cookie was not found.');
153 return FALSE;
154 }
155
156 // Decrypt the cookie data
157 if ($this->sess_encrypt_cookie == TRUE)
158 {
159 $session = $this->CI->encrypt->decode($session);
160 }
161 else
162 {
163 // encryption was not used, so we need to check the md5 hash
164 $hash = substr($session, strlen($session)-32); // get last 32 chars
165 $session = substr($session, 0, strlen($session)-32);
166
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200167 // Does the md5 hash match? This is to prevent manipulation of session data in userspace
Derek Jones4b9c6292011-07-01 17:40:48 -0500168 if ($hash !== md5($session.$this->encryption_key))
Derek Allard2067d1a2008-11-13 22:59:24 +0000169 {
170 log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
171 $this->sess_destroy();
172 return FALSE;
173 }
174 }
175
176 // Unserialize the session array
177 $session = $this->_unserialize($session);
178
179 // Is the session data we unserialized an array with the correct format?
Andrey Andreev7e087f52012-01-20 11:46:27 +0200180 if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
181 {
182 $this->sess_destroy();
183 return FALSE;
184 }
185
186 // Is the session current?
187 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
188 {
189 $this->sess_destroy();
190 return FALSE;
191 }
192
193 // Does the IP match?
194 if ($this->sess_match_ip == TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
195 {
196 $this->sess_destroy();
197 return FALSE;
198 }
199
200 // Does the User Agent Match?
201 if ($this->sess_match_useragent == TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000202 {
203 $this->sess_destroy();
204 return FALSE;
205 }
206
207 // Is there a corresponding session in the DB?
208 if ($this->sess_use_database === TRUE)
209 {
210 $this->CI->db->where('session_id', $session['session_id']);
211
212 if ($this->sess_match_ip == TRUE)
213 {
214 $this->CI->db->where('ip_address', $session['ip_address']);
215 }
216
217 if ($this->sess_match_useragent == TRUE)
218 {
219 $this->CI->db->where('user_agent', $session['user_agent']);
220 }
221
222 $query = $this->CI->db->get($this->sess_table_name);
223
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200224 // No result? Kill it!
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200225 if ($query->num_rows() === 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000226 {
227 $this->sess_destroy();
228 return FALSE;
229 }
230
Derek Jones4b9c6292011-07-01 17:40:48 -0500231 // Is there custom data? If so, add it to the main session array
Derek Allard2067d1a2008-11-13 22:59:24 +0000232 $row = $query->row();
Andrey Andreevf8868182012-01-20 13:14:53 +0200233 if (isset($row->user_data) && $row->user_data != '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000234 {
235 $custom_data = $this->_unserialize($row->user_data);
236
237 if (is_array($custom_data))
238 {
239 foreach ($custom_data as $key => $val)
240 {
241 $session[$key] = $val;
242 }
243 }
244 }
245 }
246
247 // Session is valid!
248 $this->userdata = $session;
249 unset($session);
250
251 return TRUE;
252 }
253
254 // --------------------------------------------------------------------
255
256 /**
257 * Write the session data
258 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 * @return void
260 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200261 public function sess_write()
Derek Allard2067d1a2008-11-13 22:59:24 +0000262 {
Derek Jones4b9c6292011-07-01 17:40:48 -0500263 // Are we saving custom data to the DB? If not, all we do is update the cookie
Derek Allard2067d1a2008-11-13 22:59:24 +0000264 if ($this->sess_use_database === FALSE)
265 {
266 $this->_set_cookie();
267 return;
268 }
269
270 // set the custom userdata, the session data we will set in a second
271 $custom_userdata = $this->userdata;
272 $cookie_userdata = array();
273
274 // Before continuing, we need to determine if there is any custom data to deal with.
275 // Let's determine this by removing the default indexes to see if there's anything left in the array
276 // and set the session data while we're at it
277 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
278 {
279 unset($custom_userdata[$val]);
280 $cookie_userdata[$val] = $this->userdata[$val];
281 }
282
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200283 // Did we find any custom data? If not, we turn the empty array into a string
Derek Allard2067d1a2008-11-13 22:59:24 +0000284 // since there's no reason to serialize and store an empty array in the DB
285 if (count($custom_userdata) === 0)
286 {
287 $custom_userdata = '';
288 }
289 else
290 {
291 // Serialize the custom data array so we can store it
292 $custom_userdata = $this->_serialize($custom_userdata);
293 }
294
295 // Run the update query
296 $this->CI->db->where('session_id', $this->userdata['session_id']);
297 $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
298
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200299 // Write the cookie. Notice that we manually pass the cookie data array to the
Derek Allard2067d1a2008-11-13 22:59:24 +0000300 // _set_cookie() function. Normally that function will store $this->userdata, but
301 // in this case that array contains custom data, which we do not want in the cookie.
302 $this->_set_cookie($cookie_userdata);
303 }
304
305 // --------------------------------------------------------------------
306
307 /**
308 * Create a new session
309 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000310 * @return void
311 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200312 public function sess_create()
Derek Allard2067d1a2008-11-13 22:59:24 +0000313 {
314 $sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200315 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000316 {
317 $sessid .= mt_rand(0, mt_getrandmax());
318 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200319 while (strlen($sessid) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000320
321 // To make the session ID even more secure we'll combine it with the user's IP
322 $sessid .= $this->CI->input->ip_address();
323
324 $this->userdata = array(
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200325 'session_id' => md5(uniqid($sessid, TRUE)),
326 'ip_address' => $this->CI->input->ip_address(),
327 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
328 'last_activity' => $this->now,
329 'user_data' => ''
330 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000331
332 // Save the data to the DB if needed
333 if ($this->sess_use_database === TRUE)
334 {
335 $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
336 }
337
338 // Write the cookie
339 $this->_set_cookie();
340 }
341
342 // --------------------------------------------------------------------
343
344 /**
345 * Update an existing session
346 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000347 * @return void
348 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200349 public function sess_update()
Derek Allard2067d1a2008-11-13 22:59:24 +0000350 {
351 // We only update the session every five minutes by default
Andrey Andreev9c622f32012-01-19 14:12:54 +0200352 if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Derek Allard2067d1a2008-11-13 22:59:24 +0000353 {
354 return;
355 }
356
Andrey Andreev9c622f32012-01-19 14:12:54 +0200357 // _set_cookie() will handle this for us if we aren't using database sessions
358 // by pushing all userdata to the cookie.
359 $cookie_data = NULL;
360
361 /* Changing the session ID during an AJAX call causes problems,
362 * so we'll only update our last_activity
363 */
364 if ($this->CI->input->is_ajax_request())
365 {
366 $this->userdata['last_activity'] = $this->now;
367
368 // Update the session ID and last_activity field in the DB if needed
369 if ($this->sess_use_database === TRUE)
370 {
371 // set cookie explicitly to only have our session data
372 $cookie_data = array();
373 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
374 {
375 $cookie_data[$val] = $this->userdata[$val];
376 }
377
378 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
379 array('last_activity' => $this->userdata['last_activity']),
380 array('session_id' => $this->userdata['session_id'])));
381 }
382
383 return $this->_set_cookie($cookie_data);
384 }
385
Derek Allard2067d1a2008-11-13 22:59:24 +0000386 // Save the old session id so we know which record to
387 // update in the database if we need it
388 $old_sessid = $this->userdata['session_id'];
389 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200390 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 {
392 $new_sessid .= mt_rand(0, mt_getrandmax());
393 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200394 while (strlen($new_sessid) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000395
396 // To make the session ID even more secure we'll combine it with the user's IP
397 $new_sessid .= $this->CI->input->ip_address();
398
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200399 // Turn it into a hash and update the session data array
400 $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
Derek Allard2067d1a2008-11-13 22:59:24 +0000401 $this->userdata['last_activity'] = $this->now;
402
Derek Allard2067d1a2008-11-13 22:59:24 +0000403 // Update the session ID and last_activity field in the DB if needed
404 if ($this->sess_use_database === TRUE)
405 {
406 // set cookie explicitly to only have our session data
407 $cookie_data = array();
408 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
409 {
410 $cookie_data[$val] = $this->userdata[$val];
411 }
412
413 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
414 }
415
416 // Write the cookie
417 $this->_set_cookie($cookie_data);
418 }
419
420 // --------------------------------------------------------------------
421
422 /**
423 * Destroy the current session
424 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000425 * @return void
426 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200427 public function sess_destroy()
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 {
429 // Kill the session DB row
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200430 if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000431 {
432 $this->CI->db->where('session_id', $this->userdata['session_id']);
433 $this->CI->db->delete($this->sess_table_name);
434 }
435
436 // Kill the cookie
437 setcookie(
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200438 $this->sess_cookie_name,
439 addslashes(serialize(array())),
440 ($this->now - 31500000),
441 $this->cookie_path,
442 $this->cookie_domain,
443 0
444 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000445 }
446
447 // --------------------------------------------------------------------
448
449 /**
450 * Fetch a specific item from the session array
451 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000452 * @param string
453 * @return string
454 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200455 public function userdata($item)
Derek Allard2067d1a2008-11-13 22:59:24 +0000456 {
457 return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
458 }
459
460 // --------------------------------------------------------------------
461
462 /**
463 * Fetch all session data
464 *
Greg Aker34033662011-04-18 11:18:09 -0500465 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200467 public function all_userdata()
Derek Allard2067d1a2008-11-13 22:59:24 +0000468 {
Greg Aker34033662011-04-18 11:18:09 -0500469 return $this->userdata;
Derek Allard2067d1a2008-11-13 22:59:24 +0000470 }
Mike Funkc15e17c2012-02-23 14:56:18 -0500471
472 // --------------------------------------------------------------------------
473
474 /**
475 * Fetch all flashdata
476 *
Mike Funkc91a66c2012-02-28 13:46:00 -0500477 * @return array
Mike Funkc15e17c2012-02-23 14:56:18 -0500478 */
479 public function all_flashdata()
480 {
481 $out = array();
482
483 // loop through all userdata
484 foreach ($this->all_userdata() as $key => $val)
485 {
486 // if it contains flashdata, add it
487 if (strpos($key, 'flash:old:') !== FALSE)
488 {
489 $out[$key] = $val;
490 }
491 }
492 return $out;
493 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000494
495 // --------------------------------------------------------------------
496
497 /**
498 * Add or change data in the "userdata" array
499 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000500 * @param mixed
501 * @param string
502 * @return void
503 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200504 public function set_userdata($newdata = array(), $newval = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000505 {
506 if (is_string($newdata))
507 {
508 $newdata = array($newdata => $newval);
509 }
510
511 if (count($newdata) > 0)
512 {
513 foreach ($newdata as $key => $val)
514 {
515 $this->userdata[$key] = $val;
516 }
517 }
518
519 $this->sess_write();
520 }
521
522 // --------------------------------------------------------------------
523
524 /**
525 * Delete a session variable from the "userdata" array
526 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000527 * @return void
528 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200529 public function unset_userdata($newdata = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000530 {
531 if (is_string($newdata))
532 {
533 $newdata = array($newdata => '');
534 }
535
536 if (count($newdata) > 0)
537 {
538 foreach ($newdata as $key => $val)
539 {
540 unset($this->userdata[$key]);
541 }
542 }
543
544 $this->sess_write();
545 }
546
547 // ------------------------------------------------------------------------
548
549 /**
550 * Add or change flashdata, only available
551 * until the next request
552 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000553 * @param mixed
554 * @param string
555 * @return void
556 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200557 public function set_flashdata($newdata = array(), $newval = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000558 {
559 if (is_string($newdata))
560 {
561 $newdata = array($newdata => $newval);
562 }
563
564 if (count($newdata) > 0)
565 {
566 foreach ($newdata as $key => $val)
567 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200568 $this->set_userdata($this->flashdata_key.':new:'.$key, $val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000569 }
570 }
571 }
572
573 // ------------------------------------------------------------------------
574
575 /**
576 * Keeps existing flashdata available to next request.
577 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000578 * @param string
579 * @return void
580 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200581 public function keep_flashdata($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000582 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200583 // 'old' flashdata gets removed. Here we mark all
Derek Allard2067d1a2008-11-13 22:59:24 +0000584 // flashdata as 'new' to preserve it from _flashdata_sweep()
585 // Note the function will return FALSE if the $key
586 // provided cannot be found
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200587 $value = $this->userdata($this->flashdata_key.':old:'.$key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000588
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200589 $this->set_userdata($this->flashdata_key.':new:'.$key, $value);
Derek Allard2067d1a2008-11-13 22:59:24 +0000590 }
591
592 // ------------------------------------------------------------------------
593
594 /**
595 * Fetch a specific flashdata item from the session array
596 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000597 * @param string
598 * @return string
599 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200600 public function flashdata($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000601 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200602 return $this->userdata($this->flashdata_key.':old:'.$key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000603 }
604
605 // ------------------------------------------------------------------------
606
607 /**
608 * Identifies flashdata as 'old' for removal
609 * when _flashdata_sweep() runs.
610 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000611 * @return void
612 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200613 protected function _flashdata_mark()
Derek Allard2067d1a2008-11-13 22:59:24 +0000614 {
615 $userdata = $this->all_userdata();
616 foreach ($userdata as $name => $value)
617 {
618 $parts = explode(':new:', $name);
619 if (is_array($parts) && count($parts) === 2)
620 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200621 $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value);
Derek Allard2067d1a2008-11-13 22:59:24 +0000622 $this->unset_userdata($name);
623 }
624 }
625 }
626
627 // ------------------------------------------------------------------------
628
629 /**
630 * Removes all flashdata marked as 'old'
631 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000632 * @return void
633 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200634 protected function _flashdata_sweep()
Derek Allard2067d1a2008-11-13 22:59:24 +0000635 {
636 $userdata = $this->all_userdata();
637 foreach ($userdata as $key => $value)
638 {
639 if (strpos($key, ':old:'))
640 {
641 $this->unset_userdata($key);
642 }
643 }
644
645 }
646
647 // --------------------------------------------------------------------
648
649 /**
650 * Get the "now" time
651 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000652 * @return string
653 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200654 protected function _get_time()
Derek Allard2067d1a2008-11-13 22:59:24 +0000655 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200656 return (strtolower($this->time_reference) === 'gmt')
657 ? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y'))
658 : time();
Derek Allard2067d1a2008-11-13 22:59:24 +0000659 }
660
661 // --------------------------------------------------------------------
662
663 /**
664 * Write the session cookie
665 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000666 * @return void
667 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200668 protected function _set_cookie($cookie_data = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000669 {
670 if (is_null($cookie_data))
671 {
672 $cookie_data = $this->userdata;
673 }
674
675 // Serialize the userdata for the cookie
676 $cookie_data = $this->_serialize($cookie_data);
677
678 if ($this->sess_encrypt_cookie == TRUE)
679 {
680 $cookie_data = $this->CI->encrypt->encode($cookie_data);
681 }
682 else
683 {
684 // if encryption is not used, we provide an md5 hash to prevent userside tampering
685 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
686 }
Barry Mienydd671972010-10-04 16:33:58 +0200687
Derek Joneseaa71ba2010-09-02 10:32:07 -0500688 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
Barry Mienydd671972010-10-04 16:33:58 +0200689
Derek Allard2067d1a2008-11-13 22:59:24 +0000690 // Set the cookie
691 setcookie(
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200692 $this->sess_cookie_name,
693 $cookie_data,
694 $expire,
695 $this->cookie_path,
696 $this->cookie_domain,
697 $this->cookie_secure
698 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000699 }
700
701 // --------------------------------------------------------------------
702
703 /**
704 * Serialize an array
705 *
706 * This function first converts any slashes found in the array to a temporary
707 * marker, so when it gets unserialized the slashes will be preserved
708 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000709 * @param array
710 * @return string
711 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200712 protected function _serialize($data)
Derek Allard2067d1a2008-11-13 22:59:24 +0000713 {
714 if (is_array($data))
715 {
Chris Muench95933492011-10-16 14:14:04 -0400716 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000717 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200718 elseif (is_string($data))
Derek Allard2067d1a2008-11-13 22:59:24 +0000719 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200720 $data = str_replace('\\', '{{slash}}', $data);
Derek Allard2067d1a2008-11-13 22:59:24 +0000721 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000722 return serialize($data);
723 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200724
Chris Muench95933492011-10-16 14:14:04 -0400725 /**
726 * Escape slashes
727 *
728 * This function converts any slashes found into a temporary marker
729 *
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200730 * @param string
731 * @param string
732 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400733 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200734 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400735 {
736 if (is_string($val))
737 {
738 $val = str_replace('\\', '{{slash}}', $val);
739 }
740 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000741
742 // --------------------------------------------------------------------
743
744 /**
745 * Unserialize
746 *
747 * This function unserializes a data string, then converts any
748 * temporary slash markers back to actual slashes
749 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000750 * @param array
751 * @return string
752 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200753 protected function _unserialize($data)
Derek Allard2067d1a2008-11-13 22:59:24 +0000754 {
755 $data = @unserialize(strip_slashes($data));
756
757 if (is_array($data))
758 {
Chris Muench95933492011-10-16 14:14:04 -0400759 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000760 return $data;
761 }
762
Derek Jones133e6662010-03-29 11:36:42 -0500763 return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000764 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200765
Chris Muench95933492011-10-16 14:14:04 -0400766 /**
767 * Unescape slashes
768 *
769 * This function converts any slash markers back into actual slashes
770 *
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200771 * @param string
772 * @param string
773 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400774 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200775 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400776 {
Chris Muench3e414f92011-10-16 23:03:55 -0400777 if (is_string($val))
778 {
779 $val= str_replace('{{slash}}', '\\', $val);
780 }
Chris Muench95933492011-10-16 14:14:04 -0400781 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000782
783 // --------------------------------------------------------------------
784
785 /**
786 * Garbage collection
787 *
788 * This deletes expired session rows from database
789 * if the probability percentage is met
790 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000791 * @return void
792 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200793 protected function _sess_gc()
Derek Allard2067d1a2008-11-13 22:59:24 +0000794 {
795 if ($this->sess_use_database != TRUE)
796 {
797 return;
798 }
799
800 srand(time());
801 if ((rand() % 100) < $this->gc_probability)
802 {
803 $expire = $this->now - $this->sess_expiration;
804
805 $this->CI->db->where("last_activity < {$expire}");
806 $this->CI->db->delete($this->sess_table_name);
807
808 log_message('debug', 'Session garbage collection performed.');
809 }
810 }
811
Derek Allard2067d1a2008-11-13 22:59:24 +0000812}
Derek Allard2067d1a2008-11-13 22:59:24 +0000813
814/* End of file Session.php */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200815/* Location: ./system/libraries/Session.php */