...

World Wide Web Server 2012-07-04 16:07:23 -07:00
parent 6802731004
commit c30ca8b0a4

558
NDB-Session-Class.md Executable file

@ -0,0 +1,558 @@
[[Category:Libraries::Session]]
[[Category:Session]]
[[Category:Contributions::Libraries::PHP]]
[h2] NDB Session Class for CodeIgniter - Version 1.1 [/h2]
Native Session makes good use of PHPs native session handling abilities, but it does not allow the use of a database for session storage. Saving user session data into database is more secure on any type of hosting (Shared ... ). This library overwrites normal native sassion functions too save user data directly into database and gives us some extra functions over CI Session.
[b]Follow on BitBucket: [/b]
<a href='https://bitbucket.org/Molchy/ndb-session-class-for-codeigniter/'>LINK</a>.
[b]Follow on CodeIgniter Forum:[/b]
<a href='http://codeigniter.com/forums/viewthread/191167/'>LINK</a>.
[h2]Overview[/h2]
- Is based on Native Session but has database functionality built in.
- Cmpatible with CodeIgniter 1.7 +.
- Drop-in replacement for CIs Session library.
- Config options and flash data are supported but not ession encryption.
- When using with a database, only the session_id is stored in a cookie. Any other data is stored in the database (Nativly would be stored to server ).
- PHP5+
[h2]Usage[/h2]
[b]Same usage as CI Session + Extras:[/b]
<a href='http://codeigniter.com/user_guide/libraries/sessions.html'>LINK</a>.
[b]Extras:[/b]
- Access data from database:
[code]
$_SESSION['Data];
[/code]
- Write data to database:
[code]
$_SESSION['Data'] = 'Value';
[/code]
[h2]Install[/h2]
- Download Session Class and copy it to "appliaction/libraries/"
- Insert new database table for Session storage
- Autoload or load CI database Class and Session Class
- Don't forget to setup database configuration
- Have fun
[h2]Differences between NDB Session and Native Session[/h2]
- Session ID only in cookie and no user data
- Saving user data to database and not to server
- Regenerating session id every X min
- Keeping track of session expiration and session time to update
- OOP Approach
[h2]Differences between NDB Session and CI Session[/h2]
- Using native PHP Session functions ( Smaller lib. same security )
- No encryption of cookie as only Session ID is stored in cookie (Allready hashed)
- Checking valid Session ID differently ( We dont save IP, Useragent, Activity to an cookie)
- Session garbage collector works differently ( Expired data, Useless data)
- After session destroy we create new empty session so u can set new Session data after it
- Some CI Session functions removed as not needet (Functions which PHP does it for us)
- Extras for setting and accessing Session data( $_SESSION['data'] ...)
[h2]Required Database Structure[/h2]
[code]
CREATE TABLE IF NOT EXISTS `Sessions` (
`session_id` varchar(40) collate utf8_bin NOT NULL default '0',
`ip_address` varchar(16) collate utf8_bin NOT NULL default '0',
`user_agent` varchar(50) collate utf8_bin NOT NULL,
`last_activity` int(10) unsigned NOT NULL default '0',
`user_data` text collate utf8_bin NOT NULL,
PRIMARY KEY (`session_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
[/code]
[h2]Example Configuration (/system/application/config/config.php)[/h2]
[code]
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 3600; // 1 H
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'Sessions';
$config['sess_match_ip'] = TRUE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 300; // 5 min
[/code]
[h2]Code[/h2]
[code]
&lt;?php
if(!defined('BASEPATH')) exit('No direct script access allowed');
/**
* |==========================================================
* | LIBRARY: CI_Session
* |==========================================================
* |
* | Custom Session library.
* |
* | @package eCMS
* | @subpackage Libraries
* | @category Libraries
* | @since Version 1.1
* | @author Denis Molan Dev
* | @copyright Copyright (c) 2011, Denis Molan
* | @license http://www.spletna-evolucija.com
* | @link http://www.spletna-evolucija.com
* |
*/
class CI_Session{
var $sess_table_name = '';
var $sess_expiration = 7200; // 2 H
var $sess_time_to_update = 300; // 5 min
var $sess_match_ip = TRUE;
var $sess_match_useragent = TRUE;
var $time_reference = 'time';
var $sess_cookie_name = 'ci_session';
var $cookie_prefix = '';
var $cookie_path = '';
var $cookie_domain = '';
var $cookie_secure = FALSE;
var $flashdata_key = 'flash';
var $user_ip;
var $user_useragent;
var $user_time;
var $CI;
/**
* |==========================================================
* | FUNCTION: __construct
* |==========================================================
* |
* | Constructor.
* |
* | @access private
* | @return void
* |
*/
function __construct(){
log_message('debug', "Session Class Initialized");
$this->CI = & get_instance();
// Loading CI config file or using default settings
foreach(array('sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix') as $key){
$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
}
//Database class must be loaded and table name for session must be set
if($this->sess_table_name != ''){
$this->CI->load->database();
}else{
show_error('In order to use the Session class you need to setup database class.');
}
// Set the cookie name
$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
// Detecting user preferences which will need later
$this->user_ip = $this->CI->input->ip_address();
$this->user_useragent = substr($this->CI->input->user_agent(), 0, 50);
$this->user_time = $this->_get_time();
// Client side session cookie name which contains only session id
ini_set('session.name', $this->sess_cookie_name);
// If session expiration not set we set it to 1 month
if($this->sess_expiration == 0){
$this->sess_expiration = (1314000); // 15 days
}
// Overwriting normal session functions with our own -> userdata goes into database
session_set_save_handler(
array(&$this, '_sess_open'), array(&$this, '_sess_close'), array(&$this, '_sess_read'), array(&$this, '_sess_write'), array(&$this, 'sess_destroy'), array(&$this, '_sess_gc')
);
// Session starts starts session and generate or use session id (Client side cookie)
session_start();
// Does session exists in db if not create one
$this->_sess_exists();
// We change session id every X min which u set in config file "sess_time_to_update" + running garbage collector same time
$this->_sess_update();
// Codeigniter flashdata manage
$this->_flashdata_sweep();
$this->_flashdata_mark();
log_message('debug', "Session routines successfully run");
}
/**
* |==========================================================
* | FUNCTION: __destruct
* |==========================================================
* |
* | Destructor.
* |
* | @access private
* | @return void
* |
*/
function __destruct(){
session_write_close();
}
/**
* |==========================================================
* | FUNCTION: _sess_open
* |==========================================================
* |
* | We dont need as saving data into database via CI Database
* | Open is first called after session_start
* |
* | @access private
* | @return bool
* |
*/
function _sess_open(){
return true;
}
/**
* |==========================================================
* | FUNCTION: _sess_close
* |==========================================================
* |
* | We dont need as saving data into database via CI Database
* |
* | @access private
* | @return bool
* |
*/
function _sess_close(){
return true;
}
/**
* |==========================================================
* | FUNCTION: _sess_read
* |==========================================================
* |
* | Read is second called after session_start, using it for reading data from database.
* | If session does not exist we must return '' and if it does we return data.
* |
* | @access private
* | @param string session id auto given into function
* | @return string
* |
*/
function _sess_read($sess_id){
$this->CI->db->where('session_id', $sess_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$row = $this->CI->db->get($this->sess_table_name)->row();
return (isset($row->user_data) AND $row->user_data != '') ? $row->user_data : '';
}
/**
* |==========================================================
* | FUNCTION: _sess_write
* |==========================================================
* |
* | Updating user data in database
* |
* | @access private
* | @param string session id auto given into function
* | @param mixed session user data
* | @return bool
* |
*/
function _sess_write($sess_id, $sess_data){
$this->CI->db->where('session_id', $sess_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->update($this->sess_table_name, array('user_data' => $sess_data));
return true;
}
/**
* |==========================================================
* | FUNCTION: _sess_create
* |==========================================================
* |
* | Creating new session if not exist or after destroy.
* |
* | @access private
* | @param string session id
* | @return void
* |
*/
function _sess_create(){
session_regenerate_id();
$sess_id = $this->CI->db->escape_str(session_id());
$this->CI->db->query("REPLACE INTO ".$this->sess_table_name." VALUES('$sess_id','$this->user_ip','$this->user_useragent','$this->user_time','')");
}
/**
* |==========================================================
* | FUNCTION: sess_destroy
* |==========================================================
* |
* | removing session cookie and database data.
* |
* | @access public
* | @param string session id given automaticly
* | @return void
* |
*/
function sess_destroy($sess_id = ''){
if(!isset($sess_id) || $sess_id == ''){
$sess_id = session_id();
}
session_unset();
$this->CI->db->where('session_id', $sess_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->delete($this->sess_table_name);
// Forcing browser to remove cookie on client side
setcookie(
$this->sess_cookie_name, addslashes(serialize(array())), ($this->user_time - 31500000), $this->cookie_path, $this->cookie_domain, 0
);
// Lets start new session for user
$this->_sess_create();
return true;
}
/**
* |==========================================================
* | FUNCTION: _sess_gc
* |==========================================================
* |
* | Called automaticly and manualy. Removing old sessions when expired.
* | Removing also data which didnt yet expire but useless
* | (Situation when user dont logout close browser window and comeback -> new session created
* | and old stay behind )
* |
* | @access private
* | @return void
* |
*/
function _sess_gc(){
$sess_id = session_id();
$expire = $this->user_time - $this->sess_expiration;
$this->CI->db->where("last_activity < {$expire}");
$this->CI->db->or_where("session_id !=", $sess_id);
$this->CI->db->where("ip_address", $this->user_ip);
$this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->delete($this->sess_table_name);
}
/**
* |==========================================================
* | FUNCTION: _sess_last_updated
* |==========================================================
* |
* | Updating session id after X min specified by user it self.
* | We check session garbage also that we dont do it every request.
* |
* | @access private
* | @return void
* |
*/
function _sess_update(){
$old_id = session_id();
$expire = $this->user_time - $this->sess_time_to_update;
// Checking if user session should be updated
$this->CI->db->where('session_id', $old_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->where("last_activity < {$expire}");
// Updating user session and running garbage collector
if($this->CI->db->count_all_results($this->sess_table_name) > 0){
session_regenerate_id(FALSE);
$new_id = session_id();
$data = array(
'session_id' => $new_id,
'last_activity' => $this->user_time
);
$this->CI->db->where('session_id', $old_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->update($this->sess_table_name, $data);
// That we dont collect session garbage every request we collect it same time we regenerate id.
$this->_sess_gc();
}
}
/**
* |==========================================================
* | FUNCTION: _sess_exists
* |==========================================================
* |
* | Just checking if valid session exists.
* |
* | @access private
* | @param string session id passed
* | @return bool
* |
*/
function _sess_exists(){
$sess_id = session_id();
$expire = $this->user_time - $this->sess_expiration;
$this->CI->db->where('session_id', $sess_id);
$this->CI->db->where('ip_address', $this->user_ip);
if($this->sess_match_useragent == TRUE) $this->CI->db->where('user_agent', $this->user_useragent);
$this->CI->db->where("last_activity > {$expire}");
if($this->CI->db->count_all_results($this->sess_table_name) === 0) $this->_sess_create();
}
/**
* |==========================================================
* | FUNCTIONS: CI_Session modified functions
* |==========================================================
* |
*/
function userdata($item){
return (!isset($_SESSION[$item])) ? FALSE : $_SESSION[$item];
}
function set_userdata($newdata = array(), $newval = ''){
if(is_string($newdata)){
$newdata = array($newdata => $newval);
}
if(count($newdata) > 0){
foreach($newdata as $key => $val){
$_SESSION[$key] = $val;
}
}
}
function unset_userdata($newdata = array()){
if(is_string($newdata)){
$newdata = array($newdata => '');
}
if(count($newdata) > 0){
foreach($newdata as $key => $val){
unset($_SESSION[$key]);
}
}
}
function _flashdata_mark(){
foreach($_SESSION as $name => $value){
$parts = explode(':new:', $name);
if(is_array($parts) && count($parts) === 2){
$new_name = $this->flashdata_key.':old:'.$parts[1];
$this->set_userdata($new_name, $value);
$this->unset_userdata($name);
}
}
}
function _flashdata_sweep(){
foreach($_SESSION as $key => $value){
if(strpos($key, ':old:')){
$this->unset_userdata($key);
}
}
}
/**
* |==========================================================
* | FUNCTIONS: CI_Session functions not modified
* |==========================================================
* |
*/
function set_flashdata($newdata = array(), $newval = ''){
if(is_string($newdata)){
$newdata = array($newdata => $newval);
}
if(count($newdata) > 0){
foreach($newdata as $key => $val){
$flashdata_key = $this->flashdata_key.':new:'.$key;
$this->set_userdata($flashdata_key, $val);
}
}
}
function keep_flashdata($key){
$old_flashdata_key = $this->flashdata_key.':old:'.$key;
$value = $this->userdata($old_flashdata_key);
$new_flashdata_key = $this->flashdata_key.':new:'.$key;
$this->set_userdata($new_flashdata_key, $value);
}
function flashdata($key){
$flashdata_key = $this->flashdata_key.':old:'.$key;
return $this->userdata($flashdata_key);
}
function _get_time(){
if(strtolower($this->time_reference) == 'gmt'){
$now = time();
$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
}else{
$time = time();
}
return $time;
}
/**
* |==========================================================
* | END
* |==========================================================
* |
*/
}
/*
USEFULL INFO
Called: session_start():
1. open
2. read
4. clean (if cleaning is being done this call)
5. write
6. close
Called session_destroy():
1. open
2. read
3. clean (if cleaning is being done this call)
4. destroy
5. close
Called session_regenerate_id(1):
1. open
2. read
3. clean (if cleaning is being done this call)
4. destroy
5. write
6. close
*/
[/code]