Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPBinaryTips

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for yoya yoya
November 10, 2015

 PHPBinaryTips

PHPでバイナリ処理Tips

Avatar for yoya

yoya

November 10, 2015
Tweet

More Decks by yoya

Other Decks in Programming

Transcript

  1. 公開ライブラリ •  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プロファイル編集
  2. 本発表について •  この発表の焼き直しです   – PHPでバイナリ変換プログラミング   – h8p://www.slideshare.net/yoyayoya1/ php-­‐10133775   • 

    PHP  でバイナリ変換するのは楽という話   – 小さなバイナリを処理するには良い感じ   – (メモリを沢山使うので、大きなバイナリを扱うの はキツい)  
  3. バイナリの例 •  バイナリの種類   – 実行ファイル (exe,  a.out,  jar)   • 

    セキュリティ界隈だと主にコレ   – マルチメディア系ファイル (JPEG,  PNG,  MPEG,  …)   – ネットワーク通信パケット (TCP,  ISDN,  …)   – 圧縮されたデータ (zip,  gzip)   – 暗号化されたデータ (SSL)   いろいろある!  
  4. 何故バイナリ処理するのか •  Webサービスでもテキスト以外の、画像や動 画、または生の通信プロトコルを扱う事があ る   •  そのデータを PHP  で改変する事で

      – より多くの種類の端末にサービスを提供できたり   – 通信データ量を減らせたり   •  エディタで開いて化けるだけで編集を諦める のは、勿体無い。
  5. ビット(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
  6. バイト(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
  7. バイナリエディタ諸々 •  Macintosh なら 0xED,  Windows  なら S_rling,  Bz  

    Editor   •  手で編集するのが面倒になった時、PHP  の出番
  8. PHP でバイナリ大丈夫? •  PHP  の String  型はバイナリとして使える   –  h8p://www.php.net/manual/ja/

    language.types.string.php#language.types.string.details   •  文字列としての処理を勝手にしない   – 8bit  スルー、¥0  終端無視!   PHP  における文字列型は、バイトの配列と整数値 ( バッファ長)  で実装されています。 バイト列を文字列 に変換する方法については何の情報も持っておらず、 完全にプログラマ任せとなっています。
  9. String 型でバイト単位の処理 •  (バイナリ)ファイル入出力     •  連結と分解 file_get_contents file_put_contents

    ファイル ファイル input output 連結 $c = $a . $b $b = substr($a, $x, $y) 分解 $a $b $c $a $b $x $y
  10. 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)  
  11. 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
  12. 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
  13. 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)
  14. String 型のバイト処理 その他 •  strrev で前後リバース  (逆順にする)   •  substr_replace

     で一部入れ替え   •  strcmp でバイナリ比較  (一致するか否か)   •  str_pad, str_repeat  で同じバイトの繰り返し   str  系で色々なバイナリ操作が可能!  
  15. バイト処理の注意点 •  $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  は正でも負でも受理してくれる  
  16. バイト処理の実例 JPEG分解 •  JPEGの画像サイズを抜き出す   – h8p://www.w3.org/Graphics/JPEG/  ← 仕様   • 

    JPEG  チャンクの並び   JPEG SOI DQT DHT RST APP1 SOS SOF0 EOI ここにサイズが 入っている   width height
  17. 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
  18. JPEG  サイズ抽出サンプル <?php $data = file_get_contents($argv[1]); // JPEGfile input for

    ($i = 1 ; $i < strlen($data) ; $i++) { switch(ord($data[$i++])) { // chunk marker case 0xD8: case 0xD9: // SOI (or EOI) break; // skip default: $len = unpack('n', substr($data, $i, 2)); $i += $len[1]; break; // skip case 0xC0: // SOF0 $sof0 = unpack('CP/nH/nW', substr($data, $i + 2, 5)); echo "width:{$sof0['W']} heigth:{$sof0['H']}\n"; exit (0); // OK } }
  19. IO_Bit •  やっぱり str  系関数使うの面倒ですよね   – バイナリなのに str  使うの気持ち悪い  

    •  そんな人(自分含む)の為に     •  h8ps://github.com/yoya/IO_Bit   – バイナリ編集ライブラリ  
  20. IO_Bit ライブラリ •  ビットやバイトを頭から切り出す     •  Endian 処理も簡単 <?php

    require_once ‘IO/Bit.php’; $data = file_get_contents($argv[1]); $iobit = new IO_Bit(); $iobit->input($data); var_dump($iobit->getData(4)); // 2byte のBigEndian整数を取得 var_dump($iobit->getUI16BE());
  21. IO_Bit の使い方 •  バイナリを解釈して PHP  の配列に入れる   •  PHP  の配列を操作して、またバイナリに戻す

    [[Event:9, Note:43, Velocity:100], …⋯] PHP配列 バイナリ バイナリ Input   &  parse build   &  output
  22. IO_MIDI  使い方 •  h8ps://github.com/yoya/IO_MIDI   – MIDI編集ライブラリ (IO_Bit  でバイナリ分解)   <?php

    require_once 'IO/MIDI.php'; $data = file_get_contents($argv[1]); $midi = new IO_MIDI(); $midi->parse($data); var_dump($midi);
  23. IO_MIDI 構造 IO_MIDI header tracks header Format(1) NumberOfTracks  (9)  

    Division  (480)   0 track   DeltaTime   EventType   NoteNumber   Velocity   1 8 :   :   これを   書き換えて   みる   (音程) (音の強さ)
  24. 音程を変える •  1オクターブ上げる (半音で12個上) <?php require_once 'IO/MIDI.php'; $data = file_get_contents($argv[1]);

    $midi = new IO_MIDI(); $midi->parse($data); foreach ($midi->tracks as &$track) { foreach ($track['track'] as &$event) { if (isset($event['NoteNumber'])) { $event['NoteNumber'] += 12; // octave up! } } } echo $midi->build();
  25. 結果 •  元   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    
  26. 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!