PHP言語でデータからビット情報の取得

PHP言語でデータからビット情報の取得

ソフトバンク・au・ドコモの方は、公式のオンラインショップを利用すれば頭金不要で通常のショップよりお得に購入できます。

普段、あまり利用することのないビット情報。思い浮かぶ限りでは、バイナリデータを扱う際に使用するぐらいではないでしょうか。逆に言えば、バイナリデータを扱う際には、ビット情報へのアクセスが避けられず、できないことには作業も進みません。

何故PHPでやるのか?

C言語やJAVAを使えば効率的に行える作業をわざわざWEB言語であるPHPで行うことは非効率に思えます。

しかし、PHPでバイナリデータを扱えるようになると画像、音声、動画、その他専用ツールでしか動作しないデータをアプリケーションを介さずにWEB上で処理をすることが可能になります。

画像だけで言えばImageMagickなどの外部モジュールを使って、専用のPHPコマンドで楽に処理をすることも可能ですが、データのタイプによってはモジュールが異なりますし、そもそも対象のデータタイプのモジュールが存在しない場合もあります。

必ずしもPHPMPの利用が最善というワケではありませんが、とりあえずWEBエンジニアが行う選択肢としては悪く無いという程度の考えですね。

もちろんPythonでもRubyでもJavaScriptでも・・・何でも良いというレベルでもあります。
とにかく気軽にバイナリデータを扱いましょうということなのです。

ここで、エンジニアではない人でも少し分かるように解説させていただきます。

バイナリ基礎知識

バイナリは基本的に2進数です。サクッとwikiを調べてみても、やはり同じようなことを説明しています。
<参考:ウィキペディア「バイナリ」>

それでもウィキペディアの情報だけでは、エンジニアではない人にしてみれば理解し難い情報かと思われます。できるだけ分かりやすく説明してみます。

パソコンのデータは2パターン

そもそも、パソコンのデータは「テキストデータ」と「バイナリデータ」の二種類しかありません。
テキストデータはメモ帳などで使っているような、「*.txt」などのファイル拡張子がついています。いわゆる、人の目で見て分かるデータと理解してください。
つまり、それ以外は全てバイナリデータ(ファイル)です。

サンプル

「*.csv」の中身をテキストエディタで見たことがある人は分かっていただけると思いますが、エクセルのデータが書き込まれているのが分かります。

image03

image04

しかし「*.xls」ファイルの場合はテキストエディタではまともに開けず、無理やり開いたところで訳の分からない文字列が並んでいるのが見て分かります。これがバイナリデータになります。

image07

今回は、このバイナリデータを読み込む処理を行います。

読み込みパターン

実際のプログラムでデータを読み込んでみます。
ここではvertualboxにPHPモジュールをインストールするか、サーバにデータを置いて下記を実行してみてください。なお、この環境構築はググッてください。

bit単位で読み込み

下記のPHPをCLIで実行すると、2進数のバイナリデータが確認できます。

–[getBits.php]–

  
* param @ file
* param @ start-bit (default : 0)
* param @ count-bit (default :8)
**/

//Default-set
$startBit = (isset($argv[2]))?$argv[2]:0;
$countBit = (isset($argv[3]))?$argv[3]:8;

// load data
$data = file_get_contents($argv[1]);

// getBits
echo BINARY::getBits($data,$startBit,$countBit).PHP_EOL;

exit(0);

// Library
class BINARY{
    /**
    * 対象データの指定アドレスを2進数で返す
    * param @ data
    * param @ start-address(bit-number) (default:0)
    * param @ bit-count(*bits)(default:8)
    * return @ Binary number
    **/
    function getBits($data, $bitStart=0, $bitCount=8){
        $byteShift = (int)($bitStart / 8);
        $byteOffset=0;
        $byteOffset += $byteShift;
        $bitStart  = ($bitStart % 8);
        $val = "";
        $cnt = $bitStart;
        while($bitCount--){
            if($cnt > 7){
                $cnt=0;
                $byteOffset++;
            }
            $val.= 1 & (ord($data{$byteOffset}) >> (7-$cnt));
            $cnt++;
        }
        return $val;
    }
    function getBytes(){
        
    }
}

仕様サンプル

# デフォルト(最初からの8bit分を取得)
$ php getBit.php test.xlsx
01010000

# 途中bitの取得
$ php getBit.php test.xlsx 1 4
1010

# 32bit分の取得
$ php getBit.php test.xlsx 0 32
01010000010010110000001100000100

ほとんどのバイナリデータは、データの最初の数バイトをフォーマットの共通データとして保持しています。
拡張子が同じであれば、24bitまたは32bitぐらいが同じということになります。

byte単位で読み込み

実際にbitの2進数で見ても分かりづらいので、通常のバイナリデータは16進数で閲覧します。
そのため、byte対応の読み込みを下記プログラムで実行しましょう。

–[getByte.php]–
[php] /**
* Howto) CLI only
* Ex) php getByte.php
* param @ file
* param @ start-byte (default : 0)
* param @ count-byte (default :2)
**/

//Default-set
$startByte = (isset($argv[2]))?$argv[2]:0;
$countByte = (isset($argv[3]))?$argv[3]:2;

// load data
$data = file_get_contents($argv[1]);

// getBytes
echo BINARY::getBytes($data,$startByte,$countByte).PHP_EOL;
exit(0);

// Library
class BINARY{
/**
* 対象データの指定アドレス(byte)を16進数で返す
* param @ data
* param @ start-address(byte-number) (default:0)
* param @ byte-count(*bits)(default:2)
* return @ Hex number
**/
function getBytes($data, $byteStart=0, $byteCount=2){
$val = “”;
for($i=0;$i<$byteCount;$i++){
$byteData = $data{$byteStart + $i};
$val.= join(“”, unpack(“H” , $byteData));
}
return $val;
}

}
[/php]

仕様サンプル

# デフォルト
$ php getByte.php test.xlsx
54

# 2バイト目のみ取得(1バイト目が0になります)
$ php getByte.php test.xlsx 1 1
4

# 最初から4byte分の取得
$ php getByte.php test.xlsx 0 4
5400

ヘッダ専用

ヘッダは固定文字+テキストである場合が多いので、下記のコードを実行すると分かりやすいと思います。

これはbit変換せずに、そのままテキスト表示するだけなので非常に楽です。

–[getHeader.php]–

  
* param @ file
* param @ start-bit (default : 0)
* param @ count-bit (default :8)
**/

//Default-set
$startBit = (isset($argv[2]))?$argv[2]:0;
$countBit = (isset($argv[3]))?$argv[3]:8;

// load data
$data = file_get_contents($argv[1]);

// getBits
echo BINARY::getBits($data,$startBit,$countBit).PHP_EOL;

exit(0);
// Library
class BINARY{
    /**
    * 対象データの指定アドレスを2進数で返す
    * param @ data
    * param @ start-address(bit-number) (default:0)
    * param @ bit-count(*bits)(default:8)
    * return @ Binary number
    **/
    function getBits($data, $bitStart=0, $bitCount=8){
        $byteShift = (int)($bitStart / 8);
        $byteOffset=0;
        $byteOffset += $byteShift;
        $bitStart  = ($bitStart % 8);
        $val = "";
        $cnt = $bitStart;
        while($bitCount--){
            if($cnt > 7){
                $cnt=0;
                $byteOffset++;
            }
            $val.= 1 & (ord($data{$byteOffset}) >> (7-$cnt));
            $cnt++;
        }
        return $val;
    }
    function getBytes(){
        
    }
}

仕様サンプル

$ php getHeader.php test.gif 
GIF8

$ php getHeader.php test.png
?PNG

$ php getHeader.php test.pdf
%PDF

$ php getHeader.php test.xlsx 64
P!;H?@i[Content_Types].xml ?(?

$ php getHeader.php test.docx 64
P!9??N[Content_Types].xml ?(?

$ php getHeader.php test.swf 
FWS

4byteで取得した時に、比較的キレイに取得できるのは画像ファイル系のようですね。

バイナリデータのルールを定めるのは対象のアプリケーションなので、世界標準がない以上、そのデータの特性をSDKなどで熟知して対応しないといけないようです。ただ、画像のヘッダ情報で種別判別はできそうですね。

内部情報が取得できるようになると無限の可能性もあるので、こういった技術もPHPで対応可能ということが分かりました。少しマニアックな領域に踏み込んでみましたが、エンジニアとして研究してみるのも面白いと思います。

ソフトバンク・au・ドコモの方は、公式のオンラインショップを利用すれば頭金不要で通常のショップよりお得に購入できます。

この記事を書いた人
アバター
下駄(弓削田)
Creativeに生きるRunner

【週刊bitWave】(メルマガ)始めました!

登録はこちらからメールアドレスを入力してお申込みください。

ご登録いただいたメールアドレスは 【週刊bitWave】の更新情報の配信にのみ使用します。

個人情報の取扱いに関しては、「プライバシーポリシー」をご確認ください。解除はいつでもこちらから行うことが可能です。

あなたにおすすめ