【问题标题】:How to logout after X minutes of inactivity on button click?如何在单击按钮 X 分钟不活动后注销?
【发布时间】:2020-10-05 08:21:49
【问题描述】:

我正在做一个简单的项目,我有一个包含多个用户的登录系统,每个用户都将登录并将表单条目保存在一个文件中。我正在尝试建立会话超时,以便在 2 分钟不活动后将我注销。

  • 我有 login.php 页面,我在其中提供了我的用户名和密码。
  • 如果登录成功,它会将我重定向到index.php 页面,在该页面中我的表单带有两个文本框和一个按钮。
  • index.php 页面上,我有Save Data 按钮,如果我点击它会调用save.php,然后它会通过覆盖文件来保存表单条目。
  • 我的index.php 页面上也有logout 链接,如果我点击该链接,它会将我注销并重定向到login.php 页面。

以上所有东西都可以正常工作。现在我正在尝试构建此会话超时,以便它可以在 x 分钟不活动后将我注销并将我重定向到 login.php 页面。

这是我的index.php 文件:

<?php

declare(strict_types = 1);

// Start session.
session_start();

// Include helper functions.
require_once 'helpers.php';

// 2 mins in seconds
$inactive = 120; 

if(isset($_SESSION['timeout']) ) {
    $session_life = time() - $_SESSION['timeout'];
    if($session_life > $inactive)
    { 
        redirect('logout.php');
        return;
    }
}

$_SESSION['timeout'] = time();

// Redirect user to login page if not authenticated.
if (! check_auth()) {
    redirect('login.php');
    return;
}

?>
<!doctype html>
<html>
<head>
    <title>Home</title>
</head>
<body>
    <div>
        <h1>Website Title</h1> <a href="logout.php">Logout</a> </div>
    <div>
        <p>Welcome back, <?= $_SESSION['user_id'] ?>!</p>
    </div>
    <form method="post">
        <input type="text" name="field1" />
        <input type="text" name="field2" />
        <input type="submit" name="submit" value="Save Data"> </form>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script>
    $(function() {
        $('form').submit(function(e) {
            e.preventDefault();
            $.post({
                url: 'save.php',
                data: $(this).serialize(),
            }).done(response => {
                response = JSON.parse(response);
                if(response.message) {
                    alert(response.message);
                }
            });
        });
    });
    </script>
</body>
</html>

这是我的save.php 文件:

<?php
declare(strict_types=1);
// Start session.
session_start();
// Include helper functions.
require_once 'helpers.php';

// 2 mins in seconds
$inactive = 120; 

if(isset($_SESSION['timeout']) ) {
    $session_life = time() - $_SESSION['timeout'];
    if($session_life > $inactive)
    { 
        redirect('logout.php');
        return;
    }
}

$_SESSION['timeout'] = time();

// Redirect user to login page if not authenticated.
if (! check_auth()) {
    redirect('login.php');
    return;
}

// save form entries in a file

这是我的helpers.php 文件:

<?php
declare(strict_types=1);

if (! function_exists('check_auth')) {
    function check_auth(): bool
    {
        return isset($_SESSION['user_id']);
    }
}

if (! function_exists('logout'))
{
    function logout()
    {
        if (isset($_SESSION['user_id'])) {
            $trace = json_decode(file_get_contents('current_user.txt'));

            if ((int) $trace->user_id === $_SESSION['user_id']) {
                $content = isset($trace->revoked_user_id)
                ? json_encode(['user_id' => $trace->revoked_user_id, 'created_at' => (new DateTime('now'))->format('Y-m-d H:i:s')])
                : '';
                file_put_contents('current_user.txt', $content);
            }

            unset($_SESSION['user_id']);
            unset($_SESSION['timeout']);
        }
    }
}

if (! function_exists('redirect')) {
    function redirect(string $url, int $status_code = 303): void
    {
        header('Location: ' . $url, true, $status_code);
        die();
    }
}

问题陈述

一旦index.phpsave.php 空闲2 分钟,我将重定向到logout.php 文件。这是我注意到的 -

  • 如果我在 index.php 页面上并且在 2 分钟不活动后,如果我刷新浏览器,那么它会正常注销我,没有任何问题,并将我重定向到 login.php 页面。
  • 现在假设如果我再次在index.php 页面上,并且在我点击Save Data 按钮后 2 分钟不活动后,它会在我的控制台上出现错误,但从技术上讲,它应该让我退出并重定向我登录.php 页面。

下面是我在index.php 页面中的 ajax 调用 -

<script>
$(function() {
    $('form').submit(function(e) {
        e.preventDefault();
        $.post({
            url: 'save.php',
            data: $(this).serialize(),
        }).done(response => {
            response = JSON.parse(response);
            if(response.message) {
                alert(response.message);
            }
        });
    });
});
</script>

每当我在 2 分钟不活动后单击 Save Data 按钮时,都会收到第 2 点的 json 解析错误。 response 变量的值在 html 中是完整的 login.php。我不确定为什么会这样。在调用save.php 之前,我们是否需要在 jquery 本身中检查会话验证?

【问题讨论】:

标签: php ajax session session-timeout


【解决方案1】:

总而言之,您的问题是由 ajax 请求时在 save.php 中发生的重定向引起的。

发生的情况是redirect() 请求被透明处理,结果由jQuery.ajax().done() 闭包处理,它试图为login.php 的HTML 调用 JSON.parse(response);。 单击按钮时,您应该能够通过在浏览器中查看开发人员工具(通常是 F12)来验证这一点。

解决问题的一般方法是确定请求是否为XMLHttpRequest 并发送不同的响应而不是重定向。

检测 XMLHttpRequest

要确定请求是否来自jQuery.ajax(),您需要检查X-Requested-With 请求标头。

isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'

带有 redirect 属性的 JSON 响应

此方法在响应中返回一个redirect 属性,并使用它从jQuery.ajax().done() 闭包重定向。

helpers.php

if (! function_exists('redirect')) {
    function redirect(string $url, int $status_code = 303): void
    {
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
            //do not redirect AJAX requests
            echo json_encode(['redirect' => $url]);
        } else {
            header('Location: ' . $url, true, $status_code);
        }
        die();
    }
}

index.php

$(function() {
    "use strict";
    $('form').submit(function(e) {
        e.preventDefault();
        $.post({
            url: 'save.php',
            data: $(this).serialize(),
        }).done(response => {
            response = JSON.parse(response);
            if (response.redirect) {
                //redirect user
                window.location.href = response.redirect; 
            }
            if (response.message) {
                alert(response.message);
            }
        });
    });
});

状态码响应

此方法返回200 Ok 以外的状态代码,而不是重定向并检查jQuery.ajax()statusCode: 方法中的响应状态代码。

helpers.php

if (! function_exists('redirect')) {
    function redirect(string $url, int $status_code = 303): void
    {
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
            //do not redirect AJAX requests
            http_response_code(401); //Unauthorized - PHP 5.4+
            echo $url; //optionally output the url
        } else {
            header('Location: ' . $url, true, $status_code);
        }
        die();
    }
}

您可以在此处选择根据需要处理状态代码。 对于最简单的方法,检查 fail() jqXhr 对象状态代码并执行 javascript 重定向。

index.php

$(function() {
    "use strict";
    $('form').submit(function(e) {
        e.preventDefault();
        $.post({
            url: 'save.php',
            data: $(this).serialize(),
        }).done(response => {
            response = JSON.parse(response);
            if (response.message) {
                alert(response.message);
            }
        }).fail(jqXhr => {
            if (jqXhr.status == 401) {
                //redirect to specified url in the response text
                window.location.href = jqXhr.responseText; 
               /* alternatively hard-code '/logout.php' */
            }
        });
    });
});

【讨论】:

  • 有趣。我完全没有意识到这一点。谢谢你教我这个。感谢你的帮助!我看到这个变量没有定义sapi_type?我们需要在某个地方定义吗?抱歉,这对我来说有点新鲜。
  • @DavidTodd 已更新以删除 CGI 条件检查,因为您使用的是 PHP > 5.4
  • 谢谢威尔。我看到了一个非常奇怪的问题。我有这段代码在我的公司服务器上运行,如果您第一次在浏览器上打开网站链接,那么它会询问用户和密码(进入时需要),然后如果您打开它,则后续链接不会询问任何内容它保持不变,但是在此更改之后,我注意到的是-如果我在 X 分钟不活动后刷新浏览器,那么它会注销,这很好,但是如果我在 X 分钟不活动后单击“保存数据”按钮,那么它会问同样的问题我第一次为我的网站输入的用户名和密码。
  • .. 然后,一旦我输入用户名和密码,它就会注销,然后它会带我进入登录屏幕。所以我的困惑是为什么它在Save Data 按钮点击时表现得很奇怪。有什么想法吗?
  • JS 重定向应该就像用户直接导航到/logout.php,重定向到哪里?我需要查看您的登录代码逻辑以确定实际发生的情况。请使用此解决方案发布有关新问题和更新代码的另一个问题,但听起来/logout.php 中的会话状态未正确清除。
猜你喜欢
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 2011-08-04
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
  • 2016-04-13
相关资源
最近更新 更多