blob: 3a80c162619346b09f5ba3fa81a3a835fdd6155e [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 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev57ffbbb2011-12-25 04:48:47 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
Andrey 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;
freewil4ad0fd82012-03-13 22:37:42 -040051 public $cookie_httponly = FALSE;
Andrey Andreev57ffbbb2011-12-25 04:48:47 +020052 public $sess_time_to_update = 300;
53 public $encryption_key = '';
54 public $flashdata_key = 'flash';
55 public $time_reference = 'time';
56 public $gc_probability = 5;
57 public $userdata = array();
58 public $CI;
59 public $now;
Derek Allard2067d1a2008-11-13 22:59:24 +000060
61 /**
62 * Session Constructor
63 *
64 * The constructor runs the session routines automatically
65 * whenever the class is instantiated.
66 */
Greg Akera9263282010-11-10 15:26:43 -060067 public function __construct($params = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000068 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +020069 log_message('debug', 'Session Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000070
71 // Set the super object to a local variable for use throughout the class
72 $this->CI =& get_instance();
73
74 // Set all the session preferences, which can either be set
75 // manually via the $params array above or via the config file
freewil4ad0fd82012-03-13 22:37:42 -040076 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', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
Derek Allard2067d1a2008-11-13 22:59:24 +000077 {
78 $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
79 }
80
Derek Jones5485db52010-08-30 21:31:08 -050081 if ($this->encryption_key == '')
82 {
83 show_error('In order to use the Session class you are required to set an encryption key in your config file.');
84 }
85
Derek Allard2067d1a2008-11-13 22:59:24 +000086 // Load the string helper so we can use the strip_slashes() function
87 $this->CI->load->helper('string');
88
89 // Do we need encryption? If so, load the encryption class
90 if ($this->sess_encrypt_cookie == TRUE)
91 {
92 $this->CI->load->library('encrypt');
93 }
94
Andrey Andreeveea2ff52012-01-19 13:21:53 +020095 // Are we using a database? If so, load it
Andrey Andreevf8868182012-01-20 13:14:53 +020096 if ($this->sess_use_database === TRUE && $this->sess_table_name != '')
Derek Allard2067d1a2008-11-13 22:59:24 +000097 {
98 $this->CI->load->database();
99 }
100
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200101 // Set the "now" time. Can either be GMT or server time, based on the
102 // config prefs. We use this to set the "last activity" time
Derek Allard2067d1a2008-11-13 22:59:24 +0000103 $this->now = $this->_get_time();
104
105 // Set the session length. If the session expiration is
106 // set to zero we'll set the expiration two years from now.
107 if ($this->sess_expiration == 0)
108 {
109 $this->sess_expiration = (60*60*24*365*2);
110 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200111
Derek Allard2067d1a2008-11-13 22:59:24 +0000112 // Set the cookie name
113 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
114
115 // Run the Session routine. If a session doesn't exist we'll
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200116 // create a new one. If it does, we'll update it.
Derek Allard2067d1a2008-11-13 22:59:24 +0000117 if ( ! $this->sess_read())
118 {
119 $this->sess_create();
120 }
121 else
122 {
123 $this->sess_update();
124 }
125
126 // Delete 'old' flashdata (from last request)
Barry Mienydd671972010-10-04 16:33:58 +0200127 $this->_flashdata_sweep();
Derek Allard2067d1a2008-11-13 22:59:24 +0000128
129 // Mark all new flashdata as old (data will be deleted before next request)
Barry Mienydd671972010-10-04 16:33:58 +0200130 $this->_flashdata_mark();
Derek Allard2067d1a2008-11-13 22:59:24 +0000131
132 // Delete expired sessions if necessary
133 $this->_sess_gc();
134
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200135 log_message('debug', 'Session routines successfully run');
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 }
137
138 // --------------------------------------------------------------------
139
140 /**
141 * Fetch the current session data if it exists
142 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000143 * @return bool
144 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200145 public function sess_read()
Derek Allard2067d1a2008-11-13 22:59:24 +0000146 {
147 // Fetch the cookie
148 $session = $this->CI->input->cookie($this->sess_cookie_name);
149
Derek Jones4b9c6292011-07-01 17:40:48 -0500150 // No cookie? Goodbye cruel world!...
Derek Allard2067d1a2008-11-13 22:59:24 +0000151 if ($session === FALSE)
152 {
153 log_message('debug', 'A session cookie was not found.');
154 return FALSE;
155 }
156
157 // Decrypt the cookie data
158 if ($this->sess_encrypt_cookie == TRUE)
159 {
160 $session = $this->CI->encrypt->decode($session);
161 }
162 else
163 {
164 // encryption was not used, so we need to check the md5 hash
165 $hash = substr($session, strlen($session)-32); // get last 32 chars
166 $session = substr($session, 0, strlen($session)-32);
167
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200168 // Does the md5 hash match? This is to prevent manipulation of session data in userspace
Derek Jones4b9c6292011-07-01 17:40:48 -0500169 if ($hash !== md5($session.$this->encryption_key))
Derek Allard2067d1a2008-11-13 22:59:24 +0000170 {
171 log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
172 $this->sess_destroy();
173 return FALSE;
174 }
175 }
176
177 // Unserialize the session array
178 $session = $this->_unserialize($session);
179
180 // Is the session data we unserialized an array with the correct format?
Andrey Andreev7e087f52012-01-20 11:46:27 +0200181 if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
182 {
183 $this->sess_destroy();
184 return FALSE;
185 }
186
187 // Is the session current?
188 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
189 {
190 $this->sess_destroy();
191 return FALSE;
192 }
193
194 // Does the IP match?
195 if ($this->sess_match_ip == TRUE && $session['ip_address'] !== $this->CI->input->ip_address())
196 {
197 $this->sess_destroy();
198 return FALSE;
199 }
200
201 // Does the User Agent Match?
202 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 +0000203 {
204 $this->sess_destroy();
205 return FALSE;
206 }
207
208 // Is there a corresponding session in the DB?
209 if ($this->sess_use_database === TRUE)
210 {
211 $this->CI->db->where('session_id', $session['session_id']);
212
213 if ($this->sess_match_ip == TRUE)
214 {
215 $this->CI->db->where('ip_address', $session['ip_address']);
216 }
217
218 if ($this->sess_match_useragent == TRUE)
219 {
220 $this->CI->db->where('user_agent', $session['user_agent']);
221 }
222
Timothy Warrenf1421922012-03-02 11:51:42 -0500223 $query = $this->CI->db->limit(1)->get($this->sess_table_name);
Derek Allard2067d1a2008-11-13 22:59:24 +0000224
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200225 // No result? Kill it!
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200226 if ($query->num_rows() === 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000227 {
228 $this->sess_destroy();
229 return FALSE;
230 }
231
Derek Jones4b9c6292011-07-01 17:40:48 -0500232 // Is there custom data? If so, add it to the main session array
Derek Allard2067d1a2008-11-13 22:59:24 +0000233 $row = $query->row();
Andrey Andreevf8868182012-01-20 13:14:53 +0200234 if (isset($row->user_data) && $row->user_data != '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000235 {
236 $custom_data = $this->_unserialize($row->user_data);
237
238 if (is_array($custom_data))
239 {
240 foreach ($custom_data as $key => $val)
241 {
242 $session[$key] = $val;
243 }
244 }
245 }
246 }
247
248 // Session is valid!
249 $this->userdata = $session;
250 unset($session);
251
252 return TRUE;
253 }
254
255 // --------------------------------------------------------------------
256
257 /**
258 * Write the session data
259 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000260 * @return void
261 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200262 public function sess_write()
Derek Allard2067d1a2008-11-13 22:59:24 +0000263 {
Derek Jones4b9c6292011-07-01 17:40:48 -0500264 // Are we saving custom data to the DB? If not, all we do is update the cookie
Derek Allard2067d1a2008-11-13 22:59:24 +0000265 if ($this->sess_use_database === FALSE)
266 {
267 $this->_set_cookie();
268 return;
269 }
270
271 // set the custom userdata, the session data we will set in a second
272 $custom_userdata = $this->userdata;
273 $cookie_userdata = array();
274
275 // Before continuing, we need to determine if there is any custom data to deal with.
276 // Let's determine this by removing the default indexes to see if there's anything left in the array
277 // and set the session data while we're at it
278 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
279 {
280 unset($custom_userdata[$val]);
281 $cookie_userdata[$val] = $this->userdata[$val];
282 }
283
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200284 // Did we find any custom data? If not, we turn the empty array into a string
Derek Allard2067d1a2008-11-13 22:59:24 +0000285 // since there's no reason to serialize and store an empty array in the DB
286 if (count($custom_userdata) === 0)
287 {
288 $custom_userdata = '';
289 }
290 else
291 {
292 // Serialize the custom data array so we can store it
293 $custom_userdata = $this->_serialize($custom_userdata);
294 }
295
296 // Run the update query
297 $this->CI->db->where('session_id', $this->userdata['session_id']);
298 $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
299
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200300 // Write the cookie. Notice that we manually pass the cookie data array to the
Derek Allard2067d1a2008-11-13 22:59:24 +0000301 // _set_cookie() function. Normally that function will store $this->userdata, but
302 // in this case that array contains custom data, which we do not want in the cookie.
303 $this->_set_cookie($cookie_userdata);
304 }
305
306 // --------------------------------------------------------------------
307
308 /**
309 * Create a new session
310 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000311 * @return void
312 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200313 public function sess_create()
Derek Allard2067d1a2008-11-13 22:59:24 +0000314 {
315 $sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200316 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000317 {
318 $sessid .= mt_rand(0, mt_getrandmax());
319 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200320 while (strlen($sessid) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000321
322 // To make the session ID even more secure we'll combine it with the user's IP
323 $sessid .= $this->CI->input->ip_address();
324
325 $this->userdata = array(
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200326 'session_id' => md5(uniqid($sessid, TRUE)),
327 'ip_address' => $this->CI->input->ip_address(),
328 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
329 'last_activity' => $this->now,
330 'user_data' => ''
331 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000332
333 // Save the data to the DB if needed
334 if ($this->sess_use_database === TRUE)
335 {
336 $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
337 }
338
339 // Write the cookie
340 $this->_set_cookie();
341 }
342
343 // --------------------------------------------------------------------
344
345 /**
346 * Update an existing session
347 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000348 * @return void
349 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200350 public function sess_update()
Derek Allard2067d1a2008-11-13 22:59:24 +0000351 {
352 // We only update the session every five minutes by default
Andrey Andreev9c622f32012-01-19 14:12:54 +0200353 if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
Derek Allard2067d1a2008-11-13 22:59:24 +0000354 {
355 return;
356 }
357
Andrey Andreev9c622f32012-01-19 14:12:54 +0200358 // _set_cookie() will handle this for us if we aren't using database sessions
359 // by pushing all userdata to the cookie.
360 $cookie_data = NULL;
361
362 /* Changing the session ID during an AJAX call causes problems,
363 * so we'll only update our last_activity
364 */
365 if ($this->CI->input->is_ajax_request())
366 {
367 $this->userdata['last_activity'] = $this->now;
368
369 // Update the session ID and last_activity field in the DB if needed
370 if ($this->sess_use_database === TRUE)
371 {
372 // set cookie explicitly to only have our session data
373 $cookie_data = array();
374 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
375 {
376 $cookie_data[$val] = $this->userdata[$val];
377 }
378
379 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
380 array('last_activity' => $this->userdata['last_activity']),
381 array('session_id' => $this->userdata['session_id'])));
382 }
383
384 return $this->_set_cookie($cookie_data);
385 }
386
Derek Allard2067d1a2008-11-13 22:59:24 +0000387 // Save the old session id so we know which record to
388 // update in the database if we need it
389 $old_sessid = $this->userdata['session_id'];
390 $new_sessid = '';
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200391 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000392 {
393 $new_sessid .= mt_rand(0, mt_getrandmax());
394 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200395 while (strlen($new_sessid) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000396
397 // To make the session ID even more secure we'll combine it with the user's IP
398 $new_sessid .= $this->CI->input->ip_address();
399
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200400 // Turn it into a hash and update the session data array
401 $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
Derek Allard2067d1a2008-11-13 22:59:24 +0000402 $this->userdata['last_activity'] = $this->now;
403
Derek Allard2067d1a2008-11-13 22:59:24 +0000404 // Update the session ID and last_activity field in the DB if needed
405 if ($this->sess_use_database === TRUE)
406 {
407 // set cookie explicitly to only have our session data
408 $cookie_data = array();
409 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
410 {
411 $cookie_data[$val] = $this->userdata[$val];
412 }
413
414 $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)));
415 }
416
417 // Write the cookie
418 $this->_set_cookie($cookie_data);
419 }
420
421 // --------------------------------------------------------------------
422
423 /**
424 * Destroy the current session
425 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000426 * @return void
427 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200428 public function sess_destroy()
Derek Allard2067d1a2008-11-13 22:59:24 +0000429 {
430 // Kill the session DB row
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200431 if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000432 {
433 $this->CI->db->where('session_id', $this->userdata['session_id']);
434 $this->CI->db->delete($this->sess_table_name);
435 }
436
437 // Kill the cookie
438 setcookie(
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200439 $this->sess_cookie_name,
440 addslashes(serialize(array())),
441 ($this->now - 31500000),
442 $this->cookie_path,
443 $this->cookie_domain,
444 0
445 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000446 }
447
448 // --------------------------------------------------------------------
449
450 /**
451 * Fetch a specific item from the session array
452 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 * @param string
454 * @return string
455 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200456 public function userdata($item)
Derek Allard2067d1a2008-11-13 22:59:24 +0000457 {
Andrey Andreev6b831232012-03-06 11:16:57 +0200458 return isset($this->userdata[$item]) ? $this->userdata[$item] : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000459 }
460
461 // --------------------------------------------------------------------
462
463 /**
464 * Fetch all session data
465 *
Greg Aker34033662011-04-18 11:18:09 -0500466 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000467 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200468 public function all_userdata()
Derek Allard2067d1a2008-11-13 22:59:24 +0000469 {
Greg Aker34033662011-04-18 11:18:09 -0500470 return $this->userdata;
Derek Allard2067d1a2008-11-13 22:59:24 +0000471 }
Mike Funkc15e17c2012-02-23 14:56:18 -0500472
473 // --------------------------------------------------------------------------
474
475 /**
476 * Fetch all flashdata
477 *
Mike Funkc91a66c2012-02-28 13:46:00 -0500478 * @return array
Mike Funkc15e17c2012-02-23 14:56:18 -0500479 */
480 public function all_flashdata()
481 {
482 $out = array();
483
484 // loop through all userdata
485 foreach ($this->all_userdata() as $key => $val)
486 {
487 // if it contains flashdata, add it
488 if (strpos($key, 'flash:old:') !== FALSE)
489 {
490 $out[$key] = $val;
491 }
492 }
493 return $out;
494 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000495
496 // --------------------------------------------------------------------
497
498 /**
499 * Add or change data in the "userdata" array
500 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000501 * @param mixed
502 * @param string
503 * @return void
504 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200505 public function set_userdata($newdata = array(), $newval = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000506 {
507 if (is_string($newdata))
508 {
509 $newdata = array($newdata => $newval);
510 }
511
512 if (count($newdata) > 0)
513 {
514 foreach ($newdata as $key => $val)
515 {
516 $this->userdata[$key] = $val;
517 }
518 }
519
520 $this->sess_write();
521 }
522
523 // --------------------------------------------------------------------
524
525 /**
526 * Delete a session variable from the "userdata" array
527 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000528 * @return void
529 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200530 public function unset_userdata($newdata = array())
Derek Allard2067d1a2008-11-13 22:59:24 +0000531 {
532 if (is_string($newdata))
533 {
534 $newdata = array($newdata => '');
535 }
536
537 if (count($newdata) > 0)
538 {
539 foreach ($newdata as $key => $val)
540 {
541 unset($this->userdata[$key]);
542 }
543 }
544
545 $this->sess_write();
546 }
547
548 // ------------------------------------------------------------------------
549
550 /**
551 * Add or change flashdata, only available
552 * until the next request
553 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000554 * @param mixed
555 * @param string
556 * @return void
557 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200558 public function set_flashdata($newdata = array(), $newval = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000559 {
560 if (is_string($newdata))
561 {
562 $newdata = array($newdata => $newval);
563 }
564
565 if (count($newdata) > 0)
566 {
567 foreach ($newdata as $key => $val)
568 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200569 $this->set_userdata($this->flashdata_key.':new:'.$key, $val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000570 }
571 }
572 }
573
574 // ------------------------------------------------------------------------
575
576 /**
577 * Keeps existing flashdata available to next request.
578 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000579 * @param string
580 * @return void
581 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200582 public function keep_flashdata($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000583 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200584 // 'old' flashdata gets removed. Here we mark all
Derek Allard2067d1a2008-11-13 22:59:24 +0000585 // flashdata as 'new' to preserve it from _flashdata_sweep()
586 // Note the function will return FALSE if the $key
587 // provided cannot be found
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200588 $value = $this->userdata($this->flashdata_key.':old:'.$key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000589
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200590 $this->set_userdata($this->flashdata_key.':new:'.$key, $value);
Derek Allard2067d1a2008-11-13 22:59:24 +0000591 }
592
593 // ------------------------------------------------------------------------
594
595 /**
596 * Fetch a specific flashdata item from the session array
597 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000598 * @param string
599 * @return string
600 */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200601 public function flashdata($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000602 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200603 return $this->userdata($this->flashdata_key.':old:'.$key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000604 }
605
606 // ------------------------------------------------------------------------
607
608 /**
609 * Identifies flashdata as 'old' for removal
610 * when _flashdata_sweep() runs.
611 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000612 * @return void
613 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200614 protected function _flashdata_mark()
Derek Allard2067d1a2008-11-13 22:59:24 +0000615 {
616 $userdata = $this->all_userdata();
617 foreach ($userdata as $name => $value)
618 {
619 $parts = explode(':new:', $name);
620 if (is_array($parts) && count($parts) === 2)
621 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200622 $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value);
Derek Allard2067d1a2008-11-13 22:59:24 +0000623 $this->unset_userdata($name);
624 }
625 }
626 }
627
628 // ------------------------------------------------------------------------
629
630 /**
631 * Removes all flashdata marked as 'old'
632 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000633 * @return void
634 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200635 protected function _flashdata_sweep()
Derek Allard2067d1a2008-11-13 22:59:24 +0000636 {
637 $userdata = $this->all_userdata();
638 foreach ($userdata as $key => $value)
639 {
640 if (strpos($key, ':old:'))
641 {
642 $this->unset_userdata($key);
643 }
644 }
645
646 }
647
648 // --------------------------------------------------------------------
649
650 /**
651 * Get the "now" time
652 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 * @return string
654 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200655 protected function _get_time()
Derek Allard2067d1a2008-11-13 22:59:24 +0000656 {
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200657 return (strtolower($this->time_reference) === 'gmt')
658 ? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y'))
659 : time();
Derek Allard2067d1a2008-11-13 22:59:24 +0000660 }
661
662 // --------------------------------------------------------------------
663
664 /**
665 * Write the session cookie
666 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000667 * @return void
668 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200669 protected function _set_cookie($cookie_data = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000670 {
671 if (is_null($cookie_data))
672 {
673 $cookie_data = $this->userdata;
674 }
675
676 // Serialize the userdata for the cookie
677 $cookie_data = $this->_serialize($cookie_data);
678
679 if ($this->sess_encrypt_cookie == TRUE)
680 {
681 $cookie_data = $this->CI->encrypt->encode($cookie_data);
682 }
683 else
684 {
685 // if encryption is not used, we provide an md5 hash to prevent userside tampering
686 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
687 }
Barry Mienydd671972010-10-04 16:33:58 +0200688
Derek Joneseaa71ba2010-09-02 10:32:07 -0500689 $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
Barry Mienydd671972010-10-04 16:33:58 +0200690
Derek Allard2067d1a2008-11-13 22:59:24 +0000691 // Set the cookie
692 setcookie(
freewil4ad0fd82012-03-13 22:37:42 -0400693 $this->sess_cookie_name,
694 $cookie_data,
695 $expire,
696 $this->cookie_path,
697 $this->cookie_domain,
698 $this->cookie_secure,
699 $this->cookie_httponly
700 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000701 }
702
703 // --------------------------------------------------------------------
704
705 /**
706 * Serialize an array
707 *
708 * This function first converts any slashes found in the array to a temporary
709 * marker, so when it gets unserialized the slashes will be preserved
710 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000711 * @param array
712 * @return string
713 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200714 protected function _serialize($data)
Derek Allard2067d1a2008-11-13 22:59:24 +0000715 {
716 if (is_array($data))
717 {
Chris Muench95933492011-10-16 14:14:04 -0400718 array_walk_recursive($data, array(&$this, '_escape_slashes'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000719 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200720 elseif (is_string($data))
Derek Allard2067d1a2008-11-13 22:59:24 +0000721 {
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200722 $data = str_replace('\\', '{{slash}}', $data);
Derek Allard2067d1a2008-11-13 22:59:24 +0000723 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000724 return serialize($data);
725 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200726
Chris Muench95933492011-10-16 14:14:04 -0400727 /**
728 * Escape slashes
729 *
730 * This function converts any slashes found into a temporary marker
731 *
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200732 * @param string
733 * @param string
734 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400735 */
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200736 protected function _escape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400737 {
738 if (is_string($val))
739 {
740 $val = str_replace('\\', '{{slash}}', $val);
741 }
742 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000743
744 // --------------------------------------------------------------------
745
746 /**
747 * Unserialize
748 *
749 * This function unserializes a data string, then converts any
750 * temporary slash markers back to actual slashes
751 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000752 * @param array
753 * @return string
754 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200755 protected function _unserialize($data)
Derek Allard2067d1a2008-11-13 22:59:24 +0000756 {
Andrey Andreev6b831232012-03-06 11:16:57 +0200757 $data = @unserialize(strip_slashes(trim($data)));
Derek Allard2067d1a2008-11-13 22:59:24 +0000758
759 if (is_array($data))
760 {
Chris Muench95933492011-10-16 14:14:04 -0400761 array_walk_recursive($data, array(&$this, '_unescape_slashes'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000762 return $data;
763 }
764
Andrey Andreev6b831232012-03-06 11:16:57 +0200765 return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
Derek Allard2067d1a2008-11-13 22:59:24 +0000766 }
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200767
Andrey Andreev6b831232012-03-06 11:16:57 +0200768 // --------------------------------------------------------------------
769
Chris Muench95933492011-10-16 14:14:04 -0400770 /**
771 * Unescape slashes
772 *
773 * This function converts any slash markers back into actual slashes
774 *
Andrey Andreeveea2ff52012-01-19 13:21:53 +0200775 * @param string
776 * @param string
777 * @return void
Chris Muench95933492011-10-16 14:14:04 -0400778 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200779 protected function _unescape_slashes(&$val, $key)
Chris Muench95933492011-10-16 14:14:04 -0400780 {
Chris Muench3e414f92011-10-16 23:03:55 -0400781 if (is_string($val))
782 {
783 $val= str_replace('{{slash}}', '\\', $val);
784 }
Chris Muench95933492011-10-16 14:14:04 -0400785 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000786
787 // --------------------------------------------------------------------
788
789 /**
790 * Garbage collection
791 *
792 * This deletes expired session rows from database
793 * if the probability percentage is met
794 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000795 * @return void
796 */
Andrey Andreev2c79b762011-12-26 16:54:44 +0200797 protected function _sess_gc()
Derek Allard2067d1a2008-11-13 22:59:24 +0000798 {
799 if ($this->sess_use_database != TRUE)
800 {
801 return;
802 }
803
804 srand(time());
805 if ((rand() % 100) < $this->gc_probability)
806 {
807 $expire = $this->now - $this->sess_expiration;
808
Andrey Andreev6b831232012-03-06 11:16:57 +0200809 $this->CI->db->where('last_activity < '.$expire);
Derek Allard2067d1a2008-11-13 22:59:24 +0000810 $this->CI->db->delete($this->sess_table_name);
811
812 log_message('debug', 'Session garbage collection performed.');
813 }
814 }
815
Derek Allard2067d1a2008-11-13 22:59:24 +0000816}
Derek Allard2067d1a2008-11-13 22:59:24 +0000817
818/* End of file Session.php */
Andrey Andreev57ffbbb2011-12-25 04:48:47 +0200819/* Location: ./system/libraries/Session.php */