简体   繁体   中英

Keeping track of logged in users in PHP

I'm trying to write a simple web chat app with PHP and AJAX.

I need to be aware of all the open sessions so that I can display a list of online users that are available to talk to. I also need to be aware of log outs because I use "both the sending and the receiving party are offline" as a condition for considering a chat session terminated and deleting the messages.

I'm keeping track of logged in users in a database: adding an entry on log-in and removing it on log-out works fine, but it's not comprehensive, as there are two other ways a user can become logged out:

  • server side session expires after inactivity.
  • client side cookie gets destroyed on browser close. Seems like a bad idea to use some sort of onclose triggered AJAX (what if the browser crashes or something?).

Simplest solution seems to be keeping a timestamp of last activity. I see some problems with this though:

  • AFAIK server-side expiry is chance based, so it wouldn't be accurate (and if I get the expiry time 3 minutes wrong, that's 3 minutes where some guy could be talking to an offline user wondering why no one is answering)
  • I'd have to constantly be querying the database to check every logged in users' last activity time compared to the current time. I don't see when / where I'd do this efficiently. It seems stupid to do this every single time the list of online users is needed.

Any help appreciated. I'm coding this myself because I'm not aware of any web chat frameworks that can integrate with my existing user database, do correct me if I'm wrong.

I don't think you're going to be able to do much to mitigate the constant querying to determine if users have logged off by closing the browser, internet connection issues, etc., but you could perhaps have each client make an AJAX request to the server every 5 seconds to update the last activity time, and have your application on the server consider the user "logged off" if they have missed 3-4 consecutive requests (ie, their last activity time is > 20 seconds).

On the client side, you could then check the last activity time every time your client sends a message to another user, and respond that they'd logged off if that had happened. If they attemped to open a chat with another user, you could also do an immediate call to check their status. Then you could perhaps check the status of all users in the user list every 30 seconds. That way your client gets pretty quick feedback if the person (s)he is chatting with drops offline unexpectedly.

You could invert your pattern, replacing your Ajax pull behavior with a push notification system.

In this way you can notify your chat users in realtime of login and logout of new chat members. I never did something like this in practice, but I've read about this kind of technology and it seems very interesting for cases like yours.

It's just a little bit harder than the ajax pull way, but once the main structure is implemented you can add functionality easily and the performance would be a lot better.

Some links I found that can be useful:

This is a railscast episode which deal with a javascript chat, the implementation is in rails, but even if you don't understand rails you should be able to follow it to get the core concepts: http://railscasts.com/episodes/260-messaging-with-faye

I'm not sure if you need both probability and divisor but here's what I do to auto logout people:

ini_set('session.gc_maxlifetime',3600); // 1 hour
ini_set('session.gc_probability',1); // it does garbage cleaning EVERY time
ini_set('session.gc_divisor',1); // it does garbage cleaning EVERY time
session_start();

Most of the data you are currently using and the data you need is stored in the PHP session - it's just not obvious how to derive the user id from the information.

If you switch to using a database bound session handler then it all becomes very easy. I had a quick google - and there are lots of examples out there. but a lot of them (eg this one ) don't check for expiry on reading back the session. OTOH the example I've linked to does show adding the user id to the sesion record - which you'll need later. So the session read handler function should be something like:

 read:
 SELECT session_data, username
 FROM sessions
 WHERE session_id=' . session_id() . '
 AND last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime'))

And to get all the currently logged on users:

 SELECT username
 FROM sessions
 WHERE last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime'))

...and let the (overridden) session garbage collector automatically clear out redundant data.

HTH

First separate your concerns. As far as 'list of online users' is concerned,you can use database & it seems you already have figured that out. (even if some one doesn't logs out properly,displaying a few extra online users won't do much damage)

Now for the chat app,for checking if a user is still online you will have to use ajax. There is simply no other way.Of course there always can be a hack,I don't know. see the image 图片 when you answer here (stackoverflow).it constantly checks if time has passed(& have you typed anything new) & saves a copy.

It seems that you are most concerned about performance and you have the implementation details figured out(mostly). Just change the type of the table that handles sessions to 'memory', this will reduce the performance cost of quering the db for every request to almost nothing as you are fetching data directly from RAM. Just make sure you delete the session every time a user explicity logs out, or you mark the user as inactive.

But no matter what you do implementing something that requires constant communication between client and server can never be done perfectly over HTTP. But if you put reasonable timeouts etc. it will work 99% of the time.

I am late to this party, but let me give my two cents.

In this particular scenario, there is no need for a push system for bad notifications. There is also no need for cron. Let me explain :

Say A,B and C are in a chat room & B's browser crashes, so his session expires. Right now , the server thinks B is still there but she is not. How do you update A & C? When A & C ASK for the update. Check B's last keepalive timestamp and figure out that their session has expired.

If all A,B & C crash, then this never happens I hear you ask. Who cares? There is no one to see our mistake now! The only downside is keeping up their chatroom alive which costs some database space. This can be cleaned up when another chat session is created.

A final gist :

  1. Keep timestamps for the last time an action was taken.
  2. Use a user event to loop through timestamps and take out the deadwood.

In case of users, this would be logging them out. In case of chatrooms, this would be those that have expired.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM