pack()
Neste artigo, abordamos a função pack() do PHP: visão geral, funcionamento e exemplos práticos de uso.
Este artigo aborda a função pack() do PHP: o que ela faz, a mini-linguagem de strings de formato que utiliza, como a ordem dos bytes (endianness) afeta o resultado e exemplos práticos que você pode executar — incluindo o ciclo de volta com unpack().
O que pack() faz
pack() recebe valores PHP comuns (inteiros, floats, strings) e os organiza byte a byte em uma única string binária — uma string cujos caracteres são bytes brutos em vez de texto legível.
pack(string $format, mixed ...$values): string$format— uma string de formato compacta que descreve, em ordem, como cada valor deve ser codificado (seu tipo, tamanho e ordem de bytes)....$values— um ou mais valores a codificar, associados da esquerda para a direita com os códigos de formato.
O valor de retorno é uma string binária. Como esses bytes geralmente não são imprimíveis, os exemplos abaixo passam o resultado por bin2hex() para que você possa ver exatamente quais bytes foram produzidos (dois dígitos hexadecimais = um byte).
Quando você usaria isso?
Você recorre a pack() sempre que o PHP precisa falar um formato definido em bytes brutos em vez de texto:
- Protocolos binários — construção de pacotes de rede onde um cabeçalho é "um comprimento de 2 bytes seguido de um id de 4 bytes."
- Formatos de arquivo binários — escrita de chunks PNG, cabeçalhos WAV ou qualquer layout com campos de largura fixa.
- Auxiliares de hashing/criptografia — conversão de um resumo hexadecimal na sua forma de bytes brutos para passar a
hash_hmac()ouopenssl_*. - Comunicação com sistemas C/embarcados que esperam campos de tamanho fixo e endianness fixo.
Para armazenamento PHP-a-PHP comum, serialize() ou json_encode() são mais amigáveis; pack() brilha quando o layout de bytes em si importa.
Um primeiro exemplo
123 em hexadecimal é 0x7b. O código de formato N significa "unsigned long (4 bytes), ordem de bytes de rede," portanto o valor é preenchido com quatro bytes e escrito com o byte mais significativo primeiro: 00 00 00 7b.
Lendo a string de formato
Uma string de formato é uma sequência de códigos de formato, cada um opcionalmente seguido por uma contagem de repetição:
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 stringVocê pode concatenar códigos para descrever um registro inteiro. Os valores que você passa devem se alinhar com os códigos em ordem:
<?php
// A 2-byte short (1) followed by a 4-byte long (16909060)
$header = pack('nN', 1, 16909060);
echo bin2hex($header); // 000101020304
?>Aqui n produz 00 01 (o short 1) e N produz 01 02 03 04 (o long 16909060, que é 0x01020304). Os bytes aparecem exatamente na ordem em que os códigos foram escritos.
Ordem de bytes (endianness)
O mesmo número pode ser armazenado com seus bytes em duas ordens opostas, e pack() fornece um código para cada:
- Big-endian (também conhecido como ordem de bytes de rede) armazena o byte mais significativo primeiro — códigos
n(short) eN(long). - Little-endian armazena o byte menos significativo primeiro — códigos
v(short) eV(long).
<?php
echo bin2hex(pack('N', 1)), "\n"; // 00000001 (big-endian)
echo bin2hex(pack('V', 1)), "\n"; // 01000000 (little-endian)
?>Isso importa porque o receptor deve usar a mesma convenção para ler os dados de volta. Protocolos de rede padronizam em big-endian (N/n); muitos formatos de arquivo (e dumps de memória x86) usam little-endian (V/v). Na dúvida, escolha N/n para intercâmbio — é isso que "ordem de bytes de rede" garante.
Códigos de formato comuns
Uma seleção dos códigos mais usados (consulte o manual do PHP para a lista completa):
| Código | Significado |
|---|---|
a | String preenchida com NUL |
A | String preenchida com espaço |
c / C | Char com sinal / sem sinal (1 byte) |
s / S | Short com sinal / sem sinal, ordem de bytes nativa (2 bytes) |
n / N | Short / long sem sinal, big-endian |
v / V | Short / long sem sinal, little-endian |
f / d | Float / double, formato da máquina |
H / h | String hexadecimal, nibble alto / baixo primeiro |
Códigos de string usam a contagem de repetição como uma largura de campo, não uma contagem de valores:
<?php
echo pack('A6', 'PHP'), "|"; // PHP | (padded to 6 chars with spaces)
?>Ciclo completo: pack() e depois unpack()
pack() escreve bytes; unpack() os lê de volta como valores PHP. Para recuperar os dados originais você deve descrever o mesmo layout, e unpack() adicionalmente precisa de um nome para cada 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
?>A barra (/) separa os campos nomeados no formato de unpack(). Se os layouts dos dois lados não coincidirem, você obtém dados corrompidos — codificação e decodificação estão fortemente acopladas.
Armadilhas
- Códigos e valores devem se alinhar. Passar menos valores do que códigos dispara um aviso e retorna
false; valores extras são silenciosamente ignorados (a menos que você tenha usado*). - Overflow de inteiros é truncado, não sinalizado.
pack('C', 300)mantém apenas o byte baixo (300 & 0xFF = 44) em vez de gerar um erro — valide os intervalos você mesmo. - Códigos nativos (
s,S,i,l, floats) não são portáveis. Seu tamanho e ordem de bytes dependem da plataforma. Para dados que cruzam máquinas, prefira os códigos explícitos big-/little-endian. - O resultado é uma string binária. Não use
echopara exibi-la em uma página HTML nem a compare como texto; inspecione-a combin2hex()ou escreva-a em um arquivo/stream binário.
Para a operação inversa, continue com o capítulo de unpack(). Para ver os bytes brutos em seus próprios experimentos, o auxiliar bin2hex() usado ao longo desta página é inestimável.
Conclusão
pack() converte valores PHP em uma string binária com controle preciso, com uma mini-linguagem de formato compacta para o tipo de campo, tamanho e ordem de bytes. Use-a sempre que precisar produzir bytes que outro sistema lê em seus próprios termos — protocolos binários, formatos de arquivo ou rotinas criptográficas — e combine-a com unpack() para ler os dados de volta.