首页 > PHP中$_SERVER变量赋值给$_SESSION变量时的注意事项

PHP中$_SERVER变量赋值给$_SESSION变量时的注意事项

以下这段代码保存为test.php

<?php
session_start();
var_dump($_SESSION['test']);
echo '<br />';
$_SESSION['test'] = $_SERVER['PATH_INFO'];
var_dump($_SESSION['test']);
?>
<img src="notice" />

在本地测试这段代码,访问url http://localhost/test.php/a
$_SERVER['PATH_INFO']的值是'/a',赋值后$_SESSION['test']的值是'/a',页面刷新后,在页面开头输出$_SESSION['test']理论上应该也是'/a',可是$_SESSION['test']变成了'notice'。

其中notice的值同<img src="notice" />中src的值,src的值改为其他值相应也会输出同样的值

如图:


感谢邀请,前面都回答得很好了。我补充几点:

  1. 你的提问习惯很好,从“其中notice的值同<img src="notice" />中src的值,src的值改为其他值相应也会输出同样的值”这句话看,你自己研究了一下错误重复出现的规律,浏览器也同时开着《提问的艺术》,值得鼓励。
  2. 你的代码段截得不够严谨,这个要批评。第七行(img标签上面那一行)明显是个语法错误,应该是PHP结束"?>"符,编程世界里,差之毫厘,失之千里,如果不是语法错误,编译器不报错,你可就浪费热心人的时间了

具体来分析你这段代码:

第一次执行的时候,浏览器先后发起了两次HTTP请求,http://localhost/test.php/a 和 http://localhost/test.php/notice,结果会是这样的:

此时,服务器端session文件内容如下:

对第一个HTTP请求(http://localhost/test.php/a),页面显示“Notice: Undefined index”是因为刚刚session_start()之后没有为$_SESSION['test']赋值就去打印它,必然是不存在这个数组下标的,故报错。

接着,把当前的PATH_INFO(即"/a"存入了session文件中),并输出出来,这就是你在浏览器中肉眼看到的效果了。

由于浏览器遇到了img标签,于是,根据src属性又去请求了http://localhost/test.php/notice(请自行参阅src的相对路径,我就不细说了),这个请求是浏览器在后台进行的,它不会改变当前页面的HTML源码,所以,你看不到页面上有什么变化。

test.php实际又被执行了一遍,对第一个var_dump(),它输出“/a”,接着,它把当前的PATH_INFO(即/notice)赋值给$_SESSION['test'],覆盖了session文件的原值(参见上面的截图),然后再执行第二个var_dump()。这些var_dump()的输出在哪里呢?在“http://localhost/test.php/notice”这个HTTP请求的Response里面,这些文本输出显然不是一个合法的图片,所以你的img标签会显示失败。

两个HTTP请求的证据:

可以看到,两个HTTP请求得到的Reponse Body不一样长的(149 Bytes vs 61 Bytes),因为请求http://localhost/test.php/notice时没有“Notice: Undefined index”报错了。

第二次刷页面的时候,还是两个HTTP请求:
最终你看到的页面如下:

第一个HTTP请求(http://localhost/test.php/a):先打印“/notice”(在session文件里能取出了,参见截图),然后用当前PATH_INFO(“/a”)覆盖之,再打印“/a”。

接着浏览器自动发起第二个HTTP请求(http://localhost/test.php/notice):先在后台打印"/a",再赋值“/notice”,再打印"/notice",由于不是合法的图片内容显示失败,你在页面上也看不到变化。

第3至N次跟第二次刷新页面的过程完全一样。

最后:
建议你加调试技能,刷新页面的时候多看HTTP通信的文本内容,多看session文件内容。


关键在

<img src="notice" />

浏览器访问的时候加载了/test.php/notice
这时候就触发了test.php,

$_SESSION['test'] = $_SERVER['PATH_INFO']; //此时为notice

所以即使你再刷新, 第一次打印的也是notice


检查下session是否生效,本地COOKIE里是否有PHPSESSIONID


感谢邀请,null、joyqi已经把问题解释清楚了。
顺便提醒一下,第一次var_dump($_SESSION['test']);时,会触发notice,建议严谨一下例如:

if(isset($_SESSION['test'])){
    var_dump($_SESSION['test']);
}

另外在用chrome时切换到network功能,会发现有一次 http://127.0.0.1/notice 请求。
nginx默认是不支持$_SERVER['PATH_INFO']的,不能保证这个值一定能取到。


我知道问题所在了,问题就在于你提的这个img标签里,你的img标签的src填的是notice。在html中如果你不加任http://xxx的前缀直接放在这里的话,它会访问当前目录下的此文件,也就是你在刷新这个页面的时候,这个页面又通img访问了http://localhost/test.php/notice

因为浏览器识别的是最后一个斜杠/,所以认为当前目录是http://localhost/test.php/。它自动把notice放在后面构成了此次访问的url。那么访问http://localhost/test.php/notice当然就会把pathinfonotice设置到session里面啦,所以你每次刷新看到的实际上是img标签刷新的session。

【热门文章】
【热门文章】