为什么这个索引字符串要清除$_SESSION数组?


Why does this index string clear the $_SESSION array?

我发现了一些奇怪的行为-我很好奇-谁能解释一下这个…?

今天早上花了一些时间找到导致$_SESSION数组为空的错误的原因。最后查了一下,发现在为其中一个$_SESSION变量定义索引时,使用的是&而不是.。只有当两个特定字符串为&时,它才会中断,其他字符串导致无意义的键,但$_SESSION不为空。

这是在PHP5.5.9-1ubuntu4.20和本地PHP5.6.15上运行。

你自己试试!

使用下面的示例代码,

  1. 运行set-session.php
  2. 运行check-session.php -一切正常
  3. 运行break-session.php -目前还好…
  4. 再次运行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