【问题标题】:update database table on session timeout in php在php中更新会话超时的数据库表
【发布时间】:2020-04-19 01:26:35
【问题描述】:

我有一个如下所示的 php 代码,其中会话超时发生在 60 分钟后没有活动时。以下代码位于文件 /mno.php 中。我的login and logout code也在同一个文件/mno.php中。

/mno.php

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
    session_destroy();   // destroy session data in storage
    !isset($_SESSION['pageadmin']);

    /* Update Table (START) */
    $open="false";
    $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
    $stmt->bind_param('ss', $open, $_SESSION['user_name']);
    $stmt->execute();
    /* Update Table (END) */

    header('location: /mmo.php');
    exit();
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 

代码中的 trace_users 表跟踪所有登录用户。在该表中,有两列 user_nameopen。当任何用户登录/注销时,该值设置为true/false

我已包含 sql 查询,我在其中尝试在没有活动时更新表,但不幸的是,该特定用户的列值未设置为 false 当 60 分钟内没有活动发生时。

这是我尝试过的:

在做了一些研究之后,我想我必须运行一个计时器(js/ajax)。在下面显示的 javascript 中,我计算了 Last ActivityCurrent time 之间的差异。 如果超过 60 分钟,那么它将更新一个数据库表。这是我尝试过的,但我相信需要做更多工作才能更新数据库中的表。

<script>
let x = setInterval(function() {

    let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>
    let now = <?php echo time() ?>;
    let difference = now - lastActivity;

    if (difference > 3600) {
        clearInterval(x);
    }
}, 1000
);
</script>   

问题陈述:

我想知道我应该在上面的 js(或 php)代码中进行哪些更改,以便在 60 分钟内没有活动时,它应该将列 open 更新为 false(在表 trace_users 中)用于该特定用户。

编辑 1:

我的登录代码和会话历史代码在同一个文件 /mno.php 中。我已将所有内容放在同一个文件 /mno.php 中。

【问题讨论】:

    标签: javascript php sql ajax session-timeout


    【解决方案1】:

    我认为 Vineys 和 jo0gbe4bstjbs 的答案是错误的,因为当用户关闭浏览器直到 5 秒时,它也无法在 60 分钟和会话后更新表格。会话在 php.ini 配置文件中设置的时间后删除。 你介意每 5 秒请求一次是解决这个问题的好方法吗?这对性能来说是最差的。 如果您想以专业的态度解决这个问题,您应该添加“last_request”列并从表中删除“open”列,并且在每次请求后您应该将 last_requests 值更新为当前的 unix 时间戳。您应该在哪里获取用户:

    $time = time() - 3600;
    
    "SELECT * FROM `users` WHERE last_request > $time" //active users
    "SELECT * FROM `users` WHERE last_request <= $time" //inactive users
    

    而不是每 5 秒的 ajax 请求,您应该编写 setTimeout 并具有 3600 秒的延迟时间,它运行 window.location.href= '/mmo.php';代码。 如果您想要获得最佳性能并在 60 分钟注销后获得准确结果,这很好

    【讨论】:

    • 谁告诉我们每 5 分钟做一次 ajax?
    • 很抱歉您写了“演示目的”。但是每 1000 毫秒检查一次对浏览器来说太糟糕了。我认为你应该这样做 setTimeout(function() { alert('you are logged out'); //DO AJAX REQUEST TO close.php } }, 3600000);
    【解决方案2】:

    我想你知道这段代码

    if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
        //...
    }
    $_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 
    

    在每个请求上运行并且仅在请求到达时运行

    想象一下,我访问了您的网站,然后在保持浏览器打开的情况下外出购物。你认为会发生什么? NOTHING - 因为不会有新的请求发送给你(假设你还没有实现任何周期性的 ajax 轮询/Websocket 机制)

    所以服务器不会打扰我,直到我从购物回来并刷新页面,然后服务器才会意识到“嗯..这家伙的 LAST_ACTIVITY 超过一个小时让我更新我的 trace_users 表和为他设置打开为false"

    来到您提出的解决方案,它看起来不错并且避免了 websockets/周期性 ajax 请求的复杂性

    只需要一些小的修正,请在此处进行基本演示

    <script>
    
        var lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation 
                                                                        //This will remain constant as long as page stays put
        var now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server 
                                        // but later on it will be incremented by javascript to act as counter
        var logoutAfter = 5; //I set 5 sec for demo purposes
    
        var timer = setInterval(function() {
                        now++;
                        let delta = now - lastActivity;
                        if ( delta > logoutAfter) {
                            alert('you are logged out');
                            clearInterval(timer);
                            //DO AJAX REQUEST TO close.php
                        }
                    }, 1000);
    
    </script> 
    

    这里lastActivity 将保存页面由服务器发送到浏览器时的时间戳,它永远不会被浏览器上的脚本更改, now 是您的计数器,您将使用它来跟踪自页面在浏览器上加载以来经过的时间,您将每秒递增一次并检查是否已超过给定的时间量

    如果为 true,则执行 ajax 请求(或直接重定向到 logout.php),您将在其中销毁会话并更新 trace_users 表以将用户标记为已关闭

    更新

    所以 ajax 会像

    $.ajax({      
        url: "/close.php", 
        type: 'POST', // GET also fine
        data: { },
        success: function(data) {
            window.location.href= '/mmo.php';
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(textStatus);
        }
    }); 
    

    关闭.php

    <?php
    session_start();
    $logoutAfter = 5; //5 sec timeout for testing purposes
    
    // I'm not sure whether the below if condition check is required here or not 
    // because we have already checked (whether to timeout or not ) in our javascript 
    // and we call close.php only when it's affirmative
    // I encourage you to test and find out :)
    
    if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
        session_destroy();   // destroy session data in storage
        !isset($_SESSION['pageadmin']);
    
        /* Update Table (START) */
        $open="false";
        $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
        $stmt->bind_param('ss', $open, $_SESSION['user_name']);
        $stmt->execute();
        /* Update Table (END) */
    
        //header('location: /mmo.php'); //<-- no need of it when url hit by ajax
        exit();
    }
    else  //<-- note the else
    $_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 
    

    【讨论】:

    • 我检查了您的代码,它看起来不错 Viney 感谢您的帮助。我很高兴我的方法是正确的。感谢您确认。根据您提出的解决方案,当 5 秒内没有活动时,(1) 页面应自动注销并将用户带到 login.php(我将在其中销毁会话)。 (2) 它还应该更新表格。
    • 这是我试过的jsfiddle.net/u68204ca我想知道你是否可以看看。在小提琴中,如果你能让我知道我需要在哪里调整 update query 和以下 2 行正在破坏会话。 session_destroy(); // destroy session data in storage !isset($_SESSION['pageadmin']);
    • 感谢您的更新。我检查了你的代码,想让你知道一些事情。我的登录代码和会话历史代码在同一个文件 /mmo.php 中。我已将所有内容放在同一个 php 文件 /mmo.php 中。我已尝试使用此代码sandbox.onlinephpfunctions.com/code/…,但它不起作用。我收到警告消息 您已注销错误
    • @user1950349 codesandbox 是您需要在本地系统上测试的受限环境。使用php的努力内置服务器php -S localhost:8080
    • 您好,我已经分享了沙箱链接以显示我在本地系统中使用的代码。在 cmets 中复制/粘贴代码会很麻烦。
    【解决方案3】:

    页面.php

    <!-- CODE TO INCLUDE IN HEADER.PHP -->
    
    <?php  
    session_start();
    $_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp  
    ?>
    
    
    
    <!-- CLOSE -->
    
    <html>
    
    <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    </head>
    
    <body>
    
    </body>
    
    <script>
    let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation
    //This will remain constant as long as page stays put
    let now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server+
                                    // but later on it will be incremented by javascript to act as counter
    let logoutAfter = 5; //I set 5 secs for demo purposes
    
    
    let timer = setInterval(function() {
        now++;
        let delta = now - lastActivity;
    
        if ( delta > logoutAfter) {
            alert('you are logged out');
            clearInterval(timer);
            //DO AJAX REQUEST TO close.php
            $.ajax({
                url: "/mmo.php",
                type: 'POST', // GET also fine
                data: { },
                success: function(data) {
    
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.log("I am inside error");
                    alert(textStatus);
                }
            });
        }
    }, 1000); //<-- you can increse it( till <= logoutAfter ) for better performance as suggested by @"Space Coding"
    
    </script>
    
    </html>
    

    mmo.php

    <?php
    
    $servername = "localhost";
    $username   = "username";
    $password   = "password";
    $dbname     = "myDB";
    
    $connect = new mysqli($servername, $username, $password, $dbname);
    
    if ($connect->connect_error) {
        die("Connection failed: " . $connect->connect_error);
    }
    
    session_start();
    $logoutAfter = 5; //5 sec timeout for testing purposes
    
    if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
        session_destroy();   // destroy session data in storage
        !isset($_SESSION['pageadmin']);
    
        /* Update Table (START) */
        $open="false";
    
        $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
        $usname = !empty($_SESSION['user_name'])?$_SESSION['user_name']:'';
    
        $stmt->bind_param('ss', $open, $usname );
        $stmt->execute();
        /* Update Table (END) */
    
        //header('location: /mmo.php'); //<-- no need of it when url hit by ajax
        exit();
    }
    else  //<-- note the else
    $_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp  
    ?>
    

    【讨论】:

    • 我在$stmt-&gt;bind_param('ss', $open, !empty($_SESSION['user_name'])?$_SESSION['user_name']:'' ); 这一行收到错误消息。它说只有变量可以通过引用传递。
    • 你能检查一下print_r($_SESSION['user_name']) 给出了什么吗?
    • 打印当前登录的用户。
    • 是数组还是字符串?
    • 它是一个字符串(像这样 david
    【解决方案4】:

    这是一个简单的网页时间验证:

    $modified_on = isset($SERVER['HTTP_IF_MODIFIED_SINCE']) ? $SERVER['HTTP_IF_MODIFIED_SINCE'] : null;
    
    $current_time = time();
    
    if (!is_null($modified_on) && ($current_time - strtotime($modified_on)) > 3600) {
        session_destroy();
        ...
    }
    
    header('Last-Modified: '.gmdate('D, d M Y H:i:s', $current_time).' GMT');
    
    ...
    

    【讨论】:

    • 这是一个请求头,由浏览器发送。
    猜你喜欢
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    相关资源
    最近更新 更多