mirror of
https://github.com/bcit-ci/CodeIgniter.git
synced 2025-02-20 11:13:29 +08:00
...
parent
c6298a4054
commit
ccd727b462
430
Secure-Native-Session.md
Executable file
430
Secure-Native-Session.md
Executable file
@ -0,0 +1,430 @@
|
||||
What's new?
|
||||
|
||||
[b]Warning![/b]
|
||||
It's works with database store enabled only!
|
||||
|
||||
2 way for store your session information: private & public zone.
|
||||
|
||||
[b]Config[/b]
|
||||
[u]sess_expiration[/u] - 0 -> never expire (2 years), -1 -> browser session, greater 0 -> your special expire
|
||||
[i]Warning![/i]
|
||||
[u]public data[/u] has never expire setting
|
||||
|
||||
[b]Reference[/b]
|
||||
[code]
|
||||
function system($item) // get CI standart session information
|
||||
function private_data($item) // get your private item
|
||||
function public_data($item) // get your public item
|
||||
function set_private_data($newdata,$newval) // set your private item with arguments as CI set_userdata
|
||||
function set_public_data($newdata,$newval) // set your public item with arguments as CI set_userdata
|
||||
function unset_private_data($items) // delete items (array) from private data
|
||||
function unset_public_data($items) // delete items (array) from public data
|
||||
[/code]
|
||||
|
||||
[b]CI standart[/b]
|
||||
[code]
|
||||
function set_flashdata(...)
|
||||
function flashdata(...)
|
||||
[/code]
|
||||
|
||||
[b]How to install[/b]
|
||||
1. replace CI session class & edit your code with special Secure Native Session reference
|
||||
2. rename this name class & use with happy
|
||||
|
||||
|
||||
P.S.
|
||||
not include GMT time parameter, current 'local'
|
||||
|
||||
[code]
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class CI_Session {
|
||||
|
||||
var $CI;
|
||||
var $now;
|
||||
var $userdata = array();
|
||||
var $time_to_update = 300;
|
||||
var $gc_probability = 5;
|
||||
var $flashdata_key = 'flash';
|
||||
var $sess_cookie = 'ci_session';
|
||||
var $session_length = 7200;
|
||||
var $session_table = 'ci_session';
|
||||
var $session_id;
|
||||
|
||||
|
||||
/**
|
||||
Session Constructor
|
||||
*/
|
||||
function CI_Session() {
|
||||
$this->CI =& get_instance();
|
||||
log_message('debug', "Native Session Class Initialized");
|
||||
$this->sess_run();
|
||||
}
|
||||
|
||||
/**
|
||||
get 2 years in seconds
|
||||
*/
|
||||
function _get_2years_seconds() {
|
||||
return 60*60*24*365*2;
|
||||
}
|
||||
|
||||
/**
|
||||
Run the session routines
|
||||
*/
|
||||
function sess_run() {
|
||||
// session start
|
||||
session_start();
|
||||
|
||||
// time to update
|
||||
if (is_numeric($this->CI->config->item('sess_time_to_update')))
|
||||
$this->time_to_update = $this->CI->config->item('sess_time_to_update');
|
||||
|
||||
// now - only 'local'
|
||||
$this->now = time();
|
||||
|
||||
// session life
|
||||
$expiration = $this->CI->config->item('sess_expiration');
|
||||
if (is_numeric($expiration)) {
|
||||
if ($expiration > 0) // user defined
|
||||
$this->sess_length = $this->CI->config->item('sess_expiration');
|
||||
else if ($expiration < 0) // no save
|
||||
$this->sess_length = 0;
|
||||
else // save session
|
||||
$this->sess_length = $this->_get_2years_seconds();
|
||||
}
|
||||
|
||||
// Set the cookie name
|
||||
if ($this->CI->config->item('sess_cookie_name') != FALSE)
|
||||
$this->sess_cookie = $this->CI->config->item('cookie_prefix').$this->CI->config->item('sess_cookie_name');
|
||||
|
||||
// database always is need
|
||||
$this->session_table = $this->CI->config->item('sess_table_name');
|
||||
$this->CI->load->database();
|
||||
|
||||
// Fetch the current session
|
||||
if (! $this->sess_read())
|
||||
$this->sess_create();
|
||||
else if (($this->userdata['last_activity'] + $this->time_to_update) < $this->now)
|
||||
$this->sess_update();
|
||||
|
||||
// Fetch public zone
|
||||
$this->userdata['public'] = $this->_unserialize($this->CI->input->cookie($this->sess_cookie));
|
||||
|
||||
// Delete expired sessions if necessary
|
||||
$this->sess_gc();
|
||||
|
||||
// Delete 'old' flashdata (from last request)
|
||||
$this->_flashdata_sweep();
|
||||
|
||||
// Mark all new flashdata as old (data will be deleted before next request)
|
||||
$this->_flashdata_mark();
|
||||
}
|
||||
|
||||
/**
|
||||
Remove from the DB
|
||||
*/
|
||||
function _sess_delete() {
|
||||
$this->CI->db->where('session_id', $this->session_id);
|
||||
$this->CI->db->delete($this->session_table);
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch the current session data if it exists
|
||||
*/
|
||||
function sess_read() {
|
||||
// fetch session hash
|
||||
$this->session_id = session_id();
|
||||
|
||||
// read from database
|
||||
$this->CI->db->where('session_id', $this->session_id);
|
||||
$query = $this->CI->db->get($this->session_table);
|
||||
// has session id
|
||||
if ($query->num_rows()) {
|
||||
$session = $query->row_array();
|
||||
|
||||
// Is the session current?
|
||||
if ($this->sess_length && ($session['last_activity'] + $this->sess_length) < $this->now) {
|
||||
$this->_sess_delete();
|
||||
return false;
|
||||
}
|
||||
// Does the IP Match?
|
||||
if ($this->CI->config->item('sess_match_ip') && $session['ip_address'] != $this->CI->input->ip_address())
|
||||
return false;
|
||||
|
||||
// Does the User Agent Match?
|
||||
if ($this->CI->config->item('sess_match_useragent') && trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)))
|
||||
return false;
|
||||
|
||||
// Fetch security data
|
||||
$session['private'] = $this->_unserialize($session['private']);
|
||||
|
||||
// Session is valid!
|
||||
$this->userdata = $session;
|
||||
unset($session);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Set cookie
|
||||
*/
|
||||
function _set_cookie($key,$value,$lifetime) {
|
||||
setcookie($key,$value,$lifetime,$this->CI->config->item('cookie_path'),$this->CI->config->item('cookie_domain'));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the session cookie
|
||||
*/
|
||||
function sess_write($saved = false, $only_private = true) {
|
||||
// set cookie
|
||||
$this->_set_cookie(session_name(),$this->session_id,$this->sess_length?$this->sess_length+time():0);
|
||||
|
||||
// save zones
|
||||
if ($saved) {
|
||||
// private zone
|
||||
if ($only_private)
|
||||
$this->CI->db->update($this->session_table,$this->_serialize_private(),
|
||||
array('session_id' => $this->session_id));
|
||||
else // public zone
|
||||
$this->_set_cookie($this->sess_cookie,serialize($this->userdata['public']),$this->_get_2years_seconds()+time());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Create a new session
|
||||
*/
|
||||
function sess_create() {
|
||||
|
||||
$this->userdata = array(
|
||||
'session_id' => $this->session_id,
|
||||
'ip_address' => $this->CI->input->ip_address(),
|
||||
'user_agent' => substr($this->CI->input->user_agent(), 0, 50),
|
||||
'last_activity' => $this->now
|
||||
);
|
||||
|
||||
// save in the DB
|
||||
$this->CI->db->query($this->CI->db->insert_string($this->session_table, $this->userdata));
|
||||
|
||||
// create extra fields
|
||||
$this->userdata['private'] = array();
|
||||
|
||||
// session write
|
||||
$this->sess_write();
|
||||
}
|
||||
|
||||
/**
|
||||
Update an existing sessio
|
||||
*/
|
||||
function sess_update() {
|
||||
$oldssid = $this->session_id;
|
||||
// regenerate
|
||||
session_regenerate_id();
|
||||
$this->session_id = session_id();
|
||||
|
||||
// update DB
|
||||
$this->CI->db->query($this->CI->db->update_string($this->session_table, array('last_activity' => $this->now, 'session_id' => $this->session_id), array('session_id' => $oldssid)));
|
||||
|
||||
// update data
|
||||
$this->userdata['session_id'] = $this->session_id;
|
||||
$this->userdata['last_activity'] = $this->now;
|
||||
|
||||
// session write
|
||||
$this->sess_write();
|
||||
}
|
||||
|
||||
/**
|
||||
Garbage collection
|
||||
*/
|
||||
function sess_gc() {
|
||||
if ($this->sess_length == 0) return;
|
||||
// garbage go!
|
||||
srand(time());
|
||||
if ((rand() % 100) < $this->gc_probability) {
|
||||
$expire = $this->now - $this->sess_length;
|
||||
|
||||
$this->CI->db->where("last_activity < {$expire}");
|
||||
$this->CI->db->delete($this->session_table);
|
||||
|
||||
log_message('debug', 'Session garbage collection performed.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Destroy the current session
|
||||
*/
|
||||
function sess_destroy() {
|
||||
$this->_sess_delete();
|
||||
|
||||
// Unset all of the session variables.
|
||||
$_SESSION = array();
|
||||
|
||||
// If it's desired to kill the session, also delete the session cookie.
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
if (isset($_COOKIE[session_name()]))
|
||||
$this->_set_cookie(session_name(),'',$this->now - 31500000);
|
||||
|
||||
// Finally, destroy the session.
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch a system value
|
||||
*/
|
||||
function system($item) {
|
||||
return $this->userdata[$item];
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch a specific value
|
||||
*/
|
||||
function _userdata($item,$type) {
|
||||
return (! isset($this->userdata[$type][$item]))?false:$this->userdata[$type][$item];
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch a public value
|
||||
*/
|
||||
function public_data($item) {
|
||||
return $this->_userdata($item,'public');
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch a private value
|
||||
*/
|
||||
function private_data($item) {
|
||||
return $this->_userdata($item,'private');
|
||||
}
|
||||
|
||||
/**
|
||||
Add or change a data
|
||||
*/
|
||||
function _set_userdata($type, $newdata, $newval) {
|
||||
if (is_string($newdata))
|
||||
$newdata = array($newdata => $newval);
|
||||
|
||||
if (count($newdata) > 0) {
|
||||
foreach ($newdata as $key => $val)
|
||||
$this->userdata[$type][$key] = $val;
|
||||
$this->sess_write(true,$type == 'private');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Remove a data
|
||||
*/
|
||||
function _unset_userdata($type,$data) {
|
||||
if (is_string($data))
|
||||
$data = array($data);
|
||||
if (count($data) > 0) {
|
||||
foreach ($data as $val)
|
||||
unset($this->userdata[$type][$val]);
|
||||
$this->sess_write(true,$type == 'private');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add or change a public data
|
||||
*/
|
||||
function set_public_data($newdata = array(), $newval = '') {
|
||||
$this->_set_userdata('public',$newdata,$newval);
|
||||
}
|
||||
|
||||
/**
|
||||
Add or change a private data
|
||||
*/
|
||||
function set_private_data($newdata = array(), $newval = '') {
|
||||
$this->_set_userdata('private',$newdata,$newval);
|
||||
}
|
||||
|
||||
/**
|
||||
Remove a private data
|
||||
*/
|
||||
function unset_private_data($data = array()) {
|
||||
$this->_unset_userdata('private',$data);
|
||||
}
|
||||
|
||||
/**
|
||||
Remove a public data
|
||||
*/
|
||||
function unset_public_data($data = array()) {
|
||||
$this->_unset_userdata('public',$data);
|
||||
}
|
||||
|
||||
/**
|
||||
Add or change flashdata, only available
|
||||
*/
|
||||
function set_flashdata($newdata = array(), $newval = '') {
|
||||
if (is_string($newdata))
|
||||
$newdata = array($newdata => $newval);
|
||||
|
||||
if (count($newdata) > 0) {
|
||||
$flashdata = array();
|
||||
foreach ($newdata as $key => $val)
|
||||
$flashdata[$this->flashdata_key.':new:'.$key] = $val;
|
||||
$this->set_public_data($flashdata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Fetch a specific flashdata item from the session array
|
||||
*/
|
||||
function flashdata($key) {
|
||||
return $this->public_data($this->flashdata_key.':old:'.$key);
|
||||
}
|
||||
|
||||
/**
|
||||
Identifies flashdata as 'old' for removal
|
||||
*/
|
||||
function _flashdata_mark() {
|
||||
foreach ($this->userdata['public'] as $name => $value) {
|
||||
$parts = explode(':new:', $name);
|
||||
if (is_array($parts) && count($parts) === 2) {
|
||||
$new_name = $this->flashdata_key.':old:'.$parts[1];
|
||||
$this->userdata['public'][$new_name] = $value;
|
||||
unset($this->userdata['public'][$name]);
|
||||
}
|
||||
}
|
||||
$this->sess_write(true,false);
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all flashdata marked as 'old'
|
||||
*/
|
||||
function _flashdata_sweep() {
|
||||
foreach ($this->userdata['public'] as $key => $value)
|
||||
if (strpos($key, ':old:'))
|
||||
unset($this->userdata['public'][$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
unserialize string
|
||||
*/
|
||||
function _unserialize($str) {
|
||||
if (is_array($data = @unserialize($this->_strip_slashes($str))))
|
||||
return $data;
|
||||
else
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
Strip slashes
|
||||
*/
|
||||
function _strip_slashes($vals) {
|
||||
if (is_array($vals))
|
||||
foreach ($vals as $key=>$val)
|
||||
$vals[$key] = $this->_strip_slashes($val);
|
||||
else
|
||||
$vals = stripslashes($vals);
|
||||
return $vals;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the session serialize security
|
||||
*/
|
||||
function _serialize_private() {
|
||||
return array('private' => serialize($this->userdata['private']));
|
||||
}
|
||||
}[/code]
|
Loading…
x
Reference in New Issue
Block a user