I have a web app that stores some objects in the user session so it doesn't have to keep calling to the database every time there's an AJAX hit to the server.
I want to write some cleanup/save functions that are triggered when the user closes the browser tab or navigates away from the page.
Is the session "destroyed" (i.e. calls __destruct for any objects it contains) if a user navigates away from the page - or is it better to handle this client side with a javascript that sends an AJAX request when the user navigates away?
PHP sessions are a server-side thing. The client's browser navigating away from a page won't trigger anything server-side without you explicitly making an AJAX call or similar.
The session is in PHP is not defined as a class. Instead, we have a set of session functions to manipulate the session. To make sure that you have destroyed the session, you need to explicitly call :
session_destroy();
If you have not destroyed the session, the session will do garbage collection after the session timeout. The garbage collection depends on the following parameters - session.gc_maxlifetime, session.gc_divisor and session.gc_probability. To make sure that the garbage collection runs on every session, you will have to add session.gc_probability to 100%. But it definitely add an overhead to the server, especially if yours is a high traffic server.
If you do not explicitly keep track of the sessions and destroy it after use, you are leaving some part of the session management to the OS. See the note from PHP.net:
Note: If you are using the default file-based session handler, your
filesystem must keep track of access times (atime). Windows FAT does
not so you will have to come up with another way to handle garbage
collecting your session if you are stuck with a FAT filesystem or any
other filesystem where atime tracking is not available. Since PHP
4.2.3 it has used mtime (modified date) instead of atime. So, you won't have problems with filesystems where atime tracking is not
available.
The best way is to send a flag via Ajax call when the browser or tab is closed. You can detect it via : window.onunload event of javascript.
Short in short: no. You have to end your session with session_destroy()
If you put any objects into $_SESSION, their destructors are NOT called when the script ends, but if it exists, the magic function __sleep() is calles when PHP serializes $_SESSION. When the next scripts starts the session again, any object that is stored and whose source code is known (e.g. by requiring it before calling session_start(), or using autoloading) will have the __wakeup() method called.
If PHP detects that a session was inactive for a certain time, it simply deletes the serializes file.
See the docs: http://php.net/manual/en/language.oop5.magic.php
Related
I have a script A that calls session_start() at the top and creates some session variables.
Then the script makes an ajax call that invokes script B:
$("#galleryContent").load("B.php", {op : 'get_thumbs'
},
function() {
$('.galleryThumb').draggable(thumb_dragOps);
}
s);
B needs access to the session variables script A set up so it does a session_start() to try to get at the variables. But B's session_start() hangs.
Am I doing something wrong here?
Thanks
It's due to locking; PHP locks the session file while it is writing to it. To fix this, close the session file when you are done modifying session variables using session_write_close().
I have had exactly this problem in the past, and locking was the problem. Just be sure to explicitly tell PHP you're done modifying the session using session_write_close(), and you should be fine.
From the documentation:
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.
Note: You can also set up a custom session handler and avoid this file-locking problem entirely by storing session information in a database. At any kind of scale, this is pretty much a necessity.
I'm somewhat bewildered about using session_start in PHP. Should I use it in my scripts both when user initially creates session and when resumes it on consequent queries - or only when creating?
Currently I do not call it when session already exists but I have found that session sometimes expires unexpectedly fast:
For example, from public log of my site I see:
srinivasvarma678 09:14:34 27-Jun-14
I've just logged in...
...
srinivasvarma678 08:59:38 27-Jun-14
I'm proud to tell I've just solved Vowel Count!
I.e. user's last interaction with site was at 8:59 and then in 15 minutes he needs to log in again (though session.gc_maxlifetime=1440)
Could this behavior be explained by the fact I am not calling session_start every time?
Short answer: Yes
As stated here in the PHP docs:
session_start() creates a session or resumes the current one based on a
session identifier passed via a GET or POST request, or passed via a cookie.
So if you want to continue the session, you should always use session_start() on every page...
session_start() allows you to use sessions in your script.
You should use it both when creating new sessions or reusing existent one.
It also updates the session, to it won't be garbage collected and removed.
I've been reading the manual and various pages on the web including lot's of questions here on SO. However, I've still not been able to get my head around the concept of session_destroy() in PHP in conjunction with other means of unsetting session data.
Consider this for a site that never registers session variables outside the $_SESSION superglobal array.
session_start();
$_SESSION = array();
session_regenerate_id(true); // New cookie + old session file on server deleted
session_destroy(); // What does PHP do here that was not done above?
Please note that I have built working login-logout scripts for years. This question is not about getting things to work, but I want to understand exactly what is happening.
(A lot of answers here on SO also use session_unset() which unsets registered variables. However, I never use session_register(), so that seems really redundant.)
The session_regenerate_id() function is meant to copy or move the session data based on its corresponding identifier; it's typically used when a user logs in to prevent session fixation. Afterwards, the session is still active and it can be accessed with $_SESSION.
The session_destroy() removes the current session data. Afterwards, the session is gone and you can only start a new session using session_start().
If a user signs out of your site, the most appropriate action is to destroy the session altogether; i.e. use session_destroy().
Btw, session_register() and session_unset() are deprecated and shouldn't be used.
Let's go to the source. Literally.
session_destroy() and session_regenerate_id() are both implemented in ext/session/session.c in the PHP source. It's obvious from a quick reading that if you pass true to session_regenerate_id, it calls s_destroy on the underlying session save handler, which is the exact same call as the one made by session_destroy. This behaviour has remained the same since at least 2005, according to an svn blame.
session_destroy does make two additional calls to php_rshutdown_session_globals and php_rinit_session_globals. Among other things, this causes session_destroy() to call the close function in the save handler, but this is done automatically when the request has completed, anyway (see PHP_RSHUTDOWN_FUNCTION). It also resets the session to the inactive state (like before calling session_start), which can be seen by calling session_status() (introduced in php 5.4).
The take away from all of this is that you never have to call session_destroy before calling session_regenerate_id(true). However, if you want to reset the session, you still have to call it after, because otherwise the session will still be active, and the current contents of $_SESSION will be written to storage by the save handler when the request has finished.
I am trying to make some changes to an opensource project. I want to keep track of when users log in and log out.
Right now I change their login status in db when they login or manually log out. The problem right now is that I cannot find out if the user just closed their browser without pressing on logout button.
For this reason I need to trigger a function that will change database every time the user's session expires.
I've tried session_set_save_handler in PHP, but it looks like I need to override the whole session behavior. What I am looking for is to keep default session behavior and just add functionality when the user's session expires. Is there a way to do that?
I did something really nasty once. Every time a session was "updated" by a page refresh / fetch / etc., I updated a timestamp on a DB row. A second daemon polled the DB every 10 minutes and performed "clean-up" operations.
You won't find any native PHP facilities to achieve your goal. Session timeout doesn't run in the background. You won't even know if a session is timed out, unless a timed out session attempts another access. At this point, nearly impossible to trap, you can make your determination and handle it appropriately.
I'd recommend a queue & poll architecture for this problem. It's easy and will definitely work. Add memcached if you have concerns about transaction performance.
I presume you're using standard PHP file-based sessions. If that's the case, then PHP will do its own garbage collection of stale sessions based on the session.gc_* configuration parameters in php.ini. You can override those to disable the garbage collector completely, then roll your own GC script.
You could either check the timestamps on the files (quick and easy to do in a loop with stat()) to find 'old' sessions, or parse the data in each file to check for a variable that lists the last-access time. Either way, the session files are merely the output of serialize($_SESSION) and can be trivially re-loaded into another PHP instance.
What about window close event on javascript. So basically session is destroyed when all of the windows of the session site are closed. So, when the last window is closed ( this is checked via additional js checking ) send ajax request to server.
I need to perform an action after a session times out. However I have no clue how to trigger that action without an incoming request. An event handler/a listener/a timer would suit perfect but since PHP does not support such a thing it is really difficult to accomplish what I want.
After lot of searching I bumped into session_set_save_handler but I still cannot fully understand how this method works. If I write code that triggers the action inside the close method when it will be executed?
I also need to keep the current session solution as it is and I wonder what the ramifications of using session_set_save_handler in conjunction with that will be? (My current solution sets a session cookie, assigns a name to the session and starts the session, when the user logs out or a request is done after the session timeout (that value is set in a configuration file) the session is completely destroyed)
Regards!
This is somewhat difficult to do in php, AFAIK.
But you can try by making a passive session handler:
Store session ids associated with a timestamp.
Each time the user associated with certain id makes a request, refresh it's timestamp.
You can detect defunct sessions by comparing the system's current, and each session id's timestamps. The ones that differ above a given treshold (say 30min), are assumed to have passed away. Then you can execute your own save handlers for these session ids.
This won't work if the session end handler needs to be executed inmediately, as this process is executed each time when a request arrives (from any user), so it will depend directly on the website's traffic flow.
But you can also solve it by setting cron jobs each 15min or so. Depending on how expensive your save handlers are, seems an acceptable periodicity.
PHP needs to run in some way for PHP code to execute. Either through a user request or a cronjob.
A Session is saved to the locale storage when a PHP request finishes executing or when session_write_close() is called
This session_set_save_handler() allows you to write your own save handler.