【问题标题】:Unexpected behavior of PHP unpack()PHP unpack() 的意外行为
【发布时间】:2012-07-22 19:18:57
【问题描述】:

测试

$x = sprintf( "foo\x00bar\x00baz" );
$y = unpack( 'afoo/abar/abaz' , $x );
print_r( $y );
$x = sprintf( "foo\x00bar\x00baz" );
$y = unpack( 'a*foo/a*bar/a*baz' , $x );
print_r( $y );

结果

大批 ( [foo] => f [酒吧] => o [巴兹] => o ) 大批 ( [foo] => foobarbaz [酒吧] => [巴兹] => )

注意,NULL 字节始终存在,您可以使用hexdump 进行检查。

预期结果

大批 ( [foo] => 富 [酒吧] => 酒吧 [巴兹] => 巴兹 )

注意事项

我知道我可以使用explode 来获得类似的结果。我不是在问替代方案,我只是想了解 a 格式字符背后的逻辑(文档说“NUL-padded string”)。

“NULL”值在哪里涉及到这一切?

【问题讨论】:

    标签: php unpack


    【解决方案1】:

    原答案

    ““NULL”值在哪里涉及到这一切?”

    无处可去。

    我很确定 PHP pack()/unpack() 的文档需要更新。基本上,无论你在哪里看到它指的是一个以 NULL 结尾的字符串,文档都是取自 Perl 版本的代码,而不是 PHP 中发生的事情的反映。

    基本上 Perl 有 C 风格的字符串,它可以以 null 结尾,让您知道字符串的结尾在哪里。在 PHP 中没有 NULL 字符的概念。例如

    $test1 = "Test".NULL."ing";
    $test2 = "Testing";
    
    if(strcmp($test1, $test2) == 0){
        echo "The strings are the same";
    }
    else{
        echo "They are different.";
    }
    

    将打印“字符串相同”。

    顺便说一句: "foo\x00bar\x00baz"

    可能没有做你认为它正在做的事情。它没有在 foo + bar 之间和 bar + baz 之间的字符串中放置“NULL”字符,因为没有 NULL 字符。取而代之的是放置字符“0”,它恰好在大多数字符集中没有被打印出来,但作为字符没有特殊含义。

    我知道你提到过使用explode而不是unpack,但如果你知道字符串长度,那么你可以使用:

    unpack( 'a3foo/a3bar/a3baz' , $binarydata);
    

    为清楚起见添加

    赛勒斯写道:

    “NULL byte”是指值为 0 的字节:

    我不确定你从哪里得到字符串 "foo\x00bar\x00baz" 但是:

    i) 它必须来自支持由零表示的 NULL 字符的语言。 PHP 不支持 NULL 字符,如果你调用 包(“A*A*A*”、“foo”、“bar”、“baz”); 它不会生成包含零的字符串。

    ii) PHP 版本的 unpack 不支持 NULL 字符(因为 PHP 不支持 NULL 字符)并将十六进制值为 0 的字符视为另一个字符。例如

    function strToHex($string){
        $hex='';
        for ($i=0; $i < strlen($string); $i++)
        {
            $hex .= dechex(ord($string[$i]));
        }
        return $hex;
    }
    
    $binarydata = "foo\x00bar\x00baz";
    
    echo "binarydata is ";
    
    var_dump($binarydata);
    $y = unpack( 'a3foo/a3bar/a3baz' , $binarydata);
    var_dump( $y );
    
    echo strToHex($y['foo'])."\r\n";
    echo strToHex($y['bar'])."\r\n";
    echo strToHex($y['baz'])."\r\n";
    

    将输出:

    binarydata is string(11) "foobarbaz"
    array(3) {
      ["foo"]=>
      string(3) "foo"
      ["bar"]=>
      string(3) "ba"
      ["baz"]=>
      string(3) "rb"
    }
    666f6f
    06261
    72062
    

    即它提取值 0x66、0x6f、0x6f 的前三个字符。然后它提取接下来的三个字符,即 0x0、0x62、0x61。最后,它提取值 0x72、0x0、0x62。

    【讨论】:

    • 如果您不知道字符串长度,我不知道如何使用 unpack。 Perl 支持,但 PHP 显然不支持,所以我问了一个问题 stackoverflow.com/questions/11632773/…
    • 我可以同意糟糕的文档...但请注意"Test\x00ing""Test".NULL."ing" 绝对不是一回事。
    • 是的,我的意思是它们都不会导致中间有 NULL 的字符串,所以当您说“注意 NULL 字节始终存在”时,您可能将字符 0 与空。
    • "NULL byte" 是指值为 0 的字节:php -r 'echo "foo\x00bar\x00baz";' | hd
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    • 2016-06-03
    • 1970-01-01
    相关资源
    最近更新 更多