最終更新日



CGI,PERLの基礎

1 はじめに

CGI(Common Gateway Interface)は、Commonが共通、Gatewayが出入り口、Interfaceはインターフェイス。 言語ではなく、インターネットを扱うHTTPサーバ(WWWサーバ)上においた(Perlなどで作られた)プログラムが実行されるようにする仕組みです。 アクセスのあったホームページ(wwwクライアント)からの要求に応えて、WWWサーバ上でプログラムを動かし、それに答えるようにする約束事、インターフェイスで、ホームページ作成言語であるHTMLやJavaScriptだけではできないことをさせるものです。
 例えば、アクセス・カウンター、掲示板、会員登録、検索、アンケート集計などです。
 結局はデータを残さないといけない ものですね。入力された情報を受け取って、ウエブ上で処理して、データとして蓄積、整理するとともに、結果をホームページに戻すというのが、(多くは)Perlで組まれたcgiです。

2章 準備−PerlとHTTPサーバ は、CGIで最も多く使われるプログラム言語がPerl、まずは、Windowsで使える Perlのシステム、ActivePerl5.6をダウンロード、インストールします。
 そして、Perlなどでcgiとしてプログラムしたとすると、サーバ上で動くものですから、擬似的にHTTPサーバを個人のコンピュータ上において、デバッグできれば都合がいいのですが、そういうフリーソフト、AN HTTPDをダウンロードします。以上で準備完了です。

3章 省略の美学を貫くPerlの面白さ 。 Perlは省略の美学に徹している言語ですが、そういう文化をもっている日本人向きかもしれません。しかし、最初はかなりとまどいます。

4章 ファイルと配列 は、cgiの中で必ず使われるファイルとその処理方法です。 ファイルの内容を配列で受取ることも多いのですが、その処理で私はさんざん失敗しました。アクセス・カウンタ を改変する過程でのPerlでの実験結果で、やや冗長ですが、私自身が忘れないためそのまま書きます。

5章 やや難解なCGIトライ は、 cgiの中でよく使われる例を簡単なプログラム例も含めて紹介しておきます。 AN HTTPD使用例、正規表現、環境変数 です。 全角空白とか見つけ難いエラーで苦労したことにもふれます。

2 準備−PerlとHTTPサーバ−

とほほさんの とほほのWWW入門 のperl,cgiに関する解説を多いに参考にさせていただきました。

Windowsで使えるPerlのシステムをActiveState から、ActivePerl5.6をダウンロード、インストールします。(ダウンロードはActiveState -- Programming for the People から。) 2002/3/8に、改めてダウンロードしたら、ActivePerl 5.6.1.629 でした。 昔は「Perl for Win32」という名前でしたが、マイクロソフト社からの資金援助を受けて、「ActivePerl」と名称変更したそうです。

とほほさんの CGIスクリプトをデバッグするには? に、perl,cgiプログラムのデバッグに関する解説があります。

Perlで組んだCGIのプログラムをデバッグするために、HTTP(ウェブ)サーバーソフトを個人のコンピュータ上におきます。 中田 昭雄さんの AN HTTP Server Home Page をダウンロードし、解凍してインストール完了。 ちょうど、2002年3月3日にhttpd 1.39cにパージョンアップされたばかりのものにあたりました。 「バージョン 1.21b およびそれ以前の全てのバージョンの CGIサンプルに 重大セキュリティホールがある」とのことです。

「AN HTTP Server Home Page」を解凍したフォルダにある httpd-docs/options.html#TOP には、「オプション」メニューの詳しい解説があります。 とほほさんの WindowsでCGIを動かすには? に、AN HTTPの使い方などが詳しく解説されています。 それを参考にして、次の3-2の簡単なCGIのテストプログラム(G:\HPTAK\Computer\toroku\test.cgi)を動かしてみます。

  1. AN HTTPDを解凍してできた httpd.exe を起動する。 
  2. すると、タスクバーの端に黄色いアイコンが表示される。 それをクリックする。
  3. 「オプション」メニュー−「一般」−「ドキュメントルート」に、
     G:\HPTAK\Computer\torokuと入力する。 
  4. デフォルトインデックスに、test.cgiと入力(空欄にしておいて、5のアドレスに追記してもよい)。
  5. ブラウザを起動して、http://localhost/ あるいは http://127.0.0.1/  とし て、自分
      自身の機械を意味する特別のアドレスを指定する。
         (私の場合、LAN接続のhttp://192.168.1.2/でもOK。)

以上で準備完了です。 とはいえ、AN HTTPDを使いこなすまでには、かなり苦労しています。5章4及び アクセス・カウンタ に詳述します。なお、とほほさんの WindowsでApacheを使おう というのもありますが、AN HTTPDで十分だったので、私は使っていません。 

3 省略の美学を貫くPerlの面白さ

準備完了とはいえ、Perlに慣れるのは結構、大変でした。 かなり前に一冊だけ、買っていた本を引っ張りだしました。
 「Perlモデュール活用ガイド」(Eric Foster-Johnson著 SHOEISHA 1998/12)
この1章 Perlの概要に少々びっくりしました。 なるほど、Perlは省略の美学を貫いているなぁと。

1 引数の受け取りに、$_とは?

# The foreach command with implicit $_.
foreach (@ARGV) {
    # $_ holds value...
    print "Value is $_\n";
}
print "'@ARGV' is @ARGV";
# foreach.pl

 典型的な1例が、このforeach.plというもの。 コマンドプロンプトで、下記のように実行すると、
E:\>perl F:/Perl/Book_win/CHAP1/foreach.pl 1 2 3 4 A B C
Value is 1
Value is 2
Value is 3
Value is 4
Value is A
Value is B
Value is C
'1 2 3 4 A B C' is 1 2 3 4 A B C

foreachは繰り返しの一種として理解できるし、コマンドライン引数を特別な配列、@ARGVで受けるというのも、C言語で見ていましたが、$_で一つずつ処理するなんて、はじめてPerlに接した私には驚きでした。 こんなに省略できる言語は面白そうですが、ある程度、Perlに慣れていることを前提に、オブジェクト指向とかモデュール作成法を詳述しているこの本だけでは、少々無理と、Web上でPerlを探して見ました。 GoogleでPerlで検索して245,000件もあります。

Perlメモ なども見たのですが、結局、本を購入。
Perl言語プログラミングレッスン 入門編 結城 浩著 SOFTBANK 2001/1

なお、この手法はコマンドライン引数だけではなく、CGIでも使っています。 アクセス・カウンタ のプログラムで例示します。

2 ファイルと配列、コンテクストに依存

Perlでは、変数は$、配列は@、連想配列は%で始めます。面倒だと思ったのてすが、これがコンテクスト依存とかで、省略の美学にかなった記述法らしいと気づくまでに、時間がかかりました。4章に詳述するように、
ファイル内容全体を配列で受けとるときは、@lines=<FILE>ですが、これを$line=<FILE>と変数で表わすと、ファイル1行分を受取ることになります。上記の「Perl言語プログラミングレッスン」には、1章を割いて、コンテクスト、文脈依存について触れられていますが、その1例か?

さらに、ファイルの1行は項目がひとつとは限りません。例えば、カンマ区切りでいくつかの項目を変数 $lineで受取った場合、これを各項目に分離する場合、4-4にあるように、
 ($hp,$count)=split(/,/,$line)とか、@data=split(/,/,$line)などとすることができます。ファイル表記もその処理も簡潔です。

3 正規表現

メタ文字とか修飾子とかややこしいのがたくさんあって、Perl,CGIの本格的なプログラムを見ていると、特にこの部分はまるでおまじない、省略の美学もほどほどにしてくれと言いたくなりました。

さきほどのsplit(/,/,$line)の中の/,/も正規表現で、区切り文字のパターンを表しているといわれているうちはいいのですが、複雑なのを見るたびに投げ出していました。しかし、わかってくると、マッチング、置換などいろんな角度から文書を扱う上でなるほど便利そうと面白くもなります。5-2でメール・アドレスチェックの例で複雑な例でテストのcgiテストプログラムつきでやります。

4 ファイルと配列

CGIで、まずやりたかったことはアクセスカウンタの設置です。とほほさんの作成されたwwwcount.cgiをお借りすることとし、複数のページに置きたいのですが、複数のカウンタファイルを使って、できるように作られているのですが、私は勉強をかねて、カウンタファイルは一つでやりたいということで苦労しました。

まず、ファイルの扱いが問題になるのですが、3-2のように、

 1 配列でファイルのデータ全体を受取ることができる。
 2 したがって、各行は配列の要素(変数)になる。

この2点をほんとうには理解できていなかったため、いろいろ失敗しました。自分自身のメモですから、冗長を恐れず、忘れないように書いておきます。ここはまだ、cgiとせず、すべてPerlの例です。

1 ファイル処理1−配列の区切りは無視される−

@count=qw(0 1 2 3 4 5 6 7 8 9 10)と、ちょっとこって、スペースを区切りとした配列を用意し、F:/Perl/Counter-try/savefile.txtに書き込み、次にそのファイルから、配列に読みこみます。

Perlプログラム1
@count=qw(0 1 2 3 4 5 6 7 8 9 10);
print "ファイルへ書き込む前の配列 @count\n";
open(FILE, ">F:/Perl/Counter-try/savefile.txt") or die "Can't open $input.";
#ファイルへ書き込む
print FILE @count;
close (FILE);

open(FILE, "F:/Perl/Counter-try/savefile.txt") or die "Can't open $input.";
#ファイルから配列@count1へ読み込む
@count1=<FILE>;
close (FILE);
print "ファイルから読みこんだ配列 @count1\n";
print "その配列の最初の要素 $count1[0]\n";

実行結果1
E:\>perl F:/Perl/Counter-try/savefile.pl
ファイルへ書き込む前の配列 0 1 2 3 4 5 6 7 8 9 10
ファイルから読みこんだ配列 012345678910
その配列の最初の要素 012345678910

ファイルへ書き込む前の配列も読み込んだ後の配列も同じ形をしているとばかり思っていたのに、空白もカンマ","区切りも一切無視されることに気づくのに、そうとう時間がかかりました。ようやく、配列要素が複数あるつもりでも、1行しかないものは、ファイルを経由すると、配列の要素としては1つになるのかと気づいて、確認のために作ったのがこのプログラムです。

2 ファイル処理2−全て配列で処理、失敗−

実際にやりたいことに近づけたトライです。カウンタをおく複数のホームページを想定し、それぞれのカウンタの初期値を分かりやすくするため、仮に0から5として、これを複数行のファイル、countfile.txtとしてあらかじめ、作ります。例えば、この初期値2のカウンタを1増やしたいということですが、最初は、countfile.txtを配列に読み込んで、該当項を1増やした配列とし、それを書きだすということでやりました。

Perlプログラム2
$k=$ARGV[0];
open(FILE, "F:/Perl/Counter-try/countfile.txt") or die "Can't open $input.";
@file=<FILE>;
close (FILE);

for($i=0; $i<$#file;$i++) {
    if ($i== $k) {
	print "$k番目のカウンタを増やします\n";
	$file[$k]++."\n";
}
    $i++;
}

open(FILE, ">F:/Perl/Counter-try/countfile.txt") or die "Can't open $input.";
print FILE @file;
close (FILE);

実行結果2
perl -w F:/Perl/Counter-try/counter1.pl 2
2番目のカウンタを増やします
0
1
33
4
5

初期値2の行は1増えるのですが、次の行がその横にくっついてしまう失敗です。改行"\n"を入れているのですが。

3 ファイル処理2−読みこみ、書き込みファイルを共通にすると−

そこで、countfile.txtから読み込んで、該当項を1増やせば、直ちにファイルに書きだすということでやりました。初期値2の行だけの処理で簡潔、合理的な処理なのですが、countfile.txtの内容が消されてしまい、どうしてもうまくいきません。しかたがないので、一時ファイルTMPに一行ずつ書き出して、最後にrenameでもとのファイルと置き換えるというなんともかったるい方法で逃げました。

Perlプログラム3
$k=$ARGV[0];
$data="F:/Perl/Counter-try/countfile.txt";
$temp="F:/Perl/Counter-try/temp";
$i=0;
open(FILE,$data) or die "Can't open $input.";
open(TMP,">$temp") or die "Can't open $input.";
while (defined($line=<FILE>)) {
     if ($i== $k) {
        print "$k番目のカウンタを増やします\n";
        $line++;
        print TMP "$line\n";
     } else {
        print TMP "$line";
     }
     $i++;
}
close(FILE);
close(TMP);
rename($temp,$data);

実行結果3
E:\>perl F:/Perl/Counter-try/counter.pl 2
2番目のカウンタを増やします

処理後のcountfile.txt(初期値2の行が1増えている)
0
1
3
3
4
5

なお、この手法は、「CGIプログラミング入門」 秋本祥一、古川剛著 SHOEISHA 1997/2初版 の6章にあったものですが、そこではこのような手法を使う必然性がある事例で紹介されています(訪問者リストで後からの人を上に書きだす)。
 tempファイルは自動的に作られ、自動的に消えてくれます。

4 ファイル処理3−キーで増やす行を決める−

実際にやりたいことを最終的にチェックするトライです。カウンタをおく複数のホームページには、コンピュータに関するメモのメニューページならC200,ADSL導入顛末記ならC121というようなキーを与え、アクセスがあったページのカウンタを1増やすという処理です。もっといい方法があるに違いないでしょうが、今のところは、上記と同じです。

Perlプログラム4
$k=$ARGV[0];
print "k $k\n";
print "Homepage $k のカウンタを増やします\n";
$data="F:/Perl/Counter-try/wwwcount.cnt";
$temp="F:/Perl/Counter-try/temp";
open(FILE,$data) or die "Can't open $input.";
open(TMP,">$temp") or die "Can't open $input.";
while ($line=<FILE>) {
        ($hp,$count)=split(/,/,$line);
        if ($hp eq $k) {
           $count++;
           print "line $hp,$count\n";
           print TMP "$hp,$count\n";
        } else {
           print TMP "$line";
        }
}
close (FILE);
close(TMP);
rename($temp,$data);

$totalcount="F:/Perl/Counter-try/totalcount.cnt";
open(IN, "$totalcount");
$totalcnt=<IN>;
print "totalcnt $totalcnt\n";
#カウンタをひとつインクリメントする
$totalcnt++;
close(IN);
open(OUT, ">$totalcount");
print OUT "$totalcnt\n";
close(OUT);

実行結果4
E:\>perl -w F:/Perl/Counter-try/counter3.pl D30
k D30
Homepage D30 のカウンタを増やします
line D30,2
totalcnt 1

wwwcount.cnt
T0,0  トッブページ
P10,0  プロフィール
D30,1  大東文化大講師
C100,0  コンピュータに関するメモ
C111,0  JavaScript基本
C112,0  JavaScript応用1
 以下略
totalcount.cnt
2

一応、Perlのレベルでは、目的は達成したのですが、ここにたどりつくまで、また、苦労しました。($hp,$count)=split(/,/,$line)で、各行の複数の値を区切り、カンマ","で、複数の変数に分離するのですが、配列にこだわった失敗をいろいろしております。

	@array=$line;
	$hp=shift(@array);
        $count=pop(@array);
 としてみると、if ($hp eq $k)がきかないらしく、該当項のcountが増えてくれません。
 また、
	@array=$line;
        $hp=splice(@array,0,1);
        $count=splice(@array,1,1);
 としても、同じです。

真面目に本を読み直して、($hp,$count)=split(/,/,$line) という正規表現を使ったスマートな方法にたどりついたのですが、if ($hp eq $k) の行は、それまでの例を踏襲して、if ($hp == $k) としたために、全ての行が1増えるということになり、なかなか原因がつかめませんでした。後者は数値の場合、前者は文字列の場合という区別があることに気づかなかった次第です。

全体のtotalcount.cntも別ファイルでつけてみようと考えたのですが、上のプログラムで使った、$totalcnt=<IN>は、とほほさんの例にもあり、ファイル内容が1行、1項目の場合は、これだけですみそうです。

5 改行について

細かいところですが、ファイルからから読み出した各行には、改行がついているはずです。 プログラム4の例では、改行のついたままの$totalcntで、$totalcnt++;として、1足せるようです。 これを確かめてみました。

Perl プログラム5
$total=5;
$data="1\n";
print "data $data";

chomp($data);
$total=$data+$total;
print "total $total\n";
$data++;
print "'data+1' $data";

実行結果5
E:\>perl F:/Perl/Counter-try/kaigyo.pl
data 1
total 6
'data+1' 2

6 合計されない問題

これも、実は原因が他にあったのですが、途中段階の問題点として書いておきます。 最初、各ページのカウント数、$countの和、$totalがどうしてもできず、かたや文字列、かたや数値だからか?などと詮索していました。 他の言語にはたいていある文字列を数値に変換するライブラリはないし、そんなことはコンテキスト(文脈)で判断して、適当にやってくれるのがPerlと、「Perl言語プログラミングレッスン」の9章が語っているようでした。 つまり、2つの変数を + でつなげば、数値とみて足し算するし、文字列結合なら、. を使わないといけないということです。 でも、一応、確かめて見ました。

Perl プログラム6
#perl F:/Perl/Counter-try/kaigyo20.pl
#Test ほぼOKだが、print "count $count degit\n" で
#$countの後、改行してしまうので、chomp($count)とする。

$datafile20="F:/Perl/Counter-try/wwwcount.cnt";
if (open(IN, "$datafile20")) {
	@count = <IN>;
	close(IN);
} 
$total=0;
open(OUT, "> $datafile20");
foreach $_ (@count) {
       ($hp,$count)=split(/,/,$_);
	chomp($count);
       if ($count =~ /\d+/) {print "count $count degit\n";}
       if ($_ ne "\n") {
		print OUT $_;
		$total=$count+$total;
	}
}
close(OUT);

print "カウント合計 $total";

実行結果6
E:\>perl F:/Perl/Counter-try/kaigyo20.pl
count 88 degit
count 5 degit
count 3 degit
count 14 degit
count 26 degit
count 389 degit
カウント合計 525

なお、データファイル wwwcount.cntは、
T0,88
P10,5
D30,3
C100,14

C111,26
C121,389
を使いました。

ファイルから読み出したデータはやはり数値(判定は($count =~ /\d+/)という正規表現、\dは数字1文字にマッチ)。 このテストでは問題なく、合計が求められるのに、ほんとうにやりたいcgiでだめなのはなぜか? 本番のcgiは、アクセス・カウンタ の3-2にある「ページ毎のカウンタを一括して見るcounter-table.cgi」のソースですが、文法チェックをしても、Unrecognized character \x81 と、コード表にもない文字コードが分からないと、いささか奇妙なメッセージが出るばかり、先へ進まない、手の打ちようがないと、ほんとうに立往生!!。5-1に書いたように、全角空白が入っていたこともあったのでしょう。
 ifelsの塊で、つい、elseがないからおかしいのか?と錯覚もしましたが、それも文法的には必要ないですね。

AN HTTPD使用に十分習熟していないとき、cgiはデバッグ困難、Perlに戻して模擬的にチェックしてみたら、データファイルにある、例えば、C100を判定するifels文がないため、表示が乱れていて、合計がとれないと判明したように思ったのですが、今、再現テストをしたら、合計の値はともかく、動作には特に問題なさそう。全角の空白だけの問題だったか?

データファイルの中に改行のみの行がありました。  if ($_ ne "\n")で判定して、実データの行のみを書き込むという方法もテストしています。 最初、if ($_ ne " ")として、失敗しています。

続きというか、本番をアクセス・カウンタ でどうぞ。

5 やや難解なCGIトライ

1 AN HTTPD使用例−恐ろしや、全角空白−

下記、テストプログラム にアップした簡単なプログラムは、かなり慣れたころ作ったものですが、つまらぬところで苦労しました。最初、ハードディスク上Gドライブに作り、コマンドプロンプトで
 E:\>perl -wc G:/HPtak/cgi-bin/test/test.cgi
と 文法チェックをすると、、
 unrecognized character \x81 at G:/HPtak/cgi-bin/toroku/test.cgi line 19.
となるばかり。

19行目のprint "<P>$item\n</P>"; にエラーがあるとは思われず、foreachの中でif 文が使えないの? まさかそんな馬鹿なことはなかろうとか、難航しました。このメッセージには、以前にもどこかでお目にかかったなとも思い、\x81、Asciiコード表で81を探しましたが、何もなし。HTML文でも、空白を全角で打つと問題 があったことを思い出しました。見えないから厄介。

秀丸エディタなら、表示してくれるはずと探しまわって、メニュー「その他」−「ファイルタイプ別の設定」−「全般」で、全角空白を表示するよう設定できることを知ったのは、かなりあとのことでした。

全角空白を削除、文法チェックをパスして、perl -w G:/HPtak/......と、cをとり、コマンドプロンプトで実行してOK。AN HTTPDを起動して、2章に例示したように、「オプション」−「一般」−「ドキュメントルート」に、G:\HPTAK\Computer\torokuと入力しておいて、ブラウザをたちあげて、http://192.168.1.2/test.cgiとして、やっと結果が出るようになりました。

--------------------------------------------------------------------------
#!/usr/local/bin/perl

#here documents;
print <<"HTML_EOF";  
Content-Type: text/html; charset=sjis

<HTML>
<HEAD>
<TITLE>テスト</TITLE>
</HEAD>
<BODY>
<H2>テスト</H2>
<BR>
HTML_EOF

@data=(1,2,3,4,5,6,7,8,9);
$number=5;
print "配列の2番目の要素: $data[1]\n";
foreach $item (@data) {
    if ($number == $item) {
	print "<P>変数numberと一致した配列の要素: $item\n</P>";
	last;
     }
}
--------------------------------------------------------------------------

2番目の配列要素と、変数$numberで与えた5と一致する配列要素が見付かればそれを画面に書き出して、foreachの繰り返しをlastで抜け出します。ほとんど結果らしいものも出力しないほんとうに簡単なプログラムです。配列の各要素を$itemとしたのですが、$_としても同じです。なお、コマンドプロンプトでの実行は問題ないのですが、AN HTTPDでは、冒頭に、Content-Type: text/html; ....の行が必要だし、結果表示にも、HTMLタグが必要なようでした。niftyなど、プロバイダのwwwサーバによっては、なくてもいいところもあるようですが、大東文化大のサーバでは、AN HTTPDと同様、必須のようです。cgiは、サーバにおいたプログラムで、主にファイルを処理して、その結果をブラウザに返すということからすると、当然か。しかし、最初はその問題でもひっかかって、なかなか先へ進めませんでした。

2 メールアドレスのチェックにみる正規表現

「正規表現」という表現自体が難解ですが、荒っぽく言うと、要するにマッチングのことか?「Perl言語プログラミングレッスン」は、Perlの生命として、2章にわたって丁寧な解説があります。難解な具体例をもとに整理してみます。

掲示板では多くの人がお世話になっていると思われるkENTさんのホームページKENT WEB もすごいアクセス数です。 累計が5000万以上、1日が40,000以上。 私自身の掲示板もそうですが、私が関係しているstage2では、実に14ケの掲示板でお世話になっています。

そのkENTさんの掲示板のひとつであるjoyful.cgiの「ログ書込処理」の中に、メール・アドレスのチェックをするところがあります。

 1  if ($in{'email'} && $in{'email'} !~ /(.*)\@(.*)\.(.*)/)
            { &error("Eメールの入力内容が正しくありません"); }

  フォームの入力をハッシュ(連想記憶)の%inで受けて、キー'email'の内容が空白か、
 $in{'email'} !~ /(.*)\@(.*)\.(.*)/ なら、"Eメールの入力内容が正しくない"
というのですが、一体、これは何でしょう?
  !~  左辺が右辺と同じでないならば
  //  この2本のスラッシュの間にあるのが正規表現。マッチするかしないか?
  (.*) ドットはメタ文字、任意の1文字にマッチ、*は、直前のものの0回以上の繰り返し。
           (要するに、任意の英数字の組み合わせ)。
  \@  \は、メタ文字の前にあれば、通常の文字にする、普通の文字ならメタ文字を作る(場合がある)。
     この場合は、\はなくともよく、要するに、@が必要であることを意味する。
  \.  ドットはメタ文字なので、\があることにより,普通のドットを意味する。

結局、@の前には、任意の英数字の組み合わせが、@の後は、.に挟まれた任意の英数字の組み合わせが必要であることを意味しているが、そうでなければ、メール・アドレスと認めないということです。  @の前の0回以上の繰り返しがちょっと気になります。なくてもいいということにならないか? また、@の後は、.と任意の英数字の組み合わせが複数あってもいいのですが、そのチェックは大丈夫?ということです。

yybbs.cgiの掲示板では、「フォーム入力チェック」として、

 2  if ($in_email && $in{'email'} !~ /[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,3}/)
	    { &error("E-Mailの入力が不正です"); }
     \w      1文字(英数字と_)にマッチ
   +    直前のものの1回以上の繰り返し。
  [a-zA-Z]  英文字
  {2,3}   繰り返し回数か? @以下の例えば、ne,jp,comなどの文字列の繰り返し回数でしょう。

最近のwform.cgi(v3-24)の「書き込み処理」でも同じような形ですが、{2,5}となっており、5回とは多いのではないかと思っていました。また、疑問に思っていた*ではなく、+になって、なくてもいいの?という疑問もなくなりましたが、難解。

昔のwform.cgiの「書き込み処理」では

 3	if ($in_email && $email !~ /(.+)\@(.+)\.(.+)/) {
		&error("Eメールの入力内容が正しくありません");
     このほうが分かりやすいのですが、十分ではないのでしょうか?
4  /[\w\.-]+@[\w\.-]+/g
      というのが「Perl言語プログラミングレッスン」P239にあります。
   これでも簡易チェックだそうです。
   //の後のgは、修飾子といわれるもの、繰り返してパターンマッチを行う(gはglobalの意)

//の前に、置換のs,tr、//の後に、g,e,xなどの修飾子をつけて、もっと複雑なことをすることもできる一例です(前出のP214)。

3 メールアドレスチェックのプログラム

下記は、メールアドレスチェックのプログラム にアップしたプログラムです。2で述べた疑問をチェックするというよりは、cgiでよく使われるフォームからの送信データを受取って処理するプログラムの練習です。簡単なものなので、送信側と受信側とを別プログラムにしたくないのですが、最初に出る画面に、以前の処理結果がそのまま出ているという問題があり、受信側は、mailcheck2.cgiと別プログラムにしました。

mailcheck2.cgiには、送信データを前処理するために、require './cgi-lib.pl';としていますが、これをコマンドプロンプトで実行してみると、
 Can't locate ../toroku/cgi-lib.pl at G:/HPtak/cgi-bin/test/mailcheck2.cgi line 15.
となり、「cgi-lib.plのありかが違うでしょう」ということらしいとわかるまで、また、時間を浪費しましたが、AN HTTPDやwwwサーバで実行する場合には、問題ないことを知りました。

下記のプログラムで上記の4通りをチェックすると、上記の1は、@の前に何もなくとも、また、@が存在しなくともOKとなり、やはり、正規表現の*(0回以上の繰り返し)では、不完全のようでした。また、3,4は@の後に、.がなくてもいいということになり、やはり、不完全のようでした。2は完全のようです。

#mailcheck.cgi(送信側)
--------------------------------------------------------------------------
#!/usr/local/bin/perl

print <<"HTML_EOF";  
Content-Type: text/html; charset=sjis

<HTML>
<HEAD>
<TITLE>メールアドレスチェック</TITLE>
</HEAD>
<BODY>
<BR>
<H2>メールアドレスチェック</H2>
<form action="mailcheck2.cgi" method="POST">
  <P><b>Eメール</b><input type=text name="mail" width=200></P>
  <P><input type=submit value="送信する"><input type=reset value="リセット"></P></form>
</BODY>
</HTML>
HTML_EOF

#perl -wc G:/HPtak/cgi-bin/toroku/mailcheck.cgi
--------------------------------------------------------------------------
#mailcheck2.cgi(受信側)
--------------------------------------------------------------------------
#!/usr/local/bin/perl

print <<"HTML_EOF";  
Content-Type: text/html; charset=sjis

<HTML>
<HEAD>
<TITLE>メールアドレスチェック2</TITLE>
</HEAD>
<BODY>
<BR>
<H2>メールアドレスチェック2</H2>
HTML_EOF

require '../toroku/cgi-lib.pl';
&ReadParse;
$email=$in{'mail'}; 

print "<P>Eメール $email</P>";

if ($email !~ /[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,3}/) {
   print "<P>Eメールの入力内容が正しくありません</P>";
} else {print "<P>$email = 'OK!'</P>";}

print "</BODY></HTML>";


#  if ($in{'email'} && $in{'email'} !~ /(.*)\@(.*)\.(.*)/) {
#         print "<P>Eメールの入力内容が正しくありません;</P>"; 

#if ($in_email && $email !~ /(.+)\@(.+)\.(.+)/) {
#		&error("Eメールの入力内容が正しくありません");

#$email='h-miyazaki@waltz.plala.or.jp';
#$email='mstak@nifty.com';
#$email='MHF03673@nifty.or.jp';
--------------------------------------------------------------------------

4 環境変数

CGIがWebクライアントから呼び出されるときに、ホスト名、アドレス、ブラウザ名など、さまざまな情報が、環境変数と呼ばれる、連想配列 %ENVに入ってきます。 連想配列のキーは環境変数名です。

  使用ブラウザ名     $ENV{'HTTP_USER_AGENT'}
  クライアントのホスト名 $ENV{'REMOTE_HOST'}
  クライアントのアドレス $ENV{'REMOTE_ADDR'}
  ひとつ前のページのURL  $ENV{'HTTP_REFERER'}

後にカウンタや掲示板の中で、具体例を紹介しますが、環境変数はPerlではなく、CGI独自のものでしょう。 連想配列というように、その処理はPerlでやりますが。

ページ独自カウント