Slide 1

Slide 1 text

PHP  でバイナリ処理Tips 2015/11/10   [email protected]

Slide 2

Slide 2 text

自己紹介 •  2年前、六本木のSNS系会社で働いてました       •  バイナリ変換が趣味です   1  1  0  1          0 0  1  0

Slide 3

Slide 3 text

公開ライブラリ •  h8ps://github.com/yoya/IO_Bit   –  バイナリ編集ライブラリ   –  h8ps://github.com/yoya/IO_MIDI •  音楽の MIDI  ファイル編集   –  h8ps://github.com/yoya/IO_PNG   •  画像ファイルのPNG編集   –  h8ps://github.com/yoya/IO_ICC   •  ICCプロファイル編集

Slide 4

Slide 4 text

本発表について •  この発表の焼き直しです   – PHPでバイナリ変換プログラミング   – h8p://www.slideshare.net/yoyayoya1/ php-­‐10133775   •  PHP  でバイナリ変換するのは楽という話   – 小さなバイナリを処理するには良い感じ   – (メモリを沢山使うので、大きなバイナリを扱うの はキツい)  

Slide 5

Slide 5 text

バイナリって何? •  バイナリって何?   – 本来は、コンピュータが処理し易い  0,1  の2進値 データ   – 世間的には、テキスト以外のデータ  (狭義のバイ ナリ)   GIFファイル   (php.gif)

Slide 6

Slide 6 text

バイナリとテキスト •  1バイトで0~255の値を表現できるけど、US-­‐ ASCII テキストはその一部しか使わない。(日 本語は複雑なので棚にあげる)   •  バイナリの方がより多くの情報を詰められる   0〜0x19 0x20~0xf9 0x80~0xff ! ” # … A B C … 0 1 2 … a b c … この辺りの 値が化けて 表示される  

Slide 7

Slide 7 text

バイナリの例 •  バイナリの種類   – 実行ファイル (exe,  a.out,  jar)   •  セキュリティ界隈だと主にコレ   – マルチメディア系ファイル (JPEG,  PNG,  MPEG,  …)   – ネットワーク通信パケット (TCP,  ISDN,  …)   – 圧縮されたデータ (zip,  gzip)   – 暗号化されたデータ (SSL)   いろいろある!  

Slide 8

Slide 8 text

何故バイナリ処理するのか •  Webサービスでもテキスト以外の、画像や動 画、または生の通信プロトコルを扱う事があ る   •  そのデータを PHP  で改変する事で   – より多くの種類の端末にサービスを提供できたり   – 通信データ量を減らせたり   •  エディタで開いて化けるだけで編集を諦める のは、勿体無い。

Slide 9

Slide 9 text

ビット(Bit)とバイト(Byte) •  コンピュータ内部で処理(入出力、編集)する 単位   •  バイナリ処理は、これらの単位でプログラミン グする 43 57 53 06 00 48 2c 00 78 9c b9 6b バイト列 00100011 01010111 ビット列 バイナリ バイナリ

Slide 10

Slide 10 text

ビット(Bit)について •  0  と 1  を用いて2通りの状態を示す   •  ビットを並べ4通り8通りと表現の幅を広げる 1 0 2通り   (0〜1) 1 0 4通り   (0〜3) 1 0 1 0 256通り   (0〜255) 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 8通り   (0〜7) 1 0 1 0 00,  01,  10,11   0,  1 000,  001,  010,  011,   100,  101,  110,  111   00000000,  00000001,  00000010,  00000011,  …                            …,  11111101,  11111110,  11111111   1 0 0 0 0 1 1 1

Slide 11

Slide 11 text

バイト(Byte)について •  (欧米の)1文字を表すビットの集まり   – 一般的にはビットを8つまとめた単位   – 16進数で表示する事が多い (バイナリダンプ等) 1 0 4Bit  で   16進1文字 1 0 1 0 1 0 1 0 1 0 1 0 1 0 F  F 0  0 8Bit  で   16進2文字 8bitまとめて   1byte 実例 (JPEG の頭) FF D8 FF E0

Slide 12

Slide 12 text

バイナリエディタ諸々 •  Macintosh なら 0xED,  Windows  なら S_rling,  Bz   Editor   •  手で編集するのが面倒になった時、PHP  の出番

Slide 13

Slide 13 text

閑話休題 •  ここまでがバイナリの基本   •  ここから PHP  でバイナリ処理の話

Slide 14

Slide 14 text

PHP でバイナリ大丈夫? •  PHP  の String  型はバイナリとして使える   –  h8p://www.php.net/manual/ja/ language.types.string.php#language.types.string.details   •  文字列としての処理を勝手にしない   – 8bit  スルー、¥0  終端無視!   PHP  における文字列型は、バイトの配列と整数値 ( バッファ長)  で実装されています。 バイト列を文字列 に変換する方法については何の情報も持っておらず、 完全にプログラマ任せとなっています。

Slide 15

Slide 15 text

String 型でバイト単位の処理 •  (バイナリ)ファイル入出力     •  連結と分解 file_get_contents file_put_contents ファイル ファイル input output 連結 $c = $a . $b $b = substr($a, $x, $y) 分解 $a $b $c $a $b $x $y

Slide 16

Slide 16 text

String 型とInteger型変換 •  ord  と chr  で相互変換する $b = ord($a) $a = chr($b) バイナリ $a 整数値 $b $a = ‘Yoya’; $b = ord($a[0]); echo $b; $b = 89; $c = 111; $a = chr($b).chr($c); echo $a; 実行結果   ⇒  89          =  (0x59) 実行例   (分かりやすいようにテ キストで) Y   o   実行結果   ⇒  Yo Y   (string)   (integer  or  float)  

Slide 17

Slide 17 text

Endian  に応じた処理 •  2byte以上のバイナリと整数値の相互変換   – Bit  Endian  (MSB  First)   – Li8le  Endian  (LSB  First) バイナリ 0x12 0x34 整数値 x y (x*256)+y 0x1234 = 4660 バイナリ 0x12 0x34 整数値 x y x+(256*y) 0x3412 = 13330 =0x100

Slide 18

Slide 18 text

BigEndian  で unpack •  バイナリと整数値の相互変換 (BigEndian)   •  pack  で逆変換 $b = unpack(‘n’, $a) バイナリ $a $b = unpack(‘N’, $a) $b[1] $b[1] 整数値 整数値 バイナリ $a w x y z (((((w*256)+x)*256)+y)*256)+z x y (x*256)+y

Slide 19

Slide 19 text

Li8leEndian  で unpack •  バイナリと整数値の相互変換 (Li8leEndian)   •  pack  で逆変換 $b = unpack(‘v’, $a) バイナリ $a $b = unpack(‘V’, $a) $b[1] $b[1] 整数値 整数値 バイナリ $a w x y z w+(256*(x+(256*(y+(256*z))))) x y x+(256*y)

Slide 20

Slide 20 text

String 型のバイト処理 その他 •  strrev で前後リバース  (逆順にする)   •  substr_replace  で一部入れ替え   •  strcmp でバイナリ比較  (一致するか否か)   •  str_pad, str_repeat  で同じバイトの繰り返し   str  系で色々なバイナリ操作が可能!  

Slide 21

Slide 21 text

バイト処理の注意点 •  $a[0] •  文字列を配列のように参照すると、($a  の 0  番目の数値でなく)、0番 目の文字を切り出したものが取得できる。   •  $a[0] は substr($a, 0, 1) と同じ    (C言語出身者は多分ココで躓く)   •  unpack(‘N’,  …  と ‘V’の PHP  bug   –  N,  V  は unsigned  long  (32ビット値)のはずだが、実際は signed  long(符号付き)の値が出てくる   –  負の値が出てきたら 4294967296  を足して補正   •  足すと (integer    の範囲を超えて)型が float になる。要注意。   •  64bit環境ではこの問題がなくなりました。   •  でも、今度は 64ビット非負整数  (Q,  P)で同様の問題あり   –  pack  は正でも負でも受理してくれる  

Slide 22

Slide 22 text

バイト処理の実例 JPEG分解 •  JPEGの画像サイズを抜き出す   – h8p://www.w3.org/Graphics/JPEG/  ← 仕様   •  JPEG  チャンクの並び   JPEG SOI DQT DHT RST APP1 SOS SOF0 EOI ここにサイズが 入っている   width height

Slide 23

Slide 23 text

JPEG データ形式 •  JPEG  チャンクのデータ形式 SOF0 Marker   =0xffc0 Length 2  bytes 2  bytes Data P height 1  byte width 2  byte 2  byte SOI,EOI Marker APP,DQT,  SOF0 Marker Length SOS,RSTx Marker 2  bytes 2  bytes 2  bytes 2  bytes 次のchunkまでscan Data Data Length Marker FF??  &   !  FF00

Slide 24

Slide 24 text

JPEG  サイズ抽出サンプル

Slide 25

Slide 25 text

ちなみに •  ge_magesize で画像サイズは取れます。。  

Slide 26

Slide 26 text

IO_Bit •  やっぱり str  系関数使うの面倒ですよね   – バイナリなのに str  使うの気持ち悪い   •  そんな人(自分含む)の為に     •  h8ps://github.com/yoya/IO_Bit   – バイナリ編集ライブラリ  

Slide 27

Slide 27 text

IO_Bit ライブラリ •  ビットやバイトを頭から切り出す     •  Endian 処理も簡単 input($data); var_dump($iobit->getData(4)); // 2byte のBigEndian整数を取得 var_dump($iobit->getUI16BE());

Slide 28

Slide 28 text

IO_Bit の使い方 •  バイナリを解釈して PHP  の配列に入れる   •  PHP  の配列を操作して、またバイナリに戻す [[Event:9, Note:43, Velocity:100], …⋯] PHP配列 バイナリ バイナリ Input   &  parse build   &  output

Slide 29

Slide 29 text

IO_MIDI •  h8ps://github.com/yoya/IO_MIDI   – MIDI編集ライブラリ   IO_Bit IO_MIDI ユーザ プログラム parse input 入力 output build バイナリ 出力 ここで   編集  

Slide 30

Slide 30 text

IO_MIDI  使い方 •  h8ps://github.com/yoya/IO_MIDI   – MIDI編集ライブラリ (IO_Bit  でバイナリ分解)   parse($data); var_dump($midi);

Slide 31

Slide 31 text

var_dump($midi) 出力

Slide 32

Slide 32 text

IO_MIDI 構造 IO_MIDI header tracks header Format(1) NumberOfTracks  (9)   Division  (480)   0 track   DeltaTime   EventType   NoteNumber   Velocity   1 8 :   :   これを   書き換えて   みる   (音程) (音の強さ)

Slide 33

Slide 33 text

音程を変える •  1オクターブ上げる (半音で12個上) parse($data); foreach ($midi->tracks as &$track) { foreach ($track['track'] as &$event) { if (isset($event['NoteNumber'])) { $event['NoteNumber'] += 12; // octave up! } } } echo $midi->build();

Slide 34

Slide 34 text

結果 •  元   h8p://diary.awm.jp/~yoya/data/2015/11/10/akatomb.mid       •  変換後)  1オクターブup   h8p://diary.awm.jp/~yoya/data/2015/11/10/ akatomb-­‐12up.mid    

Slide 35

Slide 35 text

1オクターブ上がると   ピンとこない人用 •  元)   h8p://diary.awm.jp/~yoya/data/2015/11/10/akatomb.mid       •  変換後)  半オクターブup   h8p://diary.awm.jp/~yoya/data/2015/11/10/ akatomb-­‐6up.mid   // $event['NoteNumber'] += 12; // octave up! $event['NoteNumber'] += 6; // half octave up!

Slide 36

Slide 36 text

という感じで •  バイナリと PHP配列構造との、相互変換 (parse  と build)  を作ってしまえば、編集し放題 です  

Slide 37

Slide 37 text

•  以上です