unpack()
In this article, we will focus on the PHP unpack() function. We will provide you with an overview of the function, how it works, and examples of its use.
PHP strings are really just sequences of raw bytes, which makes them a natural container for binary data — image headers, network packets, file formats, and protocol frames. The unpack() function reads that raw byte stream and turns it into ordinary PHP values (integers, floats, strings) you can work with. This article covers the function's signature, its format codes, endianness, common gotchas, and how it pairs with pack().
Syntax
unpack(string $format, string $data, int $offset = 0): array|false| Parameter | Description |
|---|---|
$format | A format string describing how to interpret the bytes (codes are listed below). |
$data | The binary string to read from. |
$offset | Byte position to start reading from (added in PHP 7.1). Defaults to 0. |
It returns an associative array of the unpacked values, or false on failure. unpack() is the inverse of pack(): whatever layout you write with pack() you read back with the same format codes.
A first example
The format string is a sequence of one or more codes. Each code is a single letter for a data type, an optional repeat count, and an optional name.
Here "C*" means "read every remaining byte as an unsigned 8-bit integer". The * repeat count consumes all available bytes. When you don't supply a name, unpack() numbers the results starting at 1 (not 0):
Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)Format codes
Each code maps to a fixed number of bytes. The most common ones:
| Code | Type | Size |
|---|---|---|
C / c | Unsigned / signed char | 1 byte |
n | Unsigned short, big-endian | 2 bytes |
v | Unsigned short, little-endian | 2 bytes |
S / s | Unsigned / signed short, machine byte order | 2 bytes |
N | Unsigned long, big-endian | 4 bytes |
V | Unsigned long, little-endian | 4 bytes |
L / l | Unsigned / signed long, machine byte order | 4 bytes |
f / d | Float / double, machine order | 4 / 8 bytes |
a / A | String (NUL-padded / space-padded) | as specified |
H / h | Hex string, high / low nibble first | per nibble |
A number after a code repeats it (C4 reads four chars); a * reads all remaining bytes.
Naming the fields
Real binary formats are made of mixed fields, so you usually give each one a name and separate the codes with /:
"C2chars/Sint/Nlong" reads the first two bytes as chars1/chars2, the next two as a machine-order short int, and the last four as a big-endian long long:
Array
(
[chars1] => 1
[chars2] => 2
[int] => 1027
[long] => 84281096
)When a code has a repeat count and a name, unpack() appends an index to the name (chars1, chars2, …) so the values don't collide.
Endianness matters
The same four bytes mean different numbers depending on byte order. N/n are big-endian (network order); V/v are little-endian (x86 native); S/L follow the host machine and are therefore not portable. For data that crosses machines — a file format or a network protocol — always pick an explicit-endian code so the result is the same everywhere.
<?php
$bytes = "\x01\x00\x00\x00";
print_r(unpack("Vlittle", $bytes)); // little-endian: 1
print_r(unpack("Nbig", $bytes)); // big-endian: 16777216
?>Array
(
[little] => 1
)
Array
(
[big] => 16777216
)Round-tripping with pack()
Because unpack() is the mirror image of pack(), you can serialize values to a compact binary blob and read them straight back with the matching format:
<?php
$packed = pack("nN", 1027, 84281096); // build the bytes
$result = unpack("nshort/Nlong", $packed);
print_r($result);
?>Array
(
[short] => 1027
[long] => 84281096
)Common gotchas
- Keys start at 1. Unnamed results are 1-indexed, which trips people up when looping. Name your fields or remember the offset.
- Names with repeat counts get an index suffix (
byte1,byte2), sounpack("C4byte", ...)yieldsbyte1…byte4, not onebyte. - Machine-order codes (
S,L,s,l) aren't portable. Usen/Norv/Vfor anything stored or transmitted. falseon too-little data. If the format demands more bytes than$dataholds,unpack()returnsfalseand emits a warning — check the return value before using it.
Conclusion
The unpack() function turns raw bytes into PHP values using compact format codes, and is the reading half of the pack() pair. Master the endianness codes and the field-naming syntax and you can parse virtually any binary file header or network frame. For converting binary to a readable hex string instead, see bin2hex().