我发现了一些奇怪的行为 - 我很感兴趣 - 任何人都可以对此有所了解......?
概观
今天早上花了一些时间找出导致$_SESSION数组清空的错误原因.最终得到它的底部,并发现在为其中一个$_SESSION变量定义一个索引时,一个&被用于连接而不是一个..它只在两个特定字符串被&编辑时断开,其他字符串导致无意义键但$_SESSION不为空.
这在PHP5.5.9-1ubuntu4.20上运行,在PHP5.6.15本地运行.
亲自尝试一下!
使用下面的示例代码,
$_SESSION现在是空的!示例代码
设置session.php文件
session_start();
$_SESSION = [
'colour' => 'blue',
'shape' => 'round',
'size' => 'medium'
];
Run Code Online (Sandbox Code Playgroud)
入住session.php文件
session_start();
echo '<pre>';
print_r($_SESSION);
Run Code Online (Sandbox Code Playgroud)
突破session.php文件
session_start();
$killer_string = 'Admin_CH_1_' & '101_';
$_SESSION[$killer_string] = null;
echo '<pre>';
print_r($_SESSION);
Run Code Online (Sandbox Code Playgroud)
我猜
我猜测按位运算的结果导致字符串,在这种情况下$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();
Run Code Online (Sandbox Code Playgroud)
如果检查会话文件,则可以看到它具有零字节.
到目前为止我最好的猜测(直到有人聪明地与特定的内部组件共享PHP github repo的链接)是你无意中推动了会话序列化代码的限制.此类代码假定密钥是非二进制字符串.有一定的验证(纯数字键触发跳过数字键通知),但它不包括所有可能的格式错误的输入.在某些时候它只是崩溃.
更改序列化方法可以解决问题:
ini_set('session.serialize_handler', 'php_serialize');
Run Code Online (Sandbox Code Playgroud)
在session.serialize_handler文档中我们可以阅读:
较旧的序列化处理程序不能存储数字索引,也不能在字符串索引中包含特殊字符(|和!)
$_SESSION.使用php_serialize以避免在脚本关闭数字索引或特殊字符错误.默认为php.