pack

Description

The idea for this function was taken from Perl and all formatting codes
work the same as in Perl. However, there are some formatting codes that are
missing such as Perl's "u" format code.

Note that the distinction between signed and unsigned values only
affects the function unpack(), where as
function pack() gives the same result for
signed and unsigned format codes.

Parameters

format

The format string consists of format codes
followed by an optional repeater argument. The repeater argument can
be either an integer value or * for repeating to
the end of the input data. For a, A, h, H the repeat count specifies
how many characters of one data argument are taken, for @ it is the
absolute position where to put the next data, for everything else the
repeat count specifies how many data arguments are consumed and packed
into the resulting binary string.

Return Values

Changelog

The "e", "E", "g" and "G" codes were added to enable byte order support for float and double.

5.6.3

The "q", "Q", "J" and "P" codes were added to enable working with 64-bit numbers.

5.5.0

The "Z" code was added with equivalent functionality to "a" for Perl
compatibility.

Examples

Example #1 pack() example

<?php$binarydata = pack("nvc*", 0x1234, 0x5678, 65, 66);?>

The resulting binary string will be 6 bytes long and contain
the byte sequence 0x12, 0x34, 0x78, 0x56, 0x41, 0x42.

Notes

Caution

Note that PHP internally stores integer values as
signed values of a machine-dependent size (C type long).
Integer literals and operations that yield numbers outside the bounds of the
integer type will be stored as float.
When packing these floats as integers, they are first cast into the integer
type. This may or may not result in the desired byte pattern.

The most relevant case is when packing unsigned numbers that would
be representable with the integer type if it were unsigned.
In systems where the integer type has a 32-bit size, the cast
usually results in the same byte pattern as if the integer were
unsigned (although this relies on implementation-defined unsigned to signed
conversions, as per the C standard). In systems where the
integer type has 64-bit size, the float most
likely does not have a mantissa large enough to hold the value without
loss of precision. If those systems also have a native 64-bit C
int type (most UNIX-like systems don't), the only way to
use the I pack format in the upper range is to create
integer negative values with the same byte representation
as the desired unsigned value.

$binarydata = pack ("n v c*", 0x1234, 0x5678, 65, 66);
In PHP it seems that no whitespaces are allowed in the first parameter. So if you want to convert your pack command from perl -> PHP, don't forget to remove the whitespaces!

If you need to unpack a signed short from big-endian or little-endian specifically, instead of machine-byte-order, you need only unpack it as the unsigned form, and then if the result is >= 2^15, subtract 2^16 from it.

Even though in a 64-bit architecure intval(6123456789) = 6123456789, and sprintf('%b', 5000000000) = 100101010000001011111001000000000
pack will not treat anything passed to it as 64-bit. If you want to pack a 64-bit integer:

This is how I used pack to convert base2 to base64 since base_convert doesn't support base64The base conversions don't work for long strings, which is why I convert 1 byte at a timeHope this helps someone

Or intarray (by the same person) if you don't mind using a slightly experimental package which may have problems sharing data between differently byte/bit ordered architectures.

I don't believe it would be too difficult to shove a serialize function and unserialize function in there if you rip out the code from igbinary for storing numeric arrays with the correct endianess. Looking at `igbinary_serialize32` and `igbinary_unserialize32` in igbinary.c it should be very easy to copy that functionality to intarray.c.

When trying to create a ZIP file using the pack function - I experienced trouble with the "a" code - It converted all chars correct from the std. ASCII charset but not more language specific like ÆøÅ.It seems that ZIP files do not use the same HEX for these as everything else does. The fix was a quick workaround but you'll probably get the picture:function UniHex($str) { // æ ø å Æ Ø Å //These are simply one HEX code being replaced by another to correct the issue $except = array("E6"=>"91","F8"=>"9B","E5"=>"86","C6"=>"92","D8"=>"9D", "C5"=>"8F"); for($i = 0; $i < strlen($str); $i++) { $hex = bin2hex(substr($str, $i, 1)); if ($except[strtoupper($hex)]) $hex = $except[strtoupper($hex)]; $return .= $hex; } return $return;}And then i replaced an "a100" code with "H".strlen(uniHex($mystring))

This is like i said a quick workaround, but if you find the real reason for this i'd be happy to see it