W3docs

pack()

In questo articolo approfondiremo la funzione PHP pack(): panoramica, funzionamento ed esempi pratici d'uso.

Questo articolo tratta la funzione pack() di PHP: cosa fa, il mini-linguaggio delle stringhe di formato che utilizza, come l'ordine dei byte (endianness) influisce sul risultato e alcuni esempi pratici — incluso il percorso inverso con unpack().

Cosa fa pack()

pack() prende normali valori PHP (interi, float, stringhe) e li dispone byte per byte in un'unica stringa binaria — una stringa i cui caratteri sono byte grezzi anziché testo leggibile.

pack(string $format, mixed ...$values): string
  • $format — una stringa di formato compatta che descrive, nell'ordine, come ciascun valore deve essere codificato (tipo, dimensione e ordine dei byte).
  • ...$values — uno o più valori da codificare, abbinati da sinistra a destra ai codici di formato.

Il valore restituito è una stringa binaria. Poiché quei byte di solito non sono stampabili, negli esempi di seguito il risultato viene passato a bin2hex() in modo da vedere esattamente quali byte sono stati prodotti (due cifre esadecimali = un byte).

Quando si usa?

Si ricorre a pack() ogni volta che PHP deve parlare un formato definito in byte grezzi anziché testo:

  • Protocolli binari — costruire pacchetti di rete dove un header è "una lunghezza a 2 byte seguita da un id a 4 byte."
  • Formati di file binari — scrivere chunk PNG, header WAV o qualsiasi layout con campi a larghezza fissa.
  • Funzioni di hashing/crypto — convertire un digest esadecimale nella sua forma di byte grezzi da passare a hash_hmac() o alle funzioni openssl_*.
  • Comunicazione con sistemi C/embedded che si aspettano campi di dimensione fissa e endianness fissa.

Per la memorizzazione PHP-to-PHP, serialize() o json_encode() sono più comodi; pack() eccelle quando il layout dei byte stesso è importante.

Un primo esempio

php— editable, runs on the server

123 in esadecimale è 0x7b. Il codice di formato N significa "unsigned long (4 byte), network byte order," quindi il valore viene riempito a quattro byte e scritto con il byte più significativo per primo: 00 00 00 7b.

Leggere la stringa di formato

Una stringa di formato è una sequenza di codici di formato, ognuno opzionalmente seguito da un contatore di ripetizione:

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 string

È possibile concatenare codici per descrivere un intero record. I valori passati devono corrispondere ai codici nell'ordine:

<?php
// A 2-byte short (1) followed by a 4-byte long (16909060)
$header = pack('nN', 1, 16909060);

echo bin2hex($header); // 000101020304
?>

Qui n produce 00 01 (lo short 1) e N produce 01 02 03 04 (il long 16909060, ovvero 0x01020304). I byte appaiono esattamente nell'ordine in cui sono stati scritti i codici.

Ordine dei byte (endianness)

Lo stesso numero può essere memorizzato con i suoi byte in due ordini opposti, e pack() fornisce un codice per ciascuno:

  • Big-endian (noto anche come network byte order) memorizza il byte più significativo per primo — codici n (short) e N (long).
  • Little-endian memorizza il byte meno significativo per primo — codici v (short) e V (long).
<?php
echo bin2hex(pack('N', 1)), "\n"; // 00000001  (big-endian)
echo bin2hex(pack('V', 1)), "\n"; // 01000000  (little-endian)
?>

Questo è importante perché il destinatario deve utilizzare la stessa convenzione per leggere i dati. I protocolli di rete standardizzano sul big-endian (N/n); molti formati di file (e i dump della memoria x86) usano il little-endian (V/v). In caso di dubbio, scegliere N/n per l'interscambio — è ciò che garantisce il "network byte order."

Codici di formato più comuni

Una selezione dei codici più utilizzati (vedere il manuale PHP per l'elenco completo):

CodiceSignificato
aStringa con padding NUL
AStringa con padding di spazi
c / CChar con segno / senza segno (1 byte)
s / SShort con segno / senza segno, ordine byte nativo (2 byte)
n / NShort / long senza segno, big-endian
v / VShort / long senza segno, little-endian
f / dFloat / double, formato macchina
H / hStringa esadecimale, nibble alto / basso per primo

I codici stringa usano il contatore di ripetizione come larghezza del campo, non come numero di valori:

<?php
echo pack('A6', 'PHP'), "|"; // PHP   |  (padded to 6 chars with spaces)
?>

Round trip: pack() poi unpack()

pack() scrive byte; unpack() li rilegge come valori PHP. Per recuperare i dati originali è necessario descrivere lo stesso layout, e unpack() richiede inoltre un nome per ogni campo:

<?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 barra (/) separa i campi con nome nel formato di unpack(). Se i layout dei due lati non coincidono, si otterranno dati corrotti — codifica e decodifica sono strettamente accoppiate.

Insidie

  • Codici e valori devono essere allineati. Passare meno valori dei codici genera un avviso e restituisce false; i valori in eccesso vengono ignorati silenziosamente (a meno che non si usi *).
  • L'overflow degli interi viene troncato, non segnalato. pack('C', 300) mantiene solo il byte basso (300 & 0xFF = 44) invece di generare un errore — è necessario validare i range manualmente.
  • I codici nativi (s, S, i, l, float) non sono portabili. La loro dimensione e l'ordine dei byte dipendono dalla piattaforma. Per dati che attraversano macchine diverse, preferire i codici big-/little-endian espliciti.
  • Il risultato è una stringa binaria. Non va usata con echo in una pagina HTML né confrontata come testo; ispezionarla con bin2hex() o scriverla su un file/stream binario.

Per l'operazione inversa, continuare con il capitolo su unpack(). Per visualizzare i byte grezzi nei propri esperimenti, il helper bin2hex() usato in questa pagina è indispensabile.

Conclusione

pack() converte valori PHP in una stringa binaria controllata con precisione, grazie a un mini-linguaggio di formato compatto per tipo, dimensione e ordine dei byte. Si usa ogni volta che è necessario produrre byte che un altro sistema legge secondo i propri termini — protocolli binari, formati di file o routine crittografiche — abbinandola a unpack() per rileggere i dati.

Esercizio

Pratica
Cosa fa la funzione pack() in PHP?
Cosa fa la funzione pack() in PHP?
Was this page helpful?