以下の文章は、私が1994年2月に公開したものです。公開してすでに6年以上経ち、 技術解説としてはおそらく役に立たないと思います。CGIの使い方について知りたい方は、 別の情報を探すことをおすすめします。このページは歴史的記録として残しておくことにします。

江渡 浩一郎 2000/06/11

1994年2月9日にinfotalkで公開

1994年1月21日 訪問者リストページを公開


簡単なCGIとFORMの使い方

Author: ETO Kouichirou <t91069ke@sfc.keio.ac.jp>
Update: 94/11/24

このドキュメントは、CGIおよびFORMという機能の使い方を簡単に 解説したものです。できるだけ間違いのないように注意しましたが、 いろいろあるだろうと思います。見つかったら指摘してください。 ここがわからない、こうしたほうがいい、などのコメントがありま したら、t91069ke@sfc.keio.ac.jpまでE-mailをください。

このドキュメントは、NCSAのhttpdを使っていて、標準のディレク トリー構成であることを前提としています。また、だいたいのhtml の書き方と、perlの書き方がわかっていることを前提としてます。 htmlの書き方がわからない人は、 HTML入門を読んでください。また、perlの書き方については、 ここを参考にして ください。できればserverの管理者であるほうが望ましいです。

以下のドキュメントを参考にしました。

では、はじまりはじまり。
CGI(The Common Gateway Interface)とは、http server側で、 scriptを呼び出す、server側で実行させるための共通インターフェ イスである。

client側でのscript実行にはまだ多くの問題がある。この 文章を参照のこと。 FORMというのは、HTML+で規定されたタグで、HTML文章中でinput fieldを作れるようにするものである。

CGIの簡単な使い方

例えば、Mosaicなどのclientから以下のURLをOpenしてみてほしい。 UNIXのdateの出力がでてくるはずだ。

http://andro.sfc.keio.ac.jp/cgi-bin/date

これは現在のandro.sfc.keio.ac.jpというserverの時間である。 server側でdateを実行してその出力をMosaicに出している。server 側で何を実行しているか見てみよう。

==> /usr/local/etc/httpd/cgi-bin/date <==
#!/bin/sh

DATE=`which date`

echo Content-type: text/plain
echo

if [ -x $DATE ];  then
	$DATE
else 
	echo Cannot find date command on this system.
fi
==> end <==

shell scriptの中身は、ようするに見てわかるとおり、標準出力に だしたものがhtmlのファイルとして処理されて、Mosaicの画面にで てくる。

いくつか注意。

echo Content-type: text/plain
echo

この2行を忘れてはならない。これを忘れると、でてこない。

また、server側でscriptが無限ループにはいると、clientはアクセ スした状態でとまってしまう。

このdateというscriptは、NCSA httpdについてきたものである。 /usr/local/etc/httpd/cgi-binというのがdefaultのcgi scriptの 置かれるところである。

もしあなたがserverの管理者なら、httpdの配布についてきた scriptを、/usr/local/etc/httpd/cgi-binに置いてみよう。 そして、

http://あなたのserver名/cgi-bin/date

と、実行してみよう。同じように実行できるはずだ。

cgi-binについては、設定ファイル

/usr/local/etc/httpd/conf/srm.conf

で変えられる。

# ScriptAlias: This controls which directories contain server scripts.
# Format: ScriptAlias fakename realname

ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/

ここを変更すればscriptの置き場所を自由に決定できる。もちろん、 このdirectory以外のところにおいてあるscriptは実行できない。 やろうとしても、scriptがplain textとして読み出されるだけだ。

これでserver側でのscript実行についてだいたいわかったもらえた と思う。ここまでではまだ、client側からserver側へ、情報を送る ことができない。次にFORMの使い方についてみてみよう。

FORMの簡単な使い方

Mosaicのver.1.0のころは、ISINDEXとして実現されていた機能であ る。ISINDEXの場合はひとつの情報しか送れなかったのが、もっと いろいろ送れるようになったということだ。

僕のadd-name.htmlをサンプルとして見てみよう。

=== add-name.html ===
<FORM METHOD="POST" ACTION="/cgi-bin/add-name">

Please add your name to my visited person list.<P>

Please input your name: <INPUT NAME="name" SIZE=30> <P>
Please input your mail address: <INPUT NAME="address" SIZE=40> <P>
Please input your home page URL: <INPUT NAME="url" SIZE=40> <P>
If you don't have your home page, please keep it brank.<P>

After input these field, press this button:
<INPUT TYPE="submit" VALUE="ADD"> <P>

</FORM>

余分なところは削ってある。それぞれの項目を簡単に解説する。

まずFORMというタグで、ある部分を囲むようにする。その中がひと まとまりの情報となって送られるということだ。また、FORMはネス トできない。FORMの部分をわかりやすくするために、前後に <HR>(horizontal rule)というタグをつけることが 推奨されている。

<FORM METHOD="POST" ACTION="/cgi-bin/add-name">

METHODのところはGETとPOSTの2種類から選ぶ。serverに対してどの ように情報を送るのかの方法を選んでいる。

ようするに違いは、

よって、GETは送れる情報の量に限りがあるが、POSTにはない。と いうことで、基本的にPOSTを使えばいいようだ。

INPUTというタグのところで、実際にインプットフィールドが作ら れる。NAMEというのは、そのフィールドにつけた名前。server側で はこの名前をもとにして情報を受け取る。

SIZEで大きさを指定する。defaultだと20になっている。ここでは 少し横に大きくするために、SIZEを30とか40にしている。

<INPUT TYPE="submit" VALUE="ADD">

TYPE="submit"というのは、これが選ばれると、情報が送られると いうこと。Mosaicだとボタンの形になる。INPUTが一つだけだと、 そこでリターンを押したときに自動的にsubmitになる。複数の INPUTがあるときは必ずこれを作らなくてはならない。VALUE="ADD" というのは、ボタンにつく名前。

TYPEというのはもっといろいろあるが、とりあえず省略。

詳し くは、 Fill-out Formについての文章を読んでみてほしい。 submitが押されると、FORMのところのACTIONに示されるものが実行 される。これで、インプットフィールドの情報がserverへと送られ る。次にどのように情報の受け渡しがなされるか見てみよう。

FORM+CGIの簡単な使い方

ISINDEXのころの情報の送られる形式は、
http://andro.sfc.keio.ac.jp/cgi-bin/finger?eto

のように、?のあとに情報がくっつくという形式だった。 このときは、一つしか情報が送れなかった。

FORMではどのように拡張されているかというと、上記のINPUTタグ のNAMEというところについている名前を使って指定するようになっ ている。 たとえば上記のhtmlで、情報が以下のようになっていたとする。

name
ETO Kouichirou
address
t91069ke@sfc.keio.ac.jp
url
http://andro.sfc.keio.ac.jp/eto/

このとき、

name=ETO+Kouichirou&address=t91069ke@sfc.keio.ac.jp&url=http%3a%2f%2fandro.sfc.keio.ac.jp%2feto%2f

という形で送られる。GETの場合はこれが環境変数QUERY_STRINGに、 POSTの場合はこれが標準入力から送られる。

見るとわかるように、

長さがCONTENT_LENGTHという環境変数で渡されるので、POSTの場合、 その長さのぶんだけ読みとるようにする。shellで、

cat > $tmp

とかやってもだめ。終りを読みとってくれないから、そこで止まっ てしまう。

GETとPOSTの区別は、REQUEST_METHODという環境変数で送られる。 GETの場合はQUERY_STRINGという環境変数に情報が入る。

ということで、これらをふまえた上で、これをperlで書いてみよう。 これがadd-name scriptの本体。これ は、comp.infosystems.wwwで流れていたperlによるcgiの書き方の newsを参考にして書いたものだ。これが もとの サンプル。これを元にいろいろ改変を加えている。 以下に、少しづつ解説を加えていく。

&cgi'header; まず、例の

Content-type: text/html

というヘッダーを書いている。

&cgi'decode;

というところで実際のdecodeの処理をやってくれている。0という のはverboseかどうかを指定しているのがが、とりあえず無視して いい。ここで、%cgi'tagsに、連想配列の形で送られてきた情報を 入れている。&cgi'decodeの中身を見てみよう。

        if ($ENV{'REQUEST_METHOD'} eq "POST"){
                $n_read = sysread(STDIN, $args, $ENV{'CONTENT_LENGTH'});
        } else {
                $args = $ENV{'QUERY_STRING'};
        }

POSTかGETかを判別して、$argsに送られてきた情報をいれている。

        @terms = split('&', $args);

まず、&で区切る。

        foreach (@terms) {
                ($tag, $value) = split(/=/, $_, 2);

= で区切って、

                $value =~ s/\+/ /g;

+ を ' ' に変換。

                $value =~ s/%(..)/pack("c", hex($1))/ge;

%?? を元の文字列に変換。

                $tags{$tag} = $value;           # tags is global

cgi_tags に連想配列の形でいれて、return。

	$cont = $cgi_tags{$tag};
	$cont =~ s/&/&amp;/g;
	$cont =~ s/</&lt;/g;
	$cont =~ s/>/&gt;/g;

ここで、& < >を実際にそう見えるように変換している。 あとの残りは見ればわかると思うので省略。 これをパッケージの形に書き直してみた。 here

だいたいこのくらいわかれば自分でもCGIとFORMの機能を利用した ページを作れるのではないかと思う。日本のWWWでも、これらの機 能を利用したページが増えるとうれしい。

最後に、このドキュメントを読んだ人は、ぜひここをアクセスして、僕の訪問者 リストに名前をつけくわえていってください。:-)

それでは、Have a Happy Networking!

history:

Date: 94/07/26


Please E-mail comments and questions to
ETO Kouichirou <t91069ke@sfc.keio.ac.jp>