blob: 96a0c43b218d76b33f46cea51497a09bd5fbb3b2 [file] [log] [blame]
adminb0dd10f2006-08-25 17:25:49 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
admine334c472006-10-21 19:44:22 +000010 * @license http://www.codeignitor.com/user_guide/license.html
adminb0dd10f2006-08-25 17:25:49 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
admine79dc712006-09-26 03:52:45 +000015
adminb0dd10f2006-08-25 17:25:49 +000016// ------------------------------------------------------------------------
17
18/**
19 * Session Class
admine334c472006-10-21 19:44:22 +000020 *
adminb0dd10f2006-08-25 17:25:49 +000021 * @package CodeIgniter
22 * @subpackage Libraries
23 * @category Sessions
24 * @author Rick Ellis
25 * @link http://www.codeigniter.com/user_guide/libraries/sessions.html
26 */
27class CI_Session {
28
admine334c472006-10-21 19:44:22 +000029 var $CI;
adminb0dd10f2006-08-25 17:25:49 +000030 var $now;
31 var $encryption = TRUE;
32 var $use_database = FALSE;
33 var $session_table = FALSE;
admine334c472006-10-21 19:44:22 +000034 var $sess_length = 7200;
35 var $sess_cookie = 'ci_session';
adminb0dd10f2006-08-25 17:25:49 +000036 var $userdata = array();
admine334c472006-10-21 19:44:22 +000037 var $gc_probability = 5;
38
adminb0dd10f2006-08-25 17:25:49 +000039
40 /**
41 * Session Constructor
42 *
43 * The constructor runs the session routines automatically
44 * whenever the class is instantiated.
45 */
46 function CI_Session()
47 {
adminb3ab70b2006-10-07 03:07:29 +000048 $this->CI =& get_instance();
adminb0dd10f2006-08-25 17:25:49 +000049
50 log_message('debug', "Session Class Initialized");
51 $this->sess_run();
52 }
adminb0dd10f2006-08-25 17:25:49 +000053
54 // --------------------------------------------------------------------
55
56 /**
57 * Run the session routines
58 *
59 * @access public
60 * @return void
61 */
62 function sess_run()
63 {
64 /*
65 * Set the "now" time
66 *
67 * It can either set to GMT or time(). The pref
68 * is set in the config file. If the developer
admine334c472006-10-21 19:44:22 +000069 * is doing any sort of time localization they
adminb0dd10f2006-08-25 17:25:49 +000070 * might want to set the session time to GMT so
71 * they can offset the "last_activity" and
72 * "last_visit" times based on each user's locale.
73 *
74 */
adminb3ab70b2006-10-07 03:07:29 +000075 if (strtolower($this->CI->config->item('time_reference')) == 'gmt')
adminb0dd10f2006-08-25 17:25:49 +000076 {
77 $now = time();
admine334c472006-10-21 19:44:22 +000078 $this->now = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
adminb0dd10f2006-08-25 17:25:49 +000079
80 if (strlen($this->now) < 10)
81 {
82 $this->now = time();
83 log_message('error', 'The session class could not set a proper GMT timestamp so the local time() value was used.');
84 }
85 }
86 else
87 {
88 $this->now = time();
89 }
90
91 /*
92 * Set the session length
93 *
94 * If the session expiration is set to zero in
admine334c472006-10-21 19:44:22 +000095 * the config file we'll set the expiration
adminb0dd10f2006-08-25 17:25:49 +000096 * two years from now.
97 *
98 */
adminb3ab70b2006-10-07 03:07:29 +000099 $expiration = $this->CI->config->item('sess_expiration');
adminb0dd10f2006-08-25 17:25:49 +0000100
admin1cf89aa2006-09-03 18:24:39 +0000101 if (is_numeric($expiration))
adminb0dd10f2006-08-25 17:25:49 +0000102 {
103 if ($expiration > 0)
104 {
adminb3ab70b2006-10-07 03:07:29 +0000105 $this->sess_length = $this->CI->config->item('sess_expiration');
adminb0dd10f2006-08-25 17:25:49 +0000106 }
107 else
108 {
109 $this->sess_length = (60*60*24*365*2);
110 }
111 }
112
adminb06d69f2006-10-13 21:44:17 +0000113 // Do we need encryption?
114 if ($this->CI->config->item('sess_encrypt_cookie') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000115 {
adminb3ab70b2006-10-07 03:07:29 +0000116 $this->CI->load->library('encrypt');
adminb0dd10f2006-08-25 17:25:49 +0000117 }
118
119 // Are we using a database?
adminb3ab70b2006-10-07 03:07:29 +0000120 if ($this->CI->config->item('sess_use_database') === TRUE AND $this->CI->config->item('sess_table_name') != '')
adminb0dd10f2006-08-25 17:25:49 +0000121 {
122 $this->use_database = TRUE;
adminb3ab70b2006-10-07 03:07:29 +0000123 $this->session_table = $this->CI->config->item('sess_table_name');
124 $this->CI->load->database();
adminb0dd10f2006-08-25 17:25:49 +0000125 }
126
127 // Set the cookie name
adminb3ab70b2006-10-07 03:07:29 +0000128 if ($this->CI->config->item('sess_cookie_name') != FALSE)
adminb0dd10f2006-08-25 17:25:49 +0000129 {
adminb3ab70b2006-10-07 03:07:29 +0000130 $this->sess_cookie = $this->CI->config->item('cookie_prefix').$this->CI->config->item('sess_cookie_name');
adminb0dd10f2006-08-25 17:25:49 +0000131 }
132
133 /*
134 * Fetch the current session
135 *
136 * If a session doesn't exist we'll create
137 * a new one. If it does, we'll update it.
138 *
139 */
140 if ( ! $this->sess_read())
141 {
142 $this->sess_create();
143 }
144 else
145 {
146 // We only update the session every five minutes
147 if (($this->userdata['last_activity'] + 300) < $this->now)
148 {
149 $this->sess_update();
150 }
151 }
152
153 // Delete expired sessions if necessary
154 if ($this->use_database === TRUE)
155 {
156 $this->sess_gc();
157 }
158 }
adminb0dd10f2006-08-25 17:25:49 +0000159
160 // --------------------------------------------------------------------
161
162 /**
163 * Fetch the current session data if it exists
164 *
165 * @access public
166 * @return void
167 */
168 function sess_read()
169 {
170 // Fetch the cookie
adminb3ab70b2006-10-07 03:07:29 +0000171 $session = $this->CI->input->cookie($this->sess_cookie);
adminb0dd10f2006-08-25 17:25:49 +0000172
173 if ($session === FALSE)
174 {
175 log_message('debug', 'A session cookie was not found.');
176 return FALSE;
177 }
178
179 // Decrypt and unserialize the data
180 if ($this->encryption == TRUE)
181 {
adminb3ab70b2006-10-07 03:07:29 +0000182 $session = $this->CI->encrypt->decode($session);
adminb0dd10f2006-08-25 17:25:49 +0000183 }
184
185 $session = @unserialize($this->strip_slashes($session));
186
187 if ( ! is_array($session) OR ! isset($session['last_activity']))
188 {
189 log_message('error', 'The session cookie data did not contain a valid array. This could be a possible hacking attempt.');
190 return FALSE;
191 }
192
193 // Is the session current?
admine334c472006-10-21 19:44:22 +0000194 if (($session['last_activity'] + $this->sess_length) < $this->now)
adminb0dd10f2006-08-25 17:25:49 +0000195 {
196 $this->sess_destroy();
197 return FALSE;
198 }
199
200 // Does the IP Match?
adminb3ab70b2006-10-07 03:07:29 +0000201 if ($this->CI->config->item('sess_match_ip') == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
adminb0dd10f2006-08-25 17:25:49 +0000202 {
203 $this->sess_destroy();
204 return FALSE;
205 }
206
207 // Does the User Agent Match?
adminb3ab70b2006-10-07 03:07:29 +0000208 if ($this->CI->config->item('sess_match_useragent') == TRUE AND $session['user_agent'] != substr($this->CI->input->user_agent(), 0, 50))
adminb0dd10f2006-08-25 17:25:49 +0000209 {
210 $this->sess_destroy();
211 return FALSE;
212 }
213
214 // Is there a corresponding session in the DB?
215 if ($this->use_database === TRUE)
216 {
adminb3ab70b2006-10-07 03:07:29 +0000217 $this->CI->db->where('session_id', $session['session_id']);
adminb0dd10f2006-08-25 17:25:49 +0000218
adminb3ab70b2006-10-07 03:07:29 +0000219 if ($this->CI->config->item('sess_match_ip') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000220 {
adminb3ab70b2006-10-07 03:07:29 +0000221 $this->CI->db->where('ip_address', $session['ip_address']);
adminb0dd10f2006-08-25 17:25:49 +0000222 }
223
adminb3ab70b2006-10-07 03:07:29 +0000224 if ($this->CI->config->item('sess_match_useragent') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000225 {
adminb3ab70b2006-10-07 03:07:29 +0000226 $this->CI->db->where('user_agent', $session['user_agent']);
adminb0dd10f2006-08-25 17:25:49 +0000227 }
228
adminb3ab70b2006-10-07 03:07:29 +0000229 $query = $this->CI->db->get($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000230
231 if ($query->num_rows() == 0)
232 {
233 $this->sess_destroy();
234 return FALSE;
235 }
236 else
237 {
238 $row = $query->row();
admine334c472006-10-21 19:44:22 +0000239 if (($row->last_activity + $this->sess_length) < $this->now)
adminb0dd10f2006-08-25 17:25:49 +0000240 {
adminb3ab70b2006-10-07 03:07:29 +0000241 $this->CI->db->where('session_id', $session['session_id']);
242 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000243 $this->sess_destroy();
244 return FALSE;
245 }
246 }
247 }
248
249 // Session is valid!
250 $this->userdata = $session;
251 unset($session);
252
253 return TRUE;
254 }
adminb0dd10f2006-08-25 17:25:49 +0000255
256 // --------------------------------------------------------------------
257
258 /**
259 * Write the session cookie
260 *
261 * @access public
262 * @return void
263 */
264 function sess_write()
265 {
266 $cookie_data = serialize($this->userdata);
267
268 if ($this->encryption == TRUE)
269 {
adminb3ab70b2006-10-07 03:07:29 +0000270 $cookie_data = $this->CI->encrypt->encode($cookie_data);
adminb0dd10f2006-08-25 17:25:49 +0000271 }
272
273 setcookie(
admine334c472006-10-21 19:44:22 +0000274 $this->sess_cookie,
275 $cookie_data,
276 $this->sess_length + $this->now,
277 $this->CI->config->item('cookie_path'),
278 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000279 0
280 );
281 }
adminb0dd10f2006-08-25 17:25:49 +0000282
283 // --------------------------------------------------------------------
284
285 /**
286 * Create a new session
287 *
288 * @access public
289 * @return void
290 */
291 function sess_create()
292 {
293 $sessid = '';
admine334c472006-10-21 19:44:22 +0000294 while (strlen($sessid) < 32)
295 {
adminb0dd10f2006-08-25 17:25:49 +0000296 $sessid .= mt_rand(0, mt_getrandmax());
297 }
298
299 $this->userdata = array(
300 'session_id' => md5(uniqid($sessid, TRUE)),
adminb3ab70b2006-10-07 03:07:29 +0000301 'ip_address' => $this->CI->input->ip_address(),
302 'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
adminb0dd10f2006-08-25 17:25:49 +0000303 'last_activity' => $this->now
304 );
305
306
307 // Save the session in the DB if needed
308 if ($this->use_database === TRUE)
309 {
adminb3ab70b2006-10-07 03:07:29 +0000310 $this->CI->db->query($this->CI->db->insert_string($this->session_table, $this->userdata));
adminb0dd10f2006-08-25 17:25:49 +0000311 }
312
313 // Write the cookie
314 $this->userdata['last_visit'] = 0;
315 $this->sess_write();
316 }
adminb0dd10f2006-08-25 17:25:49 +0000317
318 // --------------------------------------------------------------------
319
320 /**
321 * Update an existing session
322 *
323 * @access public
324 * @return void
325 */
326 function sess_update()
327 {
admine334c472006-10-21 19:44:22 +0000328 if (($this->userdata['last_activity'] + $this->sess_length) < $this->now)
329 {
adminb0dd10f2006-08-25 17:25:49 +0000330 $this->userdata['last_visit'] = $this->userdata['last_activity'];
admine334c472006-10-21 19:44:22 +0000331 }
adminb0dd10f2006-08-25 17:25:49 +0000332
333 $this->userdata['last_activity'] = $this->now;
334
335 // Update the session in the DB if needed
336 if ($this->use_database === TRUE)
337 {
adminb3ab70b2006-10-07 03:07:29 +0000338 $this->CI->db->query($this->CI->db->update_string($this->session_table, array('last_activity' => $this->now), array('session_id' => $this->userdata['session_id'])));
adminb0dd10f2006-08-25 17:25:49 +0000339 }
340
341 // Write the cookie
342 $this->sess_write();
343 }
adminb0dd10f2006-08-25 17:25:49 +0000344
345 // --------------------------------------------------------------------
346
347 /**
348 * Destroy the current session
349 *
350 * @access public
351 * @return void
352 */
353 function sess_destroy()
354 {
355 setcookie(
admine334c472006-10-21 19:44:22 +0000356 $this->sess_cookie,
357 addslashes(serialize(array())),
358 ($this->now - 31500000),
359 $this->CI->config->item('cookie_path'),
360 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000361 0
362 );
363 }
adminb0dd10f2006-08-25 17:25:49 +0000364
365 // --------------------------------------------------------------------
366
367 /**
368 * Garbage collection
369 *
370 * This deletes expired session rows from database
371 * if the probability percentage is met
372 *
373 * @access public
374 * @return void
375 */
admine334c472006-10-21 19:44:22 +0000376 function sess_gc()
377 {
adminb0dd10f2006-08-25 17:25:49 +0000378 srand(time());
admine334c472006-10-21 19:44:22 +0000379 if ((rand() % 100) < $this->gc_probability)
380 {
adminb0dd10f2006-08-25 17:25:49 +0000381 $expire = $this->now - $this->sess_length;
382
adminb3ab70b2006-10-07 03:07:29 +0000383 $this->CI->db->where("last_activity < {$expire}");
384 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000385
386 log_message('debug', 'Session garbage collection performed.');
admine334c472006-10-21 19:44:22 +0000387 }
388 }
adminb0dd10f2006-08-25 17:25:49 +0000389
390 // --------------------------------------------------------------------
391
392 /**
393 * Fetch a specific item form the session array
394 *
395 * @access public
396 * @param string
397 * @return string
398 */
399 function userdata($item)
400 {
admine334c472006-10-21 19:44:22 +0000401 return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
adminb0dd10f2006-08-25 17:25:49 +0000402 }
adminb0dd10f2006-08-25 17:25:49 +0000403
404 // --------------------------------------------------------------------
405
406 /**
407 * Add or change data in the "userdata" array
408 *
409 * @access public
410 * @param mixed
411 * @param string
412 * @return void
413 */
414 function set_userdata($newdata = array(), $newval = '')
415 {
416 if (is_string($newdata))
417 {
418 $newdata = array($newdata => $newval);
419 }
420
421 if (count($newdata) > 0)
422 {
423 foreach ($newdata as $key => $val)
424 {
425 $this->userdata[$key] = $val;
426 }
427 }
428
admine334c472006-10-21 19:44:22 +0000429 $this->sess_write();
adminb0dd10f2006-08-25 17:25:49 +0000430 }
adminb0dd10f2006-08-25 17:25:49 +0000431
432 // --------------------------------------------------------------------
433
434 /**
435 * Delete a session variable from the "userdata" array
436 *
437 * @access array
438 * @return void
439 */
440 function unset_userdata($newdata = array())
441 {
442 if (is_string($newdata))
443 {
444 $newdata = array($newdata => '');
445 }
446
447 if (count($newdata) > 0)
448 {
449 foreach ($newdata as $key => $val)
450 {
451 unset($this->userdata[$key]);
452 }
453 }
454
admine334c472006-10-21 19:44:22 +0000455 $this->sess_write();
adminb0dd10f2006-08-25 17:25:49 +0000456 }
adminb0dd10f2006-08-25 17:25:49 +0000457
458 // --------------------------------------------------------------------
459
460 /**
461 * Strip slashes
462 *
463 * @access public
464 * @param mixed
465 * @return mixed
466 */
admine334c472006-10-21 19:44:22 +0000467 function strip_slashes($vals)
468 {
469 if (is_array($vals))
470 {
471 foreach ($vals as $key=>$val)
472 {
473 $vals[$key] = $this->strip_slashes($val);
474 }
475 }
476 else
477 {
478 $vals = stripslashes($vals);
479 }
480
481 return $vals;
adminb0dd10f2006-08-25 17:25:49 +0000482 }
adminb06d69f2006-10-13 21:44:17 +0000483
adminb0dd10f2006-08-25 17:25:49 +0000484}
485// END Session Class
486?>