unpack()
Découvrez la fonction PHP unpack() : fonctionnement, codes de format, boutisme et exemples pratiques pour lire des données binaires.
Les chaînes PHP ne sont en réalité que des séquences d'octets bruts, ce qui en fait un conteneur naturel pour les données binaires — en-têtes d'images, paquets réseau, formats de fichiers et trames de protocoles. La fonction unpack() lit ce flux d'octets bruts et le transforme en valeurs PHP ordinaires (entiers, flottants, chaînes) avec lesquelles vous pouvez travailler. Cet article couvre la signature de la fonction, ses codes de format, le boutisme, les pièges courants et la façon dont elle s'utilise avec pack().
Syntaxe
unpack(string $format, string $data, int $offset = 0): array|false| Paramètre | Description |
|---|---|
$format | Une chaîne de format décrivant comment interpréter les octets (les codes sont listés ci-dessous). |
$data | La chaîne binaire à lire. |
$offset | Position en octets à partir de laquelle commencer la lecture (ajouté en PHP 7.1). Par défaut 0. |
La fonction retourne un tableau associatif des valeurs décompressées, ou false en cas d'échec. unpack() est l'inverse de pack() : quelle que soit la disposition écrite avec pack(), vous la relisez avec les mêmes codes de format.
Premier exemple
La chaîne de format est une séquence d'un ou plusieurs codes. Chaque code est une seule lettre pour un type de données, un nombre de répétitions optionnel et un nom optionnel.
Ici "C*" signifie « lire chaque octet restant comme un entier non signé de 8 bits ». Le compteur de répétition * consomme tous les octets disponibles. Lorsque vous ne fournissez pas de nom, unpack() numérote les résultats en commençant à 1 (et non 0) :
Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)Codes de format
Chaque code correspond à un nombre fixe d'octets. Les plus courants :
| Code | Type | Taille |
|---|---|---|
C / c | Char non signé / signé | 1 octet |
n | Short non signé, big-endian | 2 octets |
v | Short non signé, little-endian | 2 octets |
S / s | Short non signé / signé, ordre machine | 2 octets |
N | Long non signé, big-endian | 4 octets |
V | Long non signé, little-endian | 4 octets |
L / l | Long non signé / signé, ordre machine | 4 octets |
f / d | Float / double, ordre machine | 4 / 8 octets |
a / A | Chaîne (complétée par NUL / espaces) | selon spécification |
H / h | Chaîne hexadécimale, demi-octet de poids fort / faible en premier | par demi-octet |
Un nombre après un code le répète (C4 lit quatre chars) ; un * lit tous les octets restants.
Nommer les champs
Les formats binaires réels sont composés de champs mixtes, il est donc courant de donner un nom à chacun et de séparer les codes par / :
"C2chars/Sint/Nlong" lit les deux premiers octets en tant que chars1/chars2, les deux suivants en tant que short int dans l'ordre machine, et les quatre derniers en tant que long long big-endian :
Array
(
[chars1] => 1
[chars2] => 2
[int] => 1027
[long] => 84281096
)Lorsqu'un code possède un compteur de répétition et un nom, unpack() ajoute un index au nom (chars1, chars2, …) pour éviter les collisions.
Le boutisme est important
Les mêmes quatre octets représentent des nombres différents selon l'ordre des octets. N/n sont big-endian (ordre réseau) ; V/v sont little-endian (natif x86) ; S/L suivent la machine hôte et ne sont donc pas portables. Pour des données échangées entre machines — un format de fichier ou un protocole réseau — choisissez toujours un code à boutisme explicite afin que le résultat soit identique partout.
<?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
)Aller-retour avec pack()
Puisque unpack() est le miroir de pack(), vous pouvez sérialiser des valeurs dans un blob binaire compact et les relire directement avec le format correspondant :
<?php
$packed = pack("nN", 1027, 84281096); // build the bytes
$result = unpack("nshort/Nlong", $packed);
print_r($result);
?>Array
(
[short] => 1027
[long] => 84281096
)Pièges courants
- Les clés commencent à 1. Les résultats sans nom sont indexés à partir de 1, ce qui peut surprendre lors d'une boucle. Nommez vos champs ou pensez à cet décalage.
- Les noms avec compteur de répétition reçoivent un suffixe d'index (
byte1,byte2), doncunpack("C4byte", ...)produitbyte1…byte4, pas un seulbyte. - Les codes d'ordre machine (
S,L,s,l) ne sont pas portables. Utilisezn/Nouv/Vpour tout ce qui est stocké ou transmis. falsesi les données sont insuffisantes. Si le format exige plus d'octets que$datan'en contient,unpack()retournefalseet émet un avertissement — vérifiez la valeur de retour avant de l'utiliser.
Conclusion
La fonction unpack() transforme des octets bruts en valeurs PHP à l'aide de codes de format compacts, et constitue la moitié lecture de la paire pack(). Maîtrisez les codes de boutisme et la syntaxe de nommage des champs, et vous pourrez analyser pratiquement n'importe quel en-tête de fichier binaire ou trame réseau. Pour convertir des données binaires en chaîne hexadécimale lisible, consultez bin2hex().