PDA

View Full Version : Checking a user's online status



Yesideez
04-23-2005, 06:16 PM
Hi,

I'm writing my little forums on my site using PHP and MySQL - wasn't sure where this question should go so placed it in here.

For my forums each user has a profile which they can set up. The whole thing is working but what I'm having problems with is trying to figure out whether the user is online or offline.

At the moment I've got a function being called in every script (via an include) to set a timer in the MySQL database 5 minutes in the future. The table is called "usersonline". If the user doesn't access a page the timer isn't reset. In another frame on the page which is updated every 30 seconds a quick check is made in the database and any user who's timer is zero or lower they're booted off. Problem is, this doesn't seem to be reliable and I've sometimes found myself booted while typing a message.

If I disable the routine then a user who closes their browser without logging off stays registered as loggin in.

Please, can anyone recommend an efficient way using PHP of dealing with this?

Many thanks :)

mwinter
04-23-2005, 10:33 PM
At the moment I've got a function being called in every script (via an include) to set a timer in the MySQL database 5 minutes in the future. The table is called "usersonline". If the user doesn't access a page the timer isn't reset.It's probably better to reverse that: create a time stamp that marks when the user accesses a document. You can then check the age of the time stamp. The MySQL TIMESTAMP type should be very convenient for this as the first TIMESTAMP attribute[1] in a tuple can be automatically updated whenever an INSERT or UPDATE statement is executed against the entity.


In another frame on the page which is updated every 30 secondsThat seems a very bad model for at least three reasons.


Frames should be avoided on the Web. There are rare occasions when frames are the best solution to a problem, but most of the time their drawbacks do not balance against the advantages.
Self-updating pages have a usability penalty, and are not reliable. Both client-side scripting and meta "refresh" elements can be disabled if the user so chooses.
Having every client request a resource every thirty seconds is not scalable to a large number of users. Even with few users, you're placing undue pressure on the server, which your host could have issues with.



a quick check is made in the database and any user who's timer is zero or lower they're booted off. [...]I hope you don't mean they are forcably ejected. They should just be asked to log in the next time they attempt to access a members-only resource.


Please, can anyone recommend an efficient way using PHP of dealing with this?I'm not sure if what I have in mind is the best way, but it's better. It would be nice to cleanly integrate it into PHP's native session handling features, but the specifics of the mechanism has me slightly confused, and I've read of problems with customisation (should that be necessary). Anyway...

As I said previously, create a log in entry that contains the current time. With later accesses, you can update that time stamp. Whenever you need to check who is online (examples in this forum include the member list in the lobby, and the circle next to the user's name in each post), you can run a query to find all users that have a time stamp newer than x minutes and do whatever with this list. You can then invert the list to find expired sessions and delete them. To see if a user needs to log back in, it a simple matter of checking if the log in entry still exists or if it was erased.

You could search for old time stamps in a separate query, but if you do that you should store the time of the first query you don't risk having users in both result sets.

Mike


[1] You can update other TIMESTAMP attributes as well with little effort, but the first attribute can be automatic.

Yesideez
04-25-2005, 01:02 PM
Thank-you for the extensive reply, some of that went a little over my head but I'm going to have a good try at that soon when I know I have enough time free just in case I need to have a good hair pulling session.

Just out of curiosity why are frames so frowned on with sites? I think if used wisely they can give a site a nice look and feel.

mwinter
04-25-2005, 07:52 PM
Just out of curiosity why are frames so frowned on with sites?
They aren't universally supported, and can be disabled. Whilst that isn't necessarily a problem in itself, most authors don't provide useful, alternative content.
Documents within a frameset cannot be bookmarked unless the user is aware of the difference between bookmarking a frame and a frameset. Most probably aren't. Even then, the user won't return to a frameset, just the individual document.
Search engines cannot typically index a framed site.
There are proven accessibility and usability problems associated with frames.
The alt.html FAQ (http://www.html-faq.com/) contains information on why frames are so evil (http://www.html-faq.com/htmlframes/?framesareevil). The document also contains links to other resources.

Mike

Yesideez
04-26-2005, 05:23 AM
Thanks for the information, it proved to be an interesting read.

My project is an online game - it's almost finished. So far I've used HTML, PHP, MySQL, CSS, Javascipt and... frames.

It's all working fine but later on I'll post a question related to this which is about MySQL - where should I post it or is ok posting it here?

Yesideez
04-30-2005, 02:15 PM
Here's my code:


mysql_query("UPDATE usersonline SET `accesstime`=NOW() WHERE `uid`='$uid'");
mysql_query("DELETE FROM usersonline WHERE `accesstime`<SUBDATE(CURTIME(),INTERVAL 2 MINUTE)");
This doesn't seem to work - can anyone see what's wrong?

JPH
06-03-2005, 05:33 AM
I had similar problem on my site also and here's a solution a came up with:


Following script is included on every page necessary.



//current unix-time
$time_start = time();

//update field 'isonline' in table 'users'
// For database commands I'm using Abstract Pear classes
$update_onstats =
$db_object->query("UPDATE users SET isonline = $time_start WHERE username = '".$_SESSION['username']."'");

After that is quite simple to compare current time with that stored in the database whenever it's necessary. For example I use it like this:



$log = $db_object->query("SELECT id, username, isonline FROM users ORDER BY ID DESC");



if (DB::isError($log)) {
die($log->getMessage());
}


// current unix-time in which
// we will compare the one stored in the database
$currentT = time();

.
.
.
.
//this loop outputs all users and in the same time substracts
// time stored in database from current time on every row
while ($row = $log->fetchRow(DB_FETCHMODE_OBJECT) ) {


echo '<tr>';

$receiver = $row->username;
$re_id = $row->id;
$subs = $currentT - $row->isonline;
//substract time stored in database from current time
$subs = $currentT - $row->isonline;

// if the result is smaller than 1970 seconds
// td class 'act' in CSS file is chosen which highlights the users
// currently online.
// The ones which are offline are shown differently and are less
// 'visible'
// Loop also creates a link which leads straight to html-form used for
//messaging in which the user who's name was on the link is the receiver.
if ( $subs < 1790){
$tdclass= 'act';
}else { $tdclass = 'defa'; }
print ("<td class=\"" . $tdclass . "\" align=\"left\"> <a href='shal.php?choise=write&check_write=true&receiver=$receiver&re_id=$re_id'>[" . $row->username . "</a> </td>" );

}



The way I use this requires a CSS-file also but I believe it's quite simple to use similar method to output only those users who are currently online.

I use this script on my page in private-messages so that people can see who's online, but can also send messages to those who are not.

The key is to update time in the database on every pageload.

At logout before session_destroy() and unsetting variables I use this:



$update_onstats = $db_object->query("UPDATE users SET isonline = 0 WHERE username = '".$_SESSION['username']."'");


In result the name of the user which logged out isn't highlighted anymore.

Hope this helps :)