pack()
Dieser Artikel erklärt die PHP-Funktion pack(): Funktionsweise, Formatstrings, Byte-Reihenfolge und praktische Anwendungsbeispiele.
Dieser Artikel behandelt PHPs pack()-Funktion: was sie tut, die Formatstring-Minisprache, die sie verwendet, wie die Byte-Reihenfolge (Endianness) das Ergebnis beeinflusst, und praktische Beispiele — einschließlich des Rückwegs mit unpack().
Was pack() macht
pack() nimmt gewöhnliche PHP-Werte (Integer, Floats, Strings) und legt sie byteweise in einem einzelnen Binär-String ab — einem String, dessen Zeichen rohe Bytes statt lesbarem Text sind.
pack(string $format, mixed ...$values): string$format— ein kompakter Formatstring, der der Reihe nach beschreibt, wie jeder Wert kodiert werden soll (Typ, Größe und Byte-Reihenfolge)....$values— ein oder mehrere zu kodierende Werte, die von links nach rechts den Formatcodes zugeordnet werden.
Der Rückgabewert ist ein Binär-String. Da diese Bytes meist nicht druckbar sind, werden die Ergebnisse in den Beispielen unten durch bin2hex() geleitet, damit man genau sehen kann, welche Bytes erzeugt wurden (zwei Hex-Ziffern = ein Byte).
Wann verwendet man es?
pack() kommt zum Einsatz, wenn PHP ein Format sprechen muss, das in rohen Bytes statt in Text definiert ist:
- Binäre Protokolle — Netzwerkpakete aufbauen, bei denen ein Header aus „2 Bytes Länge gefolgt von einer 4-Byte-ID" besteht.
- Binäre Dateiformate — PNG-Chunks, WAV-Header oder beliebige Layouts mit fest breiten Feldern schreiben.
- Hashing/Crypto-Helfer — einen Hex-Digest in seine rohe Byte-Form umwandeln, um ihn an
hash_hmac()oderopenssl_*zu übergeben. - Kommunikation mit C/Embedded-Systemen, die fest dimensionierte Felder mit bestimmter Endianness erwarten.
Für die reine PHP-zu-PHP-Speicherung sind serialize() oder json_encode() benutzerfreundlicher; pack() glänzt, wenn das Byte-Layout selbst wichtig ist.
Ein erstes Beispiel
123 in Hexadezimal ist 0x7b. Der Formatcode N bedeutet „unsigned long (4 Bytes), Network Byte Order", daher wird der Wert auf vier Bytes aufgefüllt und mit dem höchstwertigsten Byte zuerst geschrieben: 00 00 00 7b.
Den Formatstring lesen
Ein Formatstring ist eine Folge von Formatcodes, denen optional eine Wiederholungsanzahl folgt:
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 stringCodes können verkettet werden, um einen ganzen Datensatz zu beschreiben. Die übergebenen Werte müssen der Reihe nach mit den Codes übereinstimmen:
<?php
// A 2-byte short (1) followed by a 4-byte long (16909060)
$header = pack('nN', 1, 16909060);
echo bin2hex($header); // 000101020304
?>Hier erzeugt n das Ergebnis 00 01 (der Short 1) und N produziert 01 02 03 04 (der Long 16909060, also 0x01020304). Die Bytes erscheinen genau in der Reihenfolge, in der die Codes geschrieben wurden.
Byte-Reihenfolge (Endianness)
Dieselbe Zahl kann mit ihren Bytes in zwei entgegengesetzten Reihenfolgen gespeichert werden, und pack() bietet für jede einen eigenen Code:
- Big-Endian (auch bekannt als Network Byte Order) speichert das höchstwertige Byte zuerst — Codes
n(Short) undN(Long). - Little-Endian speichert das niederwertigste Byte zuerst — Codes
v(Short) undV(Long).
<?php
echo bin2hex(pack('N', 1)), "\n"; // 00000001 (big-endian)
echo bin2hex(pack('V', 1)), "\n"; // 01000000 (little-endian)
?>Das ist wichtig, weil der Empfänger dieselbe Konvention verwenden muss, um die Daten wieder zu lesen. Netzwerkprotokolle standardisieren auf Big-Endian (N/n); viele Dateiformate (und x86-Speicher-Dumps) verwenden Little-Endian (V/v). Im Zweifelsfall N/n für den Datenaustausch wählen — das ist die Garantie von „Network Byte Order".
Häufige Formatcodes
Eine Auswahl der am häufigsten verwendeten Codes (die vollständige Liste findet sich im PHP-Handbuch):
| Code | Bedeutung |
|---|---|
a | NUL-aufgefüllter String |
A | Leerzeichen-aufgefüllter String |
c / C | Vorzeichenbehaftetes / vorzeichenloses Char (1 Byte) |
s / S | Vorzeichenbehafteter / vorzeichenloser Short, native Byte-Reihenfolge (2 Bytes) |
n / N | Vorzeichenloser Short / Long, Big-Endian |
v / V | Vorzeichenloser Short / Long, Little-Endian |
f / d | Float / Double, Maschinenformat |
H / h | Hex-String, hohes / niedriges Nibble zuerst |
String-Codes verwenden die Wiederholungsanzahl als Feldbreite, nicht als Werteanzahl:
<?php
echo pack('A6', 'PHP'), "|"; // PHP | (padded to 6 chars with spaces)
?>Hin und zurück: pack() und unpack()
pack() schreibt Bytes; unpack() liest sie zurück in PHP-Werte. Um die ursprünglichen Daten wiederherzustellen, muss dasselbe Layout beschrieben werden, und unpack() benötigt zusätzlich einen Namen für jedes Feld:
<?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
?>Der Schrägstrich (/) trennt benannte Felder im unpack()-Format. Wenn die Layouts auf beiden Seiten nicht übereinstimmen, erhält man unleserliche Daten — Kodierung und Dekodierung sind eng gekoppelt.
Fallstricke
- Codes und Werte müssen übereinstimmen. Werden weniger Werte als Codes übergeben, wird eine Warnung ausgelöst und
falsezurückgegeben; zusätzliche Werte werden stillschweigend ignoriert (es sei denn,*wurde verwendet). - Integer-Überlauf wird abgeschnitten, nicht gemeldet.
pack('C', 300)behält nur das niedrige Byte (300 & 0xFF = 44) statt einen Fehler auszulösen — Bereiche selbst validieren. - Native Codes (
s,S,i,l, Floats) sind nicht portabel. Ihre Größe und Byte-Reihenfolge hängen von der Plattform ab. Für Daten, die zwischen Maschinen ausgetauscht werden, die expliziten Big-/Little-Endian-Codes bevorzugen. - Das Ergebnis ist ein Binär-String. Nicht per
echoauf einer HTML-Seite ausgeben oder als Text vergleichen; mitbin2hex()untersuchen oder in eine Binärdatei/einen Stream schreiben.
Für die umgekehrte Operation geht es weiter mit dem unpack()-Kapitel. Um die rohen Bytes in eigenen Experimenten sichtbar zu machen, ist der auf dieser Seite verwendete bin2hex()-Helfer unverzichtbar.
Fazit
pack() wandelt PHP-Werte in einen präzise kontrollierten Binär-String um, mit einer kompakten Format-Minisprache für Feldtyp, Größe und Byte-Reihenfolge. Es kommt zum Einsatz, wann immer Bytes erzeugt werden müssen, die ein anderes System nach seinen eigenen Regeln liest — Binärprotokolle, Dateiformate oder Krypto-Routinen — und wird mit unpack() kombiniert, um die Daten wieder zu lesen.