PHP 8.5.0 Alpha 1 available for testing

pack

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

packCompacta datos en una cadena binaria

Descripción

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

Compacta los argumentos args en una cadena binaria, siguiendo el formato format.

El concepto proviene de Perl y todo el formato funciona de la misma forma que en Perl, pero algunos formatos aún faltan (como "u").

Tenga en cuenta que la distinción entre signado y no signado solo afecta a la función unpack(), mientras que la función pack() proporcionará el mismo resultado para ambos formatos.

Parámetros

format

La chaîne de caractères format consiste en códigos de formato seguidos por un argumento repetidor opcional. El repetidor puede ser un valor entero o * para una repetición hasta el final de los datos de entrada. Para a, A, h, H, el repetidor especifica cuántos caracteres de un dato se toman, para @, es la posición absoluta donde se insertan los próximos datos, para todo lo demás, el repetidor especifica cuántos argumentos de datos son consumidos y compactados en la cadena binaria resultante.

Los formatos actualmente aceptados son:

Caracteres de formato para pack()
Código Descripción
a NUL - Una cadena completada con null
A SPACE - Una cadena completada con un espacio
h Cadena hexadecimal h, bit de menor peso en primer lugar
H Cadena hexadecimal H, bit de mayor peso en primer lugar
c Carácter signado
C Carácter no signado
s entero corto signado (siempre 16 bits, orden de bytes dependiente de la máquina)
S entero corto no signado (siempre 16 bits, orden de bytes dependiente de la máquina)
n entero corto no signado (siempre 16 bits, orden de bytes big endian)
v entero corto no signado (siempre 16 bits, orden de bytes little endian)
i entero signado (tamaño y orden de bytes dependientes de la máquina)
I entero no signado (tamaño y orden de bytes dependientes de la máquina)
l entero largo signado (siempre 32 bits, orden de bytes dependiente de la máquina)
L entero largo no signado (siempre 32 bits, orden de bytes dependiente de la máquina)
N entero largo no signado (siempre 32 bits, orden de bytes big endian)
V entero largo no signado (siempre 32 bits, orden de bytes little endian)
q entero doblemente largo signado (siempre 64 bits, orden de bytes dependiente de la máquina)
Q entero doblemente largo no signado (siempre 64 bits, orden de bytes dependiente de la máquina)
J entero doblemente largo no signado (siempre 64 bits, orden de bytes big endian)
P entero doblemente largo no signado (siempre 64 bits, orden de bytes little endian)
f número de coma flotante (tamaño y representación dependientes de la máquina)
g número de coma flotante (tamaño dependiente de la máquina, orden de bytes little endian)
G número de coma flotante (tamaño dependiente de la máquina, orden de bytes big endian)
d número de coma flotante doble (tamaño y representación dependientes de la máquina)
e número de coma flotante doble (tamaño dependiente de la máquina, orden de bytes little endian)
E número de coma flotante doble (tamaño dependiente de la máquina, orden de bytes big endian)
x carácter NUL
X Retrocede un carácter
Z La cadena terminada por NUL (ASCIIZ) será completada con el valor NULL
@ Rellena con NUL hasta la posición absoluta

values

Valores devueltos

Devuelve una chaîne de caractères binaria que contiene los datos.

Historial de cambios

Versión Descripción
8.0.0 Esta función ya no devuelve false en caso de error.
7.2.0 Los tipos float y double admiten Big Endian y Little Endian.
7.0.15, 7.1.1 Se han añadido los códigos "e", "E", "g" y "G" para activar la compatibilidad con el orden de bytes para los números de coma flotante de simple y doble precisión.

Ejemplos

Ejemplo #1 Ejemplo con pack()

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

La cadena binaria resultante tendrá 6 bytes de longitud, y contendrá la secuencia 0x12, 0x34, 0x78, 0x56, 0x41, 0x42.

Notas

Precaución

Los códigos de formato q, Q, J y P no están disponibles en las versiones de PHP de 32 bits.

Precaución

Tenga en cuenta que PHP almacena internamente los valores int como valores signados dependientes de la máquina. Las operaciones sobre enteros que llevan a números fuera del espacio de definición del int serán almacenados como float. Al empaquetar estos flotantes en enteros, se convierten al tipo entero. Esto puede llevar potencialmente a una representación inesperada de los bytes.

El caso más clásico es el empaquetado de números no signados que serían representables en el tipo int si este fuera no signado. En los sistemas con un int de 32 bits, la conversión resulta en un byte idéntico al que si el tipo int fuera no signado (aunque esto sigue dependiendo de la implementación no signada a signada, del estándar C). En los sistemas con un int de 64 bits, el float no suele tener una mantisa lo suficientemente amplia para contener el valor sin pérdida de precisión. Si estos sistemas también poseen un tipo C nativo int de 64 bits (la mayoría de los *NIX no lo tienen), la única forma de usar el formato de empaquetado I en valores altos es crear valores int negativos con la misma representación de bytes que la valor no signado deseado correspondiente.

Ver también

  • unpack() - Desempaqueta datos desde una cadena binaria

add a note

User Contributed Notes 10 notes

up
90
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
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
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
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
2
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
0
ru
7 years ago
pack()
h Hex string, low nibble first (not same hex2bin())
H Hex string, high nibble first (same hex2bin())
up
-1
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