00001 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 class CI_Session {
00028
00029 var $sess_encrypt_cookie = FALSE;
00030 var $sess_use_database = FALSE;
00031 var $sess_table_name = '';
00032 var $sess_expiration = 7200;
00033 var $sess_match_ip = FALSE;
00034 var $sess_match_useragent = TRUE;
00035 var $sess_cookie_name = 'ci_session';
00036 var $cookie_prefix = '';
00037 var $cookie_path = '';
00038 var $cookie_domain = '';
00039 var $sess_time_to_update = 300;
00040 var $encryption_key = '';
00041 var $flashdata_key = 'flash';
00042 var $time_reference = 'time';
00043 var $gc_probability = 5;
00044 var $userdata = array();
00045 var $CI;
00046 var $now;
00047
00048
00049
00050
00051
00052
00053
00054 function CI_Session($params = array())
00055 {
00056 log_message('debug', "Session Class Initialized");
00057
00058
00059 $this->CI =& get_instance();
00060
00061
00062
00063 foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
00064 {
00065 $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
00066 }
00067
00068
00069 $this->CI->load->helper('string');
00070
00071
00072 if ($this->sess_encrypt_cookie == TRUE)
00073 {
00074 $this->CI->load->library('encrypt');
00075 }
00076
00077
00078 if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
00079 {
00080 $this->CI->load->database();
00081 }
00082
00083
00084
00085 $this->now = $this->_get_time();
00086
00087
00088
00089 if ($this->sess_expiration == 0)
00090 {
00091 $this->sess_expiration = (60*60*24*365*2);
00092 }
00093
00094
00095 $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
00096
00097
00098
00099 if ( ! $this->sess_read())
00100 {
00101 $this->sess_create();
00102 }
00103 else
00104 {
00105 $this->sess_update();
00106 }
00107
00108
00109 $this->_flashdata_sweep();
00110
00111
00112 $this->_flashdata_mark();
00113
00114
00115 $this->_sess_gc();
00116
00117 log_message('debug', "Session routines successfully run");
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 function sess_read()
00129 {
00130
00131 $session = $this->CI->input->cookie($this->sess_cookie_name);
00132
00133
00134 if ($session === FALSE)
00135 {
00136 log_message('debug', 'A session cookie was not found.');
00137 return FALSE;
00138 }
00139
00140
00141 if ($this->sess_encrypt_cookie == TRUE)
00142 {
00143 $session = $this->CI->encrypt->decode($session);
00144 }
00145 else
00146 {
00147
00148 $hash = substr($session, strlen($session)-32);
00149 $session = substr($session, 0, strlen($session)-32);
00150
00151
00152 if ($hash !== md5($session.$this->encryption_key))
00153 {
00154 log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
00155 $this->sess_destroy();
00156 return FALSE;
00157 }
00158 }
00159
00160
00161 $session = $this->_unserialize($session);
00162
00163
00164 if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))
00165 {
00166 $this->sess_destroy();
00167 return FALSE;
00168 }
00169
00170
00171 if (($session['last_activity'] + $this->sess_expiration) < $this->now)
00172 {
00173 $this->sess_destroy();
00174 return FALSE;
00175 }
00176
00177
00178 if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
00179 {
00180 $this->sess_destroy();
00181 return FALSE;
00182 }
00183
00184
00185 if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))
00186 {
00187 $this->sess_destroy();
00188 return FALSE;
00189 }
00190
00191
00192 if ($this->sess_use_database === TRUE)
00193 {
00194 $this->CI->db->where('session_id', $session['session_id']);
00195
00196 if ($this->sess_match_ip == TRUE)
00197 {
00198 $this->CI->db->where('ip_address', $session['ip_address']);
00199 }
00200
00201 if ($this->sess_match_useragent == TRUE)
00202 {
00203 $this->CI->db->where('user_agent', $session['user_agent']);
00204 }
00205
00206 $query = $this->CI->db->get($this->sess_table_name);
00207
00208
00209 if ($query->num_rows() == 0)
00210 {
00211 $this->sess_destroy();
00212 return FALSE;
00213 }
00214
00215
00216 $row = $query->row();
00217 if (isset($row->user_data) AND $row->user_data != '')
00218 {
00219 $custom_data = $this->_unserialize($row->user_data);
00220
00221 if (is_array($custom_data))
00222 {
00223 foreach ($custom_data as $key => $val)
00224 {
00225 $session[$key] = $val;
00226 }
00227 }
00228 }
00229 }
00230
00231
00232 $this->userdata = $session;
00233 unset($session);
00234
00235 return TRUE;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 function sess_write()
00247 {
00248
00249 if ($this->sess_use_database === FALSE)
00250 {
00251 $this->_set_cookie();
00252 return;
00253 }
00254
00255
00256 $custom_userdata = $this->userdata;
00257 $cookie_userdata = array();
00258
00259
00260
00261
00262 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
00263 {
00264 unset($custom_userdata[$val]);
00265 $cookie_userdata[$val] = $this->userdata[$val];
00266 }
00267
00268
00269
00270 if (count($custom_userdata) === 0)
00271 {
00272 $custom_userdata = '';
00273 }
00274 else
00275 {
00276
00277 $custom_userdata = $this->_serialize($custom_userdata);
00278 }
00279
00280
00281 $this->CI->db->where('session_id', $this->userdata['session_id']);
00282 $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
00283
00284
00285
00286
00287 $this->_set_cookie($cookie_userdata);
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 function sess_create()
00299 {
00300 $sessid = '';
00301 while (strlen($sessid) < 32)
00302 {
00303 $sessid .= mt_rand(0, mt_getrandmax());
00304 }
00305
00306
00307 $sessid .= $this->CI->input->ip_address();
00308
00309 $this->userdata = array(
00310 'session_id' => md5(uniqid($sessid, TRUE)),
00311 'ip_address' => $this->CI->input->ip_address(),
00312 'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
00313 'last_activity' => $this->now
00314 );
00315
00316
00317
00318 if ($this->sess_use_database === TRUE)
00319 {
00320 $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
00321 }
00322
00323
00324 $this->_set_cookie();
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 function sess_update()
00336 {
00337
00338 if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
00339 {
00340 return;
00341 }
00342
00343
00344
00345 $old_sessid = $this->userdata['session_id'];
00346 $new_sessid = '';
00347 while (strlen($new_sessid) < 32)
00348 {
00349 $new_sessid .= mt_rand(0, mt_getrandmax());
00350 }
00351
00352
00353 $new_sessid .= $this->CI->input->ip_address();
00354
00355
00356 $new_sessid = md5(uniqid($new_sessid, TRUE));
00357
00358
00359 $this->userdata['session_id'] = $new_sessid;
00360 $this->userdata['last_activity'] = $this->now;
00361
00362
00363
00364 $cookie_data = NULL;
00365
00366
00367 if ($this->sess_use_database === TRUE)
00368 {
00369
00370 $cookie_data = array();
00371 foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
00372 {
00373 $cookie_data[$val] = $this->userdata[$val];
00374 }
00375
00376 $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
00377 }
00378
00379
00380 $this->_set_cookie($cookie_data);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 function sess_destroy()
00392 {
00393
00394 if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id']))
00395 {
00396 $this->CI->db->where('session_id', $this->userdata['session_id']);
00397 $this->CI->db->delete($this->sess_table_name);
00398 }
00399
00400
00401 setcookie(
00402 $this->sess_cookie_name,
00403 addslashes(serialize(array())),
00404 ($this->now - 31500000),
00405 $this->cookie_path,
00406 $this->cookie_domain,
00407 0
00408 );
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 function userdata($item)
00421 {
00422 return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 function all_userdata()
00434 {
00435 return ( ! isset($this->userdata)) ? FALSE : $this->userdata;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 function set_userdata($newdata = array(), $newval = '')
00449 {
00450 if (is_string($newdata))
00451 {
00452 $newdata = array($newdata => $newval);
00453 }
00454
00455 if (count($newdata) > 0)
00456 {
00457 foreach ($newdata as $key => $val)
00458 {
00459 $this->userdata[$key] = $val;
00460 }
00461 }
00462
00463 $this->sess_write();
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 function unset_userdata($newdata = array())
00475 {
00476 if (is_string($newdata))
00477 {
00478 $newdata = array($newdata => '');
00479 }
00480
00481 if (count($newdata) > 0)
00482 {
00483 foreach ($newdata as $key => $val)
00484 {
00485 unset($this->userdata[$key]);
00486 }
00487 }
00488
00489 $this->sess_write();
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 function set_flashdata($newdata = array(), $newval = '')
00504 {
00505 if (is_string($newdata))
00506 {
00507 $newdata = array($newdata => $newval);
00508 }
00509
00510 if (count($newdata) > 0)
00511 {
00512 foreach ($newdata as $key => $val)
00513 {
00514 $flashdata_key = $this->flashdata_key.':new:'.$key;
00515 $this->set_userdata($flashdata_key, $val);
00516 }
00517 }
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 function keep_flashdata($key)
00530 {
00531
00532
00533
00534
00535 $old_flashdata_key = $this->flashdata_key.':old:'.$key;
00536 $value = $this->userdata($old_flashdata_key);
00537
00538 $new_flashdata_key = $this->flashdata_key.':new:'.$key;
00539 $this->set_userdata($new_flashdata_key, $value);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551 function flashdata($key)
00552 {
00553 $flashdata_key = $this->flashdata_key.':old:'.$key;
00554 return $this->userdata($flashdata_key);
00555 }
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 function _flashdata_mark()
00567 {
00568 $userdata = $this->all_userdata();
00569 foreach ($userdata as $name => $value)
00570 {
00571 $parts = explode(':new:', $name);
00572 if (is_array($parts) && count($parts) === 2)
00573 {
00574 $new_name = $this->flashdata_key.':old:'.$parts[1];
00575 $this->set_userdata($new_name, $value);
00576 $this->unset_userdata($name);
00577 }
00578 }
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 function _flashdata_sweep()
00591 {
00592 $userdata = $this->all_userdata();
00593 foreach ($userdata as $key => $value)
00594 {
00595 if (strpos($key, ':old:'))
00596 {
00597 $this->unset_userdata($key);
00598 }
00599 }
00600
00601 }
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 function _get_time()
00612 {
00613 if (strtolower($this->time_reference) == 'gmt')
00614 {
00615 $now = time();
00616 $time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
00617 }
00618 else
00619 {
00620 $time = time();
00621 }
00622
00623 return $time;
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 function _set_cookie($cookie_data = NULL)
00635 {
00636 if (is_null($cookie_data))
00637 {
00638 $cookie_data = $this->userdata;
00639 }
00640
00641
00642 $cookie_data = $this->_serialize($cookie_data);
00643
00644 if ($this->sess_encrypt_cookie == TRUE)
00645 {
00646 $cookie_data = $this->CI->encrypt->encode($cookie_data);
00647 }
00648 else
00649 {
00650
00651 $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
00652 }
00653
00654
00655 setcookie(
00656 $this->sess_cookie_name,
00657 $cookie_data,
00658 $this->sess_expiration + time(),
00659 $this->cookie_path,
00660 $this->cookie_domain,
00661 0
00662 );
00663 }
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 function _serialize($data)
00678 {
00679 if (is_array($data))
00680 {
00681 foreach ($data as $key => $val)
00682 {
00683 $data[$key] = str_replace('\\', '{{slash}}', $val);
00684 }
00685 }
00686 else
00687 {
00688 $data = str_replace('\\', '{{slash}}', $data);
00689 }
00690
00691 return serialize($data);
00692 }
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 function _unserialize($data)
00707 {
00708 $data = @unserialize(strip_slashes($data));
00709
00710 if (is_array($data))
00711 {
00712 foreach ($data as $key => $val)
00713 {
00714 $data[$key] = str_replace('{{slash}}', '\\', $val);
00715 }
00716
00717 return $data;
00718 }
00719
00720 return str_replace('{{slash}}', '\\', $data);
00721 }
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 function _sess_gc()
00735 {
00736 if ($this->sess_use_database != TRUE)
00737 {
00738 return;
00739 }
00740
00741 srand(time());
00742 if ((rand() % 100) < $this->gc_probability)
00743 {
00744 $expire = $this->now - $this->sess_expiration;
00745
00746 $this->CI->db->where("last_activity < {$expire}");
00747 $this->CI->db->delete($this->sess_table_name);
00748
00749 log_message('debug', 'Session garbage collection performed.');
00750 }
00751 }
00752
00753
00754 }
00755
00756
00757
00758