非活动/浏览器关闭 - 将状态更改为0,并在用户返回时更改为1

时间:2014-04-04 08:50:57

标签: javascript php ajax

我想让我的网站设置在线用户'当状态为非活动状态或关闭浏览器时状态为0。 如果他们重新打开网站或从空闲状态恢复(超时后),我希望状态恢复为1(除非他们因网站长期缺席而完全注销)

这是我到目前为止所尝试的内容:

Inactive.php

include 'db.php';
mysql_query("UPDATE users SET status = 0 WHERE user_id = ".$_SESSION['user_id']."");

检查浏览器是否已关闭

window.onbeforeunload = function() {
        $.ajax({
            url: 'inactive.php',
            type: 'GET',
            async: false,
            timeout: 4000
        });
    };

检查空闲超时

var IDLE_TIMEOUT = 60; //seconds
var _idleSecondsCounter = 0;
document.onclick = function() {
    _idleSecondsCounter = 0;
};
document.onmousemove = function() {
    _idleSecondsCounter = 0;
};
document.onkeypress = function() {
    _idleSecondsCounter = 0;
};
window.setInterval(CheckIdleTime, 1000);

function CheckIdleTime() {
    _idleSecondsCounter++;
    var oPanel = document.getElementById("SecondsUntilExpire");
    if (oPanel)
        oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
    if (_idleSecondsCounter >= IDLE_TIMEOUT) {
        alert("Time expired!");
        document.location.href = "inactive.php";
    }
}

我的查询似乎无效。如何判断每隔x秒检查一个用户?

5 个答案:

答案 0 :(得分:3)

window.onbeforeunload会产生竞争条件并且不会非常可靠。您还希望使用window.addEventListener('beforeunload', function () {...});代替

alert中的CheckIdleTime将停止执行javascript,因此用户必须进行互动(点击OK)才能退出。否则这种方法似乎很好。

现在,当用户离开网页时,通常您会将Cookie设置为在离开网站时过期,但似乎您希望在您的网站中为活跃用户设置运行记录。

为此你可能需要一个两步的方法,主动设置“最后活动”的标志和时间戳。并且还运行垃圾收集脚本,如果您没有看到它们中的任何活动,则将用户设置为“非活动”。

如果您需要活跃用户的真实实时日志,您可能希望查看Node.js特别是Socket.IO,它可以更好地处理实时客户端 - 服务器IO。

运行一个更新用户的查询可能要容易得多,说它们实际上是活动的

 <script>
 setInterval(function () {
      $.post('active.php');
 }, 
 15000 // every 15 seconds
 );
 </script>

在active.php中(假设您添加了新的last_active DATETIME,而user_id是一个int:

 mysql_query("UPDATE users SET status = 1, `last_active` = NOW() WHERE user_id = ". (int)$_SESSION['user_id']."");
 mysql_query("UPDATE users SET status = 0 WHERE `status` = 1 AND `last_active` < DATE_SUB(NOW(), INTERVAL 15 SECOND)"); // set all in active who have  not pinged in the last 15 seconds

以下可能是架构的外观

 CREATE TABLE `users`
    `id` IN NOT NULL,
    `status` INT(1) DEFAULT 0,
    `last_active` DATETIME
 );

您可能希望在“非活动”时间间隔内玩一下,并考虑创建索引。

答案 1 :(得分:2)

修订代码

此代码将参考我在此处提供的示例&gt;&gt; jquery-idle with jquery-ui Dialog

使用的图书馆:

嵌入式库示例:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>

没有jQuery对话框:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>

请记住,您可以使用您喜欢的对话框方法切换对话框代码。我将jquery-ui包含在对话框中,以使事情尽可能简单。这也无法处理beforeunload事件,因为您的代码中已包含该事件,但我建议您在此处进一步阅读&gt;&gt; beforeunload stackoverflow article&lt;&lt;

说明

HTML


这行代码用于存放倒数计时器的占位符。为简化起见,我也在计时器到期时使用它来显示&#34; Session Expired&#34;

<div id="sessionSecondsRemaining" style="font-size: 22px; font-weight: bolder;"></div>

这是一个使用jQuery UI的非常简单的Modal对话框。您可以随意扩展或替换它。

<div id="dialog-confirm" title="Logout" style="display: none;">
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;">Your session has expired.</span></p>
</div>

没有jQuery对话

<div id="sessionSecondsRemaining" style="display:none;"></div>

CSS


由于灰色背景中的错误无法正确显示jQuery UI模式对话框(为什么还没有修复 - facepalm ),这只是一个小小的黑客攻击。

/* override jquery ui overlay style */
.ui-widget-overlay {
   background-image: none !important; /* FF fix */
   background: #000 url(images/new-ui-overlay.png) 50% 50% repeat-x;
}

没有jQuery对话

  • 不需要CSS

的Javascript


您可以在此部分配置jquery-idletimer的参数。

        var
            session = {
                //Logout Settings
                inactiveTimeout: 10000,     //(ms) The time until we display a warning message
                warningTimeout: 10000,      //(ms) The time until we log them out
                minWarning: 5000,           //(ms) If they come back to page (on mobile), The minumum amount, before we just log them out
                warningStart: null,         //Date time the warning was started
                warningTimer: null,         //Timer running every second to countdown to logout
                logout: function () {       //Logout function once warningTimeout has expired
                    //window.location = settings.autologout.logouturl;
                },

                //Keepalive Settings
                keepaliveTimer: null,
                keepaliveUrl: "",   // set the Keep Alive URL here (aka keepalive.php)
                keepaliveInterval: 5000,     //(ms) the interval to call said url
                keepAlive: function () {
                    $.ajax({ url: session.keepaliveUrl });
                }
            }
        ;

添加&#39; keepalive.php&#39;支持,只需设置keepalive.php所在位置的完整URL(以及您希望传递的任何参数,因为您正在使用会话,您不需要任何参数)。

                keepaliveUrl: "http://example.com/keepalive.php",   // set the Keep Alive URL here (aka keepalive.php)

此行初始化并设置#sessionSecondsRemaining div中的值。

                $('#sessionSecondsRemaining').html(Math.round((session.warningTimeout - diff) / 1000));

此部分是您将控制对话框的代码警告会话到期倒计时的用户的位置(通常#sessionSecondsRemaining将在此对话框中)

                $( "#dialog-confirm" ).dialog({
                    resizable: false,
                    height:140,
                    modal: true,
                    buttons: {
                        "Extend": function() {
                            clearTimeout(session.warningTimer);
                            $( this ).dialog( "close" );
                        },
                        Cancel: function() {
                            session.logout();
                            $( this ).dialog( "close" );
                        }
                    }
                });

没有jQuery对话

  • 删除最后一个块

如果您注意到,&#39; Extend&#39;,则终止警告计时器,取消调用注销功能(也可在上面配置)

最后,这个块对于计时器倒计时到零的情况以及控制#sessionSecondsRemaining内的倒计时显示非常重要

                    if (remaining >= 0) {
                        $('#sessionSecondsRemaining').html(remaining);
                    } else {
                        $( '#dialog-confirm' ).dialog( "close" );
                        clearInterval(session.warningTimer);
                        $( '#sessionSecondsRemaining' ).html('Session Expired');
                        session.logout();
                    }

else下,可能是您在上面的块中真正需要修改的唯一位置。在那里,我调用session.logout()函数(应该是清理对话框后的最后一行,但这只是一个演示)。您可以在此处关闭对话框,和/或将用户重定向到会话过期页面,或显示消息。如果停留在同一页面上,请务必clearInterval(session.warningTimer);。如果没有,那么那条线并不重要。

没有jQuery对话

                    if (remaining >= 0) {
                        $('#sessionSecondsRemaining').html(remaining);
                    } else {
                        clearInterval(session.warningTimer);
                        session.logout();
                    }

keepalive.php

if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
include 'db.php';
$maxtimeout = 15; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 1 WHERE user_id = ".$_SESSION['user_id']."");
mysql_query("UPDATE users SET status = 0 WHERE user_id <> ".$_SESSION['user_id']." AND (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";

此任务应设置为运行服务器端以从任何流量清理数据库(如果您有大量活动,那么您不会需要此脚本)

cron.php

include 'db.php';
// Set this for a longer timeout than in keepalive.php
$maxtimeout = 90; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 0 WHERE (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";

答案 2 :(得分:1)

这就是我在我的系统中应用以跟踪用户仍在线的情况。我让客户端站点每分钟都ping回来告诉DB他还在线。

关于检测浏览器关闭,您可以Close/kill the session when the browser or tab is closed

查看此Daniel Melo
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
var timeLeft = Number(60);

setInterval(function(){
    timeLeft--;
    if(timeLeft<0){
        expiredLogout();
    }
    $("#timer").html(timeLeft);
    //If timer less than 30, show message to user will logout soon
    if(timeLeft<30){
        $("#logoutMsg").show( "slow" );
    }else{
        $("#logoutMsg").hide( "slow" );
    }
    $("#logoutMsg").html('You will logout soon, in '+timeLeft+' sec.');
},1000);
//Initial Function
$(function() {
    //Mouse move top up the time left value;
    $(document).mousemove(function(event) {
        timeLeft = Number(60);
    });
    stillAlive();
    //Every 1 minute ping the active.php
    setInterval(function(){ stillAlive();},60000);
});
//Redirect to other page if time out 
function expiredLogout(){
    window.location = "inactive.php";
};
function stillAlive(){
    //Update userID 1 still active
    var postVal = {userID:1};
    $.post("active.php", postVal, null, "json")
    .success(function(data) {})
    .error(function() {})
    .complete(function() {});
};
</script>
<label id="timer"></label>
<div id="logoutMsg"></div>
</body>
</html>

Demo

答案 3 :(得分:1)

有一个javascript库可能会有所帮助 这是Ifvisible.js

它将允许您检测用户何时不再处于活动状态。

例如,你可以这样做:

//Handle tab switch or browser minimize states    
ifvisible.on("blur", function(){
    //ajax call for inactive.php -> SET status = 0
});

ifvisible.on("focus", function(){
    //ajax call for active.php -> SET status = 1
});

//Detection of inactivity for xx seconds
ifvisible.setIdleDuration(120); // Page will become idle after 120 seconds

ifvisible.on("idle", function(){
    //ajax call for inactive.php -> SET status = 0
});

ifvisible.on("wakeup", function(){
    //ajax call for active.php -> SET status = 1
});

当然,您可以使用不同的参数调用相同的inactive.php程序,以了解是否要将状态设置为1或0。 例如,使用您的ajax调用:

// if inactive : SET status = 0
    $.ajax({
        url: 'inactive.php?status=0',
        type: 'GET',
        async: false,
        timeout: 4000
    });
// if active : SET status = 1
    $.ajax({
        url: 'inactive.php?status=1',
        type: 'GET',
        async: false,
        timeout: 4000
    });

在你的Inactive.php中:

if ($_GET["status"] == "1") // status = 1 -> active
    $tatus = "1";
else // status = 0 -> inactive
    $tatus = "0";

mysql_query("UPDATE users SET status = " . $tatus . " WHERE user_id = ".$_SESSION['user_id']."");

访问网站,获取有关Ifvisible.js的更多信息。

我希望它会对你有所帮助。 :)

答案 4 :(得分:0)

第一个问题是你定义“空闲”的方式。什么终止了“闲置”时期?将焦点转移到浏览器窗口?滚动页面?点击页面?单击按钮?点击链接? - 后者似乎是大多数网站使用的方法,这可以单独在服务器端完成:如果用户没有在您的网站上打开另一个页面,比如5分钟,那么他被认为是空闲的。 15分钟后,他被系统注销。