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.

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.

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.)

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').

The documentation is clear that an integer read using an unsigned format character will still be stored as a signed integer. The often-cited work-around is to use sprintf('%u', $bigint) to properly display integers with the MSB set.

In the case where the numeric value is more important than how it's displayed, you can still work with other large integers using intval() to "upgrade" your existing unsigned integers.

I had a problem comparing 32-bit integers read from files with hard-coded constants (file signatures tend to need this). Here's what I did to avoid converting everything into strings:

It works, but it's a little backwards. If anyone has any ideas on how to "downgrade" a signed integer into an unsigned integer without using strings, that would be a valuable note to add to the documentation.

This can be verified by checking the value of PHP_INT_SIZE.
If this value is 4, you have a PHP that internally stores 32-bit.
A value of 8 internally stores 64-bit.

To work around this 'problem', you can use the following code to avoid problems with unpack.
The code is for big endian order but can easily be adjusted for little endian order (also, similar code works for 64-bit integers):

Do note that you *could* also use sprintf('%u', $x) to show the unsigned real value.
Also note that (at least when PHP_INT_SIZE = 4) the result WILL be a float value when the input is larger then 0x7fffffff (just check with gettype);

Here's a demonstration concerning the speed of unpacking files:So let's see which method is fastest between FREAD or SUBSTR?

I was creating a script that could read scenario files from a game, and render a preview of its terrain. The terrain structure within each file was huge (between 100,000 - 1,000,000 blocks containing 3 bits of data each). Therefore, I spent much effort to ensure it was fast and robust.

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

This happened to me. I wanted to get a big number from a unsigned long, but it kept coming returning a negative. Happened to notice that sprintf('%u',$dta) will take the useless negative and restore it into its large unsigned proper magnitude.

I hadn't realized that if the number after the unpack type was 1 (i.e. "V1page"), that it would behave as if there was no number at all. I had been using a variable and didn't think to watch for this. For instance,

<?php

if ($something)$get = 2;else$get = 1;

$arr = unpack("V" . $get . "page", $data);

?>

Now if $something was FALSE, then $arr will only have one entry named "page". If $something was TRUE, $arr would have "page1" and "page2".

To convert big endian to little endian or to convert little endian to big endian, use the following approach as an example:

<?php// file_get_contents() returns a binary value, unpack("V*", _ ) returns an unsigned long 32-bit little endian decimal value, but bin2hex() after that would just give the hex data in the file if alone, so instead we use:// file_get_contents(), unpack("V*", _ ), then dechex(), in that order, to get the byte-swapping effect.?>

With the logic of the approach in this example, you can discover how to swap the endian byte order as you need.