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. Entretando, 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 formado seguidos de um argumento repetidor opcional. O arrgumento 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 caractares de um argumento de dados são tomados, para @ é a posição absoluta onde colocar 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 com bytes NUL à esquerda
@ 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

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

adicione uma nota

Notas Enviadas por Usuários (em inglês) 10 notes

up
88
chadm at codeangel dot org
12 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
8 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
24 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
18 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
16 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

<?php
function _readInt($fp)
{
return
unpack('V', fread($fp, 4));
}
?>

or unpack('N', ...) for big-endianness.
up
2
petepostma at gmail dot spam dot com
12 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
7 years ago
pack()
h Hex string, low nibble first (not same hex2bin())
H Hex string, high nibble first (same hex2bin())
up
0
Ammar Hameed
14 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