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

时间:2016-10-05 18:56:02

标签: 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现在为空!
  5. 示例代码

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

    干杯!

1 个答案:

答案 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