ひとりアドベントカレンダー2015 第18日目 〜 PHPer でもバイナリをいじってみたい その3

  • このエントリーをはてなブックマークに追加
  • Pocket

18日目です。

今日は 「PHPer でもバイナリをいじってみたい」の第3回です。PHP でバイナリプログラミングをするうえでもっとも重要な2つの関数 pack()  と unpack()  について書いてみたいと思います。これらはバイナリデータの読み書き、すなわちバイナリ文字列とPHPの数値型との相互変換に使われます。

 

pack() 関数

pack() 関数はPHPの数値をバイナリ文字列に変換します。つまり、 PHP のデータをバイナリ形式で書き込むときに使えるということですね。第一引数に出力したいバイナリ文字列のフォーマット、第二引数以降にそのフォーマットに代入したい数値を指定します。フォーマットの指定法はリンク先の公式ドキュメントをご覧ください。

たとえば、 0xCA  1バイトからなるバイナリ文字列を作りたいならば、 c (= signed char)  のフォーマット文字を使って

 とします。 bin2hex() はバイナリ文字列を16進数表記の人が読める文字列に変換してくれる関数です。これで結果を確認します:

たしかに 0xCA  というバイトが吐かれたことがわかります。

フォーマットには繰り返しを指定することができます。 例えば、short 型(2バイト整数)を3つ、残りはデータの続く限り char 型(1バイト整数)を詰める、という風にするには、 's3c*'  のようなフォーマットにします。フォーマット文字の後ろに数値で繰り返し回数を指定でき、アスタリスクでデータの終わりまで繰り返すという指定をできます:

ここで s3  は「与えられた引数のうち3個を使って short 型のバイナリを3個出力する」という意味です。また c*  は「残りの引数全てを一つずつ char 型のバイナリとして出力する」という意味になります。

これの実行結果は以下のようになります:

ここで、フォーマット文字 s はマシンのバイトオーダーでショート型を出力する、という定義になっていることに注意します。ぼくはリトルエンディアンのアーキテクチャを持つ intel の CPU を使っているので、 0x1234  は下位のバイトから先に出力され、 34 12  というふうになっていることが見て取れます。(人間のアーキテクチャはビッグエンディアンですね!)

 

unpack() 関数

unpack()  関数は pack() と逆に、バイナリ文字列から PHP の数値型への変換を行います。つまり、バイナリ形式のデータを PHP で読み込む際に使えます。読み込んだ結果は連想配列になり、そのキーをフォーマット文字列の中に指定します。

例えば、バイナリ文字列の先頭の1バイトを読み取って PHP の整数型をひとつ取り出すには以下のようにします:

ここで、読み取り用のバイナリデータを作るために昨日見たバイナリ文字列のリテラル表現を使っています。ともかくこれで、結果の連想配列 $CA  に 'byte' というキーでバイト CA  を読み取った結果が入ります:

フォーマット文字 'c'  は signed char, すなわち符号付き1バイト整数なので CA  は10進法の -54 になることに注意しましょう。

フォーマット文字列には連想配列のキー名という任意性のあるものが含まれるので、区切り文字として  '/'  を用います。また、繰り返しの指定はキー名のあとに行います:

これは先頭から short 型を2つ読み、残りを byte 型で読み込むというフォーマットです。実行結果は以下のようになります:

 繰り返しの指定があるとキー名が byte1, byte2, … のようになるのですね。。。byte というキー名で値がまた配列になる、という方が使いやすそうですが。

 

まとめ

 今日は PHP でバイナリプログラミングをするうえでもっとも重要な、 pack() , unpack()  という2つの関数について見ました。 pack() は PHP のデータをバイナリ形式で書き込む時に使い、 unpack()  はバイナリ形式のデータを PHP で読み込むときに使います。

次回はこれらの関数を使って実際のバイナリデータの読み書きなどしてみたいです。

  • このエントリーをはてなブックマークに追加
  • Pocket

SNSでもご購読できます。

コメントを残す

*