リファラーの文字化け対策

だんだん寒くなって来ましたね。先日インフルエンザの予防接種を受けて来ました。「今年は鳥インフルエンザが変化して、人にうつるようになったものが流行るかもしれないとか色々騒がれているので、受けておきます。」 とお医者さまに言ったら、「今回のインフルエンザの予防接種は、鳥インフルエンザには全く効きません。」 と言われてしまいました。(^^;)
それで、「あ〜、バソコンのウィルスのワクチンと同じですね。」 と言ったら、先生は笑って 「その通りです。」 と仰っていました。何でもパソコンに例えると分かりやすくなっている自分が怖いです。(^^;)

自宅に設置しているサーバーで、色々なCGIプログラムを日本中の人にレンタルしています。今のところ掲示板から始めまして、画像スペース、webアルバム、メール送信CGI と種類を増やしましたが、今度アクセス解析CGI をレンタルしようとレンタル用のアクセス解析CGI を製作中です。製作といってもわたしのはいつも Kent さんの作られたものを元に、色々と改造をしているだけなのですが…。

アクセス解析CGI で一番苦労するところは、リファラーの処理です。普通のサイトからのリファラーでしたら、アルファベットとハイフォン、アンダーバーくらいなので問題ないのですが、検索サイトからのリファラーですと、リファラーの中に日本語、カナ・カタカナ・漢字が含まれます。それを読める日本語に処理したとしても、今度はそれでリファラーへのリンクを張ると、文字化けして上手く飛んでくれなくなります。それでアクセス解析CGI のページに表示するためのリファラーと、<a href="〜"> の値とを別々な形でログファイルに記録することにしました。

■ プログラム自体の文字コードを euc-jp にして作る
今回、プログラム自体の文字コードを euc-jp にして作ってみました。ページに表示する方のリファラーは、Perl が 5.8 になって Encode.pm が使えるようになったので、下記のスクリプトを使って euc-jp に変換してログファイルに記録。<a href="〜"> の値としてのリファラーは、アクセス解析対象ページに書かれた JavaScript によって、アクセス解析プログラムに $ENV{'QUERY_STRING'} の値として届けられたものをそのままログファイルに記録しました。

これでできたできたと、しばらくの間喜んでいたのですが、サーバーのエラーログをチェックしていましたところ、毎日何回かこのアクセス解析プログラムの インターネットサーバーエラー として記録されているものがあることに気がつきました。そのエラーログの内容は、ひとつでなく、いくつかありました。
  • Premature end of script headers
  • Can't locate object method "name" via package "shiftjis or utf8" (perhaps you forgot to load "shiftjis or utf8"?) at …
  • Can't modify non-lvalue subroutine call at …
  • Unknown encoding '0' at …
それは検索サイトの決まった検索語句のページから来た時に、起こっていることが調査で分かりました。
  • http://search.yahoo.co.jp/search?p=HPの作り方&ei=UTF-8&fr=top&fl=0&vc=&x=wrt&meta=vc=
  • http://search.yahoo.co.jp/search?p=dion+cgi+カスタマイズ&ei=UTF-8&fr=top&fl=0&vc=&x=wrt&meta=vc=
また、 Google や MSN などからのリファラー時にもエラーになっているようでした。

これは悩みました。解決までにけっこうな時間を費やしました。結局、何の文字コードか分からない $stringeuc-jp に変換する下記のスクリプト中の
use Encode qw/ from_to /;
use Encode::Guess qw/ euc-jp shiftjis /;
$enc = guess_encoding( $string );
from_to( $string, $enc->name, "euc-jp" );


guess_encoding( $string ) で文字コードが判らなかったものに対して変換処理が行われず、下記の URL デコードの処理が行われた。
$string = s/%([a-fA-F0-9<][a-fA-F0-9])/pack("H2", $1)/eg;br> $string = s/&/&amp;/g;
$string = s/"/&quot;/g;
$string = s/</&lt;/g;
$string = s/>/&gt;/g;
$string = s/\r|\n|\0//g;

で、その中に、ログファイルに記録すると問題が起こるものがあり、その分がインターネットサーバーエラーとなっていたのか、あるいは、$enc の値が判らないのに、無理に
from_to( $string, $enc->name, "euc-jp" );
をしようとしてエラーが出ていたのか…?。だとしたら、
if( ref $enc ){
from_to( $string, $enc->name, "euc-jp" );}

としてあげればエラーにはならないのかも知れません。
あるいはこの Encode のスクリプト自体が機能しておらず、euc-jp 以外のリファラーは皆エラーになっていたのか…。追々検証してみたいと思います。(^^;)

その後、主な検索エンジンの文字コードを調べ、
主な検索エンジンの文字コード
 UTF-8
  ・ MSN
  ・ Google
  ・ Yahoo UTF-8

 euc-jp
  ・ OCN
  ・ goo
  ・ Yahoo
  ・ infoseek
  ・ Google euc-jp

 shiftjis
  ・ nifty
  ・ biglobe
  ・ exite
  ・ flrshEYE

リファラーの文字の中からキーワードを拾い出し、それが含まれていたら UTF-8 といった感じにリファラーの文字コードを分けて euc-jp に変換する形にして、
if ($string = /UTF-8/i || $string = /msn/i || ($string = /google/i && $string ! /euc-jp/i)) {
use Encode qw/ from_to /;
from_to( $string, 'utf8', 'euc-jp' );}
if ($string = /nifty/i || $string = /excite/i || $string = /SJIS/i || $string = /biglobe/i) {
use Encode qw/ from_to /;
from_to( $string, 'shiftjis', 'euc-jp' );}

ようやっとインターネットサーバーエラーが出なくなりました。注意する点としましては、上図にもありますように、同じ検索エンジンでも文字コードを複数使っているという点です。(^^;)

■ プログラム自体の文字コードを UTF-8 にして作る
プログラム自体の文字コードを UTF-8 にする方法は、何回か試し上手く行かなかったのですが、今回下記のスクリプトを使ってみたところ上手く行きました。

use Encode qw/ from_to /;
use Encode::Guess qw/ euc-jp shiftjis /;
$enc = guess_encoding( $string );
if( ref $enc ){
from_to( $string, $enc->name, "utf8" );}


shiftjisUTF-8 のリファラーもきれいに文字化けせずに表示されました。ただし、euc-jp のリファラーで、検索語句と語句の間を全角空白で分けている場合、そのリファラーを euc-jp と判別できないので、
elsif ($string = /\??/ && $string ! /UTF-8|google|msn/i){from_to( $string, "euc-jp", "utf8" );}
の部分を追加しました。この部分がないと、全角空白は %A1%A1 → ?? となってしまいます。

年賀状のインクジェット葉書もおば〜ちゃんの分と合わせて100枚買いました。お歳暮の手配もせねばなりません。何しろもう11月19日ですから…。焦ります。(^^;)

先月の14日に、東光寺緑地で撮ったハハコグサです。

PageTop