我发现了一些奇怪的行为 - 我很感兴趣 - 任何人都可以对此有所了解吗?
概述
今天早上花了一些时间找出导致$_SESSION
数组为空的错误的原因。最终得到它的底部,发现在为$_SESSION
个变量之一定义索引时,&
被用于连接而不是.
。它只在两个特定字符串被&
编辑时才会中断,其他字符串导致无意义密钥但$_SESSION
没有清空。
这是在PHP5.5.9-1ubuntu4.20上运行,在PHP5.6.15本地运行。
亲自试用!
使用下面的示例代码,
$_SESSION
现在为空!示例代码
设置session.php文件
session_start();
$_SESSION = [
'colour' => 'blue',
'shape' => 'round',
'size' => 'medium'
];
签session.php文件
session_start();
echo '<pre>';
print_r($_SESSION);
盈亏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没有错。但是,我很好奇幕后的实际情况以及造成这种情况的原因......
干杯!
答案 0 :(得分:5)
这是一个简化的测试用例(see it in action):
<?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
documentation我们可以阅读:
较旧的序列化处理程序无法存储数字索引或字符串索引 在
$_SESSION
中包含特殊字符(|和!)。使用php_serialize
以避免数字索引或特殊字符错误 脚本关闭。默认为php
。