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

Download Report

Transcript PHP でバイナリプログラミング

PHP でバイナリプログラミング
2010/05/11 よや
http://d.hatena.ne.jp/yoya/
はじめに
• PHP でバイナリ処理の話をあまり聞かないの
で、あえてニッチを狙って(多分、PHP 勉強会
らしくない)発表をさせて頂きます。
• キーワード: Binary、Format, Byte,
• デモ: JPEGからGPS抜き出し (pure PHP で)
• PHP というより、バイナリ入門といった要素が
強いですが、多分…、いつかお役に立つ日が
来ると思います。どうか、ご容赦ください。
一応、自己紹介
• http://d.hatena.ne.jp/yoya/ でプログラミング
してて困った事とか書いてます。
• 一昨年位まで、数十万ユーザ規模の携帯サ
イトでアプリ開発をしていました。
– その時に、PHP で主に動画や画像のフォーマット
を弄るお仕事をしていました。フレームワークとか
よく知りません。
• 今も、一応 PHP でお仕事してます。あと、C 言
語もたまに使います。
まずは、バイナリの定義
• Wikipedia より
– 通常バイナリとテキストは対比して用いられる。
テキストとはデータの内容すべてを人間が読んで
理解できる (human-readable) 表現形式を指し、
バイナリとはそうでない表現形式を指すことが多
い。
• なので、本発表では、バイナリファイルの事を、
– テキストエディタで開いて読めない文字とか記号
が表示されるようなファイル。
という事にしておきます。
バイナリの実例
• linux 等 UNIX 系OSには(多分) hexdump とい
うコマンドがあります。-C オプションが便利。
• % hexdump -C aria.gif
• % hexdump -C kuriboo.png
バイナリの実感
• 先頭の4文字を見るとファイルの種類が大体
分かるようになっていて、その後ろにはよく分
からないデータが続いてます。
• 普通はここで読むのを諦めるのですが、この
よく分からないデータを PHP で解釈して、欲し
いデータを抜き出す方法について説明します。
PHP とバイナリ
PHP の string 型でバイナリ処理が
簡単に出来るよ!
• というのが今回、紹介する Tips の肝です。
• (注) PHP6 では UTF-8 対応したり取りやめたりと怪し
いので、今回の発表はとりあえず、PHP5(PHP4 も多分
大丈夫) only での話しだと思ってください。
本当に PHP の string 型でバイナリ処
理できるの?
ぱっと思いつく不安としては、
• \0 文字列終端
• 8bitスルー
(不安その1) \0 は?
• C言語が典型で、\0 を文字列の(最後を表す)終端マー
クとして使う処理系も結構ある。 string型をバイナリ
データとして使う場合に、間に \0 が入る事で途中で切
れないかという不安。
• 簡単に確認 →
• 確認完了 \0 で途切れない。
(不安その2) 8bitスルー?
• 1文字は 1byte で、1byte は 8bit で構成されますが、
• US-ASCII は 7bit で表現できるので、先頭1bit が特別
扱いされたりしない?
• 8bit スルーです。日本語とかも入れられるし当然です
ね。
バイナリを取り込んでそのまま出力
• でも、細かい事考えなくても、バイナリファイルを取り込ん
で、何も変えずに出力して同じデータに戻れば、OKですよ
ね。
• 入力をそのまま出力して、同じデータになりました。
• 後は、この途中でデータを分割したり結合したり、入れ替
えたりすれば編集できる事になります。
Byte処理
• String 関数が使えます http://php.net/manual/ja/ref.strings.php
– strlen (データサイズを調べる。呼ぶたびに文字数を数えたりしないの
で安心) ☆
– substr (データから一部を抜き出す) ☆
– substr_replace (データの一部を入れ替える)
– strrev (データの前後を逆にする) Endian 処理に便利 ☆
– chr 数値 => 文字(バイナリ1byte) ☆
– ord 文字(バイナリ1byte) => 数値 ☆
– bin2hex ダンプするのに便利です ☆
• これだけ分かれば大丈夫。(今回の発表では、☆のついた関数が
出てきます) pack 関連は次回発表の機会があれば…
• さて、JPEG で試してみます。
JPEG の解析
• 今回のデモ
iPhone で写真を撮ると、位置情報が付くらしい
JPEG から GPS 情報を抜き出す
(JPEG > Exif(Tiff) > GPSInfo)
2重にくるまれてる…
初めの一歩
• まずファイルを開いてみる
• 見てても読めないし法則も分からない。
JPEGフォーマットでググる
• 「JPEG フォーマット 仕様」でググってみる
– http://siisise.net/jpeg.html#format
• 16bit は 2 byteに相当。ffxx で区切るらしい。
• 眺めていると、何となくピンと来るはず。
JPEG を marker で分割してみる
• この ffxx のマークで分割してみます。
• http://siisise.net/jpeg.html#format
– Marker の種類
FFD8, FFE0, FFDB, FFC4, FFC0, FFC1, FFDD, FFDA
… etc
データを切り出すクラス
• まず、バイナリの先頭から Byte を切り出すク
ラスを作成
• 内部的に、何処まで読んだか(cursor) を覚え
ておいて、そこから substr で一部のデータを
切り出すだけのクラス
marker 一個目
• http://siisise.net/jpeg.html#format によれば、
初めのマーカーは FFD8 (Start of Image)
Marker 逐次処理
• SOI (Start of Image) と EOI (End of Image) は
マーカー(2byte)だけ
• APP0, APP1, 等殆どのタグはマーカー(2byte)
に続いて、長さ(2byte) 、その後ろにデータが
(長さ-2分の)続く
• SOS は EOI の直前まで続く (途中で RST という
別のタグがあるが、今回は中にまとめちゃう)
Marker逐次処理コード
Marker分割結果
• 分割できた
Marker の照らし合わせ
GPS 情報は Exif にくるまれてる
• 「JPEG GPS フォーマット 仕様」でググる
– http://detail.chiebukuro.yahoo.co.jp/qa/question_det
ail/q1217494967
• 「JPEG exif フォーマット 仕様」でググる
– http://www2.airnet.ne.jp/~kenshi/exif.html
– http://hp.vector.co.jp/authors/VA032610/JPEGFormat
/AboutExif.htm
– http://www.exif.org/Exif2-2.PDF
• APP1 に入っているらしい。
• ディレクトリ構造らしい。(面倒そう…)
Little Endian ?
• Exif は Little Endian を使う事があるらしい
• バイナリを16進で見た並び => 対応する整数
値
– Big Endian
– Little Endian
ByteStream の LittleEndian対応
APP1の抽出
• JPEG を分解するついでに $jpeg_chunk 配列
に格納して
• $jpeg_chunk 配列から APP1 で Exif のデータ
を抜き出す
Exif分解コード
Exif分解結果
GPSInfo の分解
• GPS は GPSInfo というタグに入っているらしい
• 「JPEG exif GPSInfo フォーマット 仕様」でググ
る
– http://www2.airnet.ne.jp/~kenshi/exif.html
GPSInfo の分解コード
GPSInfo 分解結果
• Nは北緯、Eは東経、他は座標値等々…
Bit処理は…
• Byte を更に細かく区切ったBit処理(0,1のデー
タ)もお話したかったのですが、時間に収まら
なかったのでもし要望があれば次回に発表し
ます。
まとめ
• バイナリは大抵 TLC 構造か、難しくてもディレ
クトリ構造なので、これらが分かれば大抵処
理可能。今回は両方処理しました。
• TLC 構造
• ディレクトリ構造
蛇足的なTips
• PHP の閉じタグ ?> は使わない。?> の後ろに改行やゴミ文
字があった場合に、テキストなら最後にゴミが付くだけで大
きな問題になりにくいが、バイナリだと致命的。
• $s = '' 等、文字列でも文字数が0 だと、$s{3} = 'A' とした場
合に、array([3] => "A"); のように配列になる。
• $s = ‘ ‘(空白1文字)等としとくと、string(4) " A" のように思っ
た通りいく。足りない分は 0x20(スペース) で padding され
るのに注意
• C言語なら文字列から1文字抜き出してASCIIコードとして使
えるが、PHP の場合は文字は ord で ASCII コード値に変換
して、文字に戻す時は chr() を通す必要がある。
次回予告(?)
• 今回、PHP らしくない力づくのスマートでない手法の紹
介でした。
• もし、次回の要望があれば、Flash SWF の書き換えに
ついて発表したいです。
• Flash SWF は bit と signed 処理の組み合わせがあった
りと、そこそこ面倒なので、今回の発表から外しました。
• Google検索: yoya swfed
あ…
• ここまで頑張っておいて何ですが…
/php-5.2.9/ext/exif/
• http://php.net/manual/ja/function.exif-readdata.php
var_dump(exif_read_data($argv[1]));
• !!!!!!!!
以上です
ありがとうございました。