【问题标题】:php $_SESSION variables disappear and reappear randomlyphp $_SESSION 变量随机消失并重新出现
【发布时间】:2017-05-20 07:57:24
【问题描述】:

前言:这是我an earlier question 的“发展”,他的回答最终并没有解决我的问题。但是通过尝试所有建议并尝试其他东西,我发现真正的问题是别的东西,所以我在这里重新提出我的问题

我有一个多年来一直正常工作的登录页面/系统,让用户保持登录状态,直到他/她关闭浏览器窗口或手动注销。但最近,仅在几分钟不活动后,会话 cookie/s 似乎就过期了,导致用户自动退出。

这发生在不同的浏览器和不同的操作系统上,PHP 版本是 5.6.29,最近发生了变化(之前是 5.5 甚至 5.3)。

我使用session_start() 在每个页面上创建和刷新会话。登录脚本首先检查用户名和密码,并从数据库中获取一些其他用户数据。这些其他数据和成功登录状态保存在会话变量中,如

$_SESSION['username'] = $name;
$_SESSION['usertype'] = $type;
$_SESSION['login'] = "ok";

在其他页面上,我检查登录状态如下:

session_start();
if(($_SESSION['login'] != "ok") OR ($_SESSION['usertype'] != "xxx")) {
 header("Location: ../login.php"); /* redirects to login page if conditions are not true */
 exit;
 }

登录有效,登录用户可以继续访问其他页面一段时间,但一段时间后(变化很大),他/她似乎被注销(即重定向到尝试打开另一个页面时登录页面)。

然后我注意到(在开发人员工具中)会话 ID cookie 在会话似乎过期后保持相同的值(我曾想过,因为会话变量已经消失)。但是会话并没有过期,只是会话变量消失了。在我的测试中,我尝试在某些页面上回显其中的一些变量,但我偶然发现,在它们已经消失(没有回显输出)之后,当我重新加载页面或几分钟后,它们重新出现换到另一个页面。

现在这就是我现在卡住的地方:这怎么会发生,尤其是:我能做些什么来防止这些变量玩捉迷藏?

(顺便说一句,我无权访问服务器设置 - 这是在共享网络空间上...)

【问题讨论】:

  • 如果更改了 php 版本,请检查会话 cookie 寿命设置是否也被更改/修改。这就是我能从中得到的一切。 phpinfo() 显示什么?
  • 检查 php.ini 设置,就像 @Fred-ii- 所说的那样,而且,我知道这听起来很傻,当你真正的意思是 $_SESSION[.....] == .... 时,检查你的代码 $_SESSION[.....] == .... 一个非常常见的错过错字。
  • 嗯,之前的猜测都无法解释为什么会话值会在一段时间后恢复。您是否使用默认会话存储? (这是文件系统)如果提供者的架构在负载均衡器后面有多台机器,那么您需要将会话存储在数据库表中。 (因为机器必须使用相同的db)
  • 您使用的是什么会话存储机制?如果它是默认的(临时文件),那么在服务器上运行的一些维护/备份脚本可能会将会话数据作为垃圾删除,而另一个正在从备份中恢复数据。如果它使用数据库或内存缓存,那么这些服务器可能暂时不可用?这里只是推测
  • @Fred-ii- 感谢您的帮助!但是请考虑一下:数据(会话变量)在登录期间被写入其中 - 之后它们不会被更改,只会被读出。如果tpm 在任何时候被清空,它们就会丢失并且在几分钟后无法重新出现......

标签: php session session-variables


【解决方案1】:

对于任何有兴趣的人:

显然@Crouching Kitten 是对的 - 提供商的架构在负载均衡器或类似设备后面有多台机器,对此我无能为力。

所以我接受了他的建议,现在将之前作为会话变量的所有内容(连同会话 ID)保存在一个数据库中,我在该网站每个页面的开头访问该数据库。我还在其中保存了一个时间戳,它会随着包含相同会话 ID 的每个新查询而更新,因此我可以设置一个 cronjob,每半小时擦除一次过时的数据(超过 90 分钟 - 但该间隔可以是任何时间)。

【讨论】:

  • 我强烈建议基于 memcached 的会话处理程序。它更快,所有内容都在内存中,占用空间很小,有 TTL,没有文件锁定(HHVM 也没有锁定会话文件,类似的行为),并且您可以在所有网络服务器上获得所有会话数据。
  • 不幸的是,我无法更改服务器设置(除了 ini_set() 和相关的东西)——我只是一个相当不灵活的提供商的客户。
  • 这对我来说是不能接受的。如果您付费但它只在特殊情况下有效(当用户每次请求都访问同一台后端机器时),这是立即放弃合同甚至要求取回您的钱的好理由。
  • 是的,没错。但更准确地说,我什至不是客户端,而是客户端的网络工作者,而且客户端也不太灵活......
【解决方案2】:

这不是解决方案,只是对我在 cmets 中所写案例的测试。你能试试这个吗?

<?php

$number = (int)$_GET["number"];
$temp_dir = "/tmp/lbtest123";

if (!is_dir($temp_dir)) {
    if (!mkdir($temp_dir, 0777, true)) {
        die("Can't create directory: $temp_dir");
    }
}

file_put_contents($temp_dir."/".$number.".txt", "");

echo "<pre>\n";
print_r(glob($temp_dir."/*.txt"));
echo "</pre>";

将此复制到您的服务器。 它使用作为参数传递的数字在 /tmp/lbtest123 文件夹中创建文件。然后列出已经创建的文件。

以越来越多的数字调用它,与您期望“注销”发生的时间相同。示例:

示例结果:

Array
(
    [0] => /tmp/lbtest123/1.txt
    [1] => /tmp/lbtest123/2.txt
    [2] => /tmp/lbtest123/3.txt
    [3] => /tmp/lbtest123/4.txt
)

我希望它会在一段时间后显示类似的内容:

Array
(
    [2] => /tmp/lbtest123/4.txt
    [3] => /tmp/lbtest123/5.txt
)

Array
(
    [0] => /tmp/lbtest123/1.txt
    [1] => /tmp/lbtest123/2.txt
    [2] => /tmp/lbtest123/3.txt
    [3] => /tmp/lbtest123/6.txt
)

【讨论】:

  • 你可能是对的,我想,但这段时间是不可预测的。到目前为止,它的范围从 3 分钟到 6 小时......我认为这可能是真的原因是我所做的不可重现的观察 - 我在第一次连接失败后以另一个用户身份登录,然后让第二个用户回显过了一会儿(一个小时?),突然又得到了第一个的数据回响……但不管怎样——如果是这样,我该怎么办?
  • @Johannes:如果是这种情况,那么您可以联系提供者,或者您可以将会话数据存储在数据库表中:(sess_id, data, last_access_time) 等。还要仔细检查同一主机上的另一个应用程序正在使用同一会话进行调整的可能性。要排除这种情况,只需将 cookie 名称更改为其他名称。
猜你喜欢
  • 2017-09-03
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-15
  • 2021-12-29
相关资源
最近更新 更多