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
630
PHPBinaryTips
PHPでバイナリ処理Tips
yoya
November 10, 2015
Tweet
Share
More Decks by yoya
See All by yoya
resize_nitpick
yoya
1
130
ImageFluxBinary
yoya
2
2.4k
HEIF-kaisetsu
yoya
4
3k
go-thumber-imagick
yoya
1
150
chokaizomae
yoya
2
470
wildimagebinary
yoya
1
190
goimagicksyokai
yoya
2
980
GoImagickThumbnail
yoya
0
1.3k
sushigazou
yoya
0
11k
Other Decks in Programming
See All in Programming
#phpcon_odawara オープン・クローズドなテストフィクスチャを求めて / open closed test fixtures
77web
3
220
pixivアプリでマルチモジュールを実現するまで
gatosyocora
1
130
Changed Rules: Architectures with Lightweight Stores
manfredsteyer
PRO
0
230
ログラスを支える設計標準について / loglass-design-standards
urmot
10
2.1k
SwiftUI Performance 不要なViewの再描画と更新を抑える
bigamitiongit
1
160
単体テストを書かない技術 #phpcon_odawara
o0h
PRO
25
7.8k
今の SmartHR にエンジニアで入社するとどうなるの?
daisukeshinoku
5
4.6k
1인 개발자로 행복하게 살기 - GDG 송도 헬로월드 2024
benjaminkim
1
5.6k
OpenAPIを中心に考えるAPI開発入門 / Introduction to API Development with a Focus on OpenAPI
seike460
PRO
2
120
Ruby Function Composition
bkuhlmann
1
330
Zero Waste, Radical Magic, and Italian Graft – Quarkus Efficiency Secrets
hollycummins
0
220
TYPO3 v13 – The road to LTS: What's new and new APIs
luisasofie_xoxo
0
180
Featured
See All Featured
Documentation Writing (for coders)
carmenintech
59
3.9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
240
1.2M
Happy Clients
brianwarren
91
6.4k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
220
21k
Side Projects
sachag
451
41k
Web development in the modern age
philhawksworth
202
10k
Design by the Numbers
sachag
274
18k
Fashionably flexible responsive web design (full day workshop)
malarkey
397
65k
GraphQLとの向き合い方2022年版
quramy
31
12k
Making Projects Easy
brettharned
108
5.5k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
501
140k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
6
990
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) を作ってしまえば、編集し放題 です
• 以上です