## 情報工学実験II WWW

メールでのレポート提出は、平文で行なってください。
作成したプログラムソースと，
図のファイルなどは，nirai
からアクセスできる状態にし，URL 等を含めてレポート中に場所を明記して下さい．またプログラムは第三者が実行確認できるように簡単なREADMEファイルを付加すること．

プログラムソースを印刷して添付することはしないこと．LaTeX のソースを付けた大馬鹿者が一グループありましたが，そういう水増しはやめよう．

○Webサービスを行うデーモン
デーモン(daemon)とは、UNIX上でさまざまなサービスをする偉いやつです。通常使われている
telnet や ftp を受け付けるときもそれぞれデーモンによってその機能が提供されており、それぞれ
telnetd 、 ftpd というデーモンが動作することによって通信ができるようになってます。
当然WWWサービスもデーモンで提供されており、httpd というデーモンで行われています。

WWWサービスを提供するプログラムはたくさんありますが、pw機には apache
というパッケージがインストールされています。

○httpd のたちあげ
rootになって
% /usr/var/www/bin/start-apache
をします。

これでhttp://pw???.st.ie.u-ryukyu.ac.jp/にアクセスすることができます。

WWWサービスを停止するときは、
% kill -9 /var/run/http.pid
とします。

■課題１
rootになって httpd を起動し、http://pw???.st.ie.u-ryukyu.ac.jp/にアクセスしてみよう。プロセスが
httpd を起動する前とした後ではどうかわるでしょうか？

○httpdサービスの設定
apacheの設定ファイルは /usr/local/etc/httpd/conf/httpd.conf
にあります。このファイルには同時にアクセスできる人数や公開するroot directory
、使用 port が設定されています。

このファイルのパラメタを変えることで、httpd の詳細な設定ができます。

<例>
ServerType standalone
standalone か inetd を記述します。　boot からデーモンとして立ち上げ
るか、inetdの管理下で リクエストがあってから立ち上げるかの違いです。 inetd
は、TCP wrapper のセキュリティ機能が適用されます。

HostnameLookups off
サーバにアクセスして来たホストの DNS を参照するかどうかの設定です。
外部かアクセスを把握したいときには、on を記述します。

ServerAdmin webmaster@hogenet.jp
WEB サーバ管理者のメールアドレスを指定します。エラーがあった場合に、サーバが表示するメッセージとともに表示するメールアドレスです。

また、バーチャルホストネームの設定とかできます。
さらにいろいろな設定ができますが、http.confの説明書きを読めばわかるでしょう。

/usr/local/etc/httpd/conf/srm.conf はサーバリソースマップと呼ばれ、
各種ファイルのディレクトリの位置やインデックス化に関する情報等を設定
できます。WEB サーバは、ここで指定されたディレクトリ以外へのアクセスは出
来ない様になっています。

<例>
DocumentRoot /home/httpd/html
アクセスしたときの、サーバの最上位のドキュメントディレクトリを指定します。
http://www.hoge.jp/
とアクセスしたときに表示される HTML を置くディレクトリです。

UserDir public_html
ユーザホームページのディレクトリの指定です。ユーザ foo ディレクトリの下に
public_html
ディレクトリを作れば、http://hoge.hoge.jp/~foo/ で アクセスできます。

FancyIndexing on
ディレクトリに対する自動インデックス化の設定です。ファイル名の無い
URL のリクエストが来た時、index.html が無かった場合に、そのディレクトリをインデインデックス化してファイルリストを表示します。
※最近はセキュリティを高めるために off にすることが多いようです。

AccessFileName .htaccess
ここで設定したファイルがディレクトリにあると、その中で設定された内容を優先的に適用します。

AddHandler cgi-script .cgi
AddHandler は、特定の拡張子を持つファイルの挙動を設定します。　拡張子
.cgi
のCGIスクリプトを実行出来るようにします。

server-parsed .shtml
SSI のコール名と拡張子です。

○CGI(Common Gateway Interface) と SSI(Server Side
Include)
WWWを使用すると、掲示板やカウンタなどを見たことがあると思います。こ
れはCGIと呼ばれる機能です。主にPerlで書かれています。C でも実現可
能です。また、 HomePage 内に日付や他のファイルを読み込ませる機能を SSI
と呼びます。これはサーバに「○○してね」とコマンドを渡します。
これらは http.conf と srm.conf を調整することで使用可能となります。

■課題２
http://pw???.st.ie.u-ryukyu.ac.jp/cgi-bin/bsdi-man/
にはBSD/OSのマニュアルを参照できるようになCGIがある。ここにアクセスし、使用してみよう。このとき
HomePage のソースを参照し、「場所ツールバー」にどういう表示がされるか考
察してみよう。また、http.conf 、 srm.conf を変更し、WWWサービスがどう変化するか試してみよう。

○CGIスクリプトの作成
では、実際にCGIスクリプトを作成しましょう。
ここでは Perl を使用します。Perl は非常に柔軟な言語ですので、覚えておいて損はないです(管理者は必須)。

オンラインマニュアルは
http://bw-www.ie.u-ryukyu.ac.jp/~kono/perl/index.html
にあります。

が、これでたりないと思うので
「初めてのPerl - Learning Perl」 O'Reilly シリーズ
の購入を薦めます(通称リャマ本)。もちろんWeb上のCGIサイトで勉強しても構いません。

では、簡単な cgi スクリプトを作成しましょう。

- hello.cgi -

1 #!/usr/bin/perl5
2 print "Content-type: text/html\n\n";
3 print "<HTML>\n";
4 print "<TITLE>Simple cgi Script</TITLE>\n";
5 print "<HR>Welcome cgi sample<P>\n";
6
7 print "hello world!\n";
8 print "</HTML>\n";

■説明■
1行目 perl コマンドがどこにあるかフルパスで記述します。(おまじないです)
2〜8行目 print コマンドで"(ダブルクォーテーション)で囲まれたテキストを表示
します。

perlコマンドで実行すると、

pw008: {6} % perl hello.cgi
Content-type: text/html

<HTML>
<TITLE>Simple cgi Script</TITLE>
<HR>Welcome cgi sample<P>
hello world!
</HTML>

と表示されますね。hello.cgi はperlで実行されるとHTML言語を出力します。

これを ~/public_html に移動させて、ブラウザから実行させましょう。

% mv hello.cgi ~/public_html
% chmod +x ~/public_html/hello.cgi

として、ユーザ以外の実行権限を追加します。
※置くところは任意です。パスに応じて場所は変えてください。

http://pw???.st.ie.u-ryukyu.ac.jp/~j98????/hello.cgi
にアクセスして実行させましょう。

■課題３
hello.cgiを作成してブラウザからアクセスし、実行させてみよう。
また、なぜユーザ以外の実行権限を追加するのかhttpサーバとperlの連係を考察
してみよう。図で示すとよいです。

○SSIの使用
SSIはHTMLの途中で使用することにより、別のファイルを呼び出したり、コマンドを
実行させることができます。

※慣習的に SSI を利用できるサーバーでは，拡張子 shtml を SSI が利用で
きる html ファイル(MIME type: text/x-server-parsed-html) としている場合が多い。このような利用環境では拡張子を
html から shtml にすることで SSI が記述可能になります。また、public_html
ディレクトリに .htaccess ファイルを設置することでhtmlファイルでSSIが利用可能になります。

SSIの基本構文は

<!--#element attribute = value ... -->

で成り立っています。

※注意点

"<!--" と "#" の間にはスペースを入れない。
"-->" の前にはスペースを入れた方がよい。

elementとattributeは対になっていて、
<!--#config errmsg = "エラーなのさ" -->
<!--#echo var = "REMOTE_HOST" -->
<!--#include file="hoge.html" -->

など、
config には errmsg
echo には var
include には file
といった使用になります。それぞれ他にいろいろなattributeが使用できます。

#exec cmd は特別で UNIX コマンドを実行させることができます。
<!--#exec cmd = "/usr/bin/cal" -->
だと、cal コマンドを実行してブラウザに表示させることができます。

例えば次のようなSSI構文を ssi.shtml として作成します。

- ssi.html -

<HTML>
<BODY>
<!--#config timefmt="%Y年%m月%d日%p %I時 %M分 %S秒" -->
<!--この#config timefmtはタイムフォーマットの指定-->
あなたのマシン名：<!--#echo var = "REMOTE_HOST" --><BR>
現在のサーバの時刻：<!--#exec cmd = "date" --><BR>
このファイルの最終更新日時：<!--#flastmod file = "ssi.shtml" --><BR>
カレンダー：<BR>
<!--#exec cmd = "/usr/bin/cal" --><BR>
</BODY>
</HTML>

そのファイルにアクセスしてみましょう。SSIが実行されて、ブラウザには

あなたのマシン名：133.13.48.203
現在のサーバの時刻：Sun Oct 24 19:42:55 JST 1999
このファイルの最終更新日：1999年10月24日PM 07時 59分 09秒
カレンダー

October 1999
S M Tu W Th F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

と表示されます。

○共通(Common)の環境変数
ssi.shtml で、
<!--#echo var = "REMOTE_HOST" -->
を使ってみましたが、REMOTE_HOSTというのは環境変数と呼ばれます。これは
ssi.shtml を見た人がもつ情報を取り出したものです。tcsh で setenv コマンドを実行するとシェルでの環境変数が見えますね？
それに似たものです。

※環境変数の種類

AUTH_TYPE ユーザ認証するためのもの
CONTENT_LENGTH HTML の form タグから POST によって CGIプログラムへ送るデータのサイズ
CONTENT_TYPE CGI によって扱われるデータの種類
GATEWAY_INTERFACE サーバで使っている CGI のバージョン
HTTP_ACCEPT 訪問者の使っているブラウザがヘルパーソフト無しで表示できるファイル形式
HTTP_REFERER CGI スクリプトがどこから呼び出されたか
HTTP_USER_AGENT 訪問者の使っているブラウザやコンピュータの種類
PATH_INFO HTML タグから CGI プログラムへパス情報を送る際に使う
PATH_TRANSLATED HTML タグから CGI プログラムへフルパス情報を送る際に使う
QUERY_STRING HTML タグから GET によって CGI プログラムへ情報を送る際に使う
REMOTE_ADDR 訪問者の IP アドレス
REMOTE_HOST 訪問者のマシン名
REQUEST_METHOD HTML タグから CGI プログラムへ情報を送った手段(POST または GET)
SCRIPT_NAME 実行した CGI プログラムのファイル名
SERVER_NAME 実行した CGI プログラムの置いてあるサーバ名
SERVER_PORT 実行した CGI プログラムの置いてあるサーバのポート番号
SERVER_PROTOCOL WWW サーバのプロトコルバージョン
SERVER_SOFTWARE httpd のバージョン

■課題４
環境変数を表示するSSI(またはCGI)スクリプトを作ってブラウザからアクセスし、環境変数を確認してみよう。

○カウンタを作る
CGIとSSIについてはわかりましたね。次はカウンタを作ってみましょう。

まずは public_html/counter/ のようなディレクトリを作り、
countdata カウンタのデータを入れるファイル
count.cgi カウンタ動作するCGIスクリプト
を作ります。
countdata ファイルの中身は 0 に、パーミッションは 666 に設定します。

- countdata -

0

- count.cgi -

1 #!/usr/bin/perl5
2 $data_file=countdata;
3 open(KAZU,"<$data_file")||die "CounterReadError.......\n";
4 flock(KAZU,2);
5 $counter=<KAZU>;
6 $counter_new=($counter+1);
7 close(KAZU);
8 flock($data_file,8);
9 open(KZ,">$date_file")||die "CounterWriteError.......\n";
10 flock(KZ,2);
11 print KZ "$counter_new\n";
12 #print "$counter_new\n"; #これは端末からの確認用。
13 close(KZ);
14 flock($data_file,8);
15 #-------　実行確認の表示　-------
16 print "Content-type:text/html\n\n";
17 print "<HTML><HEAD><TITLE>OK</TITLE></HEAD>\n";
18 print "<BODYBGCOLOR=\#ffbbaa\>\n";
19 print "<CENTER>\n";
20 print "<H1>ThankYou.</H1>\n";
21 print "<H2>---Counter---</H2>\n";
22 #カウンターの新しい数値の表示。
23 print "$counter_new\n";
24 print "</CENTER>\n";
25 print "</BODY></HTML>\n";

1行目：おまじない
2行目：$data_file に countdata をプリセット
3行目：$data_file を KAZU として開く。失敗したら die 以下のメッセージを出力
4行目：flock で $data_file をロック
5行目：KAZU の1行目を $counter に読み込む
6行目：$counter_new に $counter+1 を入れる
7行目：KAZU を閉じる
8行目：$data_file を開放
9行目：$data_file を KZ として開く。失敗したら die 以下のメッセージを出力
10行目：flock で $data_file をロック
11行目：print で KZ に $counter_new を書き込む
13行目：KZ を閉じる
14行目：$data_file を開放
16〜24行目：HTMLを出力

■課題５
perl コマンドで count.cgi を実行し正しく動くかチェックしてみよう。
ブラウザからアクセスし、なんどかリロードしてカウンタを増やしてみよう。
また、ファイルをロックするのは何故でしょうか？

■課題６
このプログラムには重大な欠陥があります。実際に複数の count.cgi を同時に動作させる(バックグラウンドでね)とわかります。異常が起きるとどうなるでしょうか？
ファイルのロックに着目してこのプログラムのフローチャートを描き、まずい点を指摘してみよう。

■課題７
読み書き可能でファイルを開くには
open(HOGE,"+<hogefile")
を使用します。課題６での欠点を補うようにcount.cgiを改良しましょう。

○formからテキストを受け取る。
count.cgiはプログラムを実行してHTMLを吐くものでした。では、HTMLのformから
テキストを受けてみましょう。

- form.html -

<HTML>
<HEAD>
<TITLE> form get </TITEL>
</HEAD>
<BODY>
<H2>GETでformのデータをCGIプログラムに渡す。</H2>
<HR>
<FORM METHOD="GET" ACTION="formget.cgi">
データ１：<INPUT TYPE="TEXT" NAME="data1" SIZE=30><BR>
データ２：<INPUT TYPE="TEXT" NAME="data2" SIZE=60><BR>
URL：<INPUT TYPE="TEXT" NAME="url" VALUE="http://" SIZE=60><BR>
好きな色：<SELECT NAME="color" SIZE=1>
<OPTION VALUE="red">あか
<OPTION VALUE="blue">あお
<OPTION VALUE="yellow">きいろ
</SELECT>
<INPUT TYPE="submit" VALUE="submit"><INPUT TYPE="reset" VALUE="reset">
</FORM>
<HR>
</BODY>
</HTML>

- formget.cgi -

#!/usr/bin/perl5
$data=$ENV{'QUERY_STRING'};
print "Content-type:text/html\n\n";
print "<HTML><HEAD><TITLE>formget.cgi</TITLE></HEAD>\n";
print "<BODY>\n";
print "<H2>form.htmlから submit で受け取ったデータ</H2>\n";
print "$data\n";
print "</BODY></HTML>\n";

form.html 内の <FORM> タグで囲まれたところで <INPUT> タグ内のものをGETメソッドで
formget.cgi に送っています。送る際に、 QUERY_STRING という環境変数で渡しているのです。

■課題８
form.html formget.cgi を作成して情報を受けてみよう。

これだと日本語や特殊文字が使えん!

ということでこれを decode するために、 jcode.pl を利用します。
日本語を表現するコードには、 EUC 、 SJIS 、 JIS の３種あり、これらのコードが混在するとブラウザではうまく表示できません(俗にいう文字化け)。
例えば Windows 、 MacOS はデータを SJIS で扱い、 UNIX 系 OS では EUC
を使っています。 jcode.pl はこのようなコードの違いを簡単な操作で変換してくれます。また、
cgi-lib.pl は <FORM> タグ内で NAME で受けた各パラメタを切り出す機能があります。

- formdecode.html -

<HTML>
<HEAD>
<TITLE>formdecode.html</TITLE>
</HEAD>
<BODY>
<H2>GETでfromのデータをCGIプログラムに渡す</H2>
<HR>
<FORM METHOD="GET" ACTION="formgetdecode.cgi">
データ１：<INPUT TYPE="TEXT" NAME="data1" SIZE=30><BR>
データ２：<INPUT TYPE="TEXT" NAME="data2" SIZE=60><BR>
URL：<INPUT TYPE="TEXT" NAME="url" VALUE="http://" SIZE=60><BR>
好きな色：<SELECT NAME="color" SIZE=1>
<OPTION VALUE="red">あか
<OPTION VALUE="blue">あお
<OPTION VALUE="yellow">きいろ
</SELECT>
<INPUT TYPE="submit" VALUE="submit"><INPUT TYPE="reset" VALUE="reset">
</FORM>
</BODY>
</HTML>

- formgetdecode.cgi -

#!/usr/bin/perl5
require "cgi-lib.pl";
require "jcode.pl";
&ReadParse; #cgi-lib.pl の機能。

$data=$ENV{'QUERY_STRING'};
$data1=$in{'data1'};
$data2=$in{'data2'};
$url=$in{'url'};
$color=$in{'color'};
$colorstring;
if($color eq "red"){$colorstring='あか';}
elsif($color eq "blue"){$colorstring='あお';}
elsif($color eq "yellow"){$colorstring='きいろ';}
esle{;}

print "Content-type:text/html\n\n";
print "<HTML><HEAD><TITLE>formgetdecode.cgi</TITLE></HEAD>\n";
print "<BODY>\n";
print "<H2>decode前</H2>$data<BR></HR>\n";
print "<H2>切り出し</H2>\n";
print "$data1<BR>";
print "$data2<BR>";
print "$url<BR>";
print "好きな色：<FONT COLOR=\"$color\">$colorstring</FONT><HR>";

&jcode'convert(*data1,"euc");
&jcode'convert(*data2,"euc");
&jcode'convert(*url,"euc");
&jcode'convert(*colorstring,"euc");

print "<H2>これはEUCコード</H2>";
print "$data1<BR>";
print "$data2<BR>";
print "$url<BR>";
print "好きな色：<FONT COLOR=\"$color\">$colorstring</FONT><HR>";

&jcode'convert(*data1,"sjis");
&jcode'convert(*data2,"sjis");
&jcode'convert(*url,"sjis");
&jcode'convert(*colorstring,"sjis");

print "<H2>これはsjisコード</H2>";
print "$data1<BR>";
print "$data2<BR>";
print "$url<BR>";
print "好きな色：<FONT COLOR=\"$color\">$colorstring</FONT><HR>";

&jcode'convert(*data1,"jis");
&jcode'convert(*data2,"jis");
&jcode'convert(*url,"jis");

print "<H2>これはjisコード</H2>";
print "$data1<BR>";
print "$data2<BR>";
print "$url<BR>";
print "好きな色：<FONT COLOR=\"$color\">$colorstring</FONT><HR>";

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

■課題９
コードを統一し、一言掲示板を作ってみよう。

※HTMLファイルの<META>タグ内を適切に処理すればコードの統一は気にしなくてもよいかもしれない。

○さまざまなブラウザ
ブラウザにはいろいろなものがあります。

Netscape Navigator、Netscape Communicator
米Netscape社が開発したブラウザ。その前身は大学生が作った Mosaic
だった。今年AOL(American On Line)に買収された。ブラウザのソースが公開されているので、改変可能となっている。中核にGeckoエンジンをもち、自由にインタフェースを変えられるようになるらしい。

InternetExploror
米Microsoft社がNetscapeに対抗して作った。Windowsとの親和性は高い。

lynx
UNIX tty 端末で実行する文字ベースのブラウザ。
% lynx とすると実行できる。

i-mode
携帯電話で Web file を閲覧することができる。今年デビュー。

■課題１０
http://www.nttdocomo.co.jp/mc-user/i/tag/index.html
を参照して 自分のページの i-mode 対応pageを書いてみよう。

○plug-in と Helper-Application
NN(Netscape Navigator)、IE(Internet Exploror)には plug-in 機能があり、特別
なページを参照することができる。helper-applicationとは、ブラウザで補えない
機能を別のソフトで実現することです。
それぞれ [option] -> [general Preferences ...]でApplicationがわかります。

■課題１１
telnet を起動するhtmlを書いてみよう。

○インタレースGIF、アニメーションGIF
Webページには背景が透けて見える画像、動く画像があります。これはInterlace
GIF、Animation GIFと呼ばれ、画像フォーマットとして規格化されています。Interlace
GIF は背景が透けて見えるもの、Animation GIF はぱらぱら漫画の要領で次々とGIF画像を入れ換えていく画像です。
UNIXには gimp という素晴らしいアプリケーションがあります。Windows
や MacOS での Photoshop と同等の機能があります。さらにこれがオープンソースとは！
※Windows版の gimp はあります。

使い方：
端末から
% gimp
として gimp を起動します。ダイアログを見ながら先へ進みましょう。
起動したら[File]-[Open] や [File]-[New] などでパレットを表示します。

ある程度できるようになったらAnimationGIFを作ってみましょう。
パレット内で右クリックし、下の画像のような Layer ウィンドウを開きます。

Layerを表示させたい順に並べて階層化します。

これをセーブするときに、 Animated GIF Options の Loop をチェックします。

OKを押し、名前を付けて保存します。

■課題１２
gimp を使ってインターレースGIFとアニメーションGIFを作成してみましょう。
がんばれば
http://www6.big.or.jp/~monga/
をつくれます。