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