I'm using Codeigniter's Native Session Class for storing users information, but i have a serious problem. It appears that the session times out when the user is inactive for about half an hour and logs him out.
My config file looks like this:
$config['sess_cookie_name'] = 'cisession';
$config['sess_expiration'] = 60*60*24*30*12*2;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = FALSE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 7200;
The PHPSESSID in browser is not destroyed when the user is logged out and it expires in two years as I've set it in config file.
I don't know what are the common problems with native session class because everyone seems to be happy with it, so can somebody work it out what is the most likely thing that is causing this problem?
Edit: For those who aren't familiar with codeigniter's native session class here is link
http://codeigniter.com/wiki/Native_session
i use also codeigniter's native class. Maybe you not config it correctly. Here is code that i get from him. https://github.com/EllisLab/CodeIgniter/wiki
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CI_Session {
var $session_id_ttl; // session id time to live (TTL) in seconds
var $flash_key = 'flash'; // prefix for "flash" variables (eg. flash:new:message)
function __construct()
{
log_message('debug', "Native_session Class Initialized");
$this->object =& get_instance();
$this->_sess_run();
}
/**
* Regenerates session id
*/
function regenerate_id()
{
// copy old session data, including its id
$old_session_id = session_id();
$old_session_data = $_SESSION;
// regenerate session id and store it
session_regenerate_id();
$new_session_id = session_id();
// switch to the old session and destroy its storage
session_id($old_session_id);
session_destroy();
// switch back to the new session id and send the cookie
session_id($new_session_id);
session_start();
// restore the old session data into the new session
$_SESSION = $old_session_data;
// update the session creation time
$_SESSION['regenerated'] = time();
// session_write_close() patch based on this thread
// http://www.codeigniter.com/forums/viewthread/1624/
// there is a question mark ?? as to side affects
// end the current session and store session data.
session_write_close();
}
/**
* Destroys the session and erases session storage
*/
function destroy()
{
unset($_SESSION);
if ( isset( $_COOKIE[session_name()] ) )
{
setcookie(session_name(), '', time()-42000, '/');
}
session_destroy();
}
/**
* Reads given session attribute value
*/
function userdata($item)
{
if($item == 'session_id'){ //added for backward-compatibility
return session_id();
}else{
return ( ! isset($_SESSION[$item])) ? false : $_SESSION[$item];
}
}
/**
* Sets session attributes to the given values
*/
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;
}
}
}
/**
* Erases given session attributes
*/
function unset_userdata($newdata = array())
{
if (is_string($newdata))
{
$newdata = array($newdata => '');
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
unset($_SESSION[$key]);
}
}
}
/**
* Starts up the session system for current request
*/
function _sess_run()
{
session_start();
$session_id_ttl = $this->object->config->item('sess_expiration');
if (is_numeric($session_id_ttl))
{
if ($session_id_ttl > 0)
{
$this->session_id_ttl = $this->object->config->item('sess_expiration');
}
else
{
$this->session_id_ttl = (60*60*24*365*2);
}
}
// check if session id needs regeneration
if ( $this->_session_id_expired() )
{
// regenerate session id (session data stays the
// same, but old session storage is destroyed)
$this->regenerate_id();
}
// 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();
}
/**
* Checks if session has expired
*/
function _session_id_expired()
{
if ( !isset( $_SESSION['regenerated'] ) )
{
$_SESSION['regenerated'] = time();
return false;
}
$expiry_time = time() - $this->session_id_ttl;
if ( $_SESSION['regenerated'] <= $expiry_time )
{
return true;
}
return false;
}
/**
* Sets "flash" data which will be available only in next request (then it will
* be deleted from session). You can use it to implement "Save succeeded" messages
* after redirect.
*/
function set_flashdata($key, $value)
{
$flash_key = $this->flash_key.':new:'.$key;
$this->set_userdata($flash_key, $value);
}
/**
* Keeps existing "flash" data available to next request.
*/
function keep_flashdata($key)
{
$old_flash_key = $this->flash_key.':old:'.$key;
$value = $this->userdata($old_flash_key);
$new_flash_key = $this->flash_key.':new:'.$key;
$this->set_userdata($new_flash_key, $value);
}
/**
* Returns "flash" data for the given key.
*/
function flashdata($key)
{
$flash_key = $this->flash_key.':old:'.$key;
return $this->userdata($flash_key);
}
/**
* PRIVATE: Internal method - marks "flash" session attributes as 'old'
*/
function _flashdata_mark()
{
foreach ($_SESSION as $name => $value)
{
$parts = explode(':new:', $name);
if (is_array($parts) && count($parts) == 2)
{
$new_name = $this->flash_key.':old:'.$parts[1];
$this->set_userdata($new_name, $value);
$this->unset_userdata($name);
}
}
}
/**
* PRIVATE: Internal method - removes "flash" session marked as 'old'
*/
function _flashdata_sweep()
{
foreach ($_SESSION as $name => $value)
{
$parts = explode(':old:', $name);
if (is_array($parts) && count($parts) == 2 && $parts[0] == $this->flash_key)
{
$this->unset_userdata($name);
}
}
}
}
PHPs sessions expires after 1440 seconds (24 minutes).
http://php.net/manual/en/session.configuration.php
Related
I am currently writing a PHP site for myself. Now I am trying to secure my site. Therefor I am using session. I don't want to write one for myself so I searched and found a wonderful example.
<?php
class SessionManager
{
static function sessionStart($name, $limit = 0, $path = '/', $domain = null, $secure = null)
{
// Set the cookie name
session_name($name . '_Session');
// Set SSL level
$https = isset($secure) ? $secure : isset($_SERVER['HTTPS']);
// Set session cookie options
session_set_cookie_params($limit, $path, $domain, $https, true);
session_start();
// Make sure the session hasn't expired, and destroy it if it has
if(self::validateSession())
{
// Check to see if the session is new or a hijacking attempt
if(!self::preventHijacking())
{
// Reset session data and regenerate id
$_SESSION = array();
$_SESSION['IPaddress'] = isset($_SERVER['HTTP_X_FORWARDED_FOR'])
? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
$_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
self::regenerateSession();
// Give a 5% chance of the session id changing on any request
}elseif(rand(1, 100) <= 5){
self::regenerateSession();
}
}else{
$_SESSION = array();
session_destroy();
session_start();
}
}
/**
* This function regenerates a new ID and invalidates the old session. This should be called whenever permission
* levels for a user change.
*
*/
static function regenerateSession()
{
// If this session is obsolete it means there already is a new id
if(isset($_SESSION['OBSOLETE']) || $_SESSION['OBSOLETE'] == true)
return;
// Set current session to expire in 10 seconds
$_SESSION['OBSOLETE'] = true;
$_SESSION['EXPIRES'] = time() + 10;
// Create new session without destroying the old one
session_regenerate_id(false);
// Grab current session ID and close both sessions to allow other scripts to use them
$newSession = session_id();
session_write_close();
// Set session ID to the new one, and start it back up again
session_id($newSession);
session_start();
// Now we unset the obsolete and expiration values for the session we want to keep
unset($_SESSION['OBSOLETE']);
unset($_SESSION['EXPIRES']);
}
/**
* This function is used to see if a session has expired or not.
*
* #return bool
*/
static protected function validateSession()
{
if( isset($_SESSION['OBSOLETE']) && !isset($_SESSION['EXPIRES']) )
return false;
if(isset($_SESSION['EXPIRES']) && $_SESSION['EXPIRES'] < time())
return false;
return true;
}
/**
* This function checks to make sure a session exists and is coming from the proper host. On new visits and hacking
* attempts this function will return false.
*
* #return bool
*/
static protected function preventHijacking()
{
if(!isset($_SESSION['IPaddress']) || !isset($_SESSION['userAgent']))
return false;
if( $_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT']
&& !( strpos($_SESSION['userAgent'], ÔTridentÕ) !== false
&& strpos($_SERVER['HTTP_USER_AGENT'], ÔTridentÕ) !== false))
{
return false;
}
$sessionIpSegment = substr($_SESSION['IPaddress'], 0, 7);
$remoteIpHeader = isset($_SERVER['HTTP_X_FORWARDED_FOR'])
? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
$remoteIpSegment = substr($remoteIpHeader, 0, 7);
if($_SESSION['IPaddress'] != $remoteIpHeader
&& !(in_array($sessionIpSegment, $this->aolProxies) && in_array($remoteIpSegment, $this->aolProxies)))
{
return false;
}
if( $_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT'])
return false;
return true;
}
}
?>
I am trying to call the function over:
include 'SessionSafe.php';
SessionManager::sessionStart('InstallationName');
i am testing the session with:
if (!isset($_SESSION['userid'])) {
header('Location: Login.php');
}
Before, I wrote a value in $_SESSION['userid'], but I have the problem that the session variable is empty...
//File1.php
include 'SessionSafe.php';
session_start();
SessionManager::sessionStart('InstallationName');
// file2.php
session_start();
if (!isset($_SESSION['userid'])) {
header('Location: Login.php');
}
You still have to use session start at the top of each php file.
I am facing problems with session data. After login to the website, I'm losing session data. I have tired creating sessions in database and also tried native php session class but nothing worked. I have also cleared tmp folder from server.
The website uses code igniter framework and it is hosted on godaddy VPS
Please help me. Thank You...
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class CI_Session {
var $session_id_ttl; // session id time to live (TTL) in seconds
var $flash_key = 'flash'; // prefix for "flash" variables (eg. flash:new:message)
function CI_Session()
{
$this->object =& get_instance();
log_message('debug', "Native_session Class Initialized");
$this->_sess_run();
}
/**
* Regenerates session id
*/
function regenerate_id()
{
// copy old session data, including its id
$old_session_id = session_id();
$old_session_data = $_SESSION;
// regenerate session id and store it
session_regenerate_id();
$new_session_id = session_id();
// switch to the old session and destroy its storage
session_id($old_session_id);
session_destroy();
// switch back to the new session id and send the cookie
session_id($new_session_id);
session_start();
// restore the old session data into the new session
$_SESSION = $old_session_data;
// update the session creation time
$_SESSION['regenerated'] = time();
// session_write_close() patch based on this thread
// http://www.codeigniter.com/forums/viewthread/1624/
// there is a question mark ?? as to side affects
// end the current session and store session data.
session_write_close();
}
/**
* Destroys the session and erases session storage
*/
function destroy()
{
//unset($_SESSION);
session_unset();
if ( isset( $_COOKIE[session_name()] ) )
{
setcookie(session_name(), '', time()-42000, '/');
}
session_destroy();
}
/**
* Reads given session attribute value
*/
function userdata($item)
{
if($item == 'session_id'){ //added for backward-compatibility
return session_id();
}else{
return ( ! isset($_SESSION[$item])) ? false : $_SESSION[$item];
}
}
/**
* Sets session attributes to the given values
*/
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;
}
}
}
/**
* Erases given session attributes
*/
function unset_userdata($newdata = array())
{
if (is_string($newdata))
{
$newdata = array($newdata => '');
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
unset($_SESSION[$key]);
}
}
}
/**
* Starts up the session system for current request
*/
function _sess_run()
{
$session_id_ttl = $this->object->config->item('sess_expiration');
if (is_numeric($session_id_ttl))
{
if ($session_id_ttl > 0)
{
$this->session_id_ttl = $this->object->config->item('sess_expiration');
}
else
{
$this->session_id_ttl = (60*60*24*365*2);
}
}
session_start();
// check if session id needs regeneration
if ( $this->_session_id_expired() )
{
// regenerate session id (session data stays the
// same, but old session storage is destroyed)
$this->regenerate_id();
}
// 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();
}
/**
* Checks if session has expired
*/
function _session_id_expired()
{
if ( !isset( $_SESSION['regenerated'] ) )
{
$_SESSION['regenerated'] = time();
return false;
}
$expiry_time = time() - $this->session_id_ttl;
if ( $_SESSION['regenerated'] <= $expiry_time )
{
return true;
}
return false;
}
/**
* Sets "flash" data which will be available only in next request (then it will
* be deleted from session). You can use it to implement "Save succeeded" messages
* after redirect.
*/
function set_flashdata($key, $value)
{
$flash_key = $this->flash_key.':new:'.$key;
$this->set_userdata($flash_key, $value);
}
/**
* Keeps existing "flash" data available to next request.
*/
function keep_flashdata($key)
{
$old_flash_key = $this->flash_key.':old:'.$key;
$value = $this->userdata($old_flash_key);
$new_flash_key = $this->flash_key.':new:'.$key;
$this->set_userdata($new_flash_key, $value);
}
/**
* Returns "flash" data for the given key.
*/
function flashdata($key)
{
$flash_key = $this->flash_key.':old:'.$key;
return $this->userdata($flash_key);
}
/**
* PRIVATE: Internal method - marks "flash" session attributes as 'old'
*/
function _flashdata_mark()
{
foreach ($_SESSION as $name => $value)
{
$parts = explode(':new:', $name);
if (is_array($parts) && count($parts) == 2)
{
$new_name = $this->flash_key.':old:'.$parts[1];
$this->set_userdata($new_name, $value);
$this->unset_userdata($name);
}
}
}
/**
* PRIVATE: Internal method - removes "flash" session marked as 'old'
*/
function _flashdata_sweep()
{
foreach ($_SESSION as $name => $value)
{
$parts = explode(':old:', $name);
if (is_array($parts) && count($parts) == 2 && $parts[0] == $this->flash_key)
{
$this->unset_userdata($name);
}
}
}
}
Always prefer to create sessions based on the framework's format. Even I too had the same problem. At that time I was using codeigniter version 2.0, so I used the frameworks session definitions. But as far as I know $_SESSION global variable is supported in version 3
Adding Custom Session Data
$this->session->userdata('item');
$this->session->set_userdata($array);
Retrieving Session Data
$this->session->userdata('item');
Retrieving All Session Data
$this->session->all_userdata()
Removing Session Data
$this->session->unset_userdata('some_name');
Check this documentation, you could get a clear view
https://ellislab.com/codeigniter/user-guide/libraries/sessions.html
When there are any page redirections, keep "exit" after redirect code.
That is how I solved my problem (losing session data after page redirection). See the below example.
header("Location: example.php");
exit;
I have a site build using Codeiginiter 1.0. It was crowdfunding site and using wepay auth. When user register it was redirect to wepay landing and after loging in to wepay it was redirect back to home page. But now an error appear.
A PHP Error was encountered
Severity: Notice
Message: Undefined property: stdClass::$account_uri
Filename: controllers/home.php
Line Number: 114
A PHP Error was encountered
Severity: Warning
Message: Cannot modify header information - headers already sent by (output started at /home/content/x/e/b/xebragroup3/html/ext_domains/undercoverfunder/system/core/Exceptions.php:185)
Filename: libraries/Session.php
Line Number: 675
Here is home.php
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
class Home extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->helper(array('form','url'));
$this->load->library('form_validation');
$this->load->library('session');
$this->load->library('pagination');
$this->load->library('email');
$this->load->model('home_model');
$this->load->model('search_model');
$this->load->helper('wepay');
$this->load->library('tank_auth');
$this->lang->load('tank_auth');
}
function index()
{
$data['categories']= $this->home_model->getallCategories();
$data['home_active']='active';
$per_page = 12;
if($this->uri->segment(3)==''){ $off = 0; }else{ $off = $this->uri->segment(3); }
$result = $this->home_model->count_getallprojects();
$base_url = base_url().'/home/index/';
$data['projects'] = $this->home_model->getallprojects($off,$per_page);
$config['uri_segment'] = '3';
$total = count($result);
//code for pagging
$config['base_url'] = $base_url;
$config['total_rows'] = $total;
$config['per_page'] = $per_page;
$config['full_tag_open'] = '<span>';
$config['full_tag_close'] = '</span>';
$config['cur_tag_open'] = '<b>';
$config['cur_tag_close'] = '</b>';
$config['first_link'] = '« First';
$config['last_link'] = ' Last »';
$config['last_tag_open'] = '<span>';
$config['last_tag_close'] = '</span>';
$config['next_link'] = 'Next';
$config['next_tag_open'] = '<span>';
$config['next_tag_close'] = '</span>';
$config['prev_link'] = 'Prev';
$config['prev_tag_open'] = '<span>';
$config['prev_tag_close'] = '</span>';
$this->load->library('pagination',$result);
$this->pagination->initialize($config);
$this->load->view('frontend/home/home_view',$data);
}
function wepay()
{
if(isset($_GET['code']))
{
$url = wepayurl.$_GET['code'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB5');
$response = curl_exec($ch);
curl_close($ch);
$response_r = json_decode($response);
if(isset($response_r))
{
if (!$this->tank_auth->is_logged_in()) {
//before login
$user_id = $this->session->userdata('ses_userid_lf');
$user_fname= $this->session->userdata('ses_name_lf');
}
else
{ //after login
$user_id = $this->session->userdata('user_id');
$user_fname = $this->session->userdata('front_username');
}
$data_wepay = array('user_id'=>$user_id,'wepay_user_id'=>$response_r->user_id,'wepay_user_access_token'=>$response_r->access_token);
$this->db->insert('wc_wepay_user_account_dtls',$data_wepay);
$client_id = wepay_clientid;
$client_secret = wepay_scrite;
$access_token = $response_r->access_token;
// change to useProduction for live environments
//Wepay::useStaging($client_id, $client_secret);
Wepay::useProduction($client_id, $client_secret);
$wepay = new WePay($access_token);
$res = $wepay->request('account/create/', array(
'name' => $user_fname,
'description' => 'Subscribed to Letsfund.it.'
));
if(!empty($res))
{
if (!$this->tank_auth->is_logged_in()) { $user_id = $this->session->userdata('ses_userid_lf'); }
else
{ $user_id = $this->session->userdata('user_id');}
$currdate = date('Y-m-d h:i:s');
$data = array('account_uri'=>$res->account_uri,'account_id'=>$res->account_id,'dt_created'=>$currdate);
$this->db->where('user_id',$user_id);
$this->db->update('wc_wepay_user_account_dtls',$data);
if (!$this->tank_auth->is_logged_in()) {
$this->session->set_flashdata('message','You have successfully registered. Check your email address to activate your account.');
//redirect('auth/register');
}
else{
$this->session->set_flashdata('message','You have successfully given permitted Undercoverfunder to manage your wepay account.');
//redirect('campaign');
}
}
}
}
if(isset($_GET['error']))
{
$this->session->set_flashdata('msg','You denied the request so your account is not activated.');
//redirect('auth/register');
}
} //end function
}
Session.php :
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* CodeIgniter
*
* An open source application development framework for PHP 5.1.6 or newer
*
* #package CodeIgniter
* #author ExpressionEngine Dev Team
* #copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
* #license http://codeigniter.com/user_guide/license.html
* #link http://codeigniter.com
* #since Version 1.0
* #filesource
*/
// ------------------------------------------------------------------------
/**
* Session Class
*
* #package CodeIgniter
* #subpackage Libraries
* #category Sessions
* #author ExpressionEngine Dev Team
* #link http://codeigniter.com/user_guide/libraries/sessions.html
*/
class CI_Session {
var $sess_encrypt_cookie = FALSE;
var $sess_use_database = FALSE;
var $sess_table_name = '';
var $sess_expiration = 7200;
var $sess_expire_on_close = FALSE;
var $sess_match_ip = FALSE;
var $sess_match_useragent = TRUE;
var $sess_cookie_name = 'ci_session';
var $cookie_prefix = '';
var $cookie_path = '';
var $cookie_domain = '';
var $cookie_secure = FALSE;
var $sess_time_to_update = 300;
var $encryption_key = '';
var $flashdata_key = 'flash';
var $time_reference = 'time';
var $gc_probability = 5;
var $userdata = array();
var $CI;
var $now;
/**
* Session Constructor
*
* The constructor runs the session routines automatically
* whenever the class is instantiated.
*/
public function __construct($params = array())
{
log_message('debug', "Session Class Initialized");
// Set the super object to a local variable for use throughout the class
$this->CI =& get_instance();
// Set all the session preferences, which can either be set
// manually via the $params array above or via the config file
foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
{
$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
}
if ($this->encryption_key == '')
{
show_error('In order to use the Session class you are required to set an encryption key in your config file.');
}
// Load the string helper so we can use the strip_slashes() function
$this->CI->load->helper('string');
// Do we need encryption? If so, load the encryption class
if ($this->sess_encrypt_cookie == TRUE)
{
$this->CI->load->library('encrypt');
}
// Are we using a database? If so, load it
if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
{
$this->CI->load->database();
}
// Set the "now" time. Can either be GMT or server time, based on the
// config prefs. We use this to set the "last activity" time
$this->now = $this->_get_time();
// Set the session length. If the session expiration is
// set to zero we'll set the expiration two years from now.
if ($this->sess_expiration == 0)
{
$this->sess_expiration = (60*60*24*365*2);
}
// Set the cookie name
$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
// Run the Session routine. If a session doesn't exist we'll
// create a new one. If it does, we'll update it.
if ( ! $this->sess_read())
{
$this->sess_create();
}
else
{
$this->sess_update();
}
// 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();
// Delete expired sessions if necessary
$this->_sess_gc();
log_message('debug', "Session routines successfully run");
}
// --------------------------------------------------------------------
/**
* Fetch the current session data if it exists
*
* #access public
* #return bool
*/
function sess_read()
{
// Fetch the cookie
$session = $this->CI->input->cookie($this->sess_cookie_name);
// No cookie? Goodbye cruel world!...
if ($session === FALSE)
{
log_message('debug', 'A session cookie was not found.');
return FALSE;
}
// Decrypt the cookie data
if ($this->sess_encrypt_cookie == TRUE)
{
$session = $this->CI->encrypt->decode($session);
}
else
{
// encryption was not used, so we need to check the md5 hash
$hash = substr($session, strlen($session)-32); // get last 32 chars
$session = substr($session, 0, strlen($session)-32);
// Does the md5 hash match? This is to prevent manipulation of session data in userspace
if ($hash !== md5($session.$this->encryption_key))
{
log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
$this->sess_destroy();
return FALSE;
}
}
// Unserialize the session array
$session = $this->_unserialize($session);
// Is the session data we unserialized an array with the correct format?
if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))
{
$this->sess_destroy();
return FALSE;
}
// Is the session current?
if (($session['last_activity'] + $this->sess_expiration) < $this->now)
{
$this->sess_destroy();
return FALSE;
}
// Does the IP Match?
if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
{
$this->sess_destroy();
return FALSE;
}
// Does the User Agent Match?
if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120)))
{
$this->sess_destroy();
return FALSE;
}
// Is there a corresponding session in the DB?
if ($this->sess_use_database === TRUE)
{
$this->CI->db->where('session_id', $session['session_id']);
if ($this->sess_match_ip == TRUE)
{
$this->CI->db->where('ip_address', $session['ip_address']);
}
if ($this->sess_match_useragent == TRUE)
{
$this->CI->db->where('user_agent', $session['user_agent']);
}
$query = $this->CI->db->get($this->sess_table_name);
// No result? Kill it!
if ($query->num_rows() == 0)
{
$this->sess_destroy();
return FALSE;
}
// Is there custom data? If so, add it to the main session array
$row = $query->row();
if (isset($row->user_data) AND $row->user_data != '')
{
$custom_data = $this->_unserialize($row->user_data);
if (is_array($custom_data))
{
foreach ($custom_data as $key => $val)
{
$session[$key] = $val;
}
}
}
}
// Session is valid!
$this->userdata = $session;
unset($session);
return TRUE;
}
// --------------------------------------------------------------------
/**
* Write the session data
*
* #access public
* #return void
*/
function sess_write()
{
// Are we saving custom data to the DB? If not, all we do is update the cookie
if ($this->sess_use_database === FALSE)
{
$this->_set_cookie();
return;
}
// set the custom userdata, the session data we will set in a second
$custom_userdata = $this->userdata;
$cookie_userdata = array();
// Before continuing, we need to determine if there is any custom data to deal with.
// Let's determine this by removing the default indexes to see if there's anything left in the array
// and set the session data while we're at it
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
unset($custom_userdata[$val]);
$cookie_userdata[$val] = $this->userdata[$val];
}
// Did we find any custom data? If not, we turn the empty array into a string
// since there's no reason to serialize and store an empty array in the DB
if (count($custom_userdata) === 0)
{
$custom_userdata = '';
}
else
{
// Serialize the custom data array so we can store it
$custom_userdata = $this->_serialize($custom_userdata);
}
// Run the update query
$this->CI->db->where('session_id', $this->userdata['session_id']);
$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
// Write the cookie. Notice that we manually pass the cookie data array to the
// _set_cookie() function. Normally that function will store $this->userdata, but
// in this case that array contains custom data, which we do not want in the cookie.
$this->_set_cookie($cookie_userdata);
}
// --------------------------------------------------------------------
/**
* Create a new session
*
* #access public
* #return void
*/
function sess_create()
{
$sessid = '';
while (strlen($sessid) < 32)
{
$sessid .= mt_rand(0, mt_getrandmax());
}
// To make the session ID even more secure we'll combine it with the user's IP
$sessid .= $this->CI->input->ip_address();
$this->userdata = array(
'session_id' => md5(uniqid($sessid, TRUE)),
'ip_address' => $this->CI->input->ip_address(),
'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
'last_activity' => $this->now,
'user_data' => ''
);
// Save the data to the DB if needed
if ($this->sess_use_database === TRUE)
{
$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
}
// Write the cookie
$this->_set_cookie();
}
// --------------------------------------------------------------------
/**
* Update an existing session
*
* #access public
* #return void
*/
function sess_update()
{
// We only update the session every five minutes by default
if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
// Save the old session id so we know which record to
// update in the database if we need it
$old_sessid = $this->userdata['session_id'];
$new_sessid = '';
while (strlen($new_sessid) < 32)
{
$new_sessid .= mt_rand(0, mt_getrandmax());
}
// To make the session ID even more secure we'll combine it with the user's IP
$new_sessid .= $this->CI->input->ip_address();
// Turn it into a hash
$new_sessid = md5(uniqid($new_sessid, TRUE));
// Update the session data in the session data array
$this->userdata['session_id'] = $new_sessid;
$this->userdata['last_activity'] = $this->now;
// _set_cookie() will handle this for us if we aren't using database sessions
// by pushing all userdata to the cookie.
$cookie_data = NULL;
// Update the session ID and last_activity field in the DB if needed
if ($this->sess_use_database === TRUE)
{
// set cookie explicitly to only have our session data
$cookie_data = array();
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
$cookie_data[$val] = $this->userdata[$val];
}
$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)));
}
// Write the cookie
$this->_set_cookie($cookie_data);
}
// --------------------------------------------------------------------
/**
* Destroy the current session
*
* #access public
* #return void
*/
function sess_destroy()
{
// Kill the session DB row
if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
{
$this->CI->db->where('session_id', $this->userdata['session_id']);
$this->CI->db->delete($this->sess_table_name);
}
// Kill the cookie
setcookie(
$this->sess_cookie_name,
addslashes(serialize(array())),
($this->now - 31500000),
$this->cookie_path,
$this->cookie_domain,
0
);
// Kill session data
$this->userdata = array();
}
// --------------------------------------------------------------------
/**
* Fetch a specific item from the session array
*
* #access public
* #param string
* #return string
*/
function userdata($item)
{
return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
}
// --------------------------------------------------------------------
/**
* Fetch all session data
*
* #access public
* #return array
*/
function all_userdata()
{
return $this->userdata;
}
// --------------------------------------------------------------------
/**
* Add or change data in the "userdata" array
*
* #access public
* #param mixed
* #param string
* #return void
*/
function set_userdata($newdata = array(), $newval = '')
{
if (is_string($newdata))
{
$newdata = array($newdata => $newval);
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
$this->userdata[$key] = $val;
}
}
$this->sess_write();
}
// --------------------------------------------------------------------
/**
* Delete a session variable from the "userdata" array
*
* #access array
* #return void
*/
function unset_userdata($newdata = array())
{
if (is_string($newdata))
{
$newdata = array($newdata => '');
}
if (count($newdata) > 0)
{
foreach ($newdata as $key => $val)
{
unset($this->userdata[$key]);
}
}
$this->sess_write();
}
// ------------------------------------------------------------------------
/**
* Add or change flashdata, only available
* until the next request
*
* #access public
* #param mixed
* #param string
* #return void
*/
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);
}
}
}
// ------------------------------------------------------------------------
/**
* Keeps existing flashdata available to next request.
*
* #access public
* #param string
* #return void
*/
function keep_flashdata($key)
{
// 'old' flashdata gets removed. Here we mark all
// flashdata as 'new' to preserve it from _flashdata_sweep()
// Note the function will return FALSE if the $key
// provided cannot be found
$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);
}
// ------------------------------------------------------------------------
/**
* Fetch a specific flashdata item from the session array
*
* #access public
* #param string
* #return string
*/
function flashdata($key)
{
$flashdata_key = $this->flashdata_key.':old:'.$key;
return $this->userdata($flashdata_key);
}
// ------------------------------------------------------------------------
/**
* Identifies flashdata as 'old' for removal
* when _flashdata_sweep() runs.
*
* #access private
* #return void
*/
function _flashdata_mark()
{
$userdata = $this->all_userdata();
foreach ($userdata 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);
}
}
}
// ------------------------------------------------------------------------
/**
* Removes all flashdata marked as 'old'
*
* #access private
* #return void
*/
function _flashdata_sweep()
{
$userdata = $this->all_userdata();
foreach ($userdata as $key => $value)
{
if (strpos($key, ':old:'))
{
$this->unset_userdata($key);
}
}
}
// --------------------------------------------------------------------
/**
* Get the "now" time
*
* #access private
* #return string
*/
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;
}
// --------------------------------------------------------------------
/**
* Write the session cookie
*
* #access public
* #return void
*/
function _set_cookie($cookie_data = NULL)
{
if (is_null($cookie_data))
{
$cookie_data = $this->userdata;
}
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
if ($this->sess_encrypt_cookie == TRUE)
{
$cookie_data = $this->CI->encrypt->encode($cookie_data);
}
else
{
// if encryption is not used, we provide an md5 hash to prevent userside tampering
$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
}
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
// Set the cookie
setcookie(
$this->sess_cookie_name,
$cookie_data,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
}
// --------------------------------------------------------------------
/**
* Serialize an array
*
* This function first converts any slashes found in the array to a temporary
* marker, so when it gets unserialized the slashes will be preserved
*
* #access private
* #param array
* #return string
*/
function _serialize($data)
{
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('\\', '{{slash}}', $val);
}
}
}
else
{
if (is_string($data))
{
$data = str_replace('\\', '{{slash}}', $data);
}
}
return serialize($data);
}
// --------------------------------------------------------------------
/**
* Unserialize
*
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
* #access private
* #param array
* #return string
*/
function _unserialize($data)
{
$data = #unserialize(strip_slashes($data));
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('{{slash}}', '\\', $val);
}
}
return $data;
}
return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
}
// --------------------------------------------------------------------
/**
* Garbage collection
*
* This deletes expired session rows from database
* if the probability percentage is met
*
* #access public
* #return void
*/
function _sess_gc()
{
if ($this->sess_use_database != TRUE)
{
return;
}
srand(time());
if ((rand() % 100) < $this->gc_probability)
{
$expire = $this->now - $this->sess_expiration;
$this->CI->db->where("last_activity < {$expire}");
$this->CI->db->delete($this->sess_table_name);
log_message('debug', 'Session garbage collection performed.');
}
}
}
// END Session Class
/* End of file Session.php */
/* Location: ./system/libraries/Session.php */
I am trying to save the session in a database instead of files on the server. I have defines the session_set_save_handler() like so
//Set handler to override SESSION
session_set_save_handler( array($this, "open"),
array($this, "close"),
array($this,"read"),
array($this, "write"),
array($this,"destroy"),
array($this, "gc"));
But I keep getting this warning
Undefined variable: this
Then I tried changing it to
session_set_save_handler( "open", "close", "read", "write", "destroy", "gc" );
I don't get the error but I get the following warning
Warning: session_set_save_handler(): Argument 1 is not a valid callback
this is my open() function
static protected function open(){
// If successful return true
if($this->db)
return true;
return false;
}
My question is how can I properly override the function?
this is my entire class
<?php
class SessionManager {
/**
* AOL users may switch IP addresses from one proxy to another.
*
* #link http://webmaster.info.aol.com/proxyinfo.html
* #var array
*/
protected $aolProxies = array('195.93.', '205.188', '198.81.', '207.200', '202.67.', '64.12.9');
private $db;
/**
* This function starts, validates and secures a session.
*
* #param string $name The name of the session.
* #param int $limit Expiration date of the session cookie, 0 for session only
* #param string $path Used to restrict where the browser sends the cookie
* #param string $domain Used to allow subdomains access to the cookie
* #param bool $secure If true the browser only sends the cookie over https
*/
static function sessionStart($dbo, $name, $limit = 0, $path = '/', $domain = null, $secure = null)
{
$this->db = $dbo;
//Set the cookie name
session_name($name); //. '_Session'
//Set SSL level
$https = isset($secure) ? $secure : isset($_SERVER['HTTPS']);
//Set session cookie options
session_set_cookie_params($limit, $path, $domain, $https, true);
//Set handler to override SESSION
session_set_save_handler( "open", "close", "read", "write", "destroy", "gc" );
session_start();
// Make sure the session hasn't expired, and destroy it if it has
if(self::validateSession()){
// Check to see if the session is new or a hijacking attempt
if(!self::preventHijacking()){
// Reset session data and regenerate id
$_SESSION = array();
$_SESSION['IPaddress'] = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
$_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
self::regenerateSession();
// Give a 5% chance of the session id changing on any request
} elseif(rand(1, 100) <= 5)
self::regenerateSession();
} else {
$_SESSION = array();
session_destroy();
session_start();
}
}
/*
* This function regenerates a new ID and invalidates the old session. This should be called whenever permission
* levels for a user change.
*/
static function regenerateSession(){
// If this session is obsolete it means there already is a new id
if(isset($_SESSION['OBSOLETE']) || $_SESSION['OBSOLETE'] == true)
return;
// Set current session to expire in 10 seconds
$_SESSION['OBSOLETE'] = true;
$_SESSION['EXPIRES'] = time() + 10;
// Create new session without destroying the old one
session_regenerate_id(false);
// Grab current session ID and close both sessions to allow other scripts to use them
$newSession = session_id();
session_write_close();
// Set session ID to the new one, and start it back up again
session_id($newSession);
session_start();
// Now we unset the obsolete and expiration values for the session we want to keep
unset($_SESSION['OBSOLETE']);
unset($_SESSION['EXPIRES']);
}
/*
* This function is used to see if a session has expired or not.
* #return bool
*/
static protected function validateSession(){
if( isset($_SESSION['OBSOLETE']) && !isset($_SESSION['EXPIRES']) )
return false;
if(isset($_SESSION['EXPIRES']) && $_SESSION['EXPIRES'] < time())
return false;
return true;
}
/*
* This function checks to make sure a session exists and is coming from the proper host. On new visits and hacking
* attempts this function will return false.
*
* #return bool
*/
static protected function preventHijacking(){
if(!isset($_SESSION['IPaddress']) || !isset($_SESSION['userAgent']))
return false;
if( $_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT']
&& !( strpos($_SESSION['userAgent'], 'Trident') !== false
&& strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') !== false))
return false;
$sessionIpSegment = substr($_SESSION['IPaddress'], 0, 7);
$remoteIpHeader = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
$remoteIpSegment = substr($remoteIpHeader, 0, 7);
if($_SESSION['IPaddress'] != $remoteIpHeader
&& !(in_array($sessionIpSegment, $this->aolProxies) && in_array($remoteIpSegment, $this->aolProxies)))
return false;
if( $_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT'])
return false;
return true;
}
//Open the database connection
private function open(){
// If successful return true
if($this->db)
return true;
return false;
}
//Close the database connection
static protected function close(){
// If successful return true
if($this->db->endConnection())
return true;
return false;
}
//Read the session information
private function read($id){
//Select session data
$info = $this->db->getOneResult('SELECT data FROM sessions WHERE id = ?', array($id) );
//if data found return it
if($info)
return $info['data'];
// Return an empty string
return '';
}
//Write the session information
private function write($id, $data){
// Create time stamp
$access = time();
// Set query
$write = $this->db->processQuery('REPLACE INTO sessions VALUES (?, ?, ?)', array($id, $access, $data));
// If successful return true
if($write)
return true;
// Return False
return false;
}
//Destroy
private destroy($id){
//Delete record
$delete = $this->db->processQuery('DELETE FROM sessions WHERE id = ?',array($id) );
// Attempt execution
// If destroyed return true
if( $delete )
return true;
// Return False
return false;
}
//Garbage Collection
private function gc($max){
// Calculate what is to be deemed old
$old = time() - $max;
//Delete old sessions
$delete = $this->db->processQuery('DELETE FROM sessions WHERE access < ?', array($old));
//if Garbage has been removed return true
if($delete)
return true;
// Return False
return false;
}
}
?>
You are defining it in a static method. $this does not exist in static methods.
You can use the classname itself. So you would do something like:
//Set handler to override SESSION
session_set_save_handler( array("SessionManager", "open"),
array("SessionManager", "close"),
....);
first
//Destroy
private destroy($id){
change
//Destroy
public function destroy($id){
i think my problem is a little weird, ive wrote a little class to log in/out user, entire system is based in MVC pattern, and my libraries are custom and self written,
but the problem: when i log in the user with out the $remember flag, no problems, sessions are easily set and unset. but when i activate the $remember and i create a cookie, my logout function does not work, it deletes the session but not the cookie, so cookie remains in browser with complete data, and whenever i reload the page , my class logs me in again because there is a cookie with full authentication details, the problem is with a cookie, i cant send other headers like Location: blah blah from $this->logout; ive tried different ways to unset cookie, but no luck;
this is the class:
<?php
/**
* Pars----
* Classified --- Application
*
* #author Sallar Kaboli (me#sallar.ir)
* #copyright Copyright (C) 2009 - 2010 -----CO (dev#------.us)
* #package Pars---
* #version 1.0
*/
class ParsUser {
public $userID = false;
private $_p = null;
public $userData = null;
public function __construct() {
$this->_p = ParsRegistry::getInstance();
if( $this->_p->sess->isVarSet('parsUser') ) {
$this->loadUser($this->_p->sess->getVar('parsUser'));
}
if( isset($_COOKIE['parsUser']) and !$this->isLoggedIn() ) {
$userFromCookie = unserialize(base64_decode($_COOKIE['parsUser']));
$this->checkLogin($userFromCookie['username'], $userFromCookie['password'], true, false);
}
}
public function checkLogin($username, $password, $remember = true, $hash = true) {
if(!empty($username) and !empty($password)) {
$password = $hash ? $this->_p->valid->hash($password) : $password;
$qData = array('user' => $username, 'pass' => $password);
$query = 'SELECT * FROM people WHERE `username` = :user AND `password` = :pass';
$user = $this->_p->db->getRow($query, $qData);
if(is_object($user) AND !empty($user->id)) {
$this->userID = $user->id;
$this->userData = $user;
if( $hash ) {
$this->_p->db->execute('UPDATE people SET `last_login` = ? WHERE `id` = ?', array( time(), $this->userID ));
}
$this->loginTheUser($remember);
return true;
}
else {
return false;
}
}
else {
return false;
}
}
private function loginTheUser($remember = true) {
$this->_p->sess->setVar('parsUser', $this->userID);
if( $remember ){
$rememberPeriod = $this->_p->conf->c['cookie_remember_period'];
$cookie = array(
'username' => $this->userData->username,
'password' => $this->userData->password
);
$cookie = base64_encode(serialize($cookie));
setcookie('parsUser', $cookie, time() + $rememberPeriod/*, '/', $_SERVER['HTTP_HOST']*/);
}
return false;
}
private function loadUser($userID){
$user = $this->_p->db->getRow('SELECT * FROM people WHERE `id` = ?', $userID);
if( is_object($user) and ( $user->id == $userID ) ){
$this->userID = $user->id;
$this->userData = $user;
$this->_p->sess->setVar('parsUser', $this->userID);
return true;
}
else return false;
}
public function logout($redirectTo = false) {
setcookie('parsUser', '', mktime(12,0,0,1, 1, 1990));
unset($_COOKIE['parsUser']);
$this->_p->sess->sessionDrop();
$this->userData = null;
$this->userID = false;
if ( !empty($redirectTo) ){
$this->_p->core->redirect($redirectTo);
exit;
}
}
public function isLoggedIn() {
//return ( empty($this->userID) OR !$this->userID ) ? false : true;
if( $this->userID > 0 and $this->userID != false and !empty($this->userID) )
return true;
else return false;
}
public function checkAccess($level) {
if($level == 0) {
return true;
}
elseif($this->isLoggedIn()) {
if( $this->userData->level <= $level ) {
return true;
}
else {
return false;
}
}
else {
return false;
}
}
public function getUserData() {
$args = func_get_args();
if( empty($this->userID) )
throw new Exception('User is not loaded.');
if( is_array($args) and count($args) > 0){
foreach( $args as $arg ){
if( !isset($this->userData->$arg) )
throw new Exception('Unknown property: <b>' . $property . '</b>');
else
$props[$arg] = $this->userData->$arg;
}
if( count($args) == 1 )
return $props[$args[0]];
else
return $props;
}
else{
$props = $this->userData;
unset($props->password);
return $props;
}
}
}
sorry for my english.
try to set $path in both cases (create, remove cookie)
You could set the cookie with invalid data:
setcookie('parsUser', 'trash', time() - 3600);
If this doesn't delete the cookie, it should at least create an invalid login token.
I would also recommend against base64 encoding the username and password in the cookie. It's all but plaintext to an experienced attacker. You can easily integrate strong encryption into your application using mcrypt:
http://us2.php.net/mcrypt
If that's not an option, you can use a php-only implementation of xor encrypt with strong keys. There are also php-only implementations of blowfish and Rijndael on the internet. I'd provide links if I could, but my current reputation won't let me add more than one hyperlink.
Sorry for my strange question but why do you set a cookie in history (so it's gets deleted) and then unset a cookie that doesn't exist anymore?
Hmm looks strange if you look at the output of your image...
What is the system time of your server?
Because it said the cookie would expire in 1990.. Looks like your computer/server is way behind if that is still valid :P
By the way, maybe you can't edit the data, because you need to decode the base64 encryption first (because in your code when you set it, you use the base64 function)