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

Ste*_*eve 7 php

我发现了一些奇怪的行为 - 我很感兴趣 - 任何人都可以对此有所了解......?

概观

今天早上花了一些时间找出导致$_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现在是空的!

示例代码

设置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没有错.但是,我很好奇幕后的实际情况以及造成这种情况的原因......

干杯!

Álv*_*lez 5

这是一个简化的测试用例(见实际操作):

<?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.