アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

PHPでバイナリプログラミング その1

はじめまして、5月から入社した久保田と申します。 九州からはるばる上京してエンジニアとして働いています。

普段はanatooというIDでブログ書いたりしています。 また、BlankaというPHP5.3で動くフレームワークを開発していたり、はてな記法パーサなどに利用されているパーサコンビネータなどを公開しています。

今後、勉強会などにも積極的に参加していこうと思いますのでお会いしたときはよろしくお願いします。

さて、この記事ではPHPでのバイナリの扱い方について説明します。

バイナリとは、ざっくりと言えばテキスト以外のバイト列のことです。 バイト列とは1バイトで構成される任意の長さを持つ列の事で、1バイトとは256通りの値を表現できる8ビットのデータのことです。

画像や音楽、映像などのバイナリは全て、テキストエンコーディングに沿わないバイト列によって表現されています。

これらのバイナリを扱う方法を知ることで、プログラミングでできることの幅が広がります。

以下ではPHPで具体的にどのようにしてバイナリを扱えば良いのかを記します。

PHPでのバイナリの立場

PHPでは今のところテキストとバイナリを区別するものは何もありません。というのもPHPの文字列は単なるバイト列であるからです。マニュアルにも以下のように記述されています。



<blockquote>A string is series of characters, therefore, a character is the same as a byte. 
string は、文字が連結されたものです。PHP では、 文字は 1 バイトと同じです。
http://jp.php.net/manual/ja/language.types.string.php</blockquote>


file_get_contents関数では、通常のテキストファイルの中身を得るのと全く同じ方法でバイナリファイルの内容を得ることができます。



<?php 
$text = file_get_contents('foobar.txt');
$binary = file_get_contents('foobar.gif');


以下の様に文字列として扱っても何も問題ありません。



<?php
$binary .= 'foobar'; // しっぽに文字列をつける
strlen($binary);   // バイト列の長さが返る


PHPではテキストもバイナリも同じ文字列型に属するわけです。

unpack関数

上述したようにPHPではバイナリを文字列として扱うことができるわけですが、それだけではバイナリデータを解釈することはできません。

バイナリ内では様々な値をバイト列で表現しています。それらの値をPHPで扱えるようにするには文字列のままでは都合の悪い場合がほとんどです。例えば、数値を表現するバイト列があったとしてそれを文字列のまま扱うのはいくらなんでも面倒です。そういったデータはPHPの整数型として扱えた方がいいに決まっています。

そこでバイナリをPHPで扱い易いように変換してくれるのがunpack関数です。この関数はバイト列で表現された値を、PHPで簡単に扱える型にまとめて変換してくれる関数です。

unpack関数の使い方の詳細は公式マニュアルを参照するとして、ここでは一つ例を用意しました。 PNG画像の高さと幅を求める簡単な関数です。



<?php 

/** 
 * PNG画像の大きさを得る
 *
 * @param string $path
 * @return array
 */
function get_png_size($path)
{
    $fp = fopen($path, 'rb');
    fread($fp, 16);
    $bin = fread($fp, 8);
    fclose($fp);
    return unpack('Nwidth/Nheight', $bin);
}

var_dump(get_png_size('./foobar.png')); 
/* 結果
array(2) {
  ["width"]=>
  int(20)
  ["height"]=>
  int(10)
} */


このget_png_size関数でやっていることを簡単に説明すると、PNG画像のIHDRチャンクから画像の大きさを表現しているバイト列を取ってきてunpackでその幅と高さをPHPの整数に変換しています。

unpack関数の第一引数に渡す文字列がなにか奇妙な感じもしますが実際に自分でマニュアルを見ながら試してみればすぐに理解出来ると思います。

PNGフォーマットやIHDRチャンクの詳細などについてはPNGフォーマットの仕様書を見ましょう。

ここまでのまとめ

・バイナリを扱えるとできることの幅が広がる
PHPではテキストもバイナリも文字列型で表現される
・バイナリのデータをPHPの数値などに変換したい場合はunpack関数を使う

それでは、次回はPHPの値をバイナリに変換するやり方について説明します。