
普段、ほとんど誰もやらない処理を、めちゃくちゃ有意義になる。
それが、オレ。
誰もやらない処理というのは、世の中的に意味のないことかというと全くそういうことはなく、
実はその処理はすごく便利なのに誰も使っている事をほぼ聞いた事がないというモノです。
いつもそんな処理について、模索しているわけですが、今回の処理というのは、
「Javascriptでzlibデータを扱う」
というような内容です。
どうです?
誰もほとんど興味が無い内容でしょ?
これから先のブログを読むのは、少し勇気のいると思いますが、少しだけでもニッチな処理に興味があるという人は読んでみてください。
zlibをjavbascriptで扱う内容の詳細
先日、とあるサービスで、ホームページでとある原稿の文章を表示するときに、利用者にコピペされたくないという、サイトポリシーの会社があったので、
canvasで物理的にコピペができない機能を作ってあげた。
先日のブログ :
WEBでテキストを抜き取られないモザイク処理ツール #3「HTMLで読み取りできない隠し文字に最適なツール」
この中で、サーバーサイド(php)で、zlib圧縮(+ base64)で、暗号化した文字列にして、それをJavascriptで読み取り、フロント再度でデコードするという処理を実装しました。
これ、ライブラリにもしてgithubにアップしているんですが、テキストのコピペが簡単に禁止できてしまうので、めちゃくちゃ便利だな〜と思ってるんですが、
さほど、文章に知財を気にしている会社じゃなければ、使う価値も無いツールなんですよね。
問題発生
phpで、zlibしたテキストを、javascriptで復元する時に、何故か色々なトラブルが起きた。
<br />
よくあるHTMLの改行タグの書き方で、閉じタグが無いIMGやLINKなどのタグにも、このように、/(スラッシュ)を後ろにつけるというのは、reactなどでもルール化されていたりもするので、
今現在は十分に住民権を得られている書き方です。
このタグが次のような文字列でデコードされてしまっていました。
<br+/>
+文字が混入してしまう不具合が発生していたんですね。
色々調べたところ、zlibのコンバート自体には問題がなく、
zlibエンコード + base64エンコードをした物を、javascriptでデコードした時に、+(プラス)文字が変換されていないようでした。
検証 : javascriptで、zlib + base64のエンコードとデコード
[sample.html]
<script src="rawdeflate.min.js"></script>
<script src="rawinflate.min.js"></script>
<script>
const encode = zlib_encode("<br />")
console.log("encode : ",encode)
const decode = zlib_decode(encode)
console.log("decode : ",decode)
function zlib_encode(str){
const val = escape(encodeURIComponent(str))
const arr = new TextEncoder().encode(val)
const deflate = new Zlib.RawDeflate(arr).compress()
const data = ((chars)=>{
let str = ""
for(const char of chars){
str += String.fromCharCode(char)
}
return str
})(deflate)
return btoa(data)
}
function zlib_decode(str){
str = atob(str)
const chars = ((val) => {
const arr = []
for(let i=0; i<val.length; i++){
arr.push(val[i].charCodeAt(0))
}
return new Uint8Array(arr)
})(str)
const inflate = new Zlib.RawInflate(chars).decompress()
const decode_str = new TextDecoder().decode(inflate);
return decodeURIComponent(unescape(decode_str))
}
</script>
[結果]
encode : FcixCQAACAPBaewl4gSigziC+xcxzT28IaP2PnAxGk0=
index.html:9 decode : <br />
検証 : PHPでjavascriptでエンコード、Javascriptでデコード (zlib + base64)
<?php
$text = "<br />";
$txt1 = urlencode($text);
$txt2 = gzdeflate($txt1, 9);
$encode_txt = base64_encode($txt2);
echo $encode_txt ;
?>
<script src="rawinflate.min.js"></script>
<script>
const encode = "<?php echo $encode_txt;?>"
console.log("encode : ",encode)
const decode = zlib_decode(encode)
console.log("decode : ",decode)
function zlib_decode(str){
str = atob(str)
const chars = ((val) => {
const arr = []
for(let i=0; i<val.length; i++){
arr.push(val[i].charCodeAt(0))
}
return new Uint8Array(arr)
})(str)
const inflate = new Zlib.RawInflate(chars).decompress()
const decode_str = new TextDecoder().decode(inflate);
return decodeURIComponent(unescape(decode_str))
}
</script>
[結果]
encode : UzV2TirSVjVyUzV2BQA=
index.php:8 decode :
この通り、この方法で、完全なdecodeができていない事がわかりました。
もちろん、Javascriptだけでエンコード、デコードをした場合と、PHPのみでエンコード、デコードをした場合は、問題なく、復元(デコード)されます。
解決方法
おそらく、PHPのurlencode()でのurl文字列のエンコードと、
javasriptでのdecodeURIComponent(unescape(decode_str))という、urlデコードに問題があり、
今回の問題だけを解決するのであれば、zlibをデコードした直後に、次のように強制的に+文字列を半角スペースに置換してあげれば、簡単に修正できます。
decode_zlib.replace(/\+/g, ' ');
でも、なんかスッキリしないので、PHPでのurlencodeとJavascriptでのurldecodeを相互に問題なくやり取りできるようにしたいと考えました。
スッキリ解決
PHPでのurlエンコードが古かったようです。
次のようにエンコードして、javascriptも書き直してみました。(修正箇所のみ表示)
[php]
$txt1 = urlencode($text);
↓
$txt1 = rawurlencode($text);
[Javascript]
decodeURIComponent(unescape(decode_str))
↓
decodeURIComponent(decode_str)
あとがき
どうやら、自分の書き方が古かったせいで発生していた不具合でした。
でも、過去バージョンからの移植作業などの時にもハマる可能性があるので、ブログに残しておきますね。
0 件のコメント:
コメントを投稿