unpack()
Aprende la función unpack() de PHP: firma, códigos de formato, orden de bytes y ejemplos prácticos con pack().
Las cadenas PHP son en realidad secuencias de bytes sin procesar, lo que las convierte en un contenedor natural para datos binarios: cabeceras de imágenes, paquetes de red, formatos de archivo y tramas de protocolo. La función unpack() lee ese flujo de bytes sin procesar y lo convierte en valores PHP ordinarios (enteros, flotantes, cadenas) con los que puedes trabajar. Este artículo cubre la firma de la función, sus códigos de formato, el orden de bytes, los errores más comunes y cómo se complementa con pack().
Sintaxis
unpack(string $format, string $data, int $offset = 0): array|false| Parámetro | Descripción |
|---|---|
$format | Una cadena de formato que describe cómo interpretar los bytes (los códigos se listan a continuación). |
$data | La cadena binaria de la que se leerá. |
$offset | Posición en bytes desde la que empezar a leer (añadido en PHP 7.1). El valor por defecto es 0. |
Devuelve un array asociativo con los valores desempaquetados, o false en caso de error. unpack() es la función inversa de pack(): el diseño que escribes con pack() lo recuperas con los mismos códigos de formato.
Primer ejemplo
La cadena de formato es una secuencia de uno o más códigos. Cada código es una sola letra para un tipo de dato, un contador de repetición opcional y un nombre opcional.
Aquí "C*" significa "leer cada byte restante como un entero sin signo de 8 bits". El contador de repetición * consume todos los bytes disponibles. Cuando no se proporciona un nombre, unpack() numera los resultados empezando por 1 (no 0):
Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)Códigos de formato
Cada código corresponde a un número fijo de bytes. Los más comunes son:
| Código | Tipo | Tamaño |
|---|---|---|
C / c | Char sin signo / con signo | 1 byte |
n | Short sin signo, big-endian | 2 bytes |
v | Short sin signo, little-endian | 2 bytes |
S / s | Short sin signo / con signo, orden de bytes de la máquina | 2 bytes |
N | Long sin signo, big-endian | 4 bytes |
V | Long sin signo, little-endian | 4 bytes |
L / l | Long sin signo / con signo, orden de bytes de la máquina | 4 bytes |
f / d | Float / double, orden de la máquina | 4 / 8 bytes |
a / A | Cadena (rellena con NUL / con espacios) | según se especifique |
H / h | Cadena hexadecimal, nibble alto / bajo primero | por nibble |
Un número después de un código lo repite (C4 lee cuatro chars); un * lee todos los bytes restantes.
Nombrar los campos
Los formatos binarios reales están compuestos de campos mixtos, por lo que generalmente se le da un nombre a cada uno y se separan los códigos con /:
"C2chars/Sint/Nlong" lee los dos primeros bytes como chars1/chars2, los dos siguientes como un short int en orden de máquina, y los últimos cuatro como un long long big-endian:
Array
(
[chars1] => 1
[chars2] => 2
[int] => 1027
[long] => 84281096
)Cuando un código tiene un contador de repetición y un nombre, unpack() añade un índice al nombre (chars1, chars2, …) para que los valores no colisionen.
El orden de bytes importa
Los mismos cuatro bytes representan números diferentes según el orden de bytes. N/n son big-endian (orden de red); V/v son little-endian (nativo en x86); S/L siguen la máquina anfitriona y por tanto no son portables. Para datos que cruzan máquinas — un formato de archivo o un protocolo de red — elige siempre un código con endianness explícito para que el resultado sea el mismo en todas partes.
<?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
)Ida y vuelta con pack()
Dado que unpack() es el reflejo de pack(), puedes serializar valores en un blob binario compacto y recuperarlos directamente con el mismo formato:
<?php
$packed = pack("nN", 1027, 84281096); // build the bytes
$result = unpack("nshort/Nlong", $packed);
print_r($result);
?>Array
(
[short] => 1027
[long] => 84281096
)Errores comunes
- Las claves empiezan en 1. Los resultados sin nombre se indexan desde 1, lo que sorprende al iterar. Nombra tus campos o recuerda el desplazamiento.
- Los nombres con contadores de repetición reciben un sufijo de índice (
byte1,byte2), por lo queunpack("C4byte", ...)producebyte1…byte4, no un solobyte. - Los códigos de orden de máquina (
S,L,s,l) no son portables. Usan/Nov/Vpara cualquier dato almacenado o transmitido. falsesi hay muy pocos datos. Si el formato requiere más bytes de los que contiene$data,unpack()devuelvefalsey emite una advertencia — comprueba el valor de retorno antes de usarlo.
Conclusión
La función unpack() convierte bytes sin procesar en valores PHP usando códigos de formato compactos, y es la mitad lectora del par pack(). Domina los códigos de endianness y la sintaxis de nomenclatura de campos, y podrás analizar prácticamente cualquier cabecera de archivo binario o trama de red. Para convertir datos binarios en una cadena hexadecimal legible, consulta bin2hex().