PHP Conference Fukuoka 2025

pack

(PHP 4, PHP 5, PHP 7, PHP 8)

packEmpacota dados em uma string binária

Descrição

pack(string $format, mixed ...$values): string

Empacota os argumentos fornecidos em uma string binária de acordo com o formato especificado em format.

A ideia para esta função foi tirada do Perl e todos os códigos de formatação funcionam da mesma forma que no Perl. Entretanto, há alguns códigos de formatação que não existem, como código "u" do Perl.

Observe que a distinção entre valores com e sem sinal somente afeta a função unpack(), enquanto que a função pack() fornece o mesmo resultado para códigos de formato com e sem sinal.

Parâmetros

format

A string format consistem em códigos de formato seguidos de um argumento repetidor opcional. O argumento repetidor pode ser um valor inteiro ou * para repetir até o final dos dados de entrada. Para a, A, h, H a contagem de repetição especifica quantos caracteres de um argumento de dados são tomados, para @ é a posição absoluta onde será colocado o próximo dado, para todo o restante a contagem de repetição especifica quantos argumentos de dados são consumidos e empacotados na string binária resultante.

Os formatos atualmente implementados são:

Caracteres de formato de pack()
Código Descrição
a String com bytes NUL à esquerda
A String com espaços à esquerda
h String hexadecimal, nibble menos significativo primeiro
H String hexadecimal, nibble mais significativo primeiro
csigned char
C unsigned char
s signed short (sempre 16 bits, ordem de bytes da máquina)
S unsigned short (sempre 16 bits, ordem de bytes da máquina)
n unsigned short (sempre 16 bits, ordem de bytes Big Endian)
v unsigned short (sempre 16 bits, ordem de bytes Little Endian)
i signed integer (tamanho e ordem de bytes dependentes da máquina)
I unsigned integer (tamanho e ordem de bytes dependentes da máquina)
l signed long (sempre 32 bits, ordem de bytes da máquina)
L unsigned long (sempre 32 bits, ordem de bytes da máquina)
N unsigned long (sempre 32 bits, ordem de bytes Big Endian)
V unsigned long (sempre 32 bits, ordem de bytes Little Endian)
q signed long long (sempre 64 bits, ordem de bytes da máquina)
Q unsigned long long (sempre 64 bits, ordem de bytes da máquina)
J unsigned long long (sempre 64 bits, ordem de bytes Big Endian)
P unsigned long long (sempre 64 bits, ordem de bytes Little Endian)
f float (representação e tamanho dependentes da máquina)
g float (tamanho dependente da máquina, ordem de bytes Little Endian)
G float (tamanho dependente da máquina, ordem de bytes Big Endian)
d double (representação e tamanho dependentes da máquina)
e double (tamanho dependente da máquina, ordem de bytes Little Endian)
E double (tamanho dependente da máquina, ordem de bytes Big Endian)
x byte NUL
X Volta um byte
Z String terminada em NUL (ASCIIZ), preenchida com bytes NUL
@ Preenche com bytes NUL até a posição absoluta

values

Valor Retornado

Retorna uma string binária contendo dados.

Registro de Alterações

Versão Descrição
8.0.0 Esta função não mais retorna false em caso de falha.
7.2.0 Tipos float e double suportam tanto Big Endian quanto Little Endian.
7.0.15, 7.1.1 Os códigos "e", "E", "g" e "G" foram adicionados para habilitar suporte a ordem de byte para float e double.

Exemplos

Exemplo #1 Exemplo de pack()

<?php
$binarydata
= pack("nvc*", 0x1234, 0x5678, 65, 66);
?>

A string binária resultante terá 6 bytes de comprimento e conterá a sequência de bytes 0x12, 0x34, 0x78, 0x56, 0x41, 0x42.

Notas

Cuidado

Os códigos de formato q, Q, J e P não estão disponíveis em versões do PHP de 32 bits.

Cuidado

Observe que, internamente, o PHP armazena valores int como valores com sinal de tamanho dependente da máquina. Literais inteiros e operações que resultam em números fora da faixa do tipo int serão armazenados como float. Ao empacotar estes floats como inteiros, eles primeiro são convertidos para o tipo inteiro. Isto pode ou não resultar no padrão de bytes desejado.

O caso mais relevante ocorre ao empacotar números sem sinal que poderiam ser representáveis pelo tipo int se eles fossem sem sinal. Em sistemas onde o tipo int tem 32 bits, a conversão normalmente resulta no mesmo padrão de byte como se o int fosse sem sinal (embora isso dependa das conversões de sem sinal para com sinal definidas pela implementação, conforme o padrão C). Em sistemas onte o tipo int tem 64 bits, o tipo float provavelmente não terá a mantissa grande o suficiente para representar o valor sem perda de precisão. Se estes sistemas também tiverem o tipo int nativo de 64 bits (a maioria dos sistemas tipo UNIX não têm), a única maneira de usar o formato I de empacotamento na faixa superior é criar valores negativos int com a mesma representação de bytes do valor sem sinal desejado.

Veja Também

  • unpack() - Desempacota dados de uma string binária

adicionar nota

Notas de Usuários 10 notes

up
88
chadm at codeangel dot org
13 years ago
If you'd like to understand pack/unpack. There is a tutorial here in perl, that works equally well in understanding it for php:http://perldoc.perl.org/perlpacktut.html
up
34
stanislav dot eckert at vizson dot de
9 years ago
A helper class to convert integer to binary strings and vice versa. Useful for writing and reading integers to / from files or sockets.<?php    class int_helper    {        public static function int8($i) {            return is_int($i) ? pack("c", $i) : unpack("c", $i)[1];        }        public static function uInt8($i) {            return is_int($i) ? pack("C", $i) : unpack("C", $i)[1];        }        public static function int16($i) {            return is_int($i) ? pack("s", $i) : unpack("s", $i)[1];        }        public static function uInt16($i, $endianness=false) {            $f = is_int($i) ? "pack" : "unpack";            if ($endianness === true) {  // big-endian                $i = $f("n", $i);            }            else if ($endianness === false) {  // little-endian                $i = $f("v", $i);            }            else if ($endianness === null) {  // machine byte order                $i = $f("S", $i);            }            return is_array($i) ? $i[1] : $i;        }        public static function int32($i) {            return is_int($i) ? pack("l", $i) : unpack("l", $i)[1];        }        public static function uInt32($i, $endianness=false) {            $f = is_int($i) ? "pack" : "unpack";            if ($endianness === true) {  // big-endian                $i = $f("N", $i);            }            else if ($endianness === false) {  // little-endian                $i = $f("V", $i);            }            else if ($endianness === null) {  // machine byte order                $i = $f("L", $i);            }            return is_array($i) ? $i[1] : $i;        }        public static function int64($i) {            return is_int($i) ? pack("q", $i) : unpack("q", $i)[1];        }        public static function uInt64($i, $endianness=false) {            $f = is_int($i) ? "pack" : "unpack";            if ($endianness === true) {  // big-endian                $i = $f("J", $i);            }            else if ($endianness === false) {  // little-endian                $i = $f("P", $i);            }            else if ($endianness === null) {  // machine byte order                $i = $f("Q", $i);            }            return is_array($i) ? $i[1] : $i;        }    }?>Usage example:<?php    Header("Content-Type: text/plain");    include("int_helper.php");    echo int_helper::uInt8(0x6b) . PHP_EOL;  // k    echo int_helper::uInt8(107) . PHP_EOL;  // k    echo int_helper::uInt8("\x6b") . PHP_EOL . PHP_EOL;  // 107    echo int_helper::uInt16(4101) . PHP_EOL;  // \x05\x10    echo int_helper::uInt16("\x05\x10") . PHP_EOL;  // 4101    echo int_helper::uInt16("\x05\x10", true) . PHP_EOL . PHP_EOL;  // 1296    echo int_helper::uInt32(2147483647) . PHP_EOL;  // \xff\xff\xff\x7f    echo int_helper::uInt32("\xff\xff\xff\x7f") . PHP_EOL . PHP_EOL;  // 2147483647    // Note: Test this with 64-bit build of PHP    echo int_helper::uInt64(9223372036854775807) . PHP_EOL;  // \xff\xff\xff\xff\xff\xff\xff\x7f    echo int_helper::uInt64("\xff\xff\xff\xff\xff\xff\xff\x7f") . PHP_EOL . PHP_EOL;  // 9223372036854775807?>
up
18
plutus at gmx dot de
25 years ago
Note that the the upper command in perl looks like this:

$binarydata = pack ("n v c*", 0x1234, 0x5678, 65, 66);
In PHP it seems that no whitespaces are allowed in the first parameter. So if you want to convert your pack command from perl -> PHP, don't forget to remove the whitespaces!
up
13
FrozenFire
14 years ago
If you need to unpack a signed short from big-endian or little-endian specifically, instead of machine-byte-order, you need only unpack it as the unsigned form, and then if the result is >= 2^15, subtract 2^16 from it.

And example would be:

<?php
$foo = unpack("n", $signedbigendianshort);
$foo = $foo[1];
if($foo >= pow(2, 15)) $foo -= pow(2, 16);
?>
up
6
j.s.hoekstra
19 years ago
/* Convert float from HostOrder to Network Order */function FToN( $val ){    $a = unpack("I",pack( "f",$val ));    return pack("N",$a[1] );}    /* Convert float from Network Order to HostOrder */function NToF($val ){    $a = unpack("N",$val);    $b = unpack("f",pack( "I",$a[1]));    return $b[1];}
up
3
php at nagler-ihlein dot de
17 years ago
Be aware of format code H always padding the 0 for byte-alignment to the right (for odd count of nibbles).So pack("H", "7") results in 0x70 (ASCII character 'p') and not in 0x07 (BELL character)as well as pack("H*", "347") results in 0x34 ('4') and 0x70 ('p') and not 0x03 and 0x47.
up
2
Patrik Fimml
19 years ago
You will get the same effect with<?phpfunction _readInt($fp){   return unpack('V', fread($fp, 4));}?>or unpack('N', ...) for big-endianness.
up
2
petepostma at gmail dot spam dot com
13 years ago
Even though in a 64-bit architecure intval(6123456789) = 6123456789, and sprintf('%b', 5000000000) = 100101010000001011111001000000000
pack will not treat anything passed to it as 64-bit.  If you want to pack a 64-bit integer:

<?php
$big = 5000000000;

$left = 0xffffffff00000000;
$right = 0x00000000ffffffff;

$l = ($big & $left) >>32;
$r = $big & $right;

$good = pack('NN', $l, $r);

$urlsafe = str_replace(array('+','/'), array('-','_'), base64_encode($good));

//done!

//rebuild:
$unurl =  str_replace(array('-','_'), array('+','/'), $urlsafe);
$binary = base64_decode($unurl);

$set = unpack('N2', $tmp);
print_r($set);

$original = $set[1] << 32 | $set[2];
echo $original, "\\r\\n";
?>

results in:
Array
(
    [1] => 1
    [2] => 705032704
)
5000000000

but ONLY on a 64-bit enabled machine and PHP distro.
up
1
ru
8 years ago
pack()h    Hex string, low nibble first (not same hex2bin())H    Hex string, high nibble first (same hex2bin())
up
0
Ammar Hameed
15 years ago
Using pack to write Arabic char(s) to a file.<?php$text = "&#13574;&#13830;&#13830;";$text = mb_convert_encoding($text, "UCS-2BE", "HTML-ENTITIES");$len =  mb_strlen($text);$bom = mb_convert_encoding("&#65534;", "unicode", "HTML-ENTITIES");$fp = fopen('text.txt', 'w');fwrite($fp, pack('a2', $bom));  fwrite($fp, pack("a{$len}", $text));fwrite($fp, pack('a2', $bom)); fwrite($fp, pack('a2', "\n"));fclose($fp);?>
To Top