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.
Related
The PHP documenation for session_write_close says
...but as session data is locked to prevent concurrent writes only one script may operate on a session at any time.
Could somebody please elaborate on what this means? Does this mean that the actual session store is locked for writing? If so and I'm using a custom session handler that writes to a SQL database, how do things change? Are all subsequent requests for that session completely blocked until the lock is released?
I ask because I'm using a custom session handler that uses a table in a MySQL database, and I think I might be encountering a race condition when more than one request comes in at a time for a session. If the first request reads the session from the table, and a second request comes in before the first finishes, will the second request get blocked until the first completely finishes or calls session_write_close? If not, would it be possible for the second to overwrite whatever the first had just written if it had read before the first had written?
Also, if the first request is aborted after reading the session but before it writes, is session_write still called?
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
I have a Symfony2 project, where at the beginning of each session, I create a folder on the server where the user can manipulate and place his files.
I want to be able to delete the user's folder, when he closes his browser
(or any other related event, maybe check for a session timeout?).
How can I achieve this?
PS: I have read somewhere that java has a sessionHandler where you can code your function.
Is there anything similar in php (Symfony2 specifically)?
First of all, you cannot recongnize if a browser is closed by HTML and PHP. You would need ajax and constant polling or some kind of thing to know the browser is still there. Possible, but a bt complicated, mainly because you might run into troubles if a browser is still there (session is valid) but has no internet connection for a few minutes (laptop, crappy wlan, whatever).
You cannot have a sessionHandler which does this for you in PHP because PHP is executed when a script is retrieved from your server. After the last line is executed, it stops. If no one ever retrieves the script again, how should it do something? There is no magic that restarts the script to check if the session is still there.
So, what to do? First of all you want to make the session visible by using database session storage or something like that. Then you need a cronjob starting a script, looking up all sessions and deciding which one is invalid by now and then does something with it (like deleting the folder). Symfony can help as it allows you to configure session management in a way that it stores sessions in the database (see here) as well as creating a task which can be executed via crontab (see here).
The logical part, which contains deciding which session is invalid and what to do with this sessions) is your part. But it shouldn't be very hard as you got the session time and value in the database.
I don't know if this is possible. What I'm looking for is the event (if there is one) that launch's to end the session. I'd like to somehow grab that and perform my own action right before the session is ending. The reason for this is I have need for one of the session variables set that I will lose as soon as the session expires.
I feel this is probably a poor way of achieving my goal if even possible. It's friday 7:00pm and still at office. imagine my excitement trying to find a solution.
Thanks Guys.
If you make your own session save handler to use a database for example, you can have a callback for garbage collection that you could use to grab the appropriate data prior to deleting the data.
See session_set_save_handler, in particular, the gc callback.
If you have database access you can store the session info in a session table and retrieve that variable from the last session registered by that specific user.
That I know of, there is no solid way to trigger an event just before session termination that is guaranteed to work. It's in your best interest to restructure how the data is being handled rather than come up with a brittle hack.
You could save the data in a cookie and control the expiration date:
setcookie("TestCookie", $value, time()+3600); /* expire in 1 hour */
http://php.net/manual/en/function.setcookie.php
This way you don't need to change the regular session functionality and allow them to expire properly.
You can sort-of do this with Javascript. Have the server deliver a JS function that will sleep until the session is about to expire.
However, this isn't foolproof: when the user leaves your page, tough cookies, they're not running your JS anymore. Of course, you also can't get in touch to tell them whatever you'd say when the session expires...
You could also have your sessions "expire" before you really remove the data, and have a custom handler that alerts the users and gives them a grace period. The second time the destroy handler triggers, actually remove the data.
Technically it's not possible to tell when session that is stored by PHP (session as in server-side cookie) will be killed. In PHP settings you can say how long a cookie must survive, but it can last longer than that set time.
If you need to keep track of how long it lasts exactly, you should build a session management system manually and not use the PHP one.
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.