バイナリファイルの読み込みだけで良い場合は、簡単なサンプルクラスがあります。
バイナリファイルの読み込み
PHPでバイナリファイルを読み込む方法は、fopen、fseek、fread、fclose関数を使う方法と、file_get_contents関数を使う方法があります。 変数に読み込まれたデータの型はstring型になります。参考 バイナリファイルから読み込んだ場合の変数の型
-
fopen、fseek、fread、fclose関数
-
file_get_contents
fopen関数でバイナリファイルを開く場合、第二引数のmodeに、"b"を追加する必要があります。 読み込みだけの場合は"rb"、上書きの場合は"wb"などを指定します。 バイナリファイルの指定位置から、必要な長さだけ取得する場合は、以下のようにします。
$offset = 16; // バイナリファイル先頭の16バイト目から取得する $maxlen = 8; // 8バイト取得する $fp = fopen($path, 'rb'); if ($fp === false) { throw Exception("Can not open file: $jpg"); } fseek($fp, $offset); $data = fread($fp, $maxlen); fclose($fp);
fopen(PHPマニュアル) fread(PHPマニュアル) frseek(PHPマニュアル)
file_get_contents関数は、fopen関数などより簡単にファイルを読み込めます。 ファイル全部を読み込む場合は、以下のようにファイルパスだけを指定します。
$data = file_get_contents($path); if ($data === false) { throw new Exception("Can not read file: $path"); }
一部のデータだけを取得する場合は、第4引数に位置、第5引数に取得する長さを指定します。 例えば、バイナリファイル先頭の16バイト目から、8バイトだけ取り出す場合は以下のようになります。
$offset = 16; // バイナリファイル先頭の16バイト目から取得する $maxlen = 8; // 8バイト取得する $data = file_get_contents($path, false, null, $offset, $maxlen); if ($data === false) { throw new Exception("Can not read file: $path"); }
変数の中身確認
変数とバイナリデータの関係の確認
-
変数に16進数を代入
変数に16進数を代入した場合、型は整数型になります。
$data = 0xff; var_dump($data); //=> int(255) $data = 0xffd8; // 16進数のffd8を、10進数にすると65496 var_dump($data); //=> int(65496) $data = 0xffd8f7d6; // 16進数のffd8を、10進数にすると65496 var_dump($data); //=> int(4292409302)
バイナリファイルから読み込んだ場合の変数の型
fread関数やfile_get_contents関数でバイナリファイルを読み込んだ場合、変数にはバイナリデータが格納されますが、型はstring型になります。
例. 先頭の16バイトが以下のような、jpegの画像ファイルの場合
$ hexdump -vC -n 16 sakura01.jpg 00000000 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 |......JFIF.....H|
16進表示 : ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 ASCII表示 . . . . . . J F I F . . . . . Hfread関数での読み込み結果は以下のようになります。
$jpg = 'sakura01.jpg'; $fp = fopen($jpg, 'rb'); if ($fp === false) { throw Exception("Can not open file: $jpg"); } // 先頭から1バイト fseek($fp, 0); $data = fread($fp, 1); var_dump($data); // string(1) "?" var_dump(bin2hex($data)); // string(2) "ff" // 先頭から2バイト fseek($fp, 0); $data = fread($fp, 2); var_dump($data); // string(2) "??" var_dump(bin2hex($data)); // string(4) "ffd8" // 先頭から4バイト fseek($fp, 0); $data = fread($fp, 4); var_dump($data); // string(4) "????" var_dump(bin2hex($data)); // string(8) "ffd8ffe0" // 先頭から16バイト fseek($fp, 0); $data = fread($fp, 16); var_dump($data); // string(16) "????JFIFH" var_dump(bin2hex($data)); // string(32) "ffd8ffe000104a464946000101010048"freadで取得できるデータはバイナリデータですが、型はstringになります。 データが0xFFのような場合、var_dumpで表示すると中身が正しく表示されません。 表示したい場合は、bin2hex関数でバイナリデータをバイナリ文字列に変換します。
バイナリファイルのデータを配列にする
fread関数やfile_get_contents関数で取得したデータをbyte単位やlong単位などの配列にする場合、str_split関数か、unpack関数で行います。
参考 unpack関数を使ったバイナリファイル用のサンプルクラス
-
string型の配列で取得(str_split)
str_split関数は第二引数に指定したバイト数でデータを分割します。 そのため、バイト単位のデータが入った配列にしたい場合は、第二引数に1を指定します。
$data = file_get_contents($path);
$ar = str_split($data, 1); // 1バイトごとのstring型データが入った配列となります
文字列で16進を表すバイナリ文字列の配列
文字列で16進を表すバイナリ文字列("ff", "1a"など)でバイト単位の配列にしたい場合は、バイナリファイルから読み込んだデータをbin2hex関数でバイナリ文字列に変換後、str_split関数で2バイトごとに分割します。
$fp = fopen($jpg, 'rb');
if ($fp === false) {
throw Exception("Can not open file: $jpg");
}
fseek($fp, 0);
$data = fread($fp, 16);
$ar = str_split(bin2hex($data), 2); // $ar = array('ff', 'd8', 'ff', 'fe', '00', .... )となります
注. bin2hex関数でバイナリ文字列に変換後してstr_split関数で分割する場合、1バイト分は2文字になりますので、str_split関数の第二引数に2を指定します。
int型の配列で取得(unpack)
unpack関数で書式に"C*"を指定すると、int型のバイト単位(unsigned char)で配列取得できます。 ただし取得した配列は、0からでなく1から始まる配列となります。
$data = file_get_contents($path);
$ar = unpack("C*", $data); // $ar = array(1 => 255(0xff), 2 => 221(0xdd), 3 => 255(0xff) ...);
int型の2バイト単位(unsigned short)で配列を取得したい場合は、"S*"、"n*"、"v*"のどれかを指定します。
$data = file_get_contents($path);
$ar = unpack("S*", $data); // $ar = array(1 => 65496(0xffd8), 2 => 65504(0xffe0), 3 => 16(0x0010) ...);
連続するデータから異なる長さの複数データ取り出して配列にする
連続するデータから異なる長さの複数データを取り出したい場合は、unpack関数で可能です。
例 以下のようなjpeg画像ファイルの先頭6バイトを、ビッグエンディアンバイトオーダーで2バイト、4バイトと取り出す
$ hexdump -vC -n 16 sakura01.jpg 00000000 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 |......JFIF.....H|ビッグエンディアンバイトオーダー(上記データで、0xffd8と0xffe00010)で取り出す場合、unpack関数のフォーマト指定は2バイトに"n"、4バイトに"N"を指定します。 unpack関数のフォーマットでは、複数指定する場合"/"で区切るので、"/"で区切って "nfirst/Nsecond"と指定します。 結果は連想配列で返ってきて、最初の2バイトのキーが"first"、次の4バイトのキーが"second"になります。
$path = 'sakura01.jpg'; $fp = fopen($path, 'rb'); if ($fp === false) { throw Exception("Can not open file: $fpathIn"); } fseek($fp, 0); $data = fread($fp, 4); // unpack('nfirst/nsecond, $data)の 'n'は16bit、'N'は32bitのデータで、ビッグエンディアンバイトオーダーで扱う $val = unpack("nfirst/Nsecond", $data); var_dump($val); // 実行結果 // array(2) { // ["first"]=> int(65496) (0xffd8) // ["second"]=> int(4292870160) (0xffe00010) // }