blob: 16f373fd089be9822c3d3d6172e0b2d4d5456528 [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.
10 * @license http://www.codeignitor.com/user_guide/license.html
11 * @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
20 *
21 * @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
adminb3ab70b2006-10-07 03:07:29 +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;
34 var $sess_length = 7200;
35 var $sess_cookie = 'ci_session';
36 var $userdata = array();
37 var $gc_probability = 5;
adminb3ab70b2006-10-07 03:07:29 +000038
adminb0dd10f2006-08-25 17:25:49 +000039
40
41 /**
42 * Session Constructor
43 *
44 * The constructor runs the session routines automatically
45 * whenever the class is instantiated.
46 */
47 function CI_Session()
48 {
adminb3ab70b2006-10-07 03:07:29 +000049 $this->CI =& get_instance();
adminb0dd10f2006-08-25 17:25:49 +000050
51 log_message('debug', "Session Class Initialized");
52 $this->sess_run();
53 }
54 // END display_errors()
55
56 // --------------------------------------------------------------------
57
58 /**
59 * Run the session routines
60 *
61 * @access public
62 * @return void
63 */
64 function sess_run()
65 {
66 /*
67 * Set the "now" time
68 *
69 * It can either set to GMT or time(). The pref
70 * is set in the config file. If the developer
71 * is doing any sort of time localization they
72 * might want to set the session time to GMT so
73 * they can offset the "last_activity" and
74 * "last_visit" times based on each user's locale.
75 *
76 */
adminb3ab70b2006-10-07 03:07:29 +000077 if (strtolower($this->CI->config->item('time_reference')) == 'gmt')
adminb0dd10f2006-08-25 17:25:49 +000078 {
79 $now = time();
80 $this->now = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
81
82 if (strlen($this->now) < 10)
83 {
84 $this->now = time();
85 log_message('error', 'The session class could not set a proper GMT timestamp so the local time() value was used.');
86 }
87 }
88 else
89 {
90 $this->now = time();
91 }
92
93 /*
94 * Set the session length
95 *
96 * If the session expiration is set to zero in
97 * the config file we'll set the expiration
98 * two years from now.
99 *
100 */
adminb3ab70b2006-10-07 03:07:29 +0000101 $expiration = $this->CI->config->item('sess_expiration');
adminb0dd10f2006-08-25 17:25:49 +0000102
admin1cf89aa2006-09-03 18:24:39 +0000103 if (is_numeric($expiration))
adminb0dd10f2006-08-25 17:25:49 +0000104 {
105 if ($expiration > 0)
106 {
adminb3ab70b2006-10-07 03:07:29 +0000107 $this->sess_length = $this->CI->config->item('sess_expiration');
adminb0dd10f2006-08-25 17:25:49 +0000108 }
109 else
110 {
111 $this->sess_length = (60*60*24*365*2);
112 }
113 }
114
115 // Do we need encryption?
adminb3ab70b2006-10-07 03:07:29 +0000116 $this->encryption = $this->CI->config->item('sess_encrypt_cookie');
adminb0dd10f2006-08-25 17:25:49 +0000117
118 if ($this->encryption == TRUE)
119 {
adminb3ab70b2006-10-07 03:07:29 +0000120 $this->CI->load->library('encrypt');
adminb0dd10f2006-08-25 17:25:49 +0000121 }
122
123 // Are we using a database?
adminb3ab70b2006-10-07 03:07:29 +0000124 if ($this->CI->config->item('sess_use_database') === TRUE AND $this->CI->config->item('sess_table_name') != '')
adminb0dd10f2006-08-25 17:25:49 +0000125 {
126 $this->use_database = TRUE;
adminb3ab70b2006-10-07 03:07:29 +0000127 $this->session_table = $this->CI->config->item('sess_table_name');
128 $this->CI->load->database();
adminb0dd10f2006-08-25 17:25:49 +0000129 }
130
131 // Set the cookie name
adminb3ab70b2006-10-07 03:07:29 +0000132 if ($this->CI->config->item('sess_cookie_name') != FALSE)
adminb0dd10f2006-08-25 17:25:49 +0000133 {
adminb3ab70b2006-10-07 03:07:29 +0000134 $this->sess_cookie = $this->CI->config->item('cookie_prefix').$this->CI->config->item('sess_cookie_name');
adminb0dd10f2006-08-25 17:25:49 +0000135 }
136
137 /*
138 * Fetch the current session
139 *
140 * If a session doesn't exist we'll create
141 * a new one. If it does, we'll update it.
142 *
143 */
144 if ( ! $this->sess_read())
145 {
146 $this->sess_create();
147 }
148 else
149 {
150 // We only update the session every five minutes
151 if (($this->userdata['last_activity'] + 300) < $this->now)
152 {
153 $this->sess_update();
154 }
155 }
156
157 // Delete expired sessions if necessary
158 if ($this->use_database === TRUE)
159 {
160 $this->sess_gc();
161 }
162 }
163 // END sess_run()
164
165 // --------------------------------------------------------------------
166
167 /**
168 * Fetch the current session data if it exists
169 *
170 * @access public
171 * @return void
172 */
173 function sess_read()
174 {
175 // Fetch the cookie
adminb3ab70b2006-10-07 03:07:29 +0000176 $session = $this->CI->input->cookie($this->sess_cookie);
adminb0dd10f2006-08-25 17:25:49 +0000177
178 if ($session === FALSE)
179 {
180 log_message('debug', 'A session cookie was not found.');
181 return FALSE;
182 }
183
184 // Decrypt and unserialize the data
185 if ($this->encryption == TRUE)
186 {
adminb3ab70b2006-10-07 03:07:29 +0000187 $session = $this->CI->encrypt->decode($session);
adminb0dd10f2006-08-25 17:25:49 +0000188 }
189
190 $session = @unserialize($this->strip_slashes($session));
191
192 if ( ! is_array($session) OR ! isset($session['last_activity']))
193 {
194 log_message('error', 'The session cookie data did not contain a valid array. This could be a possible hacking attempt.');
195 return FALSE;
196 }
197
198 // Is the session current?
199 if (($session['last_activity'] + $this->sess_length) < $this->now)
200 {
201 $this->sess_destroy();
202 return FALSE;
203 }
204
205 // Does the IP Match?
adminb3ab70b2006-10-07 03:07:29 +0000206 if ($this->CI->config->item('sess_match_ip') == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
adminb0dd10f2006-08-25 17:25:49 +0000207 {
208 $this->sess_destroy();
209 return FALSE;
210 }
211
212 // Does the User Agent Match?
adminb3ab70b2006-10-07 03:07:29 +0000213 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 +0000214 {
215 $this->sess_destroy();
216 return FALSE;
217 }
218
219 // Is there a corresponding session in the DB?
220 if ($this->use_database === TRUE)
221 {
adminb3ab70b2006-10-07 03:07:29 +0000222 $this->CI->db->where('session_id', $session['session_id']);
adminb0dd10f2006-08-25 17:25:49 +0000223
adminb3ab70b2006-10-07 03:07:29 +0000224 if ($this->CI->config->item('sess_match_ip') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000225 {
adminb3ab70b2006-10-07 03:07:29 +0000226 $this->CI->db->where('ip_address', $session['ip_address']);
adminb0dd10f2006-08-25 17:25:49 +0000227 }
228
adminb3ab70b2006-10-07 03:07:29 +0000229 if ($this->CI->config->item('sess_match_useragent') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000230 {
adminb3ab70b2006-10-07 03:07:29 +0000231 $this->CI->db->where('user_agent', $session['user_agent']);
adminb0dd10f2006-08-25 17:25:49 +0000232 }
233
adminb3ab70b2006-10-07 03:07:29 +0000234 $query = $this->CI->db->get($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000235
236 if ($query->num_rows() == 0)
237 {
238 $this->sess_destroy();
239 return FALSE;
240 }
241 else
242 {
243 $row = $query->row();
244 if (($row->last_activity + $this->sess_length) < $this->now)
245 {
adminb3ab70b2006-10-07 03:07:29 +0000246 $this->CI->db->where('session_id', $session['session_id']);
247 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000248 $this->sess_destroy();
249 return FALSE;
250 }
251 }
252 }
253
254 // Session is valid!
255 $this->userdata = $session;
256 unset($session);
257
258 return TRUE;
259 }
260 // END sess_read()
261
262 // --------------------------------------------------------------------
263
264 /**
265 * Write the session cookie
266 *
267 * @access public
268 * @return void
269 */
270 function sess_write()
271 {
272 $cookie_data = serialize($this->userdata);
273
274 if ($this->encryption == TRUE)
275 {
adminb3ab70b2006-10-07 03:07:29 +0000276 $cookie_data = $this->CI->encrypt->encode($cookie_data);
adminb0dd10f2006-08-25 17:25:49 +0000277 }
278
279 setcookie(
280 $this->sess_cookie,
281 $cookie_data,
282 $this->sess_length + $this->now,
adminb3ab70b2006-10-07 03:07:29 +0000283 $this->CI->config->item('cookie_path'),
284 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000285 0
286 );
287 }
288 // END sess_read()
289
290 // --------------------------------------------------------------------
291
292 /**
293 * Create a new session
294 *
295 * @access public
296 * @return void
297 */
298 function sess_create()
299 {
300 $sessid = '';
301 while (strlen($sessid) < 32)
302 {
303 $sessid .= mt_rand(0, mt_getrandmax());
304 }
305
306 $this->userdata = array(
307 'session_id' => md5(uniqid($sessid, TRUE)),
adminb3ab70b2006-10-07 03:07:29 +0000308 'ip_address' => $this->CI->input->ip_address(),
309 'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
adminb0dd10f2006-08-25 17:25:49 +0000310 'last_activity' => $this->now
311 );
312
313
314 // Save the session in the DB if needed
315 if ($this->use_database === TRUE)
316 {
adminb3ab70b2006-10-07 03:07:29 +0000317 $this->CI->db->query($this->CI->db->insert_string($this->session_table, $this->userdata));
adminb0dd10f2006-08-25 17:25:49 +0000318 }
319
320 // Write the cookie
321 $this->userdata['last_visit'] = 0;
322 $this->sess_write();
323 }
324 // END sess_read()
325
326 // --------------------------------------------------------------------
327
328 /**
329 * Update an existing session
330 *
331 * @access public
332 * @return void
333 */
334 function sess_update()
335 {
336 if (($this->userdata['last_activity'] + $this->sess_length) < $this->now)
337 {
338 $this->userdata['last_visit'] = $this->userdata['last_activity'];
339 }
340
341 $this->userdata['last_activity'] = $this->now;
342
343 // Update the session in the DB if needed
344 if ($this->use_database === TRUE)
345 {
adminb3ab70b2006-10-07 03:07:29 +0000346 $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 +0000347 }
348
349 // Write the cookie
350 $this->sess_write();
351 }
352 // END sess_update()
353
354 // --------------------------------------------------------------------
355
356 /**
357 * Destroy the current session
358 *
359 * @access public
360 * @return void
361 */
362 function sess_destroy()
363 {
364 setcookie(
365 $this->sess_cookie,
366 addslashes(serialize(array())),
367 ($this->now - 31500000),
adminb3ab70b2006-10-07 03:07:29 +0000368 $this->CI->config->item('cookie_path'),
369 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000370 0
371 );
372 }
373 // END sess_destroy()
374
375 // --------------------------------------------------------------------
376
377 /**
378 * Garbage collection
379 *
380 * This deletes expired session rows from database
381 * if the probability percentage is met
382 *
383 * @access public
384 * @return void
385 */
386 function sess_gc()
387 {
388 srand(time());
389 if ((rand() % 100) < $this->gc_probability)
390 {
391 $expire = $this->now - $this->sess_length;
392
adminb3ab70b2006-10-07 03:07:29 +0000393 $this->CI->db->where("last_activity < {$expire}");
394 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000395
396 log_message('debug', 'Session garbage collection performed.');
397 }
398 }
399 // END sess_destroy()
400
401 // --------------------------------------------------------------------
402
403 /**
404 * Fetch a specific item form the session array
405 *
406 * @access public
407 * @param string
408 * @return string
409 */
410 function userdata($item)
411 {
412 return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
413 }
414 // END sess_destroy()
415
416 // --------------------------------------------------------------------
417
418 /**
419 * Add or change data in the "userdata" array
420 *
421 * @access public
422 * @param mixed
423 * @param string
424 * @return void
425 */
426 function set_userdata($newdata = array(), $newval = '')
427 {
428 if (is_string($newdata))
429 {
430 $newdata = array($newdata => $newval);
431 }
432
433 if (count($newdata) > 0)
434 {
435 foreach ($newdata as $key => $val)
436 {
437 $this->userdata[$key] = $val;
438 }
439 }
440
441 $this->sess_write();
442 }
443 // END set_userdata()
444
445 // --------------------------------------------------------------------
446
447 /**
448 * Delete a session variable from the "userdata" array
449 *
450 * @access array
451 * @return void
452 */
453 function unset_userdata($newdata = array())
454 {
455 if (is_string($newdata))
456 {
457 $newdata = array($newdata => '');
458 }
459
460 if (count($newdata) > 0)
461 {
462 foreach ($newdata as $key => $val)
463 {
464 unset($this->userdata[$key]);
465 }
466 }
467
468 $this->sess_write();
469 }
470 // END set_userdata()
471
472 // --------------------------------------------------------------------
473
474 /**
475 * Strip slashes
476 *
477 * @access public
478 * @param mixed
479 * @return mixed
480 */
481 function strip_slashes($vals)
482 {
483 if (is_array($vals))
484 {
485 foreach ($vals as $key=>$val)
486 {
487 $vals[$key] = $this->strip_slashes($val);
488 }
489 }
490 else
491 {
492 $vals = stripslashes($vals);
493 }
494
495 return $vals;
496 }
497 // END strip_slashes()
498}
499// END Session Class
500?>