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
150
ImageFluxBinary
yoya
2
2.7k
HEIF-kaisetsu
yoya
4
3.3k
go-thumber-imagick
yoya
1
170
chokaizomae
yoya
2
560
wildimagebinary
yoya
1
210
goimagicksyokai
yoya
2
1.1k
GoImagickThumbnail
yoya
0
1.5k
sushigazou
yoya
0
12k
Other Decks in Programming
See All in Programming
AIプログラマーDevinは PHPerの夢を見るか?
shinyasaita
1
190
Code as Context 〜 1にコードで 2にリンタ 34がなくて 5にルール? 〜
yodakeisuke
0
120
5つのアンチパターンから学ぶLT設計
narihara
1
150
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
3
350
0626 Findy Product Manager LT Night_高田スライド_speaker deck用
mana_takada
0
140
WindowInsetsだってテストしたい
ryunen344
1
230
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
160
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
890
プロダクト志向ってなんなんだろうね
righttouch
PRO
0
180
生成AIコーディングとの向き合い方、AIと共創するという考え方 / How to deal with generative AI coding and the concept of co-creating with AI
seike460
PRO
1
350
20250628_非エンジニアがバイブコーディングしてみた
ponponmikankan
0
640
エラーって何種類あるの?
kajitack
5
340
Featured
See All Featured
A Modern Web Designer's Workflow
chriscoyier
694
190k
Statistics for Hackers
jakevdp
799
220k
Faster Mobile Websites
deanohume
307
31k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.3k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
5
240
The Language of Interfaces
destraynor
158
25k
It's Worth the Effort
3n
185
28k
Raft: Consensus for Rubyists
vanstee
140
7k
The Cost Of JavaScript in 2023
addyosmani
51
8.5k
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) を作ってしまえば、編集し放題 です
• 以上です