blob: c1fc345d9c87144e49effb20ba601e68edac87dc [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
admin36e64422006-10-22 01:30:50 +0000113 // Do we need encryption?
114 $this->encryption = $this->CI->config->item('sess_encrypt_cookie');
115
116 if ($this->encryption == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000117 {
adminb3ab70b2006-10-07 03:07:29 +0000118 $this->CI->load->library('encrypt');
adminb0dd10f2006-08-25 17:25:49 +0000119 }
120
121 // Are we using a database?
adminb3ab70b2006-10-07 03:07:29 +0000122 if ($this->CI->config->item('sess_use_database') === TRUE AND $this->CI->config->item('sess_table_name') != '')
adminb0dd10f2006-08-25 17:25:49 +0000123 {
124 $this->use_database = TRUE;
adminb3ab70b2006-10-07 03:07:29 +0000125 $this->session_table = $this->CI->config->item('sess_table_name');
126 $this->CI->load->database();
adminb0dd10f2006-08-25 17:25:49 +0000127 }
128
129 // Set the cookie name
adminb3ab70b2006-10-07 03:07:29 +0000130 if ($this->CI->config->item('sess_cookie_name') != FALSE)
adminb0dd10f2006-08-25 17:25:49 +0000131 {
adminb3ab70b2006-10-07 03:07:29 +0000132 $this->sess_cookie = $this->CI->config->item('cookie_prefix').$this->CI->config->item('sess_cookie_name');
adminb0dd10f2006-08-25 17:25:49 +0000133 }
134
135 /*
136 * Fetch the current session
137 *
138 * If a session doesn't exist we'll create
139 * a new one. If it does, we'll update it.
140 *
141 */
142 if ( ! $this->sess_read())
143 {
144 $this->sess_create();
145 }
146 else
147 {
148 // We only update the session every five minutes
149 if (($this->userdata['last_activity'] + 300) < $this->now)
150 {
151 $this->sess_update();
152 }
153 }
154
155 // Delete expired sessions if necessary
156 if ($this->use_database === TRUE)
157 {
158 $this->sess_gc();
159 }
160 }
adminb0dd10f2006-08-25 17:25:49 +0000161
162 // --------------------------------------------------------------------
163
164 /**
165 * Fetch the current session data if it exists
166 *
167 * @access public
168 * @return void
169 */
170 function sess_read()
171 {
172 // Fetch the cookie
adminb3ab70b2006-10-07 03:07:29 +0000173 $session = $this->CI->input->cookie($this->sess_cookie);
adminb0dd10f2006-08-25 17:25:49 +0000174
175 if ($session === FALSE)
176 {
177 log_message('debug', 'A session cookie was not found.');
178 return FALSE;
179 }
180
181 // Decrypt and unserialize the data
182 if ($this->encryption == TRUE)
183 {
adminb3ab70b2006-10-07 03:07:29 +0000184 $session = $this->CI->encrypt->decode($session);
adminb0dd10f2006-08-25 17:25:49 +0000185 }
186
187 $session = @unserialize($this->strip_slashes($session));
188
189 if ( ! is_array($session) OR ! isset($session['last_activity']))
190 {
191 log_message('error', 'The session cookie data did not contain a valid array. This could be a possible hacking attempt.');
192 return FALSE;
193 }
194
195 // Is the session current?
admine334c472006-10-21 19:44:22 +0000196 if (($session['last_activity'] + $this->sess_length) < $this->now)
adminb0dd10f2006-08-25 17:25:49 +0000197 {
198 $this->sess_destroy();
199 return FALSE;
200 }
201
202 // Does the IP Match?
adminb3ab70b2006-10-07 03:07:29 +0000203 if ($this->CI->config->item('sess_match_ip') == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
adminb0dd10f2006-08-25 17:25:49 +0000204 {
205 $this->sess_destroy();
206 return FALSE;
207 }
208
209 // Does the User Agent Match?
adminb3ab70b2006-10-07 03:07:29 +0000210 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 +0000211 {
212 $this->sess_destroy();
213 return FALSE;
214 }
215
216 // Is there a corresponding session in the DB?
217 if ($this->use_database === TRUE)
218 {
adminb3ab70b2006-10-07 03:07:29 +0000219 $this->CI->db->where('session_id', $session['session_id']);
adminb0dd10f2006-08-25 17:25:49 +0000220
adminb3ab70b2006-10-07 03:07:29 +0000221 if ($this->CI->config->item('sess_match_ip') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000222 {
adminb3ab70b2006-10-07 03:07:29 +0000223 $this->CI->db->where('ip_address', $session['ip_address']);
adminb0dd10f2006-08-25 17:25:49 +0000224 }
225
adminb3ab70b2006-10-07 03:07:29 +0000226 if ($this->CI->config->item('sess_match_useragent') == TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000227 {
adminb3ab70b2006-10-07 03:07:29 +0000228 $this->CI->db->where('user_agent', $session['user_agent']);
adminb0dd10f2006-08-25 17:25:49 +0000229 }
230
adminb3ab70b2006-10-07 03:07:29 +0000231 $query = $this->CI->db->get($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000232
233 if ($query->num_rows() == 0)
234 {
235 $this->sess_destroy();
236 return FALSE;
237 }
238 else
239 {
240 $row = $query->row();
admine334c472006-10-21 19:44:22 +0000241 if (($row->last_activity + $this->sess_length) < $this->now)
adminb0dd10f2006-08-25 17:25:49 +0000242 {
adminb3ab70b2006-10-07 03:07:29 +0000243 $this->CI->db->where('session_id', $session['session_id']);
244 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000245 $this->sess_destroy();
246 return FALSE;
247 }
248 }
249 }
250
251 // Session is valid!
252 $this->userdata = $session;
253 unset($session);
254
255 return TRUE;
256 }
adminb0dd10f2006-08-25 17:25:49 +0000257
258 // --------------------------------------------------------------------
259
260 /**
261 * Write the session cookie
262 *
263 * @access public
264 * @return void
265 */
266 function sess_write()
267 {
268 $cookie_data = serialize($this->userdata);
269
270 if ($this->encryption == TRUE)
271 {
adminb3ab70b2006-10-07 03:07:29 +0000272 $cookie_data = $this->CI->encrypt->encode($cookie_data);
adminb0dd10f2006-08-25 17:25:49 +0000273 }
274
275 setcookie(
admine334c472006-10-21 19:44:22 +0000276 $this->sess_cookie,
277 $cookie_data,
278 $this->sess_length + $this->now,
279 $this->CI->config->item('cookie_path'),
280 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000281 0
282 );
283 }
adminb0dd10f2006-08-25 17:25:49 +0000284
285 // --------------------------------------------------------------------
286
287 /**
288 * Create a new session
289 *
290 * @access public
291 * @return void
292 */
293 function sess_create()
294 {
295 $sessid = '';
admine334c472006-10-21 19:44:22 +0000296 while (strlen($sessid) < 32)
297 {
adminb0dd10f2006-08-25 17:25:49 +0000298 $sessid .= mt_rand(0, mt_getrandmax());
299 }
300
301 $this->userdata = array(
302 'session_id' => md5(uniqid($sessid, TRUE)),
adminb3ab70b2006-10-07 03:07:29 +0000303 'ip_address' => $this->CI->input->ip_address(),
304 'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
adminb0dd10f2006-08-25 17:25:49 +0000305 'last_activity' => $this->now
306 );
307
308
309 // Save the session in the DB if needed
310 if ($this->use_database === TRUE)
311 {
adminb3ab70b2006-10-07 03:07:29 +0000312 $this->CI->db->query($this->CI->db->insert_string($this->session_table, $this->userdata));
adminb0dd10f2006-08-25 17:25:49 +0000313 }
314
315 // Write the cookie
316 $this->userdata['last_visit'] = 0;
317 $this->sess_write();
318 }
adminb0dd10f2006-08-25 17:25:49 +0000319
320 // --------------------------------------------------------------------
321
322 /**
323 * Update an existing session
324 *
325 * @access public
326 * @return void
327 */
328 function sess_update()
329 {
admine334c472006-10-21 19:44:22 +0000330 if (($this->userdata['last_activity'] + $this->sess_length) < $this->now)
331 {
adminb0dd10f2006-08-25 17:25:49 +0000332 $this->userdata['last_visit'] = $this->userdata['last_activity'];
admine334c472006-10-21 19:44:22 +0000333 }
adminb0dd10f2006-08-25 17:25:49 +0000334
335 $this->userdata['last_activity'] = $this->now;
336
337 // Update the session in the DB if needed
338 if ($this->use_database === TRUE)
339 {
adminb3ab70b2006-10-07 03:07:29 +0000340 $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 +0000341 }
342
343 // Write the cookie
344 $this->sess_write();
345 }
adminb0dd10f2006-08-25 17:25:49 +0000346
347 // --------------------------------------------------------------------
348
349 /**
350 * Destroy the current session
351 *
352 * @access public
353 * @return void
354 */
355 function sess_destroy()
356 {
357 setcookie(
admine334c472006-10-21 19:44:22 +0000358 $this->sess_cookie,
359 addslashes(serialize(array())),
360 ($this->now - 31500000),
361 $this->CI->config->item('cookie_path'),
362 $this->CI->config->item('cookie_domain'),
adminb0dd10f2006-08-25 17:25:49 +0000363 0
364 );
365 }
adminb0dd10f2006-08-25 17:25:49 +0000366
367 // --------------------------------------------------------------------
368
369 /**
370 * Garbage collection
371 *
372 * This deletes expired session rows from database
373 * if the probability percentage is met
374 *
375 * @access public
376 * @return void
377 */
admine334c472006-10-21 19:44:22 +0000378 function sess_gc()
379 {
adminb0dd10f2006-08-25 17:25:49 +0000380 srand(time());
admine334c472006-10-21 19:44:22 +0000381 if ((rand() % 100) < $this->gc_probability)
382 {
adminb0dd10f2006-08-25 17:25:49 +0000383 $expire = $this->now - $this->sess_length;
384
adminb3ab70b2006-10-07 03:07:29 +0000385 $this->CI->db->where("last_activity < {$expire}");
386 $this->CI->db->delete($this->session_table);
adminb0dd10f2006-08-25 17:25:49 +0000387
388 log_message('debug', 'Session garbage collection performed.');
admine334c472006-10-21 19:44:22 +0000389 }
390 }
adminb0dd10f2006-08-25 17:25:49 +0000391
392 // --------------------------------------------------------------------
393
394 /**
395 * Fetch a specific item form the session array
396 *
397 * @access public
398 * @param string
399 * @return string
400 */
401 function userdata($item)
402 {
admine334c472006-10-21 19:44:22 +0000403 return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
adminb0dd10f2006-08-25 17:25:49 +0000404 }
adminb0dd10f2006-08-25 17:25:49 +0000405
406 // --------------------------------------------------------------------
407
408 /**
409 * Add or change data in the "userdata" array
410 *
411 * @access public
412 * @param mixed
413 * @param string
414 * @return void
415 */
416 function set_userdata($newdata = array(), $newval = '')
417 {
418 if (is_string($newdata))
419 {
420 $newdata = array($newdata => $newval);
421 }
422
423 if (count($newdata) > 0)
424 {
425 foreach ($newdata as $key => $val)
426 {
427 $this->userdata[$key] = $val;
428 }
429 }
430
admine334c472006-10-21 19:44:22 +0000431 $this->sess_write();
adminb0dd10f2006-08-25 17:25:49 +0000432 }
adminb0dd10f2006-08-25 17:25:49 +0000433
434 // --------------------------------------------------------------------
435
436 /**
437 * Delete a session variable from the "userdata" array
438 *
439 * @access array
440 * @return void
441 */
442 function unset_userdata($newdata = array())
443 {
444 if (is_string($newdata))
445 {
446 $newdata = array($newdata => '');
447 }
448
449 if (count($newdata) > 0)
450 {
451 foreach ($newdata as $key => $val)
452 {
453 unset($this->userdata[$key]);
454 }
455 }
456
admine334c472006-10-21 19:44:22 +0000457 $this->sess_write();
adminb0dd10f2006-08-25 17:25:49 +0000458 }
adminb0dd10f2006-08-25 17:25:49 +0000459
460 // --------------------------------------------------------------------
461
462 /**
463 * Strip slashes
464 *
465 * @access public
466 * @param mixed
467 * @return mixed
468 */
admine334c472006-10-21 19:44:22 +0000469 function strip_slashes($vals)
470 {
471 if (is_array($vals))
472 {
473 foreach ($vals as $key=>$val)
474 {
475 $vals[$key] = $this->strip_slashes($val);
476 }
477 }
478 else
479 {
480 $vals = stripslashes($vals);
481 }
482
483 return $vals;
adminb0dd10f2006-08-25 17:25:49 +0000484 }
adminb06d69f2006-10-13 21:44:17 +0000485
adminb0dd10f2006-08-25 17:25:49 +0000486}
487// END Session Class
488?>