在浏览器关闭 PHP/MySQL 时将用户从数据库中注销

Posted

技术标签:

【中文标题】在浏览器关闭 PHP/MySQL 时将用户从数据库中注销【英文标题】:Loggin a user out of a database on browser close PHP/MySQL 【发布时间】:2013-10-12 15:52:55 【问题描述】:

我之前在网上看到过很多关于这个的问题,但是,在大约 30 个论坛等等中,没有一个有我需要的解决方案,其中包括 ***。如果有人可以帮助我找到可靠的解决方案,将不胜感激,在此先感谢!

我将尽可能详细地解释我的网站和情况,以帮助任何想要帮助回答我的问题的人。这是我的情况:

我有一个网站,我使用 phpmysql。我的网站是一个“私人”组织网站。为了允许人们访问该站点,我发送了我们组织的新成员并邀请代码。然后用户访问该网站,index.php 文件只包含一个用于登录的表单以及一个指向注册页面的链接。新会员点击“在此注册”链接开始注册。第一个注册页面询问用户的姓氏和邀请代码,这些信息会根据数据库进行检查,以确保该人在列表中并且尚未注册。如果他们通过检查,他们将被带到下一页,在其中输入所需信息(用户名和密码、电子邮件地址等)以及一些可选信息(电话、简历等)。如果用户创建了有效的用户名和密码并填写了所有必填字段,则他们的信息将存储在数据库中。密码都经过适当且安全的加盐和散列处理,因此没有问题,整个注册过程都可以正常进行。注册后,用户将返回 index.php,他们现在可以使用刚刚创建的用户名和密码登录。这也有效;当用户登录时,将根据数据库检查他们的用户名和密码,如果成功,则用户已登录。当用户登录时,数据库中的 ONLINE 值从 False 设置为 True。用户现在已登录并可以按预期使用该站点。在我的网站上,有一列列出了当前在线的用户(基于数据库中的 ONLINE 值)。当用户单击站点每个页面上的“注销”按钮时,logout.php 脚本将运行,结束会话并将 ONLINE 值设置回 False。这一切都很好而且花花公子,但是,当用户没有先注销就关闭浏览器时,问题就来了。这是我在互联网上不同地方看到许多不同“解决方案”的地方。我将解释为什么它们不起作用以及为什么我需要更好的解决方案。

我最常看到的答案涉及某种会话超时或破坏会话,这是无关紧要的,因为会话实际上已经在用户关闭浏览器时结束,但这对告诉没有影响其他用户,无论该人当前是否在线。会话结束时,数据库不会更新,这会导致问题,因为用户只能从单个实例登录。如果用户在其 ONLINE 值已设置为 TRUE 时尝试登录,则不允许他们登录。

我还看到了使用“Last Seen”值而不是在线值的建议,如果用户在过去 x 分钟内没有任何活动,请将用户注销。然而,这行不通,有两个原因。 1)该脚本仍然必须在某个地方运行才能使其工作,这意味着必须有另一个用户登录才能使其工作。这基本上意味着,如果使用此方法,如果用户关闭浏览器或断开连接,他们将无法重新登录,直到另一个用户登录。我的组织是一个小型的本地组织,因为它也就是说,可能有很多次没有用户在线。此外,即使其他用户登录,连接丢失的用户仍然无法重新登录,直到 x 分钟过去后,所以如果用户不小心关闭了浏览器并想立即重新登录,他们根本做不到。

我遇到的一个不太常见的解决方案涉及使用 onBeforeUnload javascript 函数,但这些解决方案肯定不会起作用,因为它们会在用户单击链接或“返回”和“前进”时触发纽扣。此外,如果用户在他们的浏览器中禁用了 JavaScript,这将根本不起作用。

我看到的最后一件事涉及 while 循环和 connection_aborted 函数,这是唯一一个似乎可以工作的东西,但我还没有看到关于它应该如何工作的非常清晰的描述,并且经过几个月的试验有了它,我仍然没有想出一个可靠的解决方案。

在许多论坛中,我看到人们说“这是不可能的”,但考虑到有些网站以某种方式做到这一点,情况并非如此。我已经在几个站点上对此进行了测试和试验。在拥有 Facebook 或任何论坛网站等用户的网站上,有一个“在线”用户列表,如果用户关闭浏览器,他们的名字将不再出现在列表中,所以有可能,即使只能通过一些晦涩难懂的方法来实现。因此,如果有人知道解决方案,如果您能分享您在这个问题上的一些智慧,我将不胜感激!

【问题讨论】:

您最好的办法是简单地合并一个不活动超时。如果在过去 10 或 15(或其他)分钟内没有任何活动,请注销此人。我不相信你认为这行不通的论点;正在运行的 Web 应用程序就是正在运行的 Web 应用程序。 也许有点牵强,或者实现起来的工作量太大,但您可以查看 socket.io,它提供了一种通过 HTTP 到客户端的非常可靠的传输方法,并且可以轻松检测到套接字断开连接。跨度> 您可以设计客户端浏览器代码,以在用户离开页面时发送结束用户会话的消息。但是,尽管您的直觉与此相反,您不能保证此类消息将始终由 Web 应用程序客户端代码发送。如果用户在您的窗口打开时从她的笔记本电脑中取出电池怎么办?您需要一个超时策略作为会话取消的备份。 @mobius 建议使用持久连接。猜猜 TCP 堆栈如何检测持久连接的丢失?超时。 @RobertHarvey 我知道这一切,但这不是问题所在。如果用户关闭浏览器或断开连接,超时将检查自上次登录以来的时间,这很好。问题是,如果用户的浏览器崩溃,他们可能希望重新启动浏览器并立即重新登录,但由于超时可能比他们重新启动浏览器并导航回网站需要 15 秒,导致用户必须等待超时到期才能重新登录。 【参考方案1】:

尝试在 javascript 中创建心跳机制。 此方法会在及时使用时开始向您的 webmethod 发送 ajax 调用。

setInterval(function()
sendPulse();
,30000);


sendPulse()

var varUserID = userID;//any unique user identifier that can be found on server side
$.ajax(

    url: "Default.php/updateUserStatus",
    UserID: varUserID,
    type: "POST",
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function (mydata) 

        //alert("pulse sent");
    
    );
   

在服务器端,您必须有一个具有相同名称和区分大小写参数的方法。应该是静态的并标记为 webmethod。在此方法中为用户保存当前时间。您应该有一种机制来了解用户的脉搏非常旧,当用户尝试做某事或执行任何操作时执行此检查。我已经实现了这种方法并且效果很好。

【讨论】:

【参考方案2】:

这就是答案:客户端和服务器之间的持久连接。为此,您将需要一个 TCP 连接,例如现在的 websockets,或者一个闪存旧的双工连接。从这里开始,当有人连接或断开连接时,TCP 会注意到您。你要做的是一个 websocket 服务器(例如),它只是 traks 连接(从数组中推送和弹出),也是一种响应“get_users_online”消息的方法。您可以通过websocket服务器访问您用户的会话(只读),然后查看用户是否登录(这样您可以将他的昵称存储在会话中,从websocket服务器进一步访问),看看他是否登录管理员(会话->is_admin)。

很简单,我想说。

这是我一直在使用的库:http://socketo.me/。它使用一个库来解码 symfony2 会话,但是对于简单的应用程序,您不需要解码(symfony2 应用程序对会话进行编码,因此 websocket 服务器必须对其进行解码)。

重要提示:会话必须像 ORM 或 NoSql 一样存储在外部(而不是文件系统 /tmp)。

无论哪种方式,请不要打扰我,但我不得不说,看到的“最后一次”非常好。大多数网站都依赖于此。你理解错了,你不需要有一个活的服务器来检查“最后一次”,当你请求 /admin.php?users_online=1 时,你会查询“Last seen > NOW() - 5 minutes "(这样写是行不通的),所以你甚至可以去掉 "ONLINE" "OFFLINE" 字段。

我建议使用 websocket 方法,这很有趣。 :)

祝你好运!

【讨论】:

这对我来说似乎是件好事。我会试试这个。谢谢。

以上是关于在浏览器关闭 PHP/MySQL 时将用户从数据库中注销的主要内容,如果未能解决你的问题,请参考以下文章

试图在php MYSQL中将数据从一个表插入另一个表[关闭]

如何通过创建会话使用 PHP、MYSQL 和 HTML 创建登录系统 [关闭]

弹出窗口以在关闭时将数据返回给父级

使用选项编码 PHP/MYSQL 搜索的最佳方法 [关闭]

有啥方法可以检查是不是有人使用 Javascript/PHP 关闭了浏览器? [关闭]

从mysql数据库中提取5条随机记录[关闭]