バイナリファイル用サンプル
バイナリファイルデータを処理するためのサンプルクラス・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;
}
}