我发现了一些奇怪的行为-我很好奇-谁能解释一下这个…?
今天早上花了一些时间找到导致$_SESSION
数组为空的错误的原因。最后查了一下,发现在为其中一个$_SESSION
变量定义索引时,使用的是&
而不是.
。只有当两个特定字符串为&
时,它才会中断,其他字符串导致无意义的键,但$_SESSION
不为空。
这是在PHP5.5.9-1ubuntu4.20和本地PHP5.6.15上运行。
你自己试试!
使用下面的示例代码,
- 运行set-session.php
- 运行check-session.php -一切正常
- 运行break-session.php -目前还好…
- 再次运行check-session.php -
$_SESSION
现在为空!
set-session.php
session_start();
$_SESSION = [
'colour' => 'blue',
'shape' => 'round',
'size' => 'medium'
];
check-session.php
session_start();
echo '<pre>';
print_r($_SESSION);
break-session.php
session_start();
$killer_string = 'Admin_CH_1_' & '101_';
$_SESSION[$killer_string] = null;
echo '<pre>';
print_r($_SESSION);
我猜
我猜按位操作的结果是一个字符串,在本例中是$killer_string
,这导致PHP在试图将$_SESSION
数组存储在服务器上时生气。奇怪的是,当$killer_string
被用作$_SESSION
子数组的键时,它不再是一个杀手了。
想法?
我知道代码实际上没有意义,所以PHP没有错。然而,我很好奇幕后到底发生了什么,是什么导致了这一切……
干杯!
下面是一个简化的测试用例(查看实际操作):
<?php
header('Content-Type: text/plain');
ob_start();
session_start();
$_SESSION = [
'colour' => 'blue',
'shape' => 'round',
'size' => 'medium',
//'Admin_CH_1_' & '101_' => 'Gone',
chr(0x01) . chr(0x20) . chr(0x21) . chr(0x49) => 'Gone',
];
var_dump($_SESSION);
session_write_close();
session_start();
var_dump($_SESSION);
ob_end_flush();
如果你检查会话文件,你可以看到它是零字节。
到目前为止,我最好的猜测是(直到有更聪明的人分享到PHP github repo的链接与特定的内部),你无意中推动了会话序列化代码的限制。这些代码假设键是非二进制字符串。有一定的验证(纯数字键触发跳过数字键通知),但它不包括所有可能的格式错误输入。在某些时候,它会崩溃。
这得到了以下事实的支持:更改序列化方法修复问题:
ini_set('session.serialize_handler', 'php_serialize');
在session.serialize_handler
文档中我们可以读到:
旧的序列化处理程序不能存储数字索引和字符串索引
$_SESSION
包含特殊字符(|和!)。使用php_serialize
以避免数字索引或特殊字符错误脚本关闭。默认为php
。