I'm developing a site in PHP. When the user session starts I load all his db row in the $_SESSION var. When the user changes a db value I update the $_SESSION var too.
The problem starts when more than one session is active for the same user. Is there a way to update the data for all the sessions of the same user without overloading the database? Or, alternatively, is there a way to force php to use the same session file for all the session that belongs to the same user? Or I must simply query the db every time a session continues?
And another dilemma is: is it worth it? I mean, I do not know how much this mechanism could alleviate the server load, and I do not know if this mechanism is applicable to file-based sessions or I must use another session storing type.
This question is somewhat related to this other question on mine (even if the workaround for this is simply to delete all session files).
It really reaches the question why would you need to many data in a $_SESSION. And you should really take a time to decide which data is so often needed to be displayed.
In most of the cases you only need session identifier that keeps the user logged in, containing user_id, to take the needed data directly from the database.
Assuming the user can change its avatar, and you haven't go so many places to display this avatar, you don't need to store it in session, nor to SELECT it at the very same time. For instance, you can have a trigger page, which SELECTS the avatar by $_SESSION['user_id'] when he tries to send personal message to another user. Otherwise, you can put a cache (i.e. using memcached) where a query, which selects the user avatars should not be made more often than once an hour.
If user changes an email, it's the same. If somebody else tries to send him message, you trigger the SELECT query. Otherwise a cache is set.
So, let's say the user has changed his avatar, email, some other trivial info, then accessed your index page. In his session you load only the identifier. In the db the records are present, but they are not selected yet. So you have neither server load, because the session is light, nor database load, because no SELECT queries were sent.
No matter how many times the user tries to set his session (in this case logs second time), you have a present data in the db, and a session only with identifier. You can identify all his instances, but never use a data, which is not needed.
1 Well, I (don't, but) could do this with my session handler. I use databased SESSIONS with some extra information/columns like username and userid. That way I can exactly determine which session belongs to which user without fiddeling around with the serialized data.
http://php.net/manual/de/function.session-set-save-handler.php
2 But in your case it might be simpler to update your user table and then SELECT the user again to put the (new) data to $_SESSION['user']. (You will need some "user data was updated" info, to reload new data for all sessions).
3 Or you just avoid that a user can login more than once.
Related
Currently when the user logs in my site, a (PHP) session is started and his database row is saved in his $_session. I do so because the size of user's data is small for now, and this way I do not have to ask the database for user's data every time I need it.
The problem is that, when I want to add or change something during the development and I touch the database, the session is not updated this way. The user have to logout and login again to update the session. This is good for now since the site is in development phase, but in production this is not desirable.
I wouldn't delete session files, because people are lazy and I would avoid to force them to re-login every time something change in database, and I do not want to reload the session every X minutes. My solution for now is a boolean column inside the user's table, false by default, that I set true when I change the database. Every time a session is continued, session data will be updated if that value becomes true. Anyway this way I have to do a (small) query every time an user continues a session. I do not know if this will be a problem in production.
Is there an alternative / better way to solve my problem?
If I understand the problem correctly, one way to handle this would be every time a user row in the DB is updated that user's session data could be updated as well in PHP.
If it is not the user updating the records (such as an administrator changing a user's permissions) most likely you would want to force a logout of the user. If it is the user updating the records (such as changing information in their user profile) simply updating those values in the session variables may be enough.
In both of these cases you probably also want to provide a message to the user letting them know what happened.
I have a login page. User can login to their account and can get their details. But I am confused, should I store the users details in the session variables or should I pass only the ID as session variables, and in next page all the details retrieved by class using the ID.
If I pass only the ID as session variable, then I have to call the class in every page. Please give me the right idea, I don't want to call the class repeatedly, the page should load faster.
Thanks in advance.
It won't matter performance-wise for a long, long time. You can pick any of the methods.
In my experience, storing the ID in the session, and retrieving the user data when needed in the user class is the more common way to go.
Storing an object containing the user data in serialized form in the session is also possible, but
it can cost a lot of memory (because the session data is loaded into the PHP script on every request)
You can't rely on the data being fresh (what if the user changed their preferences, or something else happened?)
I think you should only store the session ID in session variables. You will get no performance benefit if you store some information about the user in session becouse you will never no what kind of additional information will you need later and serialization-deserialization takes some time also (specially when you store sessions in database!).
For exampla i'm always load user data from db in every single request becouse i have to check the user for several reason: is he/she locked, is he/she disabled, what is his/her preferred language, when was he/she here last time and so on.
I have application that has to check multiple data from user table, in order to create page.
Not just id and password, but other data as well, about 7 parts of information at this moment.
This check-up is done on every page.
Do I load all this data in session, and check it from there, or do I fire query on every page request? Needless to say, there are also other queries going on.
What's better practice, regarding optimization?
You should call the data once from the database and store it in a Session Variable. I generally put my user_id, username, email, user firstname & access_levels in a session when the user first logs in, Then I can call them anywhere in my application whilst the user is logged in.
Do not store the password in the session as it would not be required.
You an also create a variable called logged_in and set it to true or false to test against, (i.e: Show the "Account menu if the user is logged in, else show "Register" Menu).
[Update]
Here is a link to the Pro's/Con's of MySQL caching.
Scroll down to the bottom before the comments.
It kinda depends on your site, for a small site query caching would be fine, but if you wanted to develop more scalable applications, You have to keep speed in mind.
How to tell is mysql query cache is enabled: [LINK]
MySQL will cache the query if it's exactly the same as last time, so getting the user information via MySQL is fine. And especially so if you are getting everything via the primary key which is very fast.
Trips to database are slower than accessing sessions. You should definitely use sessions. Just don't forget that if this data changed in a database, it should also be changed in the current session.
If the data doesn't change too much you could cache it to a file ... or cache it to memory using something like memcache.
Then you can include it via this file and set some theshholds on when to fetch from db or just include.
Your question uses "check" - do you mean that you have to validate data on every page request? If so, you probably can't avoid going to the database.
If all you need to do is store data that doesn't change between pages for the same user, you should use sessions. Be sure to read the white paper "PHP is Not Java" on the zend.com website first!
I've implemented a mysql-based session interface in php.
I just found out that if I log in to my account using browser A (e.g. Chrome), and then I log in to the same account in another browser B (e.g. IE), each browser is assigned 2 separate session ids. How can I make it such that when I log in again using browser B, I retain the active session of the previous browser A?
The issue at hand is that I'm storing certain information in the session and the data not being synchronised between the same users in different browsers and is wrecking havoc. :S
Is there a way to achieve this?
Thanks!
If you're storing the session in the database, add a mechanism whereby the userId is stored as part of your database's session record, creating what I like to call a "semantic session". When the user logs in, check to see if another session already exists; if so, use session_id() to fixate the new session to the old session's ID, which will join them (and should change your new session's ID for all subsequent requests). Be sure to only perform this action during the login step, or you might end up with freaky race conditions of two sessions trying to be each other and "swapping".
Don't store the data in session, store it in the database.
Sessions are normally identified by cookies, which are only visible in one browser. You could probably use Flash to share the session ID between browsers, but I cannot think of a use case. The point of the session is to store data which is bound to a single browsing session, and not to the user in general. You should use a database or some other form of server-side storage for generic user data.
I'm working a site where users could technically stay logged in forever, as long as they never close their browser (and therefore never get a new session key). Here's what I could see happening: a user leaves a browser open on computer A. The then use computer B, login and change their name which is stored in the session. They logout of B, but A is still logged in and still has their old name stored in the session. Therefore, their name won't be updated till the next time they logout manually or they close their browser and open it again and are logged in through the remember me function.
Name is a simple example, but in my case the subscription level of their account is stored in the session and can be changed.
How do you deal with this?
A few ideas that I have are:
After a period of 10 minutes or more, the session data get's reloaded. It might be exactly 10 minutes if the user is highly active as the function will get triggered right at the 10 minute point or it could be after 2 hours if the user leaves and comes back and then triggers the functionality.
Store as little information as possible in the session and load the rest from the DB on every page call. (I really don't like this idea.)
Use database sessions and use the same session on all the computers. I like this, but I could see it getting confusing when something like search criteria are stored in the session--the same criteria would show up on both browsers/comptuers.
For information, even such as the user's name or username/email address, store it in the session, but for other information that would heavily affect their abilities on the site, don't store it in the session and load when needed (attempt to only do it once per instance).
Are there other better methods?
--
Another option: 5. Use database session and when an update is made load the user's other sessions (just unserialize), change the relevant information and save them back to the database.
I would go either with number 1 or number 4. If you store the time of the last update of the information, you could even ask on every request whether the date has been updated.
Don't store information likely to change in the session, if you're looking at scenarios like the one you outline. Just get over your dislike of loading user data with every page - it's by far the best idea.
I'm guessing you don't want to load the data from the database because you're concerned about performance issues somehow. Before you try out any of the other solutions, you might want to test how long it takes to actually load a users data from the database, then check that against your number of users - chances are you won't see any performance problems due to loading user profiles on every page.
Regards
I'd go with option 6: only store userid and session specific stuff (search criteria) in his session and put the rest into APC/xcache (memcached if you're using multiple servers).
this way you'll only have to go to the database the first time (and after the cache expires) and you can still share any data between users sessions.
Normally you should do 2), but you don't like it.
maybe you can use sessions stored in db.
when a user change his name, put into all sessions from that user the information "refresh userdata".
on the next request the userdata is reloaded again into the session and is cached there.
this can be done be reusing your loaduserdata function which called at login.
php session_set_save_handler() - also read comments
php session_decode() - to read the username from the session to store it additionally to the sessiondata. usefull for easily to find the users sessions for updating.
[edit]
don't forget:
when you are updating all the sessions while the page is generated (between session_start and session_write_close) you changes maybe lost.