|
|
 |
unpack (PHP 3, PHP 4, PHP 5) unpack -- Unpack data from binary string Descriptionarray unpack ( string format, string data )
unpack() from binary string into array
according to format. Returns array
containing unpacked elements of binary string.
unpack() works slightly different from Perl as
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 /.
Example 1. unpack() example |
<?php
$array = unpack("c2chars/nint", $binarydata);
?>
|
The resulting array will contain the entries "chars1",
"chars2" and "int".
|
| Caution |
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.
|
See also pack() for an explanation of the format
codes.
User Contributed Notes
unpack
info at dreystone dot com
04-May-2005 01:31
Here is my solution to reading a Big-Endian formatted double on an Little-Endian machine.
<?php
function ToDouble($data) {
$t = unpack("C*", pack("S*", 256));
if($t[1] == 1) {
$a = unpack("d*", $data);
} else {
$a = unpack("d*", strrev($data));
}
return (double)$a[1];
}
?>
MagicalTux at FF dot st
28-Apr-2005 09:17
tomlove at gmail dot com gave a code to easily unpack a string. Here's a variant :
<?php
$packed = pack("s*", 123);
list($unpacked) = unpack("s*0", $packed);
?>
$unpacked now holds the value 123, not an array.
unpack() will use numeric keys if you give only numbers (probably same check as is_numeric(), but I didn't test). This can be useful in some cases (like for getting directly your data without using arrays).
tomlove at gmail dot com
01-Jan-2005 11:32
If you have one packed item, here's a quick way to get it out of its array when unpacking:
<?
$packed = pack("s*", 123);
list(,$unpacked) = unpack("s*", $packed);
?>
$unpacked now holds the value 123, not an array.
jjfoerch at earthlink dot net
21-Oct-2004 06:57
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.
<?php
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:
<?php
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.
kennwhite dot nospam at hotmail dot com
28-Aug-2004 02:32
If having a zero-based index is useful/necessary, then instead of:
$int_list = unpack("s*", $some_binary_data);
try:
$int_list = array_merge(unpack("s*", $some_binary_data));
This will return a 0-based array:
$int_list[0] = x
$int_list[1] = y
$int_list[2] = z
...
rather than the default 1-based array returned from unpack when no key is supplied:
$int_list[1] = x
$int_list[2] = y
$int_list[3] = z
...
It's not used often, but array_merge() with only one parameter will compress a sequentially-ordered numeric-index, starting with an index of [0].
Sergio Santana: ssantana at tlaloc dot imta dot mx
09-Jul-2004 12:54
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 <br>\n";
?>
This outputs:
$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:
<format-code> [<count>] [<array-key>] [/ ...],
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,
Sergio.
Sergio Santana: ssantana at tlaloc dot imta dot mx
08-Jul-2004 09:41
Suppose we need to get some kind of internal representation of an integer, say 65, as a four-byte long. Then we use, something like:
<?
$i = 65;
$s = pack("l", $i); echo strlen($s) . "<br>\n";
echo "***$s***<br>\n";
?>
The output is:
X-Powered-By: PHP/4.1.2
Content-type: text/html
4
***A***
(That is the string "A\0\0\0")
Now we want to go back from string "A\0\0\0" to number 65. In this case we can use:
<?
$s = "A\0\0\0"; $arr = unpack("l", $s);
foreach ($arr as $key => $value)
echo "\$arr[$key] = $value<br>\n";
?>
And this outpus:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$arr[] = 65
Let's give the array key a name, say "mykey". In this case, we can use:
<?
$s = "A\0\0\0"; $arr = unpack("lmykey", $s);
foreach ($arr as $key => $value)
echo "\$arr[$key] = $value\n";
?>
An this outpus:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$arr[mykey] = 65
The "unpack" documentation is a little bit confusing. I think a more complete example could be:
<?
$binarydata = "AA\0A";
$array = unpack("c2chars/nint", $binarydata);
foreach ($array as $key => $value)
echo "\$array[$key] = $value <br>\n";
?>
whose output is:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$array[chars1] = 65 <br>
$array[chars2] = 65 <br>
$array[int] = 65 <br>
Note that the format string is something like
<format-code> [<count>] [<array-key>] [/ ...]
I hope this clarifies something
Sergio
David Alsbury
25-Apr-2003 04:04
This is the best example I have found to use unpack. I was finally able to make sense of the documentation afters seeing how they used the function.
http://fooassociates.com/phpfer/html/rn45re878.html
Quick Example:
<?
header("Content-type: text/plain");
$assoc_array = unpack("N2int_var/Cchar_var", "A324&*12J");
echo "int_var1 = ", $assoc_array['int_var1'], "\n";
echo "int_var2 = ", $assoc_array['int_var2'], "\n";
echo "char_var = ", $assoc_array['char_var'], "\n";
?>
Sample Output:
int_var1 = 1093874228
int_var2 = 640299314
char_var = 74
adam at adeptsoftware dot com
16-Jun-2002 11:01
If you just want to extract a dword/long int from a binary string, the following code works beautifully (intel endian):
$Number = ord($Buffer{0}) | (ord($Buffer{1})<<8) | (ord($Buffer{2})<<16) | (ord($Buffer{3})<<24);
DanRichter.at.programmer.dot.net
10-Apr-2001 01:26
If no key name is given [e.g., unpack('C*',$data)], the keys are simply integers starting at 1, and you have a standard array. (I know of no way to get the array to start at zero.)
<P>
If you use multiple types, you must give a key name for all of them (except optionally one), because the key counter is reset with each slash. For example, in unpack('n2/C*',$data), indices 1 and 2 of the returned array are filled by integers ('n'), then overwritten with characters ('C').
iredden at redden dot on dot ca
11-Mar-2000 06:34
function parse_pascalstr($bytes_parsed, $parse_str) {
$parse_info = unpack("x$bytes_parsed/cstr_len", $parse_str);
$str_len = $parse_info["str_len"];
$bytes_parsed = $bytes_parsed + 1;
$parse_info = unpack("x$bytes_parsed/A".$str_len."str", $parse_str);
$str = $parse_info["str"];
$bytes_parsed = $bytes_parsed + strlen($str);
return array($str, $bytes_parsed);
}
| |