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.2k
go-thumber-imagick
yoya
1
160
chokaizomae
yoya
2
520
wildimagebinary
yoya
1
200
goimagicksyokai
yoya
2
1.1k
GoImagickThumbnail
yoya
0
1.5k
sushigazou
yoya
0
12k
Other Decks in Programming
See All in Programming
コミュニティ駆動 AWS CDK ライブラリ「Open Constructs Library」 / community-cdk-library
gotok365
2
240
CDKを使ったPagerDuty連携インフラのテンプレート化
shibuya_shogo
0
110
AIプログラミング雑キャッチアップ
yuheinakasaka
18
4.4k
Djangoにおける複数ユーザー種別認証の設計アプローチ@DjangoCongress JP 2025
delhi09
PRO
4
470
Generating OpenAPI schema from serializers throughout the Rails stack - Kyobashi.rb #5
envek
1
380
お前もAI鬼にならないか?👹Bolt & Cursor & Supabase & Vercelで人間をやめるぞ、ジョジョー!👺
taishiyade
7
4.2k
ファインディLT_ポケモン対戦の定量的分析
fufufukakaka
0
920
Learning Kotlin with detekt
inouehi
1
130
Multi Step Form, Decentralized Autonomous Organization
pumpkiinbell
1
860
CI改善もDatadogとともに
taumu
0
200
「個人開発マネタイズ大全」が教えてくれたこと
bani24884
1
200
データの整合性を保つ非同期処理アーキテクチャパターン / Async Architecture Patterns
mokuo
54
19k
Featured
See All Featured
The Language of Interfaces
destraynor
156
24k
Designing Experiences People Love
moore
140
23k
Become a Pro
speakerdeck
PRO
26
5.2k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
For a Future-Friendly Web
brad_frost
176
9.6k
Statistics for Hackers
jakevdp
797
220k
A Philosophy of Restraint
colly
203
16k
Faster Mobile Websites
deanohume
306
31k
Docker and Python
trallard
44
3.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Product Roadmaps are Hard
iamctodd
PRO
50
11k
Building a Scalable Design System with Sketch
lauravandoore
461
33k
Transcript
PHP でバイナリ処理Tips 2015/11/10 yoya@awm.jp
自己紹介 • 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) を作ってしまえば、編集し放題 です
• 以上です