views:

611

answers:

8

I have a community site where a user can have many friends. When displaying all of his friends, I want to include whether his friend is online or offline.

My method is, when user logs in, create a session and update the users table, on status column "online". If he click the logout button, then i will set the status to "offline". What if he close his browser without clicking the logout button? Here is what I want to do:

session_start();
if (!isset($_SESSION['LAST_ACTIVITY'])) {
    // initiate value
    $_SESSION['LAST_ACTIVITY'] = time();
}
if (time() - $_SESSION['LAST_ACTIVITY'] > 3600) {
    // last activity is more than 10 minutes ago
    session_destroy();
    //direct to a php, say this user is idle and thus status = offline
    header("location: update_status.php?user=".$_SESSION['username']."&status=offline");
    // den redirect them to login page
} else {
    // update last activity timestamp
    $_SESSION['LAST_ACTIVITY'] = time();
}

Is this an appropriate way?


EDIT:

It would be helpful to see some easy sample code with how to check whenever a user is online and update whenever a user visits a page?

Do I need to include php?user=$_SESSION['userid'] in every link?

+3  A: 

In my Opinion this will not work. When the User closes the Browser, the code you put here will never be called.

A possible way would be to save the last time the user was active in the database, whenever the User calls a page. If the Users last Activity was longer than say 5 minutes ago, you could count him as offline, and show this to other Users.

I think that phpbb3 does it that way...

Getting an Event when the User closes the Browser is heavy and does not always work.

Paul Weber
That's kind of what i would do. But what if the user never comes back? Then he never loads another page to set himself as offline.You should put that script somewhere and have it called every 10 minutes or so, maybe by a cronjob
Galen
you do not need a cronjob. just check for his activity, when somebody else want to know if he is only or not.
Hippo
A: 

I see a couple of problems in your code:

if (time() - $_SESSION['LAST_ACTIVITY'] > 3600) {
  // last activity is more than 10 minutes ago
  session_destroy();
  //direct to a php, say this user is idle and thus status = offline
  header("location: update_status.php?user=".$_SESSION['username']."&status=offline");
}

In this piece of code you destroy the session and then get the username from the session you just destroyed.

By the way, if I understand your question, you don't get the intended behaviour with this code.

You check if the user is just accessing your site (owner of the session you start) has been idle form more than 10 minutes and, if true, you disconnect him just now that it tries to reenter in the site.

Eineki
A: 

As far as I understand your solution is the user still marked as online even when the last time the user was on the site is more then 10 minutes ago.

You should save in your database, the last time an user was active on your site. When a user looks then on the list of friends you get also this time and look if that is more then 10 minutes ago, i.e. the friend is inactive.

seb
A: 

The best way to do this is to store activity times for logged in users. When they navigate to a page, or perform an action, update their "last activity" time in the database with the current time. If this time falls outside of a threshold (say, 15 minutes), then you can class the user as no longer active.

James Burgess
+2  A: 

After the header location redirect, definitely put this line:

die();

Not all user agents (browsers, web spiders, etc) will listen to your redirect header. Killing the script is the only safe way to make sure they don't get the rest of the page.

nickf
+1 : for a good time, disable your browser redirect occasionally and note that it completely circumvents many poor-quality authentication systems that use redirect for security.
Kent Fredric
+4  A: 

Well if you determine whether or not a user is logged out, simply by your online/offline column - then users closing their browser window (without hitting your logout link/button) will still be logged in.

The normal approach here is to keep track of when your users move around your site, storing the last time of when they navigated to a page. Then you set a predefined constant of what makes a user active (say navigating around your page within the last 15 minutes) - and then you use this on your SQL Query to grab every user that is a friend of the visiting person and has been on the site within the last 15 minutes.

In a SQL Query where you store your time as datetime (this is a query for MySQL) this could look something like:

SELECT col1, col2, col3 FROM Users WHERE DATE_ADD(LastActive, INTERVAL 15 MINUTE) > NOW() AND UserIsFriendOfCurrentUser

Of course your query would need adapted to fit your setup better, but hopefully you get the idea.

kastermester
A: 

In our project we use this technique:

  1. every user after login is being associated with session id.
  2. browser sends an "activity-request" with AJAX by timer.
  3. a lightweight server-side script updates last activity in DB, searching user by session id.
  4. cronjob updates all timed-out users, marking them as offline (actually session id gets empty), and executes logout routines for every user to avoid corrupted data on business-level layer.

What happens to user? Until user closes his browser - activity is being updated. After closing the browser user gets timed out and marked as offline. When user tries to reach any location which requires authorization - the first thing we try to do is to find him in DB by session id, and if not - he just can see nothing but login form (i.e. include(); exit();).

Bad thing - tabbed browsers use the same session id for each opened tab in the same window. But our project is a game and multi-users from one browser are not allowed. Actually it's a very rare situation wher 2 or more users try to login from different tabs of one browser...

Jet
A: 

You shouldn't use $_SESSION for storing the last activity time. Every time a user goes to a page, update a column called last_activity with the current time in the users table:

<?php
session_start();

$userId = (int)$_SESSION['user']; // make sure it's an integer
$db->exec('
    UPDATE users 
    SET last_activity = NOW() 
    WHERE id = ' . $_SESSION['id']
);
//...

When you retrieve your list of friends, add an if statement to check if they are online (this is the MySQL version):

SELECT 
    u.user_name, u.name, etc,
    IF(
        UNIX_TIMESTAMP() - UNIX_TIMESTAMP(u.last_activity) < 300, 
        1, 0
    ) as online
    ...

The 300 is seconds so 5 minutes. Adjust this as you see fit. Then your friends can be accessed like so:

$friends = $db->query(/* above SQL */);
foreach($friends as $friend)
{
    if($friend['online'] == 1)
        // online specific stuff
    else
        // offline specific stuff
}
rojoca