在Internet Explorer中,PHP会话数据发生变化

6

我已经定义了一个会话来使用PHP存储令牌,如下所示:

$_SESSION['token'] = sha1(uniqid(mt_rand(), true));

当我想要阅读这个会话时,在Chrome或Firefox中没有任何问题。但在IE中,在重新生成之前会变成其他内容。例如,如果我将其值存储在表单的隐藏字段中,并像这样提交:

<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>" />

在下一页中,我将在IE上得到这个结果:
echo $_SESSION['token']; // shows 1b05fab5ec11f1d50713aea6e74f84727d29b4a3
echo $_POST['token']; // shows e8fac6d55b04d1752f37ecde953f7f08b112ccca

如果我在创建$_SESSION['token']之后立即打印它,甚至在创建页面的末尾打印它,它会准确地显示内容,没有任何问题。

这是什么问题?

编辑:
这是我的表格:

<form action="process/login.php" method="post">
   <input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>" />
   <label>Email: </label><input type="text" name="email" />
   <div class="space"></div>
   <label>Password: </label><input type="password" name="password" />
   <div class="space"></div>
   <input type="submit" value="Login" class="button" />
</form>

展示一下将令牌放入POST数据中的代码。 - nl-x
你尝试将$_SESSION ['token']的名称改为其他名称吗?例如,尝试使用$_SESSION ['my_app_token']。这样,您就可以确保与其他应用程序/脚本没有冲突了。 - KodeFor.Me
请查看此链接:https://dev59.com/3GjWa4cB1Zd3GeqPmw2q - Viswanath Polaki
1
页面是否在 iframe 中? - Mika Tuupola
你有另一个名为token的输入吗?这种情况以前发生过,所以我想问一下。同时,通过验证器运行页面来检查所有HTML是否正确格式化。Firefox和Chrome往往更加宽容。http://validator.w3.org/ 最后,为了排除一些奇怪的本地IE配置/插件问题,你能在另一台电脑上复制这个问题吗? - Chris Gunawardena
显示剩余15条评论
7个回答

4

由于PHP和会话存储是服务器端的,而IE显然是一个客户端,在您的会话代码中不存在问题。

会话通常由Cookie(会话Cookie)或通过POST / GET变量跟踪。在PHP中,默认情况下,此值的名称为PHPSESSID。

可能,在您的情况下,与您的服务器端会话相关联的会话cookie或POST / GET变量在IE中没有正确传递。对于Cookie,这可能与Cookie设置有关,以及是否允许Cookie。对于POST / GET,可能是您的HTML格式不正确,IE不喜欢,但其他浏览器可以理解。

现在,一旦在IE中丢失该值,PHP就会在每个请求上为该浏览器分配一个新会话,并在每个请求上重新生成会话令牌。但是,您的隐藏字段也记忆着旧令牌……

如果您向我们展示更多代码(您可以编辑您的问题),我可以编辑我的答案以给您更多细节。

编辑 您可以首先向我们显示涉及会话和会话cookie的相关php.ini设置行。并且仔细检查您的IE cookie设置。具体而言,我想知道您是否设置了cookie_path,使cookie仅在同一目录中可用。

也许您甚至已经安装了IE安全设置或附加程序来防止cookie。因此,请尝试检查您的IE设置并禁用所有附加组件,然后再次测试。

还要检查第一个页面(设置会话的页面)和第二个页面(读取会话的页面)是否具有完全相同的域名。

例如,在第一个页面中使用www.yourdomain.com,在第二个页面中不应该是yourdomain.com(没有www),也不应该是www.yourdomain.com.(末尾带有额外的点号)。


感谢您的关注。会话和Cookie没有任何问题。我已经创建了另一个会话$_SESSION ['test'] = 123,在相同的场景下它没有任何问题。当我提交它时,它的值与会话值相等。 - Mohammad Saberi
是的,但由于“123”是一个固定字符串,您不知道它是否在第二个请求中被自己覆盖。我95%确信这是一个cookie问题...尝试使用FF / Chrome中的元素检查器和IE中的F12开发人员工具查看cookie。您可能在IE中看不到它们,或每次看到不同的值。 - nl-x
在php.ini中,我有这个:session.cookie_path = /。第一页和第二页在同一路径下。同时,我在IE中没有任何特殊的插件。 - Mohammad Saberi
你停止回答了! - Mohammad Saberi
@MohammadBagherSaberi Cookie设置似乎没问题。一个好的跟进可能是:在Firefox(FF)和Internet Explorer(IE)中打开您的网站。在FF中打开元素检查器,在IE中打开开发人员工具。您可以通过在浏览器中按F12键来同时打开它们。在两者中都转到网络选项卡。现在刷新并查看页面加载的请求标头。(忽略图像请求等)。特别注意名为PHPSESSID的cookie或POST参数。...然后转到您的第二个页面,并查找相同的cookie / POST参数。 - nl-x
显示剩余5条评论

2
我认为在您的表单提交后,您可能会创建另一个令牌值。
使用:
if(!isset($_POST['token'])){
  $_SESSION['token'] = sha1(uniqid(mt_rand(), true));
}

如果是那样的话,我猜在Chrome或Firefox上对OP不起作用,他说问题是IE特定的。 - aleation
将 type="hidden" 替换为 hidden="yes" - Viswanath Polaki
2
@ViswanathPolaki,你的答案将导致在第二或第三页请求时,$_SESSION['token']不再存在。而且你上面的评论真的很愚蠢,因为这在HTML中是不合法的,并且会使隐藏字段变为可见。 - nl-x

1
我会尝试更改输入的名称,也许IE正在使用令牌名称进行一些奇怪的操作。在网上搜索了一下,但没有提到这一点,为了保险起见并删除此选项,我会这样做。
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>" />

至:

<input type="hidden" name="my_session_token" value="<?php echo $_SESSION['token']; ?>" />

尝试按照上面的评论所述,将$_SESSION['token']更改为$_SESSION['my_session_token']


你尝试将 $_SESSION['token'] 更改为其他名称,例如 $_SESSION['my_session_token'] 吗? - CodeBird
由于 OP 在所有浏览器中都获取到了 $_POST['token'] 的值,因此该值的名称显然不是问题。 - nl-x
由于 OP 使用了 $_SESSION['test'] 进行测试并且正常工作,那么我认为除了命名问题之外别无他法。 - CodeBird
@CodeBird 我不是100%确定。但由于测试OP使用的是固定字符串“123”,所以我担心这并不能证明什么。也许OP想用 $_SESSION['test']=sha1(uniqid(mt_rand(), true));<input type="hidden" name="test" value="<?php echo $_SESSION['test']; ?>" /> 来排除这种可能性? - nl-x
@nl-x 是的,我认为他应该这样做,只是为了确保简单的东西能够正常工作。我的意思是,在进行更复杂的事情之前,我总是更喜欢测试简单的东西。 - CodeBird

1
我几乎可以确定你两次分配了$_SESSION['token']。可能是同一行代码被执行了两次,或者你在其他地方也分配了变量。为了找到问题,你需要定义一个函数作为分配会话条目的包装器。然后调用函数而不是直接分配变量。以下是示例代码:
function assign_token()
{
    $_SESSION['token'] = sha1(uniqid(mt_rand(), true));
}

但是你需要确保在代码中从未直接分配token,而是调用此函数。完成后,如果您有调试器,您只需在此函数内设置断点并查看它被调用的次数和来自哪里。

但是,如果您没有安装调试器,甚至更糟的是,如果分配发生在两个请求中而不是一个请求中,您需要将函数修改为以下内容:

function assign_token()
{
    file_put_contents('/tmp/assign_token.txt', time() ."\n". print_r(debug_backtrace(), true), FILE_APPEND);
    $_SESSION['token'] = sha1(uniqid(mt_rand(), true));
}

添加的这行代码将帮助您跟踪每次调用该函数的时间。即使在两个独立请求中调用两次,也可以通过FILE_APPENDtime()进行识别。第一个函数附加到文件中(显然),因此日志条目不会互相覆盖,第二个函数则有助于知道日志的两个条目是否在同一请求中生成。

就这些了。最后,您可能想要为日志条目设置样式,使其更易读。


我没有两次创建 $_SESSION["token"]。如果你的想法是正确的,我也应该在其他浏览器中看到类似于 FF 和 Chrome 的问题。 - Mohammad Saberi
也许只有在IE中才会发送更新会话的第二个请求!如果我是你,我会在深入更深层次之前考虑这种可能性。 - Mehran

0

如果我错了,请纠正我,但我已经在Chrome FF和IE 7中测试了下面的代码,似乎IE没有任何问题。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form method="POST" action="/">
            <?php
            session_start();
            if(!$_SESSION['token']){
                $_SESSION['token'] = sha1(uniqid(mt_rand(), true));
            }
            ?>
            <input type="hidden" value="<?php echo $_SESSION['token']; ?>" name="token"/>
            <button type="submit" name="send">Send</button>
            <?php
            if(!empty($_POST)){
                var_dump($_POST);
                var_dump($_SESSION['token']);
            }
            ?>
        </form>

    </body>
</html>

如果您的php版本> = 5.4,请尝试使用此命令在php中设置内置服务器():

php -S localhost:88 -t /path/to/your/app

假设您正在本地计算机上进行测试。也许您的服务器上的apache+php堆栈出了一些问题。

我看不出这会改变任何事情。 - nl-x

0
我会更倾向于这样做:
md5(uniqid($_SERVER['REMOTE_ADDR'], true))

确保令牌始终是唯一的。


真的是一个糟糕的想法。容易被黑客攻击。而且仍然没有解释为什么问题存在。 - nl-x

0

检查sha1(uniqid(mt_rand(), true))的值。IE浏览器在名称中包含'-'或'_'时会出现问题-它们无法维护会话!我过去遇到过这个问题两次,总是需要花费几周时间才能解决,而且我很惊讶IE还没有修复它。

只要确保您没有这样的字符即可!


sha1 不是一个名称……它是一个值。 - nl-x

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