Unexpected PHP unpack () behavior

Test

$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 ); 

results

  Array
 (
     [foo] => f
     [bar] => o
     [baz] => o
 )
  Array
 (
     [foo] => foobarbaz
     [bar] => 
     [baz] => 
 )

Note that the NULL byte always exists, you can check it with hexdump .

Expected Result

  Array
 (
     [foo] => foo
     [bar] => bar
     [baz] => baz
 )

Notes

I know that I can use explode to achieve a similar result. I do not ask for alternatives, I just want to understand the logic of a character of the format a ("NUL-padded string", as doc says).

Where does the NULL value go into all of this?

+6
source share
1 answer

Original answer

"Where is the NULL value involved in all of this?"

Nowhere.

I am sure that updating pack PHP () / unpack () requires updating. Basically wherever you see this, referring to a NULL terminating string, the documentation was taken from a version of Perl code and is not a reflection of what is happening in PHP.

Basically, Perl has C-style strings that can be null-terminated so you know where the end of the string is. In PHP, there is no concept of a NULL character. eg.

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

The lines are the same.

By the way, this is: "Foo \ x00bar \ x00baz"

You probably are not doing what you think. It does not put the "NULL" character on the line between foo + bar and between bar + baz, since there is no NULL character. Instead, it places the character "0", which simply does not print on most character sets, but does not have much meaning as a character.

I know that you mentioned using an explosion instead of unpacking, but if you know the length of the string, you can use:

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

Addendum for clarity.

Cyrus wrote:

With "NULL byte", I mean a byte with a value of 0:

I'm not sure where you got the string "foo \ x00bar \ x00baz", but:

i) It must be from a language that supports the NULL character represented by zero. PHP does not support the NULL character, and if you call pack ("A * A * A *", "foo", "bar", "baz"); It does not generate a string with zeros in it.

ii) The PHP version of the decompression does not support NULL characters (since PHP does not support NULL characters) and treats the character with the hexadecimal value 0 as just another character. eg.

 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"; 

It will display:

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

i.e. it extracts the first three characters, which are the values ​​0x66, 0x6f, 0x6f. He then extracts the following three characters, which are 0x0, 0x62, 0x61. Finally, it retrieves the values ​​0x72, 0x0, 0x62.

+6
source

Source: https://habr.com/ru/post/921203/


All Articles