miguelmota / util.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
function string2ByteArray ( $ string ) |
return unpack( ‘C*’ , $ string ); |
> |
function byteArray2String ( $ byteArray ) |
$ chars = array_map(» chr «, $ byteArray ); |
return join( $ chars ); |
> |
function byteArray2Hex ( $ byteArray ) |
$ chars = array_map(» chr «, $ byteArray ); |
$ bin = join( $ chars ); |
return bin2hex( $ bin ); |
> |
function hex2ByteArray ( $ hexString ) |
$ string = hex2bin( $ hexString ); |
return unpack( ‘C*’ , $ string ); |
> |
function string2Hex ( $ string ) |
return bin2hex( $ string ); |
> |
function hex2String ( $ hexString ) |
return hex2bin( $ hexString ); |
> |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
include ( ‘./util.php’ ); |
$ byteArray = unpack( ‘C*’ , ‘hello’ ); |
assert(string2ByteArray( ‘hello’ ) == $ byteArray ); |
assert(byteArray2String( $ byteArray ) == ‘hello’ ); |
assert(byteArray2Hex( $ byteArray ) == ‘68656c6c6f’ ); |
assert(hex2ByteArray( ‘68656c6c6f’ ) == $ byteArray ); |
assert(string2Hex( ‘hello’ ) == ‘68656c6c6f’ ); |
assert(hex2String( ‘68656c6c6f’ ) == ‘hello’ ); |
?> |
Free Online Tutorials
The PHP’s core offers some function to convert data between binary, decimal, hexadecimal and etc. But how to convert from binary to text, we offer some function to do that.
Method 1: using functions pack and base_convert
echo binToStr('1110100011101010111010001101111'); //tuto
But with the long binary data, we can’t convert
echo binToStr('0111010001110101011101000110111101110010011010010110000101101100011100110111000001101111011101000111001100101110011000110110111101101101'); //tutori`
Because of the function base_convert can’t work with the big number. The limitation is:
echo(PHP_INT_MAX);//2147483647
What’s the sulution? we can split the binary into chunks, convert each chunk to string and join them. We must change the above function:
function binToStr($input) < if (!is_string($input)) return false; $chunks = str_split($input,8); $ret = ''; foreach ($chunks as $chunk) < $temp = base_convert($chunk, 2, 16); $ret .= pack('H*',str_repeat("0", 2 - strlen($temp)) . $temp); >return $ret; >
echo binToStr('0111010001110101011101000110111101110010011010010110000101101100011100110111000001101111011101000111001100101110011000110110111101101101'); //tutorialspots.com
Method 2: use function bindec and chr to convert
function binToStr($input) < if (!is_string($input)) return false; $chunks = str_split($input,8); $ret = ''; foreach ($chunks as $chunk) < $ret .= chr(bindec($chunk)); >return $ret; >
echo binToStr('01110000011010000111000001110100011101010111010001110011'); //phptuts
unpack
Unpacks from a binary string into an array according to the given format .
The unpacked data is stored in an associative array. To accomplish this you have to name the different format codes and separate them by a slash /. If a repeater argument is present, then each of the array keys will have a sequence number behind the given name.
- The «a» code now retains trailing NULL bytes.
- The «A» code now strips all trailing ASCII whitespace (spaces, tabs, newlines, carriage returns, and NULL bytes).
- The «Z» code was added for NULL-padded strings, and removes trailing NULL bytes.
Parameters
See pack() for an explanation of the format codes.
The offset to begin unpacking from.
Return Values
Returns an associative array containing unpacked elements of binary string, or false on failure.
Changelog
Version | Description |
---|---|
7.2.0 | float and double types supports both Big Endian and Little Endian. |
7.1.0 | The optional offset has been added. |
Examples
Example #1 unpack() example
$binarydata = «\x04\x00\xa0\x00» ;
$array = unpack ( «cchars/nint» , $binarydata );
print_r ( $array );
?>?php
The above example will output:
Example #2 unpack() example with a repeater
$binarydata = «\x04\x00\xa0\x00» ;
$array = unpack ( «c2chars/nint» , $binarydata );
print_r ( $array );
?>?php
The above example will output:
Array ( [chars1] => 4 [chars2] => 0 [int] => 40960 )
Notes
Note that PHP internally stores integral values as signed. If you unpack a large unsigned long and it is of the same size as PHP internally stored values the result will be a negative number even though unsigned unpacking was specified.
If you do not name an element, numeric indices starting from 1 are used. Be aware that if you have more than one unnamed element, some data is overwritten because the numbering restarts from 1 for each element.
Example #3 unpack() example with unnamed keys
The above example will output:
Note that the first value from the c specifier is overwritten by the first value from the n specifier.
See Also
User Contributed Notes 14 notes
A helper class to convert integer to binary strings and vice versa. Useful for writing and reading integers to / from files or sockets.
class int_helper
public static function int8 ( $i ) return is_int ( $i ) ? pack ( «c» , $i ) : unpack ( «c» , $i )[ 1 ];
>
public static function uInt8 ( $i ) return is_int ( $i ) ? pack ( «C» , $i ) : unpack ( «C» , $i )[ 1 ];
>
public static function int16 ( $i ) return is_int ( $i ) ? pack ( «s» , $i ) : unpack ( «s» , $i )[ 1 ];
>
public static function uInt16 ( $i , $endianness = false ) $f = is_int ( $i ) ? «pack» : «unpack» ;
if ( $endianness === true ) < // big-endian
$i = $f ( «n» , $i );
>
else if ( $endianness === false ) < // little-endian
$i = $f ( «v» , $i );
>
else if ( $endianness === null ) < // machine byte order
$i = $f ( «S» , $i );
>
return is_array ( $i ) ? $i [ 1 ] : $i ;
>
public static function int32 ( $i ) return is_int ( $i ) ? pack ( «l» , $i ) : unpack ( «l» , $i )[ 1 ];
>
public static function uInt32 ( $i , $endianness = false ) $f = is_int ( $i ) ? «pack» : «unpack» ;
if ( $endianness === true ) < // big-endian
$i = $f ( «N» , $i );
>
else if ( $endianness === false ) < // little-endian
$i = $f ( «V» , $i );
>
else if ( $endianness === null ) < // machine byte order
$i = $f ( «L» , $i );
>
return is_array ( $i ) ? $i [ 1 ] : $i ;
>
public static function int64 ( $i ) return is_int ( $i ) ? pack ( «q» , $i ) : unpack ( «q» , $i )[ 1 ];
>
public static function uInt64 ( $i , $endianness = false ) $f = is_int ( $i ) ? «pack» : «unpack» ;
if ( $endianness === true ) < // big-endian
$i = $f ( «J» , $i );
>
else if ( $endianness === false ) < // little-endian
$i = $f ( «P» , $i );
>
else if ( $endianness === null ) < // machine byte order
$i = $f ( «Q» , $i );
>
return is_array ( $i ) ? $i [ 1 ] : $i ;
>
>
?>
Usage example:
Header ( «Content-Type: text/plain» );
include( «int_helper.php» );
echo int_helper :: uInt8 ( 0x6b ) . PHP_EOL ; // k
echo int_helper :: uInt8 ( 107 ) . PHP_EOL ; // k
echo int_helper :: uInt8 ( «\x6b» ) . PHP_EOL . PHP_EOL ; // 107
echo int_helper :: uInt16 ( 4101 ) . PHP_EOL ; // \x05\x10
echo int_helper :: uInt16 ( «\x05\x10» ) . PHP_EOL ; // 4101
echo int_helper :: uInt16 ( «\x05\x10» , true ) . PHP_EOL . PHP_EOL ; // 1296
echo int_helper :: uInt32 ( 2147483647 ) . PHP_EOL ; // \xff\xff\xff\x7f
echo int_helper :: uInt32 ( «\xff\xff\xff\x7f» ) . PHP_EOL . PHP_EOL ; // 2147483647
// Note: Test this with 64-bit build of PHP
echo int_helper :: uInt64 ( 9223372036854775807 ) . PHP_EOL ; // \xff\xff\xff\xff\xff\xff\xff\x7f
echo int_helper :: uInt64 ( «\xff\xff\xff\xff\xff\xff\xff\x7f» ) . PHP_EOL . PHP_EOL ; // 9223372036854775807
This is about the last example of my previous post. For the sake of clarity, I’m including again here the example, which expands the one given in the formal documentation:
$binarydata = «AA\0A»;
$array = unpack(«c2chars/nint», $binarydata);
foreach ($array as $key => $value)
echo «\$array[$key] = $value
\n»;
?>
$array[chars1] = 65
$array[chars2] = 65
$array[int] = 65
Here, we assume that the ascii code for character ‘A’ is decimal 65.
Remebering that the format string structure is:
[] [] [/ . ],
in this example, the format string instructs the function to
1. («c2. «) Read two chars from the second argument («AA . ),
2. (. chars. ) Use the array-keys «chars1», and «chars2» for
these two chars read,
3. (. /n. ) Read a short int from the second argument (. \0A»),
4. (. int») Use the word «int» as the array key for the just read
short.
I hope this is clearer now,
I had a situation where I had to unpack a file filled with little-endian order double-floats in a way that would work on either little-endian or big-endian machines. PHP doesn’t have a formatting code that will change the byte order of doubles, so I wrote this workaround.
/*The following code is a workaround for php’s unpack function
which does not have the capability of unpacking double precision
floats that were packed in the opposite byte order of the current
machine.
*/
function big_endian_unpack ( $format , $data ) $ar = unpack ( $format , $data );
$vals = array_values ( $ar );
$f = explode ( ‘/’ , $format );
$i = 0 ;
foreach ( $f as $f_k => $f_v ) $repeater = intval ( substr ( $f_v , 1 ));
if ( $repeater == 0 ) $repeater = 1 ;
if ( $f_v < 1 >== ‘*’ )
$repeater = count ( $ar ) — $i ;
>
if ( $f_v < 0 >!= ‘d’ ) < $i += $repeater ; continue; >
$j = $i + $repeater ;
for ( $a = $i ; $a < $j ; ++ $a )
$p = pack ( ‘d’ , $vals [ $i ]);
$p = strrev ( $p );
list ( $vals [ $i ]) = array_values ( unpack ( ‘d1d’ , $p ));
++ $i ;
>
>
$a = 0 ;
foreach ( $ar as $ar_k => $ar_v ) $ar [ $ar_k ] = $vals [ $a ];
++ $a ;
>
return $ar ;
>
list ( $endiantest ) = array_values ( unpack ( ‘L1L’ , pack ( ‘V’ , 1 )));
if ( $endiantest != 1 ) define ( ‘BIG_ENDIAN_MACHINE’ , 1 );
if ( defined ( ‘BIG_ENDIAN_MACHINE’ )) $unpack_workaround = ‘big_endian_unpack’ ;
else $unpack_workaround = ‘unpack’ ;
?>
This workaround is used like this:
function foo () global $unpack_workaround ;
$bar = $unpack_workaround ( ‘N7N/V2V/d8d’ , $my_data );
//.
>
?>
On a little endian machine, $unpack_workaround will simply point to the function unpack. On a big endian machine, it will call the workaround function.
Note, this solution only works for doubles. In my project I had no need to check for single precision floats.