我的网站存在问题,PHP无法使用Internet Explorer为特定用户保存会话变量。但对于其他一些使用Internet Explorer的用户来说根本没有问题,而使用其他浏览器的用户也没有任何问题。
我创建了以下三个小脚本,以确保网站中没有其他代码:
test.php的:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test.php");
logMsg($content);
$_SESSION['test'] = array('test' => 'lalala');
$_SESSION['count'] = 1;
?>
<a href="test2.php">Next</a>
test2.php:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test2.php");
logMsg($content);
$_SESSION['count']++;
?>
<a href="test3.php">Next</a>
test3.php:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test3.php");
logMsg($content);
var_dump($_SESSION)
的预期输出类似于:
array(0) {
}
array(2) {
["test"] => array(1) {
["test"] => string(6) "lalala"
},
["count"] => int(1)
}
array(2) {
["test"] => array(1) {
["test"] => string(6) "lalala"
},
["count"] => int(2)
}
但是,有问题的用户的输出如下:
array(0) {
}
array(0) {
}
array(1) {
["count"] => int(1)
}
这意味着不会为这些用户存储会话变量。但是,有问题的用户的会话ID对于所有3个测试页都是相同的。
有人知道这可能是什么吗?据我所知,有问题的代码工作了好几年,问题在上个月左右开始显现。
修改
评论中的问题答案:
修改2
正如@ nl-x在评论中所述,数据存储在第二个请求中。所以我调整了测试场景并添加了另一个步骤来查看会话是否适用于后续请求。情况就是这样。 step2.php
和step3.php
中设置的会话数据在请求之间保存。
现在问题是为什么第一个请求的会话数据丢失而后续请求没有?
答案 0 :(得分:5)
我发现有问题的用户都安装了Chrome Frame。我通过在本地计算机上安装Chrome Frame来验证这一点,在这种情况下,我能够复制问题。
问题是由于我们的服务器安装了Suhosin。启用了以下Suhosin设置:
suhosin.session.cryptua
suhosin.cookie.cryptua
这意味着用户代理字符串也是用户会话标识的一部分。通常这不是问题,但对于安装了Chrome框架的用户,第一个请求和后续请求之间的用户代理字符串不同。禁用这些Suhosin设置后,没有其他问题。
答案 1 :(得分:2)
我会假设这个,而不是等待具有PHP会话机制特定知识的人:
我主要使用ASP.NET,Session
对象使用cookie来保存跨请求的数据。如果PHP以相同的方式工作,最明显的结论是会话问题的用户要么禁用cookie,要么使用仅允许列入白名单的域设置cookie的软件。我会看看能不能找到任何支持这个理论的事实......
从PHP手册(http://www.php.net/manual/en/intro.session.php):
这可以存储在用户端的cookie中,也可以传播 网址。
答案 2 :(得分:1)
我无法确切地告诉你为什么在第一次请求之后/之后,cookie似乎迷路了。 (这就是我的想法。)为什么在第二次请求之后/之后不会丢失。
也许确实是一个缓存问题。检查开发人员工具,查看网络选项卡中的确切内容。第一个请求是否带有200 - OK,响应是否包含cookie头?或者它是否确实被缓存,正如其中一条评论所暗示的那样?
但最终你应该实现正确的session id passing(阅读它)。这适用于不想要或不能处理cookie的人。
基本上它意味着改变:
<a href="test3.php">Next</a>
成:
<a href="test3.php?<?php echo htmlspecialchars(SID); ?>">Next</a>
或:
启用--enable-trans-sid
现在,当PHP通知会话未通过cookie传递时,它将以不太安全的方式在URL中提供它们。特别是在这种情况下,您需要session_regenerate_id()
。
修改强> 噢,我想早些提到它,但后来认为不可能。但第二个想法我仍然会提到它! :
默认情况下,Cookie是特定于域的。如果用户转到 http://yourdomain.com (没有 www。),第二个请求转到 http://www.yourdomain.com , cookie将无法在域名更改中存活!从而影响你的会话。
要解决此问题,请设置会话Cookie域,或始终使用相同的域(使用或不使用www。)
答案 3 :(得分:-1)
首先,您应该验证您的php.ini会话配置,尤其是cookie持续时间。在您的问题中添加部分。 在客户端上安装Fiddler,该客户端会向您提供错误并生成会话的完整http转储。这应该可以帮助您轻松追踪问题。