如何在不重新加载页面的情况下保持会话活动?

29

我在我的在线测试管理系统中遇到了一个奇怪的问题。

有些用户在测试表单(test.php)中需要很长时间来回答问题并提交表单。

提交表单后,会话已过期,用户必须重新登录。

这不是代码问题。

我在所有页面的顶部设置了这个值。

ini_set('session.gc_maxlifetime', 18000);

有没有一种方法可以在测试表单中不重新加载页面的情况下每10分钟刷新会话以防止会话过期?

请帮帮我。

谢谢。


也许可以做一些ajax调用?你能描述一下你的脚本吗?也许一些代码示例会有所帮助 :) - Gogol
1
有趣。我正在处理一个类似的问题,但我的观点是应该避免在一定时间间隔内自动重置会话超时,因为这将有效地创建一个无限会话,只要浏览器窗口打开,它就会持续存在。相反,我建议您增加最大生命周期,并根据用户操作刷新超时。即使鼠标移动也可以解决问题,一旦移动鼠标就启动计时器。除非包括某些用户交互组件,否则会产生巨大的安全漏洞。会话被设计为过期。 - Jesse Ivy
3个回答

42

你可以使用JavaScript XHR,或者其他人称之为AJAX。

使用AJAX可以调用一个PHP脚本,每10分钟刷新一次您的会话。 :)


这就是我能做到的“精确”程度。

JavaScript

var refreshSn = function ()
{
    var time = 600000; // 10 mins
    setTimeout(
        function ()
        {
        $.ajax({
           url: 'refresh_session.php',
           cache: false,
           complete: function () {refreshSn();}
        });
    },
    time
);
};

// Call in page
refreshSn()

刷新会话的refresh_session.php

<?php
session_start();

// store session data
if (isset($_SESSION['id']))
$_SESSION['id'] = $_SESSION['id']; // or if you have any algo.
?>

无论如何,另一个解决方法是仅针对测试页面使用此处提供的解决方案来延长会话时间。 如何在30分钟后使PHP会话过期?

14
在 PHP 脚本中,仅使用 session_start() 就足够了吗? - lorenzo-s
8
您可以用这一行代码替换整个JavaScript函数:setInterval(function(){$.post('path/to/refresh_session.php');},600000); - myfunkyside
3
@myfunkyside:你的一行代码也有一个好处,那就是它不会在调用栈上不断累积。虽然说具有 10 分钟延迟的递归函数需要约100天才能超过最大栈大小限制,但是小心使用递归函数还是一个好习惯。 - okdewit
1
是的,这是一个六年前的解决方案@sheeks06,这就是为什么我认为值得注意的地方在于正确维护超时时间的方式是通过利用用户操作(例如鼠标移动、页面转换或调用其他端点)来调用端点,而不是或结合设置间隔,这样,当用户处于不活动状态时,账户仍将超时。重置ID来启动会话仍然有效。因此+1。是否有更好的方法?好答案。维护超时很重要,也许答案需要编辑。 :) - Jesse Ivy
1
如何在用户关闭页面时保持会话未被销毁?即如何在页面未打开时保持会话不中断?我已经在php.ini中测试了gc_maxlifetime,但它似乎无效。只有让它始终可用才是最好的解决方案。 - Aria5h4h
显示剩余4条评论

16
你所需要的只是这个(使用jQuery的$.post):
JavaScript(将其放在你的onload函数或其他地方)
setInterval(function(){
  $.post('path/to/refresh_session.php');
},600000); //refreshes the session every 10 minutes

refresh_session.php

<?php
  session_start();

  // if you have more session-vars that are needed for login, also check 
  // if they are set and refresh them as well
  if (isset($_SESSION['token'])) { 
    $_SESSION['token'] = $_SESSION['token'];
  }
?>

最大的变化在于JavaScript,你不需要整个函数,只需要一行代码。

额外信息

虽然我认为在php中只调用session_start()就足够了,但如果我理解正确(https://www.php.net/function.session-start):

读取回调函数将检索任何现有的会话数据(以特殊的序列化格式存储),并在读取回调函数返回保存的会话数据时进行反序列化,并自动填充$_SESSION超全局变量,以供PHP会话处理使用。

在测试期间,我只在我的访客页面上放置了上述代码,而没有放在管理员页面上。但我在同一个浏览器(Chrome)中同时打开了这两个页面,管理员页面也保持登录状态,至少持续了一个小时(没有检查更长时间)。 但是,我不知道如果只使用session_start()而不手动刷新任何会话变量,它是否仍然有效。

无论如何,我希望确保我需要的会话变量确实仍然存在:)


1
你的“额外信息”似乎不正确。我也遇到了同样的问题。创建了一个ajax调用(ping/pong)到服务器,试图保持我的会话活动状态。为了测试目的,每5分钟运行一次。无论如何,大约2个小时后我都会被取消身份验证。现在正在尝试会话更改方法。 - Flip Vernooij
@FlipVernooij,那么“会话更改方法”进行得如何了? - Damilola Olowookere

0

Javascript:

function doStayAlive() {
  var request = new XMLHttpRequest();

  request.open('GET', 'stayalive.php', true);
  request.send();
}

timerStayAlive = setInterval(doStayAlive, 600000);  // 10 minutes

PHP: (stayalive.php)
<?php
  session_start();
  http_response_code(204);
?>

不需要“触碰”会话变量


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接