pack()
Cet article présente la fonction PHP pack() : son fonctionnement, la mini-langue de format qu'elle utilise et des exemples pratiques.
Cet article présente la fonction pack() de PHP : ce qu'elle fait, la mini-langue de chaîne de format qu'elle utilise, comment l'ordre des octets (endianness) influence le résultat, et des exemples pratiques que vous pouvez exécuter — y compris le voyage retour avec unpack().
Ce que fait pack()
pack() prend des valeurs PHP ordinaires (entiers, flottants, chaînes) et les dispose octet par octet dans une seule chaîne binaire — une chaîne dont les caractères sont des octets bruts plutôt que du texte lisible.
pack(string $format, mixed ...$values): string$format— une chaîne de format compacte qui décrit, dans l'ordre, comment chaque valeur doit être encodée (son type, sa taille et son ordre d'octets)....$values— une ou plusieurs valeurs à encoder, associées de gauche à droite aux codes de format.
La valeur de retour est une chaîne binaire. Comme ces octets ne sont généralement pas imprimables, les exemples ci-dessous passent le résultat par bin2hex() pour voir exactement quels octets ont été produits (deux chiffres hexadécimaux = un octet).
Quand l'utiliser ?
On recourt à pack() chaque fois que PHP doit parler un format défini en octets bruts plutôt qu'en texte :
- Protocoles binaires — construction de paquets réseau où un en-tête est « une longueur sur 2 octets suivie d'un identifiant sur 4 octets ».
- Formats de fichiers binaires — écriture de chunks PNG, d'en-têtes WAV, ou de toute mise en page à champs de largeur fixe.
- Auxiliaires de hachage/crypto — conversion d'un condensé hexadécimal en sa forme d'octets bruts à passer à
hash_hmac()ouopenssl_*. - Communication avec des systèmes C/embarqués qui attendent des champs de taille fixe et d'endianness fixe.
Pour le stockage PHP-vers-PHP, serialize() ou json_encode() sont plus pratiques ; pack() excelle quand la disposition des octets elle-même est importante.
Premier exemple
123 en hexadécimal vaut 0x7b. Le code de format N signifie « unsigned long (4 octets), ordre réseau », donc la valeur est complétée à quatre octets et écrite avec l'octet le plus significatif en premier : 00 00 00 7b.
Lire la chaîne de format
Une chaîne de format est une séquence de codes de format, chacun suivi optionnellement d'un compteur de répétition :
N one unsigned long
N4 four unsigned longs in a row
N* as many unsigned longs as there are remaining values
A10 a 10-character space-padded stringVous pouvez concaténer des codes pour décrire un enregistrement complet. Les valeurs passées doivent correspondre aux codes dans l'ordre :
<?php
// A 2-byte short (1) followed by a 4-byte long (16909060)
$header = pack('nN', 1, 16909060);
echo bin2hex($header); // 000101020304
?>Ici, n produit 00 01 (le short 1) et N produit 01 02 03 04 (le long 16909060, qui vaut 0x01020304). Les octets apparaissent exactement dans l'ordre où les codes ont été écrits.
Ordre des octets (endianness)
Le même nombre peut être stocké avec ses octets dans deux ordres opposés, et pack() vous fournit un code pour chacun :
- Big-endian (a.k.a. ordre réseau) stocke l'octet le plus significatif en premier — codes
n(short) etN(long). - Little-endian stocke l'octet le moins significatif en premier — codes
v(short) etV(long).
<?php
echo bin2hex(pack('N', 1)), "\n"; // 00000001 (big-endian)
echo bin2hex(pack('V', 1)), "\n"; // 01000000 (little-endian)
?>Cela est important car le destinataire doit utiliser la même convention pour relire les données. Les protocoles réseau standardisent sur le big-endian (N/n) ; de nombreux formats de fichiers (et les dumps mémoire x86) utilisent le little-endian (V/v). En cas de doute, choisissez N/n pour l'échange — c'est ce que garantit l'« ordre réseau ».
Codes de format courants
Une sélection des codes les plus utilisés (consultez le manuel PHP pour la liste complète) :
| Code | Signification |
|---|---|
a | Chaîne complétée par des NUL |
A | Chaîne complétée par des espaces |
c / C | Char signé / non signé (1 octet) |
s / S | Short signé / non signé, ordre natif (2 octets) |
n / N | Short / long non signé, big-endian |
v / V | Short / long non signé, little-endian |
f / d | Float / double, format machine |
H / h | Chaîne hexadécimale, quartet de poids fort / faible en premier |
Les codes de chaîne utilisent le compteur de répétition comme largeur de champ, et non comme nombre de valeurs :
<?php
echo pack('A6', 'PHP'), "|"; // PHP | (padded to 6 chars with spaces)
?>Aller-retour : pack() puis unpack()
pack() écrit des octets ; unpack() les relit sous forme de valeurs PHP. Pour récupérer les données originales, vous devez décrire la même disposition, et unpack() nécessite en plus un nom pour chaque champ :
<?php
// Encode two fields
$binary = pack('Nn', 65536, 7);
// Decode using the same layout, naming each field
$values = unpack('Nfirst/nsecond', $binary);
echo $values['first'], ' ', $values['second']; // 65536 7
?>La barre oblique (/) sépare les champs nommés dans le format de unpack(). Si les dispositions des deux côtés ne correspondent pas, vous obtenez des données corrompues — l'encodage et le décodage sont étroitement couplés.
Pièges à éviter
- Les codes et les valeurs doivent être alignés. Passer moins de valeurs que de codes déclenche un avertissement et renvoie
false; les valeurs supplémentaires sont ignorées silencieusement (sauf si vous avez utilisé*). - Le dépassement d'entier est tronqué, pas signalé.
pack('C', 300)ne conserve que l'octet de poids faible (300 & 0xFF = 44) au lieu de lever une erreur — validez les plages vous-même. - Les codes natifs (
s,S,i,l, flottants) ne sont pas portables. Leur taille et leur ordre d'octets dépendent de la plateforme. Pour des données qui traversent plusieurs machines, préférez les codes big-/little-endian explicites. - Le résultat est une chaîne binaire. Ne l'affichez pas avec
echodans une page HTML et ne la comparez pas comme du texte ; inspectez-la avecbin2hex()ou écrivez-la dans un fichier/flux binaire.
Pour l'opération inverse, continuez avec le chapitre unpack(). Pour voir les octets bruts dans vos propres expériences, l'utilitaire bin2hex() utilisé tout au long de cette page est indispensable.
Conclusion
pack() convertit des valeurs PHP en une chaîne binaire précisément contrôlée, avec une mini-langue de format compacte pour le type, la taille et l'ordre des octets du champ. Utilisez-la chaque fois que vous devez produire des octets qu'un autre système lira selon ses propres règles — protocoles binaires, formats de fichiers ou routines cryptographiques — et associez-la à unpack() pour relire les données.