PHPでは、バイナリデータを処理する場合、 pack()とunpack()関数は2つの非常に実用的なツールです。データを特定の形式でバイナリ文字列に変換するか、バイナリ文字列を構造化されたデータに解析できます。これは、カスタムデータ構造のシリアル化と降下を実装したり、基礎となるプロトコルやファイル形式との対話をするために非常に重要です。
この記事では、Pack()とunpack()関数を組み合わせて、カスタムデータ構造の解析と変換を実装する方法について詳しく説明します。
pack(format、args ...) :フォーマット文字列に従ってパラメーターargsをバイナリ文字列にパッケージ化します。
[フォーマット、データ] :[形式]文字列に従ってバイナリ文字列データを連想配列に解除します。
フォーマット文字列は、データ型、長さ、およびエンディアン性を定義するフォーマットコードで構成されています。例えば:
C :署名されていない文字(1バイト)
N :署名されていない16ビットのビッグエンディアンエンディアンエンディアン整数
V :署名されていない32ビットリトルエンディアンエンディアンエンディアン整数
A :nul塗りつぶされた文字列
A :スペースが充填された文字列
その他のフォーマットコードについては、公式のPHPドキュメントを参照してください。
単純なデータ構造を次のように定義しているとします。
フィールド名 | タイプ | 長さ(バイト) | 説明します |
---|---|---|---|
タイプ | uint8 | 1 | データ型識別 |
長さ | UINT16 | 2 | 後続のデータ長 |
ペイロード | バイトストリーム | 長さ | 特定のデータコンテンツ |
私たちの目標は次のとおりです。
PHPデータ構造を上記の形式を満たすバイナリデータにパッケージ化します。
バイナリデータは解析され、タイプ、長さ、ペイロードフィールドが抽出されます。
<?php
function packData(int $type, string $payload): string {
$length = strlen($payload);
// 'C' - 1バイト符号なし整数
// 'n' - 2バイト署名されていないビッグエンディアン整数
// 'a*' - 任意の長さの文字列,NUL充填(这里不需要充填)
return pack('Cn', $type, $length) . $payload;
}
// テスト
$type = 5;
$payload = "Hello, World!";
$binaryData = packData($type, $payload);
echo bin2hex($binaryData);
?>
ここでは、Pack( 'cn'、$ type、$ length)は、最初にタイプと長さを個別にパックし、次に元の文字列$ペイロードをスプライスします。
解析中に、最初に固定長い部分のタイプと長さを取り出し、長さに応じて残りのペイロードを傍受します。
<?php
function unpackData(string $binaryData): array {
// 先解包前3バイト,type(1バイト) + length(2バイト大端)
$header = unpack('Ctype/nlength', substr($binaryData, 0, 3));
$type = $header['type'];
$length = $header['length'];
// 残りを取り出しますpayloadデータ
$payload = substr($binaryData, 3, $length);
return [
'type' => $type,
'length' => $length,
'payload' => $payload,
];
}
// テスト
$data = $binaryData; // 上から仮定しますpackData出力
$result = unpackData($data);
var_dump($result);
?>
上記の2つの関数を統合して、カスタム構造のシリアル化と敏aserializationを実装します。
<?php
function packData(int $type, string $payload): string {
$length = strlen($payload);
return pack('Cn', $type, $length) . $payload;
}
function unpackData(string $binaryData): array {
$header = unpack('Ctype/nlength', substr($binaryData, 0, 3));
$type = $header['type'];
$length = $header['length'];
$payload = substr($binaryData, 3, $length);
return [
'type' => $type,
'length' => $length,
'payload' => $payload,
];
}
// 使用の例
$type = 10;
$payload = "PHP pack/unpack デモ";
$packed = packData($type, $payload);
echo "二进制データ(hex):" . bin2hex($packed) . "\n";
$unpacked = unpackData($packed);
echo "分析結果:\n";
print_r($unpacked);
?>
実行結果:
二进制データ(hex):0a0017... (hexエンコードされたバイナリコンテンツ)
分析結果:
Array
(
[type] => 10
[length] => 23
[payload] => PHP pack/unpack デモ
)
pack()およびunpack()は、バイナリデータを処理するための強力なツールであり、複数のデータ型とエンディアン変換をサポートしています。
カスタムデータ構造を解析するには、最初に固定ヘッダー形式を定義し、次に文字列操作を使用して可変長フィールドを処理できます。
バイナリ処理と組み合わせることで、PHPはネットワークプロトコル、ファイル形式の解析、その他のシナリオを簡単に扱うこともできます。