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