pack

Packs values into a binary string according to a format of type codes and repeaters.

Signature
pack(string $format, mixed ...$values): string
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$formatstringA sequence of single-letter type codes, each optionally followed by a repeat count or * to consume all remaining values.
$valuesoptionalmixedThe values to pack, in the order the format codes consume them. Variadic.

Return value

stringA binary string containing the packed data.

Errors

Throws a ValueError for an unknown format code, a bad repeater, or when the format asks for more values than were supplied. Verified on PHP 8.5: pack('NN', 1) throws ValueError with the message "Type N: too few arguments", not ArgumentCountError. ArgumentCountError is only raised by the engine when pack() is called with no arguments at all.

Changelog

  • PHP 8.0.0No longer returns false on failure; an invalid format code, a bad repeater or too few values now throw a ValueError instead.
  • PHP 7.2.0float and double codes gained explicit big-endian and little-endian support.
  • PHP 7.1.1The e, E, g and G codes were added for byte-order control on floats and doubles.

pack() turns PHP values into raw bytes. You describe the layout with one letter per field, optionally followed by a count: pack('Nn', $id, $port) writes a 32-bit big-endian integer followed by a 16-bit big-endian one.

Picking the right code

Fixed-width, explicit-endian codes are almost always what you want, because they behave the same on every machine:

  • n/v — unsigned 16-bit, big/little endian
  • N/V — unsigned 32-bit, big/little endian
  • J/P — unsigned 64-bit, big/little endian
  • a/A/Z — NUL-padded, space-padded and NUL-terminated strings

Avoid i, l, s, f and d in anything that crosses machines: their size or byte order follows the host CPU, so a file written on one box may not read back on another.

What trips people up

A repeater on a string code is a width, not a repeat: pack('a10', 'hi') produces one ten-byte field, whereas pack('C10', ...) consumes ten separate values. And the result is binary — echoing it to a terminal or into JSON will mangle it. Wrap it in bin2hex() or base64_encode() for display.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Building a fixed-layout message header for a binary network protocol.
  • Writing a small binary file format such as a custom index or cache header.
  • Converting an integer to its 4-byte big-endian representation for a checksum or hash input.

Frequently asked questions

What is the difference between pack and unpack?

pack() converts PHP values into a binary string; unpack() reads a binary string back into an array of PHP values. They use the same format codes.

Which pack format should I use for a 32-bit integer?

Use N for big-endian (network byte order) or V for little-endian. Avoid l and L unless the data never leaves the current machine, because their byte order follows the CPU.

Why is my packed string shorter than expected?

On string codes the repeater is a field width, not a repeat count, so a10 is one 10-byte field rather than ten fields — check the result with strlen(). Note that pack() does not silently stop when it runs out of values: since PHP 8.0 a format that asks for more values than were supplied throws a ValueError ("Type N: too few arguments") instead of producing a shorter string.

More examples

Endianness made visible

The same number comes out as 0a0b0c0d, 0d0c0b0a and 000000000a0b0c0d, showing exactly how the byte order and width codes differ.

Example · php
<?php
$value = 0x0A0B0C0D;

echo 'N (big endian):    ', bin2hex(pack('N', $value)), "\n";
echo 'V (little endian): ', bin2hex(pack('V', $value)), "\n";
echo 'J (64-bit BE):     ', bin2hex(pack('J', $value)), "\n";

Fixed-width string fields

Each field occupies exactly 8 bytes; the padding differs (NUL, space, NUL-terminated) and unpack shows that A strips trailing whitespace while a keeps the NUL bytes.

Example · php
<?php
$record = pack('a8A8Z8', 'nul', 'space', 'zero');

echo strlen($record), " bytes\n";
echo str_replace("\0", '.', $record), "\n";
print_r(unpack('a8one/A8two/Z8three', $record));

Discussion

  • Be the first to comment on this lesson.