日記ブログ、または雑多なメモ

perl/cgiでutf8読み込み書き出し、文字化け対策




女主任・岸見栄子単行本発売
広告


 こんなことをしている暇はまったくないぐらい忙しいのだが、なぜだかどうにもなんだかやる気がでないので現実逃避にコメント機能を実装してみた。 実際は大昔にあらかたコードを組んであったのをちょっと整理して、文字コード処理をちょっといれたというべきか。

 まず最初に、ソースも読み込むログもUTF-8で統一してはいるものの、文字コードに関する操作は一切しない仕組みのまま単純に書き込み機能を付けてみたら、普通に文字化け。

……で、ぐぐってみたところ以下の様なやり方を見つけてきた。

use utf8;
binmode(STDOUT, ":utf8");

 を行頭につけて出力は自動でutf8になるように設定、あとは外部から読み込んだデータに対してだけ
utf8::decode($val);

 とデコード処理するようにしたら文字化けなくなった。
のだが、しかし。  なぜかこれをhi-hoのサーバで動かすとべらぼう~~~~に重くなり、軽く(重く?)2倍以上の時間がかかる。
どういうことだ……なんとなくデジャブ。


 とりあえずuse utf8binmodeをベタに使っているのがマズいっぽいので、これを使わない方法をいろいろやってみたところ、

use Encode;
を使って、外部から読み込むデータに対しては
$val = Encode::decode_utf8($val);

 とデコード処理して、「ファイルに」出力するデータに対しては

print LOG Encode::encode_utf8($val);

 とエンコードすれば文字化けずに、かつ重くならずに動いた。 まあ、単純にそのままではある。
外部から読んだデータと内部で作ったデータを適当にまぜまぜしちゃうと大変なことになるようなので(自動でまとめて変換してくれたりはしないっぽい……ちゃんと確かめてはいないが)それぞれマメにちゃんとエンコード・デコードしないといけない模様。

 そういえば、クッキーとフォームからクエリーで受け取るデータも外部から来るデータなので、URLデコードするときにutf8のデコードも一緒にすべし。

    if ($ENV{'REQUEST_METHOD'} eq "POST") {
      if ($ENV{'CONTENT_LENGTH'} > 25600) { &printError('max_err'); }
      read(STDIN, $buf, $ENV{'CONTENT_LENGTH'});
    } else { $buf = $ENV{'QUERY_STRING'}; }

    foreach ( split(/&/, $buf) ) {
      ($key, $val) = split(/=/);
      $val =~ tr/+/ /;
      $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg;
      $val = Encode::decode_utf8($val);
      $in{$key} = $val;
    }
    $title = $in{'title'};

    foreach (split(/;/, $ENV{'HTTP_COOKIE'})) {
      my ($key, $val) = split(/=/);
      $val =~ tr/+/ /;
      $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg;
      $val = Encode::decode_utf8($val);
      $cook{$key} = $val;
    }

こんなかんじで。

詳しくはこちら参照。
Perl のuse utf8のメモ - CGIのutf-8改造で文字化けしたときの処方箋

ちなみに、ファイルに出力するためにエンコードした書き込みフォームの名前欄の$nameが、そのまま再びフォームに収まっている(デコードしていないので表示時にエラーになる)のを見逃すという自分で作ったトラップにはまり、結構な時間を無駄にしてしまった。 ぐぅ…

- C'sGallery Blogっぽく見えるシステム3.2 -
小武 (管理人) eta2@tim.hi-ho.ne.jp