ルモーリン
ホーム 更新 Perl Sample サービス 雑談 鉄ゲタ Linux リンク 連絡先

Perlサンプル14 文字化けしないCGI

2020-01-16

内容

最近、CGIで文字化けする話をネットで2件見かけて、こういったお話も需要がありそうなので急遽作ってみました。 このサンプルについては、できるだけ要望に合わせて修正していくつもりです。 質問、要望がございましたら、私のツイッターアカウント@lemorin_jpまでご連絡ください。 各サンプルのコードはutf8、改行コードは0x0a(unixの改行)です。

実行サンプル1

リンクからCGIを呼びます。 呼び出しにパラメタがありませんからCGIだけでhtmlを生成します。 出力が文字化けしないようにutf8に設定しましょう。 あとhttpの改行コードはCR(0x0d), LF(0x0a)ですから"\n"を0x0d, 0x0aで出力するよう設定します。

ここをクリック

#/usr/bin/perl

use utf8;
use strict;
use warnings;

use DateTime;

binmode STDOUT, ":utf8 :crlf";

print <<EOF;
Content-Type: text/html;charset=UTF-8

<html>
<head>
<title>サンプル1の実行結果</title>
</head>
<body>
<p>
サンプル1の実行結果<br />
</p>
<p>
EOF

my $dt = DateTime->now(time_zone => "local");
print $dt->strftime("只今の日時は%F %Tです。<br />\n");

print <<EOF;
</p>
<p>
<a href="../sample/0e_perlsample_014.html">元のページに戻る</a><br />
</p>
</body>
</html>
EOF

実行サンプル2

フォームからCGIを呼びます。 テキストを入力してCGIが受け付けてhtmlを生成します。 モジュールはCGI.pmを利用します。 テキスト→CGI.pmでの扱い→CGIの受け取り→CGIの出力と全部上手くできて完成します。 ここで肝となる文字コードの変換、Perlで言う所のデコード/エンコードはPerlやモジュールに任せましょう。 まあ自分でやれば自爆します(笑)。 サンプルのコードをご覧いただければ分かりますがデコード/エンコード処理を一切書きません。

こちらがフォームです。
text1:

#/usr/bin/perl

use utf8;
use strict;
use warnings;

use CGI qw/ -utf8 :html /;
use DateTime;
use Encode;

binmode STDOUT, ":utf8";

my $cgi = CGI->new;
my $text1 = $cgi->param("text1");

print $cgi->header(
	-charset => "utf-8",
);
print $cgi->start_html(
	-title => "サンプル2の実行結果",
	-lang => "ja",
);
print $cgi->p("サンプル2の実行結果");
my $dt = DateTime->now(time_zone => "local");
print $cgi->p($dt->strftime("只今の日時は%F %Tです。"));
print $cgi->p("入力したテキストは「$text1」です。");
print $cgi->a({ href => "../sample/0e_perlsample_014.html" }, "元のページに戻る");
print $cgi->end_html();

実行サンプル2.5(GETメソッド)

サンプル2はPOSTメソッドでしたので、GETメソッドでやります。 といってもPOSTとGETの違いはモジュールCGI.pmが吸収していて、同一のスクリプトで動作します。 同じサンプルを別フォームから呼び出します。

こちらがGETメソッド版フォームです。
text1:

(CGIはサンプル2を呼びましたので省略)

実行サンプル3

textareaから入力、ファイルに書き込み、読み出しましょう。 同じデータを読み出して表示してもつまらないので、前回書き込んだ内容を読み出してから、入力データをファイルに保存します。 データがファイルに入り周回遅れで表示される訳ですね。 ホームページカウンタ(懐かしいなあ)でお馴染みのファイルアクセス競合は無視して今後のサンプルで紹介します。 ですから、他のユーザーと交互に書き込めばチャットになるかも!?(なりません)

text2:
#/usr/bin/perl

use utf8;
use strict;
use warnings;

use CGI qw/ -utf8 :html /;
use DateTime;
use Encode;

binmode STDOUT, ":utf8";

use constant FILE_NAME => "sample3.txt";

my $cgi = CGI->new;

print $cgi->header(
	-charset => "utf-8",
);
print $cgi->start_html(
	-title => "サンプル3の実行結果",
	-lang => "ja",
);
print $cgi->p("サンプル3の実行結果");
my $dt = DateTime->now(time_zone => "local");
print $cgi->p($dt->strftime("只今の日時は%F %Tです。"));

print $cgi->p("前回入力したテキスト(ファイルから読み出し)です。");
print $cgi->hr;
if (open my $fh, "<:utf8 ", FILE_NAME) {
	while (<$fh>) {
		chomp;
		print $cgi->p($_);
	}

	close $fh;
}
print $cgi->hr;

print $cgi->p("今回入力したテキスト(ファイルに書き込み)です。");
print $cgi->hr;
my $text2 = $cgi->param("text2");
my @text2 = split /\n/, $text2;
if (open my $fh, ">:utf8 ", FILE_NAME) {
	for (@text2) {
		print $fh "$_\n";
		print $cgi->p($_);
	}
	close $fh;
}
print $cgi->hr;

print $cgi->a({ href => "../sample/0e_perlsample_014.html" }, "元のページに戻る");
print $cgi->end_html();

実行サンプル4

4番目はファイルアクセス競合の整理です。 CGIに限らない処理なので別ページにしました。 こちらをご覧ください。
Perlサンプル15 ファイルアクセスの競合整理

実行サンプル5

ファイルをアップロードします。 送っただけでは面白くないので、ファイル名とSHA2のダイジェストを表示します。 このサンプルではアップロードするファイル名がデコードされないので自前でデコードします。

フォーム

ファイル:

コード

#/usr/bin/perl

use utf8;
use strict;
use warnings;

use CGI qw/ -utf8 :html /;
use DateTime;
use Encode;
use Digest::SHA2;

binmode STDOUT, ":utf8";

use constant TITLE => "サンプル5の実行結果";

my $cgi = CGI->new;
print $cgi->header(
	-charset => "utf-8",
);
print $cgi->start_html(
	-title => TITLE,
	-lang => "ja",
);
print $cgi->p(TITLE);
my $dt = DateTime->now(time_zone => "local");
print $cgi->p($dt->strftime("只今の日時は%F %Tです。"));

print $cgi->hr;
my $filename = Encode::decode(utf8 => $cgi->param("up_file"));
print $cgi->p("アップロードしたファイルは「$filename」です。");
print $cgi->p("SHA2は次の通りです。");
my $fh = $cgi->upload("up_file");
if ($fh) {
	binmode $fh;
	my $digest = Digest::SHA2->new->addfile($fh)->hexdigest;
	print $cgi->p($digest);
} else {
	print $cgi->p("エラー発生:@{[$cgi->cgi_error]}");
}

print $cgi->hr;
print $cgi->a({ href => "../sample/0e_perlsample_014.html" }, "元のページに戻る");
print $cgi->end_html();

実行例

アップロード用の写真

「ルカ姐さんも俺の嫁.jpg」です。

ダイジェストを計算

パソコンにダウンロードしてSHA2のダイジェストを計算します。

フォームに指定

フォームに指定します。 ※この下のフォームは画像です。

アップロード

アップロードボタンをクリックするとファイルをアップロード、SHA2のダイジェストを表示します。
パソコンで計算したSHA2のダイジェストと一致する事を確認してください。