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


Inactive/browser close - change status to 0 and back to 1 when user returns

我正在尝试让我的网站在在线用户处于非活动状态或关闭浏览器时将他们的状态设置为 0。如果他们重新打开网站或从空闲状态(超时后)恢复,我希望状态恢复为 1(除非他们由于长时间不在网站而完全注销)

这是我到目前为止尝试过的:

非活动.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 秒检查一次哪个用户?

window.onbeforeunload将产生竞争条件,并且不是很可靠。您还想改用window.addEventListener('beforeunload', function () {...});

CheckIdleTime中的alert将停止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
 );

您可能希望稍微调整一下该"非活动"间隔,并考虑创建一个索引。

修订后的代码

这段代码将引用我在这里编写的示例>>jquery-idle with jquery-ui 对话框

使用的库:

  • jQuery-idletimer

嵌入式库示例:

<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事件,因为您的代码中已经涵盖了该事件,但是我建议您在此处进一步阅读>>卸载之前加载堆栈溢出文章<<

解释

.HTML


此行代码用于存储倒数计时器的占位符。为了简化事情,我还在计时器过期时使用它来显示"会话已过期"

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

这是一个使用 jQuery UI 的非常简单的模态对话框。您可以在闲暇时扩展或替换它。

<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

爪哇语


在本节中,您可以配置 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 });
                }
            }
        ;

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

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

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

                $('#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 对话框

  • 删除最后一个块

如果您注意到,"扩展"将终止警告计时器,并且"取消"将调用注销功能(也可在上面配置)

最后,这个块对于计时器倒计时到零时会发生什么非常重要,并且对于控制 # 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();
                    }

保持活力.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 . "";

任务应设置为运行服务器端以清除任何杂散的数据库(如果您有很多活动,则不需要此脚本)

克龙.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 . "";

有一个JavaScript库可能会有所帮助。
这是如果可见.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
});

当然,您可以使用不同的参数调用相同的非活动.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
    });

在您的非活动状态.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 的更多信息。

我希望它能帮助你。:)

这是我在我的系统中应用的,以保持跟踪用户仍然在线。我让客户端站点每分钟ping一次,告诉数据库他仍然在线。

关于检测浏览器关闭,您可以查看此 关闭/终止会话 当浏览器或选项卡被丹尼尔·梅洛关闭时

<!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>

演示

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