バイナリファイル用サンプル
バイナリファイルデータを処理するためのサンプルクラス・BinaryUtil.phpを使ってのテスト。 BinaryUtil.phpでは、バイナリファイルのデータを8bit、16bit、32bitやASCII文字列で取得できます。
参考 PHP・バイナリデータ
例. 先頭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|
サンプルクラスのBinaryUtil.phpを使ったテストプログラム。 上記JPEGファイル"sakura01.jpg"の先頭16バイトを読み込み、データを表示しています。 BinaryUtil.phpのデフォルトは、ビッグエンディアンでデータを取得するようにしています。
<?php require_once('BinaryUtil.php'); $util = new BinaryUtil(); $util->read('sakura01.jpg', 0, 4); $data = $util->getByte(0); // 先頭の0xffを取得 printf("%d (%x)%s", $data, $data, PHP_EOL); // 255 (ff) $data = $util->getByte(1); // 先頭2番目の0xd8を取得 printf("%d (%x)%s", $data, $data, PHP_EOL); // 216 (d8) $data = $util->getShort(0); // 先頭0xffd8の2バイトを取得 printf("%d (%x)%s", $data, $data, PHP_EOL); // 65496 (ffd8) $data = $util->getShort(2); // 先頭3番目0xffe0の2バイトを取得 printf("%d (%x)%s", $data, $data, PHP_EOL); // 65504 (ffe0) $data = $util->getInt(0); // 先頭0xffd8fe0の4バイトを取得 printf("%d (%x)%s", $data, $data, PHP_EOL); // 4292411360 (ffd8ffe0) // リトルエンディアンのテスト。先頭0xff, 0xd8, 0xff, 0xe0の4バイトをリトルエンディアンで取得 $data = $util->getInt(0, BinaryUtil::LITTLE_ENDIAN); printf("%d (%x)%s", $data, $data, PHP_EOL); // 3774863615 (e0ffd8ff) // 文字列のテスト。 先頭7番目から 0x4a('J')、0x46('F')、0x49('I')、0x46 (’F')を取得 $data = $util->getString(6, 4); printf("%s(%d)%s", $data, strlen($data), PHP_EOL);これを実行すると以下のようになります。
$ php test_bin.php 255 (ff) 216 (d8) 65496 (ffd8) 65504 (ffe0) 4292411360 (ffd8ffe0) 3774863615 (e0ffd8ff) JFIF(4)
-
バイナリファイル処理用クラス
シンプルなバイナリファイルからデータを取得するためのクラスを作成。 バイナリファイルは内部でバイト単位の配列にして、PHPのint型にしています。 メソッドは、byte(8bit)、short(16bit)、int(32bit)の取得用と、ASCII文字列の取得用のみを実装しています。 日本語文字列の取得は未対応です。
<?php class BinaryUtil { const BIG_ENDIAN = 0; const LITTLE_ENDIAN = 1; /** * The buffer for data from a binary file. * * @var */ private $buffer; private $isBigEndian = true; /** * Set endian * * @param $val */ public function setEndian($val) { $this->isBigEndian = $this->checkBigEndian($val); } /** * Return true if the value is big endian, otherwise return false. * * @param int $endian * @return boolean */ public function checkBigEndian($endian) { if ($endian == self::BIG_ENDIAN) { return true; } elseif ($endian == self::LITTLE_ENDIAN) { return false; } else { throw new Exception("Invalid endian type: $endian"); } } /** * Read from the binary file and return string data of 8bit unsigned char. * * @param string $path * @param int $offset * @param int $length * @return array */ public function read($path, $offset = 0, $length = null) { if (is_null($length)) { if (empty($offset)) { $buffer = file_get_contents($path); } else { $buffer = file_get_contents($path, false, null, $offset); } } else { $buffer = file_get_contents($path, false, null, $offset, $length); } if ($buffer === false) { throw new Exception("Can not read file: $path"); } return $this->buffer = unpack('C*', $buffer); } /** * Return one PHP integer data of 8bit unsigned char * * @param int $offset * @return mixed */ public function getByte($offset) { return $this->buffer[$offset + 1]; } /** * Return one PHP integer data of 16 bit unsigned short * * @@aram int $offset * @param int $endian self::BIG_ENDIAN or self::LITTLE_ENDIAN * @return int|null */ public function getShort($offset, $endian = null) { if (!isset($this->buffer[$offset + 1]) || !isset($this->buffer[$offset + 2]) ) { return null; } if (is_null($endian)) { $isBigEndian = $this->isBigEndian; } else { $isBigEndian = $this->checkBigEndian($endian); } if ($isBigEndian) { $first = $this->buffer[$offset + 1]; $second = $this->buffer[$offset + 2]; } else { $first = $this->buffer[$offset + 2]; $second = $this->buffer[$offset + 1]; } return ($first << 8) + $second; } /** * Return one PHP integer data of 32 bit unsigned integer * * @param int $offset * @param int $endian self::BIG_ENDIAN or self::LITTLE_ENDIAN * @return int|null */ public function getInt($offset, $endian = null) { if (!isset($this->buffer[$offset + 1]) || !isset($this->buffer[$offset + 2]) || !isset($this->buffer[$offset + 3]) || !isset($this->buffer[$offset + 4]) ) { return null; } if (is_null($endian)) { $isBigEndian = $this->isBigEndian; } else { $isBigEndian = $this->checkBigEndian($endian); } if ($isBigEndian) { $first = $this->buffer[$offset + 1]; $second = $this->buffer[$offset + 2]; $third = $this->buffer[$offset + 3]; $fourth = $this->buffer[$offset + 4]; } else { $first = $this->buffer[$offset + 4]; $second = $this->buffer[$offset + 3]; $third = $this->buffer[$offset + 2]; $fourth = $this->buffer[$offset + 1]; } return ($first << 24) + ($second << 16) + ($third << 8) + $fourth; } /** * Return PHP string data * * @param int $offset * @param int $length * @return string */ public function getString($offset, $length) { $str = ''; for ($i = 0; $i < $length; $i++) { $str .= chr($this->getByte($offset + $i)); } return $str; } }