日本語コードの取り扱い
 
CGIで漢字を扱う場合は注意が必要です。ブラウザから入力されるデータはJISかSJISかEUCであるか不定なのですが、CGI中で扱う漢字コードは統一しておく必要があります。漢字コード変換には jcode.pl が広く用いられています。jcode.plの最新バージョンは次のサイトから得られます。

ftp://ftp.iij.ad.jp/pub/IIJ/dist/utashiro/perl/

さらに漢字コードは通常1文字が2バイトで構成されていますが、SJIS の場合はその2バイトのうちのどちらかがメタ文字(1バイトコードの特殊文字)と重複している場合があり、print した場合などに正しく処理(表示)されないことがあります。
 
print "饅頭がたべたい。\n";

この例の場合、「饅」は16進数で0xE95Cで下位バイトの0x5Cはメタ文字であるバックスラッシュ(\)と重複していてこれ以降文字化けしてしまうのですが、これを回避するには、文字列の日本語部分を ' (シングルクォート)で囲むか q// を使います。改行 \n は " で囲まないとそのまま出力されてしまいます。
 
print '饅頭が食べたい。',"\n";
print q(饅頭が食べたい。),qq(\n);

ただし、'饅' の文字を単独で
 
 
print '饅', "\n";

とすると、「饅」の下位バイトがバックスラッシュなので後に続くシングルクォート(')をエスケープしてしまい、クォートを閉じるものがなくなってしまうため、エラーとなります。「饅」を単独で使うことはないと思いますが、例えば、「可能」の「能」は16進数で0x945Cなので、下位バイトがやはりバックスラッシュと重複しています。根本的な解決ではないですが、
 
print '可能 ', "\n";

のように空白文字を入れておけば回避できます。

EUCで記述しておけば、このようなことがないので、できればEUCで書くことをおすすめします。

また、Perには日本語対応版のJPerlがあり、これを使うとメタ文字の問題や正規表現中の日本語がうまく処理することができたりします。

引数に文字コード(jis/sjis/euc)のいずれかが指定されていた場合は、jcode.plのconvertでデータをこの文字コードに変換します。
 
util.pl
#
# parseInput(encoding)
# <IN>  encoding: 日本語コード(jis|sjis|euc)
# <OUT> Name=>Val のハッシュ(グロブ)
#
sub parseInput
{
        my($encoding) = @_;
        my($method) = $ENV{'REQUEST_METHOD'};
        local($query, @in, $key, $val);


        # 日本語が必要な場合は jcode.pl を取り込む
        require 'jcode.pl' if $encoding;

        # GETメソッドかPOSTメソッドかを判別する
        if ($method eq 'GET') {
                $query = $ENV{'QUERY_STRING'};
        }
        elsif ($method eq 'POST') {
                read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
        }

        # 入力データを分解する
        local(@query) = split(/&/, $query);

        # Name=Val を $in{'Name'} = 'Val' のハッシュにする。
        foreach (@query) {

                # + を空白文字に変換
                tr/+/ /;

                # Name=Val を分ける
                ($key, $val) = split(/=/);

                # %HH形式を元の文字にデコードする。
                $key =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c", hex($1))/ge;
                $val =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c", hex($1))/ge;

                $val =~ s/\r\n/\n/g;

                # 日本語コードが指定されている場合は変換する。
                jcode'convert(*key, $encoding) if ($encoding);
                jcode'convert(*val, $encoding) if ($encoding);

                # 連想配列(ハッシュ)にセット
                $in{$key} = $val;
        }

        # 連想配列のグロブを返す
        return *in;
}