cgiにおける文字コードの扱いとか

久々にcgi書いてたら文字コード周りでハマったので備忘録。

Perlで日本語処理を書いてると文字コード周りでハマるのは誰もが一度は経験するはず。
慣れてくると、ちゃんとuse utf8 or encodingとbinmodeしてればいいんでしょ、となると思うんだけど、今回の敵はcgiでした。

今回の教訓は、utf8フラグ付いている文字列と付いていない文字列でeqしてもtrueが返ってくること。
そして、もう1つはwebにあるコードもきちんと意味を考えて使いましょうということ。

CGI.pmでutf8フラグの扱いがおかしい話は前から知っていて、このページCGI.pmとUTF8 flag : blog.nomadscafe.jpを参考に、

use utf8;
binmode STDOUT, ":utf8";
use Encode;
for my $p ($q->param) {
my @v = map {Encode::decode('utf8',$_)} $q->param($p);
$q->param($p,@v);
}

としていました。ところがどうもうまく行かないなと悩んでいたのですが、これパラメータの値の方だけutf8フラグをきちんと処理してて、キーの方は修正してないんですよね…
cgiのキーの方に日本語とか使う人がどれくらいいるかは知りませんが、その場合には

use utf8;
binmode STDOUT, ":utf8";
use Encode;
for my $p ($q->param) {
my @v = map {Encode::decode('utf8',$_)} $q->param($p);
$q->delete($p);
$p = Encode::decode('utf8',$p);
$q->param($p,@v);
}

とする必要があるみたいです。