Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHPBinaryTips
Search
yoya
November 10, 2015
Programming
0
640
PHPBinaryTips
PHPでバイナリ処理Tips
yoya
November 10, 2015
Tweet
Share
More Decks by yoya
See All by yoya
resize_nitpick
yoya
1
140
ImageFluxBinary
yoya
2
2.6k
HEIF-kaisetsu
yoya
4
3.1k
go-thumber-imagick
yoya
1
160
chokaizomae
yoya
2
500
wildimagebinary
yoya
1
200
goimagicksyokai
yoya
2
1k
GoImagickThumbnail
yoya
0
1.4k
sushigazou
yoya
0
12k
Other Decks in Programming
See All in Programming
Snowflake x dbtで作るセキュアでアジャイルなデータ基盤
tsoshiro
2
520
イベント駆動で成長して委員会
happymana
1
320
ヤプリ新卒SREの オンボーディング
masaki12
0
130
PHP でアセンブリ言語のように書く技術
memory1994
PRO
1
170
Amazon Qを使ってIaCを触ろう!
maruto
0
400
광고 소재 심사 과정에 AI를 도입하여 광고 서비스 생산성 향상시키기
kakao
PRO
0
170
Quine, Polyglot, 良いコード
qnighy
4
640
Remix on Hono on Cloudflare Workers
yusukebe
1
290
Generative AI Use Cases JP (略称:GenU)奮闘記
hideg
1
290
WebフロントエンドにおけるGraphQL(あるいはバックエンドのAPI)との向き合い方 / #241106_plk_frontend
izumin5210
4
1.4k
watsonx.ai Dojo #4 生成AIを使ったアプリ開発、応用編
oniak3ibm
PRO
1
100
C++でシェーダを書く
fadis
6
4.1k
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Rails Girls Zürich Keynote
gr2m
94
13k
4 Signs Your Business is Dying
shpigford
180
21k
Practical Orchestrator
shlominoach
186
10k
Teambox: Starting and Learning
jrom
133
8.8k
Site-Speed That Sticks
csswizardry
0
23
Making Projects Easy
brettharned
115
5.9k
Statistics for Hackers
jakevdp
796
220k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
Happy Clients
brianwarren
98
6.7k
Designing for humans not robots
tammielis
250
25k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
860
Transcript
PHP でバイナリ処理Tips 2015/11/10
[email protected]
自己紹介 • 2年前、六本木のSNS系会社で働いてました • バイナリ変換が趣味です 1
1 0 1 0 0 1 0
公開ライブラリ • 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プロファイル編集
本発表について • この発表の焼き直しです – PHPでバイナリ変換プログラミング – h8p://www.slideshare.net/yoyayoya1/ php-‐10133775 •
PHP でバイナリ変換するのは楽という話 – 小さなバイナリを処理するには良い感じ – (メモリを沢山使うので、大きなバイナリを扱うの はキツい)
バイナリって何? • バイナリって何? – 本来は、コンピュータが処理し易い 0,1 の2進値 データ – 世間的には、テキスト以外のデータ
(狭義のバイ ナリ) GIFファイル (php.gif)
バイナリとテキスト • 1バイトで0~255の値を表現できるけど、US-‐ ASCII テキストはその一部しか使わない。(日 本語は複雑なので棚にあげる) • バイナリの方がより多くの情報を詰められる
0〜0x19 0x20~0xf9 0x80~0xff ! ” # … A B C … 0 1 2 … a b c … この辺りの 値が化けて 表示される
バイナリの例 • バイナリの種類 – 実行ファイル (exe, a.out, jar) •
セキュリティ界隈だと主にコレ – マルチメディア系ファイル (JPEG, PNG, MPEG, …) – ネットワーク通信パケット (TCP, ISDN, …) – 圧縮されたデータ (zip, gzip) – 暗号化されたデータ (SSL) いろいろある!
何故バイナリ処理するのか • Webサービスでもテキスト以外の、画像や動 画、または生の通信プロトコルを扱う事があ る • そのデータを PHP で改変する事で
– より多くの種類の端末にサービスを提供できたり – 通信データ量を減らせたり • エディタで開いて化けるだけで編集を諦める のは、勿体無い。
ビット(Bit)とバイト(Byte) • コンピュータ内部で処理(入出力、編集)する 単位 • バイナリ処理は、これらの単位でプログラミン グする 43 57
53 06 00 48 2c 00 78 9c b9 6b バイト列 00100011 01010111 ビット列 バイナリ バイナリ
ビット(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
バイト(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
バイナリエディタ諸々 • Macintosh なら 0xED, Windows なら S_rling, Bz
Editor • 手で編集するのが面倒になった時、PHP の出番
閑話休題 • ここまでがバイナリの基本 • ここから PHP でバイナリ処理の話
PHP でバイナリ大丈夫? • PHP の String 型はバイナリとして使える – h8p://www.php.net/manual/ja/
language.types.string.php#language.types.string.details • 文字列としての処理を勝手にしない – 8bit スルー、¥0 終端無視! PHP における文字列型は、バイトの配列と整数値 ( バッファ長) で実装されています。 バイト列を文字列 に変換する方法については何の情報も持っておらず、 完全にプログラマ任せとなっています。
String 型でバイト単位の処理 • (バイナリ)ファイル入出力 • 連結と分解 file_get_contents file_put_contents
ファイル ファイル input output 連結 $c = $a . $b $b = substr($a, $x, $y) 分解 $a $b $c $a $b $x $y
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)
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
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
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)
String 型のバイト処理 その他 • strrev で前後リバース (逆順にする) • substr_replace
で一部入れ替え • strcmp でバイナリ比較 (一致するか否か) • str_pad, str_repeat で同じバイトの繰り返し str 系で色々なバイナリ操作が可能!
バイト処理の注意点 • $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 は正でも負でも受理してくれる
バイト処理の実例 JPEG分解 • JPEGの画像サイズを抜き出す – h8p://www.w3.org/Graphics/JPEG/ ← 仕様 •
JPEG チャンクの並び JPEG SOI DQT DHT RST APP1 SOS SOF0 EOI ここにサイズが 入っている width height
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
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 } }
ちなみに • ge_magesize で画像サイズは取れます。。 <?php $imagesize = getimagesize($argv[1]); //
JPEGfile input var_dump($imagesize);
IO_Bit • やっぱり str 系関数使うの面倒ですよね – バイナリなのに str 使うの気持ち悪い
• そんな人(自分含む)の為に • h8ps://github.com/yoya/IO_Bit – バイナリ編集ライブラリ
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());
IO_Bit の使い方 • バイナリを解釈して PHP の配列に入れる • PHP の配列を操作して、またバイナリに戻す
[[Event:9, Note:43, Velocity:100], …⋯] PHP配列 バイナリ バイナリ Input & parse build & output
IO_MIDI • h8ps://github.com/yoya/IO_MIDI – MIDI編集ライブラリ IO_Bit IO_MIDI ユーザ プログラム
parse input 入力 output build バイナリ 出力 ここで 編集
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);
var_dump($midi) 出力
IO_MIDI 構造 IO_MIDI header tracks header Format(1) NumberOfTracks (9)
Division (480) 0 track DeltaTime EventType NoteNumber Velocity 1 8 : : これを 書き換えて みる (音程) (音の強さ)
音程を変える • 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();
結果 • 元 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
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!
という感じで • バイナリと PHP配列構造との、相互変換 (parse と build) を作ってしまえば、編集し放題 です
• 以上です