no link
2011年05月10日 02:28:38
● 問題の背景
bit.lyは、Twitter公式で利用されている、URLの短縮サービスです。
bit.lyは外国の会社なので、日本の文字コード事情には疎いようです。そのため、CGIなどで生成されるページで、そのクエリーにEUCの文字列を含んでいると、文字化けが発生します。
これは、ブラウザの文字化けとは違い、bit.lyのデータベースに、文字化けしたURLが保存されるために、ユーザー側での対処はほぼできません。
内部的にどういったことが起こっているかと言うと、たとえば「利用」という日本語文字列は、EUCでは「%CD%F8%CD%D1」とエンコードされます。
この「%〜」という部分を、bit.lyでは、別の文字コード(たぶんUTF8?)として解釈してしまうようです。
そして、生成された短縮URLから、短縮前のURLに飛ぼうとすると、元とは違うURLに転送されてしまいます。結果として、ユーザーは希望のURLに到達できません。
……クエリーをそのままDBに保存してくれればいいのに、なんだかなあという感じです。
● 問題との関わり
私のサイトでは、「マンガで分かるJavaScriptプログラミング講座」など、一部のページで日本製のWikiを使っています。このCGIは、URLをEUCでエンコードするので、bit.lyの文字化け問題に引っ掛かります。
bit.lyのバグなので、そのうち解決されるかなと思っていたのですが、どうも解決される気配が全くないので、自前で対処することにしました。
● 対処方法
以下の3ステップで対処を行うことにしました。
1.bit.lyの文字化けしたURLから、元のURLを強引に復元する。
2.復元したURLが完全ではなかった場合に、ページの名前一覧から、似た名前を検索してそのページを該当ページとする。
3.似たページを推測できなかった場合は、FrontPageに飛ばす。
たぶん、もう少しスマートな方法があるように思えるのですが、「とりあえず動けばよい」ということで、あまり時間を掛けないことにしました。
ちなみに、拙サイトのいくつかのページで確認してみたところ、2までのステップで収まっていたので、大きな問題はなさそうです。
できれば、全部1で対処可能だとよかったのですが。
● ソースコード抜粋 「URLの復元処理」
「URLの復元処理」です。以下のようなソースコードで簡単な変換を行ないます。
プログラム言語はPerlです。
# 変換用文字列
my $enc_str = shift;
$enc_str =~ s/%C([2-3])%([A-Fa-f0-9])([A-Fa-f0-9])/repairShrtrBug1($1, $2, $3)/ge;
sub repairShrtrBug1 {
my $a = shift;
my $b = shift;
my $c = shift;
# 「%C2%A4」のように「%C2」で始まる場合は「%A4」をそのまま戻す
if ($a eq '2') {return '%' ."$b$c";}
# 「%C3%8E」のように「%C3」で始まる場合は「%8E」の「8」に4を足して戻す
my $b2 = sprintf("%X", hex($b) + 4);
return '%' ."$b2$c";
}
$enc_str =~ s/%EF%BF%([A-Fa-f0-9])([A-Fa-f0-9])/repairShrtrBug2($1, $2)/ge;
sub repairShrtrBug2 {
my $a = shift;
my $b = shift;
# 「%EF%BF%8E」のような場合は「%8E」の「8」に4を足して戻す
my $a2 = sprintf("%X", hex($a) + 4);
return '%' ."$a2$b";
}
これで、8割方復元できました。ものによっては、これだけで正しいURLになりました。
しかし、前後の値の組み合わせによっては、この単純なルールでは変換できない場合がけっこうあります。
細かく調べるのは面倒だったので、今回は、この断片的に復元した文字列から似た名前を検索するという手法を取ることにしました。
こちらは単純な連続一致文字列の数で判定させているので省略します。
というわけで、こういった問題があることを書いたので、誰かちゃんとした変換ライブラリを作ってくれればいいなと思います。
けっこう疲れたので。
なんか、もっと楽な方法がありそうです。教えていただければ、そちらに差し替えます。