2

我有一个用户可以有很多朋友的社区网站。在显示他所有的朋友时,我想包括他的朋友是在线还是离线。

我的方法是,当用户登录时,在状态列“在线”上创建一个会话并更新用户表。如果他单击注销按钮,那么我会将状态设置为“离线”。如果他没有点击注销按钮就关闭了浏览器怎么办?这是我想做的事情:

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();
}

这是合适的方式吗?


编辑:

看看一些简单的示例代码会很有帮助,如何检查用户何时在线并在用户访问页面时更新?

我需要包含php?user=$_SESSION['userid']在每个链接中吗?

4

9 回答 9

5

好吧,如果您确定用户是否已注销,只需通过您的在线/离线列 - 那么关闭浏览器窗口(不点击您的注销链接/按钮)的用户仍将登录。

这里的常规方法是跟踪用户何时在您的网站上移动,存储他们最后一次导航到页面的时间。然后你设置一个预定义的常量来让用户活跃(比如在过去 15 分钟内浏览你的页面) - 然后你在你的 SQL 查询中使用它来获取每个访问者的朋友并且一直在的用户网站在过去 15 分钟内。

在您将时间存储为日期时间的 SQL 查询中(这是对 MySQL 的查询),这可能类似于:

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

当然,您的查询需要调整以更好地适应您的设置,但希望您能理解。

于 2009-05-20T15:21:02.160 回答
4

在我看来,这行不通。当用户关闭浏览器时,您在此处放置的代码将永远不会被调用。

一种可能的方法是在用户调用页面时保存用户上次在数据库中处于活动状态的时间。如果用户的最后一个活动比 5 分钟前的时间长,您可以将他视为离线,并将其显示给其他用户。

我认为phpbb3就是这样做的......

当用户关闭浏览器时获取事件很繁重并且并不总是有效。

于 2009-05-20T15:19:36.623 回答
2

在标头位置重定向之后,一定要把这一行:

die();

并非所有用户代理(浏览器、网络蜘蛛等)都会监听您的重定向标头。杀死脚本是确保他们不会获得页面其余部分的唯一安全方法。

于 2009-05-20T15:20:43.237 回答
0

数据库会话可能是您管理谁在线和谁不在线的好方法。从理论上讲,它们应该自行到期。我在我的博客上写了一篇关于它的操作方法,您可以在http://brennydoogles.wordpress.com/2011/09/06/taking-control-of-your-php-sessions-using-database-sessions阅读更多内容/

这还有一个额外的好处,就是允许您在需要时远程终止用户会话:)

于 2011-12-29T18:43:59.573 回答
0

最好的方法是存储登录用户的活动时间。当他们导航到页面或执行操作时,将数据库中的“上次活动”时间更新为当前时间。如果此时间超出阈值(例如 15 分钟),则您可以将用户归类为不再活动。

于 2009-05-20T15:20:20.257 回答
0

您不应该$_SESSION用于存储上次活动时间。每次用户访问一个页面时,更新一个名为last_activityusers 表中当前时间的列:

<?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']
);
//...

当你检索你的朋友列表时,添加一个 if 语句来检查他们是否在线(这是 MySQL 版本):

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

300是秒所以5分钟。根据需要进行调整。然后可以像这样访问您的朋友:

$friends = $db->query(/* above SQL */);
foreach($friends as $friend)
{
    if($friend['online'] == 1)
        // online specific stuff
    else
        // offline specific stuff
}
于 2009-05-20T21:53:42.727 回答
0

我在您的代码中看到了几个问题:

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");
}

在这段代码中,您销毁会话,然后从刚刚销毁的会话中获取用户名。

顺便说一句,如果我理解您的问题,那么您不会通过此代码获得预期的行为。

您检查用户是否刚刚访问您的站点(您启动的会话的所有者)是否已空闲超过 10 分钟,如果是,则您刚刚断开他的连接,因为它试图重新进入该站点。

于 2009-05-20T15:20:06.933 回答
0

据我了解,您的解决方案是即使用户最后一次访问网站是在 10 分钟前,该用户仍被标记为在线。

您应该将用户上次在您的站点上处于活动状态的时间保存在数据库中。当用户查看您的好友列表时,这一次您也可以查看是否是 10 分钟前,即该好友处于非活动状态。

于 2009-05-20T15:20:07.950 回答
0

在我们的项目中,我们使用这种技术:

  1. 登录后的每个用户都与会话 ID 相关联。
  2. 浏览器通过计时器发送带有 AJAX 的“活动请求”。
  3. 一个轻量级的服务器端脚本更新数据库中的最后一个活动,通过会话 ID 搜索用户。
  4. cronjob 更新所有超时用户,将它们标记为离线(实际上会话 id 为空),并为每个用户执行注销例程,以避免损坏业务层上的数据。

用户会发生什么?直到用户关闭他的浏览器 - 活动正在更新。关闭浏览器后,用户会超时并标记为离线。当用户试图到达任何需要授权的位置时——我们要做的第一件事是通过会话 ID 在 DB 中找到他,如果没有——他只能看到登录表单(即 include(); exit(); )。

坏事 - 选项卡式浏览器在同一窗口中为每个打开的选项卡使用相同的会话 ID。但是我们的项目是一个游戏,一个浏览器的多用户是不允许的。实际上,当 2 个或更多用户尝试从一个浏览器的不同选项卡登录时,这种情况非常罕见......

于 2009-05-20T16:11:31.997 回答