猿问

使用ajax强制注销时数据库表未更新

如标题中所述,当 30 分钟内没有任何活动发生时,数据库表trace_users不会更新,但在 6 分钟内会更新。


以下代码(JS 和 PHP)位于同一个 php 文件mno.php中。


我通过let lastActivity = <?php echo time(); ?> ; 下面脚本中的这一行存储用户的最后一个活动。


<?php

session_start();     

if (isset($_GET['action']) && $_GET['action'] == "logout")

{

    session_destroy(); // destroy session data in storage

    !isset($_SESSION['admin']);

    $open = "false";

    $write = "0";

    $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");

    $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';

    $stmt->bind_param('sss', $open, $write, $usname);

    $stmt->execute();

}

?>

<script>

    jQuery(document).ready(function($) {


        let lastActivity = <?php echo time(); ?> ;  // storing last activity of user


        let now = <?php echo time(); ?> ;


        let logoutAfter = 360;


        let timer = setInterval(function() {

            now++;

            let delta = now - lastActivity;

            console.log(delta);

            if (delta > logoutAfter) {

                clearInterval(timer);

                //DO AJAX REQUEST TO close.php

                $.ajax({

                    url: "/abc/mno.php",

                    type: 'GET',

                    data: {

                        action: 'logout'

                    }, // Line A

                    success: function(data) {

                        console.log(data); // Line B

                    },

                    error: function(jqXHR, textStatus, errorThrown) {

                        alert(textStatus);

                    }

                });

            }

        }, 1000);

    }); 

</script>

问题陈述:


我想知道我应该在上面的代码中进行哪些更改,以便在 30 分钟(1800 秒)内没有任何活动发生时,数据库表也应该得到更新。


Case1(不工作): 1800 秒(页面注销,数据库不更新)

Case2(工作): 360 秒(页面注销,数据库更新)


session.gc_maxlifetime 里面的值是 1440(Local Value) 1440(Master Value)


这是我尝试过/调试过的:


在网络选项卡上,当会话超时设置为6 mins和60 mins时,我得到 Request Method GET。


慕标琳琳
浏览 152回答 4
4回答

至尊宝的传说

您需要向 javascript 传递某种永久 UID,即使在会话过期后也能识别用户。为了简化起见,我正在使用user_name您的代码中已经存在的那个。但是您也可以为每个用户分配一个 UUID,这样就无法猜测另一个用户的名称,也无法修改他们的统计信息。首先,您将把$_SESSION['user_name']from PHP 传递给 JS 闭包。let userName = "<?php echo $_SESSION['user_name']; ?>";&nbsp; // don't forget to wrap the JS string value in quotes or apostrophes然后,您将在 AJAX 请求负载中传递它。data: {&nbsp; &nbsp; action: 'logout',&nbsp; &nbsp; user_name: userName&nbsp; // added param},最后,您将覆盖发送到 DB 的值(如果它与有效负载一起发送)$usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';&nbsp; // original lineif (isset($_GET['user_name']) && !empty($_GET['user_name'])) {&nbsp; &nbsp; $usname = $_GET['user_name'];}$stmt->bind_param('sss', $open, $write, $usname);&nbsp; // original line完整更新代码:<?phpif (isset($_GET['action']) && $_GET['action'] == "logout"){&nbsp; &nbsp; session_destroy(); // destroy session data in storage&nbsp; &nbsp; !isset($_SESSION['pageadmin']);&nbsp; &nbsp; $open = "false";&nbsp; &nbsp; $write = "0";&nbsp; &nbsp; $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");&nbsp; &nbsp; $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';&nbsp; &nbsp; if (isset($_GET['user_name']) && !empty($_GET['user_name'])) {&nbsp; &nbsp; &nbsp; &nbsp; $usname = $_GET['user_name'];&nbsp; &nbsp; }&nbsp; &nbsp; $stmt->bind_param('sss', $open, $write, $usname);&nbsp; &nbsp; $stmt->execute();}?><script>&nbsp; &nbsp; jQuery(document).ready(function($) {&nbsp; &nbsp; &nbsp; &nbsp; let lastActivity = <?php echo time(); ?> ;&nbsp; // storing last activity of user&nbsp; &nbsp; &nbsp; &nbsp; let now = <?php echo time(); ?> ;&nbsp; &nbsp; &nbsp; &nbsp; let logoutAfter = 10;&nbsp; &nbsp; &nbsp; &nbsp; let userName = "<?php echo $_SESSION['user_name']; ?>";&nbsp; &nbsp; &nbsp; &nbsp; let timer = setInterval(function() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; now++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let delta = now - lastActivity;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(delta);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (delta > logoutAfter) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clearInterval(timer);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //DO AJAX REQUEST TO close.php&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $.ajax({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; url: "/abc/mno.php",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: 'GET',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; action: 'logout',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_name: userName&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, // Line A&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; success: function(data) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(data); // Line B&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; error: function(jqXHR, textStatus, errorThrown) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; alert(textStatus);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; });&nbsp;</script>最后的几点说明:将 PHP、HTML 和 JS 完全组合在一个文件中是一种不好的做法。您的代码的某些部分不容易重现,我不得不从上下文中猜测(例如,我猜想会话已经设置,使用了 jQuery 但没有<script src="...jquery.js">,有一个 DB 查询但没有单独的 SQL 导入来尝试它迅速地)。请在您的下一个问题中阅读并应用如何创建一个最小的、可重现的示例中的知识,以便更多的人能够或愿意帮助您。

不负相思意

问题是您没有更改任何会阻止会话在 N 秒后过期的内容,您只是在编写脚本以使其在此时间后销毁会话。会话 gc(垃圾收集器)定期执行并删除旧会话,当这种情况发生时,$_SESSION['LAST_ACTIVITY']也将被删除。您必须尝试阻止 gc 删除会话或更改应用程序中的逻辑。

郎朗坤

PHP 进程不会无限期地坐下来,也没有程序结构作为循环 ala Node.js 服务器,它不允许您对会话到期做出反应,因为它不是使其无效的进程,而是与会话相关联的简单时间戳每次您尝试使用它时都会检查它。我提供的解决方案是一个简单的脚本,它每 N 分钟运行一次,以执行最后一次用户活动时间戳(我假设根据该用户的请求更新)与到期期限(在您的情况下为 30 分钟)的比较。您还可以将会话到期时间设置为 30 分钟,但严格来说这不是必需的。如果时间差将超过 30 分钟,则更新表中用户的时间戳,并在必要时使他们的会话无效。该脚本可以通过 cron 或其替代方案运行,并通过您需要执行检查的所有用户。不要忘记处理用户在服务器上注销但客户端不知道并可能继续发送注销请求的情况 - 引发警报框相当不清楚(最好返回 HTTP Unauthorized 代码并以不同方式处理 - 重定向例如登录屏幕)

小唯快跑啊

您需要解决两件事。1)。将 ajax 请求设置为async:false.$.ajax({&nbsp; &nbsp; url: "/abc/mno.php",&nbsp; &nbsp; &nbsp; type: 'GET',&nbsp; &nbsp; &nbsp; async: false,&nbsp; &nbsp;//&nbsp; <---- ADDED ASYNC FALSE&nbsp; &nbsp; &nbsp; data: {&nbsp; &nbsp; &nbsp; &nbsp; action: 'logout'&nbsp; &nbsp; }, // Line A&nbsp; &nbsp; &nbsp;success: function(data) {&nbsp; &nbsp; &nbsp; &nbsp; console.log(data); // Line B&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp;error: function(jqXHR, textStatus, errorThrown) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alert(textStatus);&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp;});2)。执行 SQL 查询后销毁会话。<?phpsession_start();&nbsp; &nbsp; &nbsp;if (isset($_GET['action']) && $_GET['action'] == "logout"){&nbsp; &nbsp; !isset($_SESSION['pageadmin']);&nbsp; &nbsp; $open = "false";&nbsp; &nbsp; $write = "0";&nbsp; &nbsp; $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");&nbsp; &nbsp; $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';&nbsp; &nbsp; $stmt->bind_param('sss', $open, $write, $usname);&nbsp; &nbsp; $stmt->execute();&nbsp; &nbsp; session_destroy(); // destroy session data in storage <---- DESTORY AT THE END}?>
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答