PHP Do something when session gets expired - php

So let's say user did something on my website, for example uploaded some images or whatever, and he left without logging out and never came back or let's say he did come back after few months.
So my question would be, is there some kind of way for example to delete his uploaded files after session have expired, let's say after 30 mins (keep in mind that user never reloaded page), so that would need to run entirely on server side without user interfering at all.
EDIT Thank you all for your wonderful answers, it gave me quite a few great ideas, i wish i could accept all of your answers :)

Good question! My first idea was to use a database based solution. If you don't already, you'd keep track of all active sessions in a table sessions which contains, among other things you may need, the session_id and the last_visited_time. This entry would be updated every time a user visits your site:
UPDATE sessions WHERE session_id = "<current session id>" SET last_visited_time = NOW()
The second part of the mechanism would be a cronjob that scans the the sessions table for sessions whose last_visisted_time hasn't been updated lately (in whatever time interval you'd like) and deletes the files for that session.

One way would be to call
$thePath = session_save_path();
and iterate over all saved session file, unserialze each and check them for the specified timeout property.
Unfortunately, you need to scan the whole directory to find all session files, which are older than a defined period of time. You'd use start() to figure out the age of a session file.
On a well-maintained server, each virtual host should have a separate directory for its session data. A not-so-well-maintained might store all sessions in a unified shared directory. Therefore, ensure that you don't read or delete other virtual hosts' session data.
Better Approach using a database
Therefore I propose to save session data to your application's backend database. Using SQL, it would be trivial to find all outdated session files.
The documentation for session_set_save_handler() provides a sample, which explains this whole process quite nicely based on objects.

I like all the answers above, but a different solution would be to name the uploaded files in a way that you know they are "temporary", for example prepending their name with a timestamp. This way, a periodic process would clean any such files, unless your program decides that they should be kept after all, renaming them accordingly.

Related

Storing data into session and storing to database upon "major" action

I know there are hundreds of these questions but what I am asking however is slightly different.
When the user logs in I would like to get all their data from each table in a database and store it in a session variable (obviously not sensative data such as encrypted password/salts etc basically data that would be useless or have no value to a hacker!!), and whilst the user uses the website the relevant data stored in the session will be used as opposed to accessing the database everytime. Moreover when the data is changed or added this will be written or added to the session file, and upon a major action such as "saving" or "loggin out" the new/changed data will be written to the database.
The reason I wish to do this is simply for efficieny, I want my application to not only be fast but less resource consuming. I am no expert on either which may explain why my idea makes no differnece or is more resource intensive.
If there is an alternative to my solution please let me know or if there is something to improve on my solution I will be glad to hear it.
Thank you.
My application is using PHP and mysql.
If any of these don't apply to your app, then please ignore. In general, I'm against using sessions as caches (especially if anything in the session is going to be written back to the DB). Here's why.
Editing the session requires a request from the user. Editing a php session outside of the request-response cycle is very difficult. So if a user Alice makes a change which affects Bob, you have no way to dirty Bob's cache
You can't assume users will log out. They may just leave so you have to deal with saving info if the session times out. Again, this is difficult outside of the request-response cycle and you can't exactly leave session files lying around forever until the user comes back (php will gc them by default)
If the user requires authentication, you're storing private information in the session. Some users may not be happy about that. More importantly, a hacker could imploy that private information to conduct a social engineering attack against the end-user.
Mallory (a hacker) might not be able to use the information you put in the session, but she can poison it (ie. cache poisoning), thereby causing all sorts of problems when you write your cache to your permanent storage. Sessions are easier to poison then something like redis or memcache.
TL;DR Lots of considerations when using a session cache. My recommendation is redis/memcache.
You can also go for local-storage in HTML5, check The Guide and THE PAST, PRESENT & FUTURE OF LOCAL STORAGE FOR WEB APPLICATIONS
Local Storage in HTML5 actually uses your browsers sqlite database that works as cookies but it stores data permanently to your browser
unless someone by force remove the data from the browser finding the data files
Or if someone remove/uninstall browser completely,
or if someone uses the application in private/incognito mode of the browser,
What you need to do
Copy the schema for required tables and for required columns and update data at a regular interval
you dont have to worry about user's state, you only have to update the complete data from the localStorage to mysql Server (and from the mysql server to localStorage if required) every time user backs to your application and keep updating the data at regular interval
Now this is turning out to be more of localStorage but I think this is one of the best solution available for me.
redis is a good solution if it is available for you (sometimes developers can't install external modules for some reason) what I would do is either go with your Session approach but with encoded/encrypted and serialized data. Or, which I really prefer is to use HTML5 data properties such as:
<someElement id="someId" data-x="HiX" data-y="Hi-Y" />
which BTW works fine with all browsers even with IE6 but with some tweaks, specially if your application uses jquery and ajax. this would really be handful.
You need to use Memcache for this kind of work. To solve the problem of keeping the updated data everywhere you can create functions for fetching the data, for example when the user logs in you, authenticate the user and after that insert all the user data into the memcache with unique keys like :-
USER_ID_USERNAME for user's username
USER_ID_NAME for user's name
etc...
Now create some more functions to fetch all this data whenever you need it. For ex
function getName($user_id){
if(Memcache::get($user_id."_name"){
return Memcache::get($user_id."_name");
} else {
//Call another function which will fetch the data from the DB and store it in the cache
}
}
You will need to create functions to fetch every kind of data related to the user. And as you said you want to update this data on some major event. You can try updating the data using CRON or something like that, because as tazer84 mentioned users may never log out.
I also use what the OP described to avoid calls to db. For example, when a user logs-in, i have a "welcome-tip" on their control panel like
Welcome, <USERS NAME HERE>
If i stored only his user_id on $_SESSION then in every pageview i would have to retrieve his information from the database just to have his name available, like SELECT user_name FROM users WHERE user_id = $_SESSION['user']['user_id'] So to avoid this, i store some of his information in $_SESSION.
Be careful! When there is a change on data, you must modify the data in db and if successfull also modify the $_SESSION.
In my example, when a user edits his name (which i also store in $_SESSION so i can use it to welcome-tip), i do something like:
If (UpdateCurrentUserData($new_data)) // this is the function that modifies the db
{
$_SESSION['user']['user_name']=$new_data['user_name']; // update session also!
}
Attention to:
session.gc_maxlifetime in your php.ini
This value says how much time the $_SESSION is protected from being erased by the garbage collector (the file that exists on your disk in which the $_SESSION data are stored)
If you set this very low, users may start getting logged-out unexpectedly if they are idle more than this amount of time because garbage collector will delete their session file too quickly
if you set this very high, you may end up with lots of unused $_SESSION files of users that have left your website a long time ago.
also i must add that gc_maxlifetime works together with session.gc_probability where in general you need lower probability for high-traffic websites and bigger probability for lower traffic since for each pageview there is a session.gc_probability that garbage collector will be activated.
A nice more detailed explanation here http://www.appnovation.com/blog/session-garbage-collection-php
I know this sounds stupid but ....
If ur data is not sensitive the best way to make it accessible faster is to store it in hidden variables inside the forms itself. You can save comma separated or values in an array.

How can i know if a session is still active or not?

I'm storing the sessions ids in a database table. I
want to run a script that reads from the table every
session id and check if this session is active or not.
I know that session information is stored in a
directory (/tmp by default) and removed from there
when the session is closed. But if the user close his
browser without disconnecting from the session the
session file is still in the /tmp directory.
How can I know if a session is still active or not?
I have searched the session functions and didn't find
anything that could help.
Generally speaking, the only way is to have a "last used" datetime/timestamp which you update every time the session is referenced, and discard/deactivate sessions after they haven't been used for a certain amount of time.
It's not possible to tell if a session will be referenced further as they're not kept open between requests, simply referenced when needed ... and need is dictated by the ever fickle client.
If your sessions are file based, as it sounds, you can use the last accessed date of the individual files, possibly save yourself a bit of trouble.
If you are keeping sessions in the database. Add a last accessed or modified timestamp to the database table. I've put code in my procedures that retrieve or store session information that DELETE FROM sessions WHERE modified is more than an hour ago. However long you want your session to be. At every call you can update that timestamp. It seems that would cause a performance hit, but I've used that pattern/process quite a bit. I almost always use the database to store session information. You should research session_set_save_handler(). I can try to gather some of my own code from previous project where I utilized this, but I'm sure that reading the manual on this and googling implementations will help you quite a bit.
Why would you care about this already outdated sessions? They will be cleared from temporary folder in some random time anyway.
You should check last access time in your database and if it's more then some predefined timeout - mark it as dead.
But think about your performance too. It's a way better approach to store your session data in memcache or something similar to it - just store it in memory, not in DB. Read more about it here: http://memcached.org/
It's really easy to store your session data in memcached: http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/
There isn't such a function.
PHP itself use somewhat an hack to determine when a session is expired, there are several
options into the php.ini configuration file.
In short, every time a session started there is a gc_probability/gc_divisor chanche that php will start a
garbage collection of pending data.
The session accessed before gc_maxlifetime seconds are considered expired and PHP deletes them.
You can relay on this behaviour tuning the envolved options or mimic this behaviour with a
similar approach.
For reference:
http://it.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime
http://it.php.net/manual/en/session.configuration.php#ini.session.gc-probability
http://it.php.net/manual/en/session.configuration.php#ini.session.gc-divisor

Best practice for storing global data in PHP?

I'm running a web application that allows a user to log in. The user can add/remove content to his/her 'library' which is displayed on a page called "library.php". Instead of querying the database for the contents of the users library everytime they load "library.php", I want to store it globally for PHP when the user logs in, so that the query is only run once. Is there a best practice for doing this? fx. storing their library in an array in a session?
Thanks for your time
If you store each user's library in a $_SESSION as an array, as you suggested (which is definitely possible) you will have to make sure that any updates the user makes to the library are instantly reflected to that session variable.
Honestly, unless there is some seriously heavy querying going on to fetch a library, or you have tons of traffic, I would just stick to 'execute query whenever the user hits library.php'.
Consider the size of the data. Multiply that by the maximum number of concurrent users.
Then compare that the to memory avaiable on your server. Also consider whether or not this is a shared server; other sites needs resources too.
Based on this, it is probably best to either create a file that can be used (as per Remi's comment), or remain in the default stateless form and read every time. I doubt that reading the data each time is creating much of an overhead.
When the user login you can generate a xml file (USER_ID.xml for instance) that you display with xslt.
http://php.net/manual/en/book.xslt.php
Each PHP script dies when it completes, so data can not be kept permanentely live in a web application as you would do in a PC application.
One way could be sessions, but it depends on the amount of data you want to save. According to your example you are talking about a library, so it sounds to me like big quantity of data need to be saved, in such case the DB is the way to go, and yes you have to query it each time.
Another way could be to save them in an array inside a php file, but in the same way you have to query the DB each time, you would have to include such php file each time.
Since this is a db performance optimization, I would suggest that you take a look at memcached which matches your problem perfectly:
memcached is [..] intended for use in speeding
up dynamic web applications by
alleviating database load.
I think it would be best to store it in a Session.
It the user logs in, the Session is being created and you can save data in it using the superglobal:
$_SESSION['key'] = "value";
You can also store Arrays or everything else there and it can be cleared if the user logs out.
you care for performance; Please note:
Session may use database or file to store data.
database is here to be used instead of files, for it's performance and abilities.
use database, it is designed to be used exactly in such situations!

Should PHP session be created before login or after successful login

If PHP session is created before login, there will be one session file created for each request to login page.
The problem is if user makes multiple requests to server through a script then those many session files will be created.
If user wants to attack server,he can send abnormally huge number of requests creating so many session files eating up all the temporary space and making the service unavailable.
I am not sure if this kind of attack is really possible/feasible.
Please share your comments on this and implications if PHP sessions is created before/after successful login.
I think you are misunderstanding session_start()
What happens with session_start is, yes, it will create a file for the individual user. But the next time you call session_start(), it is going to use that same file for that same user because the user has a cookie on their system that tells it what ID to use. In order to have the $_SESSION array available, you must call session_start() on every page.
It is very possible that someone could whip up a scenario like you just described.
In reality, yes, a hacker could always have a robot that clears its cookies after every attempt, make 10,000 requests, and possibly create a disk writing problem, but I really wouldn't worry about it too much, because the files are tiny, much smaller than the script you are writing. You'd have to write a lot more files (on the size of millions or billions) to actually create a problem.
If you really want to see what the effects would be on your server. Write a script that creates files in a directory with the equivalent of 2 paragraphs of text. and put it in a loop for 10,000 files.
If you are then worried about the affects it would have, I suggest implementing a tracker that can see an large amount of hits coming to the site from a single IP address and then either temporarily ban the IP address, or do what Google does and just provide them with a static captcha page that doesn't take many resources to serve.
So, going back to the actual 'question':
I set a session for every single user that ever visits my site, because I use sessions for not only User Authentication, but for tracking other variables on my site. So, I believe that you should set it even if they aren't logged in.
If you're worried about a session fixation attack, think about using session_regenerate_id() function.
once you run the session_start() creates the file.
what you can do as an attack is to create a robot to send separate session id in the cookie, but just have to give that one exists.
It doesn't matter, really. Your server, as cheap as it could be, will have enough space to store millions of (almost empty) session files.
Worst it can do is slow down the files access in the folder where session files are stored, but your server's disks should be monitored to begin with, and a quickly filling /tmp partition should raise an alert at some point.

Safe timeout value for codeigniter session class?

I am using codeigniter's session class to handle my PHP sessions. One of the session variables automatically created on every visit to the site is session_id:
The user's unique Session ID (this is a statistically random string with very strong entropy, hashed with MD5 for portability, and regenerated (by default) every five minutes)
On my site I need to have functionality to track unregistered user's and I currently have this implemented by comparing the visitor's session_id with a stored id value in a VISITOR table in the database. This works perfectly except for the fact that the session id times out every five minutes. I would like my application to remember visitors for longer than 5 minutes (kind of like what SO does when you post a question or answer without registering).
My question is this: can you see any security issues with simply extending the regeneration time of the session class (to something like 12 hours)?
Update: based on the answers I've seen so far, it seems like its more of a performance concern rather than a safety issue. Its kinda weird how the codeigniter session class works because when creating a new session, it also creates a new cookie which seems to persist as long as the session. I guess I could create another cookie with the session ID that lasts as long as I need it to. But how much of a performance concern would it be if I were to save the sessions for something like 12 hours? Would it slow things down unless I have millions of unique visitors within a 12 hour period (in which case I'd have bigger problems to worry about...)?
Two things with that idea :
If users go away from their computer (without locking it / closing their browser), someone else might use it to go to your site with their account
well, that's probably not your problem
if you have some login/password fields, your users probably already have their login+password memorized by the browser anyway (well, for the registedred ones, anyway -- and those probably have more "power" than not registered ones)
If you have lots of users on your site, you will have more session files
as sessions are stored in files
(same if they are stored in DB / memcached -- in which case you must ensure you have configured memcached so there is enough RAM to store more sessions)
So, yes, there is a small security risk ; but I don't think it is really relevant.
Another idea would be to keep a short session lifetime, but to store some informations in cookies, with a lifetime more important than that ?
Enough information, actually, to allow re-creation of a new session, without the user noticing anything ?
But, yes, that would require a bit more work on your side...
To add a bit more precisions after your edit :
Its kinda weird how the codeigniter
session class works because when
creating a new session, it also
creates a new cookie which seems to
persist as long as the session.
This is the "standard" way of dealing with sessions -- at least, in PHP :
The session's data is stored in a file, on disk, on the server
and a cookie is used to keep a "link" between a user, and the file containing his session's information. Without that cookie, there would be no way of knowing which one of those files contains the session of a specific user.
But how much of a performance concern
would it be if I were to save the
sessions for something like 12 hours?
If you're having millions of users on your site, this will means having millions of files, each one containing the session's data of one user -- and it's not good to have too many files.
But is you are having a few hundreds user, that should be allright, I guess.
Depending on the amount of visitors to your site, saving sessions for 12 hours may not be a good idea. Why not use cookies? This is dependent on whether or not the user has it enabled in his browser though: http://www.php.net/setcookie.
One Security Tip:
Leave True on sess_match_useragent(application/config/config.php)

Categories