Query Stringを縮める取り組み

RFCによるとQuery Stringで遅れる文字数はエンコードした状態で255文字らしい。とてもじゃないがマビノギのMMLをQueryStringで送るには不足している。単純なMMLだと&のような文字が含まれるから始末が悪い。&をQueryStringで送るだけで%26の3文字を消費するのだ。255文字というと練習ランクのMMLでさえ規格をオーバーしてしまっている。そうなると、別の形式で送る抜本的対処案が必要になってくる。

普通ならPOSTで送るようにすればいいと考えるだろう。実際自分も最初はPOSTでMMLデーターをスクリプトに渡し、IFRAMEで送ったスクリプトの出力を表示するという形をとった。しかし、またしてもIEだと正常に変換されたMIDIが再生されないという問題が起きた。IEたいがいにしろ!と、愚痴っても仕方がない。結局GETで送ることにしたわけだ。

GETで送るとなると、さっきも書いたように字数が過大になる。そこで思いついたのが高度な JavaScript 技集で、公開されているdeflate.jsである。コピーライトをみると1999年!Jcode.plよりも古いのか!?なにはともあれ、これでMMLを圧縮すればかなり削れるに違いない。

サンプルのMML:

MML@
l64c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&c&cv0c2t144v15l12<d&dderrfrrgrd4derrfr>f<grd4dero5d24d+24o3fr>b+<grd4der>b+<fr>a<gr<g4garra+rr>cr<g4garo4ao2a+ro4g<cr<g4garra+>g<a+>ar<g4garo5do2a+rr>c4d&dderrfrrgrd4derrfr>f<grd4dero5d24d+24o3fr>b+<grd4der>b+<fr>a<gr<g4garra+ro4e<cr<g4garo4ao2a+ro4a+<cr<g4garra+>g<a+>ar<g4garra+rr>c4>g2g&gre&ef4g4d4e4&eg2g&ga&ab&b>c24d8.&d48<b&ba4b4a24g+24g2g&gre&ef4g4d4e4&eg2g&ga&ab&b>c24d8.&d48<b&b>e2&eo2a&aabrr>crrd&d<a4abrr>crrd&d<a4abrr>crrd&d<a4abrr>c>de<d&d<a4abrr>crrd&d<a4abrr>crrd&d<a4abo5g&go3crrd&d<a4abrr>crrd&d
,
r1v15>c2.&c12&c12c2l12rcdcd&dc2rer4rdrr<br4arrarg2&gd&degr>crr<a+r4gr4r>g2rg&gde&ef4er4.r24d4rc2.&c&cc2rcdcd&dc2rer4rdrr<br4arrarg2&gd&drgr>crr<a+r4gr4r>g2rg&gde&ef4errdrrd4r<d2&d&dd2.r4d4&dd1.&drd4&dd2&d&dd2.r4d4&dd1.&drd4rg2.l24<fgab>del12b&b>c&cd&de&ed&dc&c<b4&bb+ab4.&b24a24g+24g2ef+gaa+b2&bb>cdba+r<b&b>c&cd&de&ed&dc&c<b4&bb+ab4.&b24a24g+24g1
,
r1v15f2.&f12&f12f2l12rf&fr4f1f1e1e2&ee&eerre1a+4arrarra4rf2.&f&ff2rf&fr4f1f1e1e2&ee&eerre1a+4arrarra4r<g+1.&g+rg+4&g+g1.&grg4&gg+1.&g+rg+4&g+g1.&grd4r>b1g1g1e2r4ff+g1>a1r24f+24g&gf+r4f+rg&gf+r24g+24a1
;

文字数1143。で、これを先ほどのdeflate.jsで圧縮する。そのままでは表示できないのでbase64変換もする。

rVLbilsxDHwP5Df04nKotUpZqDH9gO5HyDe9BA6Ist/fsZMlD83uprQYnyPJ0ng08svLzx/Hw/mbVPqn9fq18q8o8hpP58ipUW
vdfbibN7mYeaSrs58aSwss+xPCJbzFp4mAwk8mpu4a3HO9ervozojsYqneMrIlfPQt6dRWEsrkP7LYpac/eWh4n8iVu2RjI/NO
fYhJky7UV0hJC5VcQeJ5oybPCa5KEWUx0PqrutyZOliRalmSOZpPKp97ufX0SO5+wt37073z4+HL8eARswerjWrkuSvjJXhtFR
mVvbt4c0/FZYrjxmQ46bZQoJyLIQVyOS5qq2/UbI4+xRcu1fo5oH8MOEuAlxrTfB68OeBhREjpy7p/APjtzJKGaYFkaG0NgSYZ
QE9KVFMRKiVokY0K3wbZRzDVUBinubYCbunx8njTd0CGAXmxx5J30HAZccQe5wsAFFrsUcNFE1fxVUNjPJScLKBhC25B8LPpuM
G8F4cquUTD6gxgNBmzRgxsTNpkAyPAvliXZhTNfD8efgM=

文字数401。半分以下に圧縮できたことがわかる。

しかし、みての通り/や=など好ましくない文字もできてしまっているので、Queryで送る場合は、やはりURLencodeする必要がある。

rVLbilsxDHwP5Df04nKotUpZqDH9gO5HyDe9BA6Ist%2ffsZMlD83uprQYnyPJ0ng08svLzx%2fHw%2fmbVPqn9fq18q8o8hpP
58ipUWvdfbibN7mYeaSrs58aSwss%2bxPCJbzFp4mAwk8mpu4a3HO9ervozojsYqneMrIlfPQt6dRWEsrkP7LYpac%2feWh4n8
iVu2RjI%2fNOfYhJky7UV0hJC5VcQeJ5oybPCa5KEWUx0PqrutyZOliRalmSOZpPKp97ufX0SO5%2bwt37073z4%2bHL8eARsw
erjWrkuSvjJXhtFRmVvbt4c0%2fFZYrjxmQ46bZQoJyLIQVyOS5qq2%2fUbI4%2bxRcu1fo5oH8MOEuAlxrTfB68OeBhREjpy7
p%2fAPjtzJKGaYFkaG0NgSYZQE9KVFMRKiVokY0K3wbZRzDVUBinubYCbunx8njTd0CGAXmxx5J30HAZccQe5wsAFFrsUcNFE1
fxVUNjPJScLKBhC25B8LPpuMG8F4cquUTD6gxgNBmzRgxsTNpkAyPAvliXZhTNfD8efgM%3d

それでも562文字である。半分以下に圧縮できているので十分だろう。つまり、実際送る場合もこれを使えばいい。

もちろん、圧縮する前に本来入れるべきパラメータをいれてもいだろう。今回の場合は、楽器選択などだ。しかし、あらかじめ送るデーター形式は決まっているのでa=so&b=ou&c=anaのようにQueryをくんでから圧縮する必要はない。たとえば、これの場合はso;ou;anaというように;ごとに区切ったデーターを作って圧縮し、サーバーサイド側でsplit関数あたりを利用して分割すればいいだろう。

実際コーディングしてみる。

PluginRenderer::executePluginBlock(): プラグイン#code()は、実装されていません。

で、変換されたコード

ASAA3//jgbLjgY3jgZPjgoLjgos744Kq44K/44KvO+mAhuilsg==

で、これをURLencodeし、スクリプトに送る

PluginRenderer::executePluginBlock(): プラグイン#code()は、実装されていません。

結果:

/script.php?q=ASAA3%2f%2fjgbLjgY3jgZPjgoLjgos744Kq44K%2f44KvO%2bmAhuilsg%3d%3d

さて、JavaScript側はこれでいい。次はPHP側である。PHPでdeflate圧縮したデーターを解凍(inflate)するにはどうすればいいか?phpにはgzinflateという関数がある。これを用いて解凍すればいいだろう。

当然JavaScriptで行ったアクションとは逆から行う

PluginRenderer::executePluginBlock(): プラグイン#code()は、実装されていません。

$status = 'ひきこもる';
$destin = 'オタク';
$action = '逆襲';

これで、PHPにデーターが渡すことができる。関数の順番は、Queryで送るのとは違って、常に決めていなければならないが、まぁPath-Infoを使ってデーターを転送することを考えればたいしたことでもない。我ながらナイスアイデア。

応用

今回は、MMLを送信してMIDI変換し再生するためにこのスクリプトを使ったが、応用範囲は広いと思う。Queryや使われる文字列を簡単に知られたくない場合などで役立つだろう。さらにダミー文字を入れて暗号化するのもいいかもしれない。また、スクリプトそのものを圧縮するのもありかもしれない。/packer/で圧縮したJavaScriptをdeflateでさらに削ることができた。

script = base64decode(data);
data = zip_inflate(data);
eval(data);

みたいなことをやればJavaScriptそのものも暗号化に役立つのではないだろうか?