Is it possible to tell codeigniter to skip session timeout reset if post request is coming via ajax to a particular controller function. I have a frequent ajax call inside user login dashboard to check something, but these calls keeps the session alive so even if the user stays inactive for 10 minutes (sess_expiration time) session wont be killed and they still remain logged in for ever.
If (and only IF) your Ajax call is completely session-agnostic (that is, it doesn't required to be logged in to run, it doesn't need any session data from the user, etc) you could serve the Ajax request from a separate ajax-specific controller and then inhibit the session library autoload when that specific controller is used.
If the ajax call requires a logged in user you're mostly out of luck.
However, if you meet these conditions, find the $autoload['libraries] section in application/config/autoload.php and use this dirty hack:
// Here, an array with the libraries you want/need to be loaded on every controller
$autoload['libraries'] = array('form_validation');
// Dirty hack to avoid loading the session library on controllers that don't use session data and don't require the user to have an active session
$CI =& get_instance();
// uncomment the one that fits you better
// Alternative 1: you only have a single controller that doesn't need the session library
// if ($CI->router->fetch_class() != 'dmz') array_push($autoload['libraries'], 'session');
// END alternative 1
// Alternative 2: you have more than one controller that doesn't need the session library
// if (array_search($CI->router->fetch_class(), array('dmz', 'moredmz')) === false) array_push($autoload['libraries'], 'session');
// END alternative 2
In the above code, dmz and moredmz are my two imaginary controller names that require the session library to not be loaded. Whenever these are NOT used, the session library is pushed into autoload and thus loaded. Otherwise, the session library is ignored.
I actually have this running on one of my sites in order to allow the health checks from my loadbalancer to run (once every 5 seconds on each application server, from both the primary loadbalancer and its backup) and fill up my sessions table with useless data and works like a charm.
Not sure what version of CI you're using, but the above code is tested on CI 3.1.11.
Now, as you state the Ajax call requires the session driver, the only way around this would be to mess a little with the Session driver itself. In 3.1.11, the session driver is located in system/libraries/Session/Session.php and the part you'd need to change is the final part of the constructor method (look from line 160 onwards). For this example, I'll assume your Ajax calls are handled by a specific controller called "Ajax"
// This is from line 160 onwards
elseif (isset($_COOKIE[$this->_config['cookie_name']]) && $_COOKIE[$this->_config['cookie_name']] === session_id())
{
$CI =& get_instance();
$new_validity = ($CI->router->fetch_class() !== 'ajax') ? time() + $this->_config['cookie_lifetime'] : $_SESSION['__ci_last_regenerate'] + $this->_config['cookie_lifetime'];
setcookie(
$this->_config['cookie_name'],
session_id(),
(empty($this->_config['cookie_lifetime']) ? 0 : $new_validity),
$this->_config['cookie_path'],
$this->_config['cookie_domain'],
$this->_config['cookie_secure'],
TRUE
);
}
$this->_ci_init_vars();
log_message('info', "Session: Class initialized using '".$this->_driver."' driver.");
In a nutshell, this example (haven't tested it so please do before deploying it, it may have a typo or two) will first instantiate the CI core and get the controller name from the Router. If it's a regular controller, it'll determine the new cookie validity as "now plus the cookie validity from the config". If it's the ajax controller, the cookie validity will be the same as the current validity (last regeneration time plus cookie validity.. had to reiterate it as the ternary operator requires it)
Afterwards, the setcookie is modified to use the pre-computed cookie validity depending on what the _config['cookie_lifetime'] value is.
Related
I'm trying to implement a SessionProvider auth plugin for a mediawiki install.
I'm trying to integrate with an existing auth system that uses $_SESSION to indicate that a user is logged in, however any method I try, the resulting $_SESSION variable that I get inside the class' provideSessionInfo function is empty.
Previously this was done with a onUserLoadFromSession hook (that contained the bulk of the logic code below), but the update appears to have broken actually looking at the existing $_SESSION:
public function provideSessionInfo(WebRequest $request)
{
// $_SESSION is hidden away per-request, but $request->getSession likes to call this function (yay infinite loops)
if (!isset($_SESSION['memberid'])) {
return null;
}
$memberid = $_SESSION['memberid'];
$mr_user = MyRadio_User::getInstance($memberid);
$user = User::newFromName($memberid);
$dbr = wfGetDB(DB_REPLICA);
$s = $dbr->selectRow('user', ['user_id'], ['user_name' => $memberid]);
if ($s === false) {
return null;
} else {
$user->mName = $memberid;
$user->mId = $user->idForName();
$user->loadFromDatabase();
$user->saveSettings();
}
if ($mr_user->hasAuth(AUTH_WIKIADMIN) && !in_array('sysop', $user->getGroups())) {
$user->addGroup('sysop');
}
$user->mTouched = wfTimestampnow();
return new SessionInfo(SessionInfo::MAX_PRIORITY, [
'provider' => $this,
'persisted' => true,
'userInfo' => UserInfo::newFromUser($user, true),
]);
}
If I hardcode $memberid, the function and the session provider works fine, but I just can't seem to find a way to transfer the session from one PHP "application" to another.
Adding debugging shows the PHPSESSID variable still set in the cookie, but for whatever reason it can't be pulled out into an actual session object. I've tried various session_start() style methods to no effect.
I feel like I'm missing something obvious, but the documentation for this stuff is just a basic wiki page and the raw generated doxygen.
Session handling is not a good way of cross-application communication. MediaWiki uses its own session handling, which means there is no connection between $_SESSION in MediaWiki and $_SESSION in your application at all. The first will be populated from MediaWiki's object cache (as configured by $wgSessionCacheType), the other from PHP session files or whatever.
If you really do not have a better way to pass data, you'll have to write a custom access class which can be called by your provider, which will save the current session handler, install a null session handler (which restores PHP's native session handling which will hopefully be interoperable with the other application), start the session, fetch the session data, restore the original session handler, and probably start the session again.
I am using a small PHP framework.
When calling session_start(), a class implementing SessionHandlerInterface
allows a creation of the cookie file throught its method read($id).
A file like sess_533stse23wsdd23rs is created on disk. Good.
Eventually a further call to the SessionHandlerInterface implementation writes more information in the cookie server file. This information can be viewed on call to write($id, $data).
When debugging, I break in the write method implementation and view the call stack and see a call from session_write_close(). I cannot discover where the data passed as parameter to the write is coming from. I do not seem to have this info from the debugger. This type of information is not accessible:
session_write_close(){
// Where this $data is coming from ?
handler...write( $id, $data )
}
In PHP, is there a method to save information to the cookie, so that a call to the session_write_close() will flush this information to the persistent file on disk ?
Ok, finally, from what I discovered, it seems that any data in $_SESSION will be flushed to the cookie file.
Can I get somebody's confirmation ?
New to Laravel and having some problems with Sessions. Specifically, reading session data from a PHP file outside of Laravel.
For example, let's say I set the session variable like so: Session::put('isAuthorized', 'yes') - I can retrieve this just fine in the Laravel context with Session::get('isAuthorized') but the following PHP will not retrieve this session key -
<?php
session_start();
echo $_SESSION['isAuthorized'];
?>
returns
Notice: Undefined index: isAuthorized in C:\xampp\htdocs\session.php on line 3
I have tried setting the Laravel session driver to both the default cookie and file modes, same result.
You could also write a session adapter, so the $_SESSION variable will be an instance of it:
<?php
class SessionAdapter implements \ArrayAccess {
public function offsetExists($offset) {
return Session::has($offset);
}
public function offsetGet($offset) {
return Session::get($offset);
}
public function offsetSet($offset, $value) {
return Session::put($offset, $value);
}
public function offsetUnset($offset) {
return Session::forget($offset);
}
}
And then somewhere in your code:
<?php
$_SESSION = new SessionAdapter();
// or
$GLOBALS['_SESSION'] = new SessionAdapter();
This way native PHP session and Laravel session will be "the same".
Laravel uses storage drivers for its sessions, namely cookie, file, database, memory, memcached and redis (and APC in Laravel 4).
The web is a stateless environment. This means that each request to your application is considered unrelated to any previous request. However, sessions allow you to store arbitrary data for each visitor to your application. The session data for each visitor is stored on your web server, while a cookie containing a session ID is stored on the visitor's machine. This cookie allows your application to "remember" the session for that user and retrieve their session data on subsequent requests to your application.
http://laravel.com/docs/session/config
The default storage driver is Cookie, so try this:
print_r($_COOKIE);
Please note that this answer is specific to Laravel 3
Laravel doesn't use PHP sessions, so forget session_start(), $_SESSION, etc.
If you're running with file session driver, the session data is stored in a file in storage/sessions. You can obtain the name of the file by reading the Laravel session ID from the cookie. So the hacky way to solve your problem would be to write some code that obtains the session ID from the cookie and then looks for the file with that name in the storage/sessions folder, read that file in, json_decode() it and you can read the whole thing.
If you're running with cookie session driver, all of the session data is stored in the cookie, but it is encrypted, so you'd have to have a copy of the key (which should be in application/config/application.php) and then figure out what encryption method Laravel is using so you can decrypt it. Then you can read all the session variables.
To achieve what you're hoping to achieve - that is, figure out if the current person is authorized, it might be better to build an API into your app and secure it so that it can only be accessed by localhost. Not a great solution from a performance standpoint, but potentially more elegant because you're not hacking around with the internals of Laravel session management.
Session handling in Laravel is indeed different from native PHP session. To use native PHP session, set the value as below:
<?php
session_start();
$_SESSION['isAuthorized'] = 'yes';
echo $_SESSION['isAuthorized']; // output yes
?>
I having issues with Codeigniter sessions dying on IE randomly, I search everywhere and tried everything, the bug just wouldnt dissappear, i tried the function to check if ajax and wont sess_update() not working either, so my question is, what is the setback if I initialize the CI session every controller call? I have both native and CI sessions, but It would take me a few more days to change everything to Native sessions. its a temp fix.
class Transactions extends Controller {
function Transactions()
{
session_start();
parent::Controller();
$this->load->model('Modelcontracts');
$this->load->model('Modelsignup');
$this->load->model('Modeltransactions');
$this->session->set_userdata('account_id',$_SESSION['account_id']);
$this->session->set_userdata('email',$_SESSION['email']);
$this->session->set_userdata('account_type',$_SESSION['account_type']);
$this->session->set_userdata('parent_account_id',$_SESSION['parent_account_id']);
$this->session->set_userdata('accountrole_id',$_SESSION['accountrole_id']);
$this->session->set_userdata('user_type_id',$_SESSION['user_type_id']);
}
function index()
{
I never experience any problems with CodeIgniters sessions. Have you created the MySQL table for ci_sessions?
The setback is basicly that it's an unlogical call. If that doesn't matter, then I can't see any setbacks with it.
You could ease up the code like this though:
$arr = array('account_id', 'email', 'account_type', 'parent_account_id', 'accountrole_id', 'user_type_id');
foreach($arr as $h)
if (isset($_SESSION[$h]))
$this->session->set_userdata($h, $_SESSION[$h]);
// else echo "Session [{$h}] doesn't exist!";
Or extend your session library to do a
foreach(array_keys($_SESSION) as $h)
$this->CI->session->set_userdata($h, $_SESSION[$h]);
When loaded.
I don't think you should be using session_start() if you're having CodeIgniter manage your sessions (which you are if you're using CodeIgniter's set_userdata() / get_userdata() functions).
It says right at the top of the CI user docs that CI doesn't use PHP's native session handling, so this may be causing you trouble. The session is started automatically by loading the session library, either automatically if you put it in the config file or explicitly with $this->load->library('session');.
http://codeigniter.com/user_guide/libraries/sessions.html
-Gus
Edit: I came across a CI forum post regarding IE/CI session issues. Apparently it's a well-known issue. http://codeigniter.com/forums/viewthread/211955/
A question with respect to Session Expiration in PHP.
I need my server to throw away session information if that user has been inactive for a while (for testing purposes, 5 seconds).
I've looked at this question and particular at the answer by Gumbo (+28 votes) and I've been wondering about the feasibility of this answer with respect to inactive users. On my site I already implemented this suggestion and it works fine, so long as the user requests some data at least once after the session expired. But the problem with inactive users is that they don't request new data. So the expiration code is never called.
I've been looking at session.gc_maxlife and associated parameters in my PHP.ini, but I couldn't make this work the way I wanted it to.
Any suggestions on this problem?
The session expiration logic I mentioned does already do what you’re expecting: The session cannot be used once it has expired.
That the session data is still in the storage doesn’t matter as it cannot be used after expiry; it will be removed when the garbage collector is running the next time. And that happens with a probability of session.gc_probability divided by session.gc_divisor on every session_start call (see also How long will my session last?).
Edit Since you want to perform some additional tasks on an expired session, I would rather recommend to use a custom session save handler.
When using a class for the session save handler, you could write two classes, one for the basics save handler and one with a extended garbage collector that performs the additional tasks, e.g.:
interface SessionSaveHandler {
public function open();
public function close();
public function read($id)
public function write($id, $data);
public function destroy($id);
public function gc($callback=null);
}
class SessionSaveHandler_WithAdditionalTasks implements SessionSaveHandler {
// …
public function gc($callback=null) {
if (!is_null($callback) && (!is_array($callback) || !is_callable($callback))) return false;
while (/* … */) {
if ($callback) $callback[0]::$callback[1]($id);
// destroy expired sessions
// …
}
}
public static function doAdditionalTasksOn($id) {
// additional tasks with $id
}
}
session_set_save_handler(array('SessionSaveHandler_DB_WithAdditionalTasks', 'open'),
array('SessionSaveHandler_DB_WithAdditionalTasks', 'close'),
array('SessionSaveHandler_DB_WithAdditionalTasks', 'read'),
array('SessionSaveHandler_DB_WithAdditionalTasks', 'write'),
array('SessionSaveHandler_DB_WithAdditionalTasks', 'destroy'),
array('SessionSaveHandler_DB_WithAdditionalTasks', 'gc')
);
If you need to call specific expiration logic (for example, in order to update a database) and want independence from requests then it would make sense to implement an external session handler daemon that looks at access times of session files. The daemon script should execute whatever necessary for every session file that has not been accessed for a specified time.
This solution has two prerequisites: the server's filesystem supports access times (Windows does not) and you can read files from session save path.
The garbage collector isn't called per-session, the garbage collector has a change to be called based on tge gc_* values, which can invalidate multiple sessions. So as long as someone triggers it, other people can be logged out. If you need a more reliable method, if your timeout is in minutes use a cronjob, if your timeout is in seconds you'll have to use some kind of daemon process.
One way you can do this is using javascript to refresh the page a little after the timeout period. Granted your users will have to have Javascript enabled for this to work. You can also add extra features like having javascript pop up a timeout notice with a count down, etc. So essential what happens the session is expired due to your settings, then the refresh hits, clean up runs and your done.
<html>
<head>
<script type="text/JavaScript">
<!--
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
}
// -->
</script>
</head>
<body onload="JavaScript:timedRefresh(5000);">
</body>
</html>