roy > naoya > 基礎プログラミングII > (9)CGI[1]

(9) 12/07の授業内容:CGI[1]

[1]CGIとは

インターネット上の掲示板では、入力エリアにデータを入力し「OK」を押すと、実際に書き込みが行われる。このようにHTML文書内にデータ入力エリアを配置し、入力後にボタンを押すとあらかじめ定められた処理を行い、結果が表示されるような仕掛けがある。このような仕組みをCGI(Common Gateway Interface)という。

CGIのデータ入力窓の集合を入力フォームという。 以下の入力フォームに値を入力、あるいは選択し「OK」ボタンを押してみよう。

氏名:
身長: cm  体重: kg

上のフォームで入力もしくは選択された値はCGI変数という特別な変数で、入力結果を処理するプログラムであるCGIスクリプトに送られる。このCGIスクリプトは一般にRubyもしくはPerlという言語で書かれており、何らかの処理を行った結果を、HTML文書として出力する。これを概念的に示すと以下のようになる。

氏名:[公益太郎]
身長:[1][7][0]cm
体重:[0][6][5]kg
[OK][reset]

Ruby(Perl)プログラムが値を受け取り、何らかの処理を実行すると同時に、結果出力用のHTML文書を生成する。

<html>
<head>
<title>結果!</head>
</head>
<body>
<p>うんたら</p>
</body>
</html>

[2]CGIの作り方

CGIは以下の3つのファイルにより構成される。

CGIを構成する3つのファイル

  1. Webサーバーに対して「ここでCGIプログラムを利用する」という宣言を記述したファイル
  2. 利用者がデータを入力するためのHTML文書
  3. 入力したデータを受け取って処理をするプログラム

[3]CGIプログラムの利用宣言

CGIを構成するファイルのうち「入力したデータを受け取って処理をするプログラム」がRubyのプログラムに相当する。

通常は、Rubyプログラムは自分で作成したruby/などのディレクトリに保存していたが、Web上でプログラムを実行させるためには、putlic_htmlの中にプログラムのファイルを置く。htmlファイルと同様に、ブラウザから閲覧させたいファイルは全てpublic_htmlのディレクトリ内に置いておかなければならない。

ここでは、CGIを利用するためのディレクトリをpublic_htmlの中に新たに作成し、CGI関連のファイルは全てその中に保存しておくことにする。

仮に、作成するディレクトリがcgi-binである場合、まず

pan{c10xxxx}% cd public_html[Return]
pan{c10xxxx}% mkdir cgi-bin[Return]

というように、mkdirコマンドでcgi-binというディレクトリを作成する。

次に、「このディレクトリ内でCGIを利用する」という宣言を行う。具体的にはcgi-binのディレクトリ内に.htaccessという名前のファイルを作成する(先頭のドットを忘れない!)。

このファイルを作成するためには、emacsでFile:~/public_html/cgi-bin/.htaccess[Return]とすればよい。ファイルを新規作成したら、以下の内容を記述して保存する。

AddHandler cgi-script   .rb
Options  +ExecCGI

これにより、以後このディレクトリに作成する.rbの拡張子を持つファイルは、全てCGIスクリプトと認識される

CGIプログラムの利用宣言

  1. CGI関連ファイルはpublic_htmlの中に専用のディレクトリを作成し、その中に一括で置いておく(授業ではcgi-binとする)。
  2. ディレクトリを作成するためのコマンドはmkdir
  3. cgi-binの中に.htaccessという名称のファイルを置く(ファイル内の記載内容は上を参照)。

[4]データ入力用HTML文書の構成

HTML言語を使用したWebページの記述方法については、1年生の情報リテラシーIIで実施済みであるが、入力フォームの作成は多少複雑である。ここでは入力フォームの作り方について確認する。HTML自体に不安がある場合は情報リテラシーIIのページを確認しよう。

冒頭で示した入力フォームとそのソースを見てみよう(form.html)。

氏名:
身長: cm  体重: kg

<html>
<head><title>購入ページ</title></head>
<body>
<form method="POST" action="./bmi.rb">
<p class="item">氏名:
<input type="text" name="name" maxlength="40"><br>
身長:
<select name="height1">
  <option> 1</option>
  <option> 2</option>
 </select>
<select name="height2">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>
<select name="height3">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>cm  
 体重:<select name="weight1">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
 </select>
<select name="weight2">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>
<select name="weight3">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>kg<br>

<input name="ok" type="submit" value="OK">
<input name="ng" type="reset" value="reset">
</p>
</form>
</body>
</html>

ソースを見ると、入力フォームは、form要素(<form>タグ)を使って書かれていることがわかる。form要素の基本構造は

<form method="メソッド" action="./スクリプト">


</form>

となる。メソッドの部分はGETまたはPOSTのどちらかを指定する。GETは最大で255文字までしか送ることができない(今回は名前や数字があるが、これらを全て含めて255文字)。項目数が多い場合や長い文章を入力させる場合はPOSTを指定する。ここではPOSTを使うものとして説明を続ける。

スクリプトの部分は入力データの引渡し先である。このソースを見ると、./bmi.rbとなっており(./は同一ディレクトリをあらわすので)、cgi-binディレクトリの中にあるbmi.rbがデータを受け取って処理をしていることがわかる。

このformの例では、

  • nameという名前の最大40文字の文字列
  • height1という名前で1、2のいずれか
  • height2という名前で0〜9のいずれか
  • height3という名前で0〜9のいずれか
  • weight1という名前で0、1、2、3のいずれか
  • weight2という名前で0〜9のいずれか
  • weight3という名前で0〜9のいずれか

をそれぞれ受け取り、bmi.rbに引き渡していることがわかる。入力フォームに用いる部品の詳細については次週とりあげる。

データ入力用のHTML文書

  • 入力フォームはform要素で記述する。form要素にはmethod属性とaction属性を指定する。
  • 1行のテキスト入力フィールドはinput要素を用いる。
  • プルダウンメニューはselect要素を用い、メニュー項目はoption要素を用いて記述する。

[5]CGIスクリプト(Rubyプログラム)の構成

CGIスクリプトとなるRubyプログラムでは、冒頭で必ず以下を記述する。

#!/usr/bin/env ruby

require 'cgi'
c = CGI.new("html4")
print "Content-type: text/html; charset=EUC-JP\n\n"

1行目は必ず記述するおまじないであるが、CGIスクリプトを書く場合は通常とは異なるので注意しよう。

c = CGI.new("html4")で、HTMLの入力フォームから引き渡された値が、ハッシュ変数cに代入される。変数cはどんな名前にしても構わない。

cにハッシュ値として代入されていることから、各入力値は、HTMLが引き渡す際に設定したnameやheight1をkeyとするvalueという形で指定することで取り出すことが可能となる。

例えば

var1 = c["height1"]

とすれば、keyのheight1に対応するvalueがvar1に代入される。

以下は、上記の入力フォームに入力後、HTMLが引き渡すRubyプログラム(bmi.rb)である。

注意

  • このRubyプログラムは、~/public_html/cgi-bin/の中に保存すること。
  • 保存後に、このページにアクセスした人が誰でもCGIスクリプトを実行できるようにするため、ktermで以下を入力してファイルに実行属性を与える。
  • pan{c10xxxx]% chmod 755 bmi.rb[Return]もしくは
  • pan{c10xxxx]% chmod +x bmi.rb[Return]
#!/usr/bin/env ruby

require 'cgi'
c = CGI.new("html4")
print "Content-type: text/html; charset=EUC-JP\n\n"

name = c["name"]
var1 = c["height1"]
var2 = c["height2"]
var3 = c["height3"]
var4 = c["weight1"]
var5 = c["weight2"]
var6 = c["weight3"]

height = (100 * var1.to_f + 10 * var2.to_f + var3.to_f) / 100
weight = (100 * var4.to_f + 10 * var5.to_f + var6.to_f)

bmi = weight / (height ** 2)


print"<html>
<head><title>BMI値</title></head>
<body>\n"

print"<h1>#{name}さんのBMI値</h1>\n"

print"<p>身長:#{height}m</p>\n"
print"<p>体重:#{weight}kg</p>\n"
printf("<p>BMI:%3.1f (理想は女性:21.5、男性:22)</p>\n",bmi)
printf("<p>理想体重は%4.1fkgです(男性の場合)。</p>\n",height ** 2 * 22)
printf("<p>理想体重は%4.1fkgです(女性の場合)。</p>\n",height ** 2 * 21.5)
print"</body>\n"
print"</html>\n"

このプログラムの上部では、HTMLより送られた値をnamevar1var2var3var4var5var6に代入し、heightweightbmiを計算している。

下部では、結果をHTML形式で出力するために<html>や<body>、<p>などのタグをprintやprintfを使って記述している。プログラムの下部には#{・・・}という記法があるが、{}内には計算式や変数を指定することができる。例えば、

print"10+20は#{10+20}です\n"

とすると{}内の10+20の計算が行なわれ、

10+20は30です

と表示される。また、

x=30
print"10+20は#{x}です\n"

とすると、xに代入された値である30が入れ込まれ、

10+20は30です

と表示される。これらは、いずれもprintfで書き直すことができる。すなわち、

x=30
print"10+20は#{x}です\n"

x=30
printf("10+20は%dです\n",x)

の出力結果は同一となる。

[6]CGIのまとめ

CGIを作成するためには幾つかのルールがあった。この点についてまとめよう。

  1. public_htmlの中にcgi専用のディレクトリ(例えばcgi-bin)を作る。以下で作成する3つのファイルはいずれもこのディレクトリに保存する。
  2. このディレクトリでcgiを利用するという宣言を記述した.htaccessを作成する。
  3. ユーザがデータを入力するためのHTML文書(xxx.html)を作成する。
  4. 入力したデータを受け取って処理をして結果出力用のHTML文書を生成するCGIスクリプト(xxx.rb)を作成する。
  5. Rubyで書かれたCGIスクリプトを自分以外の人でも実行できるように、アクセス権を与える。

CGI専用ディレクトリの作成

CGIを利用するためのディレクトリcgi-binをpublic_htmlの中に新たに作成する。このためにpublic_htmlディレクトリにcdコマンドで移動してから、ディレクトリ新規作成コマンドのmkdirを使用する。

pan{c10xxxx}% cd public_html[Return]
pan{c10xxxx}%  mkdir cgi-bin[Return]

.htaccessの作成

.htaccessの記述内容は以下の通り。emacsで作成する際に、File:~/public_html/cgi-bin/.htaccessとする。以下の2行を記述して保存する。

AddHandler cgi-script   .rb
Options  +ExecCGI

入力フォームのHTMLファイルの作成

emacsで~/public_html/cgi-bin/の中にform.htmlを新規作成し、以下をコピーして貼り付け保存(字が小さいが上で示したものと同じ)。

<html>
<head><title>購入ページ</title></head>
<body>
<form method="POST" action="./bmi.rb">
<p class="item">氏名:
<input type="text" name="name" maxlength="40"><br>
身長:
<select name="height1">
  <option> 1</option>
  <option> 2</option>
 </select>
<select name="height2">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>
<select name="height3">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>cm  
 体重:<select name="weight1">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
 </select>
<select name="weight2">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>
<select name="weight3">
  <option> 0</option>
  <option> 1</option>
  <option> 2</option>
  <option> 3</option>
  <option> 4</option>
  <option> 5</option>
  <option> 6</option>
  <option> 7</option>
  <option> 8</option>
  <option> 9</option>
 </select>kg<br>

<input name="ok" type="submit" value="OK">
<input name="ng" type="reset" value="reset">
</p>
</form>
</body>
</html>

CGIスクリプト(Rubyプログラム)の作成

以下はCGIスクリプトの例である。bmi.rbという名前をつけて保存する。cgi-binの中に保存するため、emacsで新規作成する場合、File:~/public_html/cgi-bin/kakaku.rbとする(字が小さいが上で示したものと同じ)。

#!/usr/bin/env ruby

require 'cgi'
c = CGI.new("html4")
print "Content-type: text/html; charset=EUC-JP\n\n"

name = c["name"]
var1 = c["height1"]
var2 = c["height2"]
var3 = c["height3"]
var4 = c["weight1"]
var5 = c["weight2"]
var6 = c["weight3"]

height = (100 * var1.to_f + 10 * var2.to_f + var3.to_f) / 100
weight = (100 * var4.to_f + 10 * var5.to_f + var6.to_f)

bmi = weight / (height ** 2)


print"<html>
<head><title>BMI値</title></head>
<body>\n"

print"<h1>#{name}さんのBMI値</h1>\n"

print"<p>身長:#{height}m</p>\n"
print"<p>体重:#{weight}kg</p>\n"
printf("<p>BMI:%3.1f (理想は女性:21.5、男性:22)</p>\n",bmi)
printf("<p>理想体重は%4.1fkgです(男性の場合)。</p>\n",height ** 2 * 22)
printf("<p>理想体重は%4.1fkgです(女性の場合)。</p>\n",height ** 2 * 21.5)
print"</body>\n"
print"</html>\n"

CGIスクリプト(Rubyプログラム)への実行属性の付与

保存後には、CGIスクリプトとして実行できるようにするため、ktermで以下を入力する。
pan{c10xxxx]% chmod 755 bmi.rb[Return]もしくは
pan{c10xxxx]% chmod +x bmi.rb[Return]

これら全ての手順を抜け落ちなく実施すると

http://roy.e.koeki-u.ac.jp/~c10xxxx/cgi-bin/form.html

で入力フォームが表示され、適宜入力してOKを押すと何らかの結果が出るはずである。

[7]CGI実行時のエラーメッセージ

表示されるエラーメッセージの内容によって、エラー内容を概ね特定することができる。

ブラウザに入力フォームのURLを入力するとNot Foundと表示される。

  1. URLが間違っている。URLはhttp://roy.e.koeki-u.ac.jp/~c10xxxx/cgi-bin/yyyy.htmlとなる。xxxxは自分の学籍番号(チェックディジットなし)、yyyは作成した入力フォームのファイル名となる。
  2. form.htmlの保存場所が間違っている。ktermでcgi-binのディレクトリに移動し、lsを入力して作成したファイルがあるかどうか確認する。違う場所に保存した場合は、ktermでmvコマンドを使用して移動する。mvコマンドについては、UNIX主要コマンドのページを参照のこと。

入力フォームに入力しOKを押すとPermission Deniedと表示される。

  1. .htaccessファイルを作成していないか、作成したが保存できていないか、保存した場所が違う。
  2. CGIスクリプト(Rubyプログラム)に実行属性を付与していない。

入力フォームに入力しOKを押すとInternal Server Errorと表示される。

CGIスクリプト(Rubyプログラム)の書き間違え。具体的には、変数名の入力間違いの可能性が高い。

入力フォームに入力しOKを押すと真っ白な画面になる。

CGIスクリプト(Rubyプログラム)の書き間違え。具体的には、変数名の入力間違いの可能性が高い。

[8]出席課題

自分でCGIを設置して動作を確認する。

うまく実行できたら、入力フォームのURL(http://roy.e.koeki-u.ac.jp/~学籍番号/cgi-bin/form.html)と、次週以降に、CGIで作成してみたいページについて報告する。

出席点は2点。提出要領は下記の通り。

  • 提出先:課題提出用メールアドレス
  • メールのSubject:attend09
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目にURLを記載し、その他感想等を記載する。

Tips:emacsでの日本語入力のオンオフはCtrl+oです

Tips:Mewによるメールの送り方はMewコマンドを参照

[9]プログラムの公開

CGIはWebページ上で動くプログラムであるため、1)HTMLに関する知識、2)Web上にプログラムを公開する上でのルールについて理解を深めておくと良い。HTMLについては、情報リテラシーの授業で実施しているが、自信がない場合は以下のページを確認しておこう。

ここでは、プログラムを公開する上での配慮や工夫について述べる。

プログラム公開用のディレクトリ作成

作成したプログラムはRubyディレクトリに保存されており、このままでは公開できない。公開するためには、公開用ディレクトリであるpublic_htmlにファイルをコピー(移動)する必要がある。ただし、public_htmlの中に様々なファイルを保存していくと、数が多くなったときに整理がつかなくなる。そこで、プログラム公開用の専用ディレクトリをpubli_html内に作成しよう。ディレクトリ作成コマンドはmkdirであり、仮にprogramというディレクトリを作成する場合はktermで次のように入力する。

pan{c10xxxx}% mkdir ~/public_html/program[Return]

プログラムのコピー

Rubyディレクトリ内にあるプログラムをpublic_html内のprogramディレクトリにコピー(移動)するためには、ktermでcp(mv)コマンドを使用する。

pan{c10xxxx}% cp ~/Ruby/プログラム.rb  ~/public_html/program[Return]

プログラムのハイパーリンクと紹介

単にプログラムをコピーしても公開したことにはならない。Webページからリンクをしてダウンロードできるようにする必要があるし、プログラムの概要や操作方法などを示す必要もある。

また、プログラムそのものの使い勝手のみでなく、Webページの見栄えもプログラムを実行したいと思うかどうかに影響する。

まず、programディレクトリ内にindex.htmlを作成する。このファイルから以下に対してハイパーリンクを設置する。

  • テキスト版解説書(readme.txt)
  • プログラム(プログラム.rb)

テキスト版解説書

テキスト版解説書では、ユーザが最初に使うときにすぐに知りたいと思う情報を記す。たとえば、

  • プログラムの概要(何のプログラムか)
  • 実行方法
  • 操作方法

を簡潔に記述する。また、最後には必ず著作権について表記する。ファイル名は、readme.txtのようにすぐに分かるような名称にしておく。

readme.txt

// Five Seconds!! //

Copyright 2009 by チームにゃんこ

Five Seconds!!とは
------------------

    Five Seconds!!は、ルビー星人の魔の手から逃れるために
    立ち上がったあなたが、スーパーコンピュータpanとroyに
    保存されたインタプリタを破壊する新感覚エキサイティン
    グプログラムだ。要するに5秒あてゲームだ!
    
    
実   行   方   法
------------------

    このゲームのプログラムはfive.rbだ。このファイルを好き
    なディレクトリに保存して下さい。そうしたら、ktermで保
    存したディレクトリに移動し

    % ruby five.rb
	
    で、実行できます。


操   作   方   法
------------------

    プログラムを起動するとこんなメッセージが出てきます。

    1回目の挑戦だ
    準備が出来たらReturnキーを押すんだ
    最初のキーを押してからちょうど5秒後に
    rm[Return]で削除するんだ。
    最初のReturnの後でrmと打っておくと良いぞ!

    ここにあるように、[Return]の後でちょうど5秒後にrm[Ret
    urn]と入力しよう。挑戦できるのは5回です。人類の平和は
    あなたの手にかかっています!
	

Copyright 2009
------------------

    このプログラムは 東北公益文科大学2009年度生チームにゃ
    んこが著作権を保有しています。このプログラムの入手・
    実行・改変・再配布は、いずれも無料で自由に行なうことが
    できます。ただしこのプログラムを取り扱うことで生じたい
    かなる結果に対しても著作権者は責任を負いません。
    このプログラムに対するする、感想・助言・要望・愚痴・説
    教など大歓迎致します。
    ruby-hoge@e.koeki-u.ac.jp
    までメッセージをお送り下さい。

HTML版解説書

HTML版解説書では、テキスト版解説書と同様に

  • プログラムの概要(何のプログラムか)
  • 実行方法
  • 操作方法

を記述する。さらに、ロゴをつけたり、背景色や文字色を工夫して、読んでみたい、実行してみたいと感じるようにする。

HTML版解説書

[10]レポート課題

以下について実施しなさい。

  • 情報リテラシーIIの授業で作成をしたindex.htmlを更新し、現在の情報に書き換えなさい(URLはhttp://roy.e.koeki-u.ac.jp/~学籍番号/index.html)
  • これまでに作成したプログラムの中から1つを選び、Webページで公開しなさい。作成要領は以下の通り
    • public_html内にrubyディレクトリを作成。以下のファイルは全てrubyディレクトリに公開
    • index.htmlを作成し、HTML版解説書と同じように遊び方や著作権について記載。あわせて以下の2つのファイルにハイパーリンクを設置。
      • readme.txt
      • プログラム本体
  • http://roy.e.koeki-u.ac.jp/~学籍番号/index.html から http://roy.e.koeki-u.ac.jp/~学籍番号/ruby/index.html にハイパーリンクを設置する

  • 提出先:課題提出用メールアドレス
  • 提出期限:12/13(日)23:00
  • メールのSubject:課題6
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
    1. ホームページのURL(http://roy.e.koeki-u.ac.jp/~学籍番号/index.html)
    2. 感想

  • 採点基準(問題1):期限内提出点(2点)、メールの体裁(1点)、CSS・デザイン(2点)、htmlの構文(2点)、記載情報の過不足(1点)
  • 今回は、全員分を記名で公開します。他の人がどのようなページを作ったのか、お互いに確認してみよう。

Tips:emacsでの日本語入力のオンオフはCtrl+oです

Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする

Tips:Mewによるメールの送り方はMewコマンドを参照