HTML文書内にあるデータ入力窓とそれらを受け渡すスクリプト 名を書いておき、ボタンを押すとそのスクリプトに入力値が 渡るようなしくみをCGI(Common Gateway Interface)という。
CGIのデータ入力窓の集合を入力フォームという。 以下の入力フォームに値を入力、あるいは選択し「OK」ボタンを押してみよう。
上の入力窓に入れられた値は全て入力名という特別な 変数でCGIスクリプトに送られる。 自分で作るプログラムではその変数を受け取りそれに応じた処理をした上で、 結果を表すHTML文書を出力する。
|
→ |
|
→ |
|
CGIは、利用者にデータを入力してもらうためのHTML文書と そこから送られて来るデータを受け取って処理をするプログラムファイルを 作る。さらに、Webサーバに対して「ここでCGIプログラムを利用する」ことの 宣言を行なう必要がある。
.htaccess
ファイルの作成順を追って行なう。なお、 慣れたあとは2と3をまとめて1つの Ruby プログラムで行うほうが楽であるが、 HTMLとCGI実行プログラムは分けたほうが理解しやすいので 以下の説明は分ける方法で記述する。
「この場所でCGIを利用する」ためのディレクトリを作成し、そこに
.htaccess
という名前のファイルを作成する。ここではたとえば、
~/public_html/mycgi
というディレクトリを作成し、
そこでCGI利用宣言をするものとする。まず
cd ~/public_html mkdir mycgi
としてディレクトリを作成する。次にEmacsで
~/public_html/mycgi/.htaccess
ファイルを新規に開き、
以下の内容を記述して保存する(コピーペーストしてよい)。
AddHandler cgi-script .rb Options +ExecCGI AddType "text/html; charset=utf-8" .html
1行目と2行目により、このディレクトリに作成する .rb
という名前で
終わるファイルはCGIスクリプトと認識される。3行目の記述により、
HTMLファイルの文字コードが UTF-8 であることを宣言する。
RubyプログラムをUTF-8で作成するので、HTMLファイルもそれに合わせる。
次は入力フォームを構成するHTML文書を作る。入力フォームは form要素を使って記述する。form要素は
<form method="メソッド" action="./スクリプト"> 〜〜〜 </form>
のように記述する。メソッドの部分は GET
または
POST
のどちらかを指定する。文章など、長いデータを入力させた
いときはPOST
を指定する。
以下のform要素例は
入力させ、./btype.rb
というスクリプトに
入力値を渡すためのHTML記述である(該当部分抜粋)。
<form method="POST" action="./btype.rb"> <p>お名前: <input name="namae" type="text" maxlength="40"><br> 血液型: <select name="blood"> <option>A</option> <option>AB</option> <option>B</option> <option>O</option> </select><br> <input type="submit" value="OK"> <input type="reset" value="reset"><br></p> </form>
上記の入力フォームのみを含むHTML文書の例を
btype.html
に示す(ソース)。
次節で、./btype.rb
の作り方を示す。
CGIスクリプトとなるRubyプログラムでは、最低限以下の内容を記述して 作成する。
#!/usr/bin/env ruby
# coding: utf-8
require 'cgi'
c = CGI.new(:accept_charset => "UTF-8")
print "Content-type: text/html; charset=UTF-8\n\n"
変数c
はどんな名前でもよい。このあとに、HTML文書となり得
る文字列を順次出力していく。
require
は、プログラムに必要な
外部モジュールを現在のプログラムに取り込む記法で、
require 'cgi'
はCGIプログラムを組むのに便利なクラスが定義された cgi.rb
を取り込む宣言である。これで以下のようにCGIクラスが
使えるようになる(CGI.new
の部分)。
CGIプログラムに渡された入力値を取り出すには、CGI.new
を受け取った変数のハッシュ値として取り出す。以下の例はform入力された
パラメータ namae
と blood
を単にHTML文書形式で
出力するRubyプログラムである。
#!/usr/bin/env ruby
# coding: utf-8
require 'cgi'
c = CGI.new(:accept_charset => "UTF-8")
print "Content-type: text/html; charset=UTF-8\n\n"
name = c["namae"] # フォームに記入されたnamaeの値を取り出す
bt = c["blood"] # フォームに記入されたbloodの値を取り出す
# 「<<EOF」とすると、次に見つかる「EOF」まですべてを文字列として処理する
# これを「ヒアドキュメント」という
print <<EOF
<!DOCTYPE html>
<html>
<head><title>Blood type</title></head>
<body>
<h1>#{name}さんの血液型</h1>
<p>#{name}さんは#{bt.upcase}型ですね!</p>
</body>
</html>
EOF
# ↑このEOFまでがすべて文字列として処理される。CGI等で便利。
プログラム中現れる <<
はヒアドキュメント
といい、その次の行から、
<<
の直後に書かれた単語が見つかる行までをまとめて
1つの文字列として括る記号である。改行文字を含む長文文字列を
扱いたいときに便利な記法であり、文字列中にダブルクォートやシングルクォー
トを自由に入れることもできるため、ダブルクォートを多用することの多い
HTML 文の出力には有用である。
さらにこの文字列中で利用している
#{...}
という記法はその部分をRubyの式としてその値に
置き換える働きを持つ。たとえば、
print "1+2は#{1+2}です\n"
とすると、
1+2は3です
と出力される。HTML出力文に変数結果を入れたい場合に #{...} は有用である。
このCGIを動かす例が以下の入力フォームである。
少し進んで、入力した値により出力を切り替える例を作成してみよう。 入力されうる値をキーとして、対応する文字列をハッシュで登録しておき、 メッセージ出力部分をハッシュの値を引くことによって切り替える。
#!/usr/bin/env ruby # coding: utf-8 require 'cgi' c = CGI.new(:accept_charset => "UTF-8") print "Content-type: text/html; charset=UTF-8\n\n" name = c["namae"] bt = c["blood"] kekka = { # A, B, AB, O に対応する値をHashで設定する "A" => "えーっすなあ", "AB" => "だぶる!", "B" => "びびっとね", "O" => "おーすげー", } kekka.default = "人間なの??" # Hashのデフォルト値(キーがない場合の値) bt.upcase! # 念のため大文字に変えておく # ここ↓の <<EOF の部分が次の行からEOF行手前までの文字列に置き換わる printf(<<EOF, bt, kekka[bt]) # 8行下の%sに入る <!DOCTYPE html> <html> <head><title>Blood type</title></head> <body> <h1>#{name}さんの判定結果</h1> <p>%s型のあなたは%s</p> </body> </html> EOF
プログラム作成作業を進めるに当たって、ここの手順を取らないと非常に苦労する。
簡単なRubyプログラムでも、CGIとして動かすには困難がともなう。 なぜなら、プログラムを起動して出てくるエラーメッセージなどが見えないから である。文法エラーなどもWebブラウザ経由では見ることができない。
Web上で動かすプログラムは以下の手順で段階的に作成・デバッグする。
cgi.rb
モジュールを利用したプログラムはCGI経由だけでなく、
ターミナル上でもデバッグできる。上記の
btype.rb
の場合は、HTMLからプログラムに渡す入力名として namae, blood
を利用している。nameに「太郎」を、bloodに「A」を代入した状態で
デバッグする場合以下のように起動する。
echo 'name=太郎&blood=A' | ./btype.rb
つまり、入力名の値を
'入力名1=値1&入力名2=値2&入力名3=値3&...'
の形式でechoコマンドで出力し、実行プログラムに送り込めばよい。 まとめると、以下のようなプログラム起動で確認する。
echo '入力名1=値1&入力名2=値2&入力名3=値3' | ./作成中のプログラム.rb
正しい(と思われる)HTML文が出力されたらローカルPCのWebサーバでテストする 2の手順に進む(手順3に先に進んで詰まったら次の2に戻るのでもよい)。
本来Webサーバは専用サーバで動かすものだが、Rubyには簡易Webサーバ 機能があり手軽に動かすことができる。
保存したwebserv.rb
を起動すると以下のようなメッセージが出る:
chmod +x webserv.rb ./webserv.rb http://localhost:1234/ファイル名 で接続してください
「ファイル名」の部分を作成中のCGIファイルにしてブラウザで開く。
たとえばbtype.html
を作成中の場合はブラウザで
http://localhost:1234/btype.html
を開く(1234は人によって違う)。もしエラーが出ると、webserv.rb
を起動したターミナルにエラーメッセージが出るので自分の作ったプログラムに
出された部分を選んで確認し、修正する。
以上のような起動方法で、正しくHTML文書が出力されたら正式Webサーバの URLで開く。
たとえば以下のようなURLである。
http://roy.e.koeki-u.ac.jp/~cユーザ名/mycgi/ファイル名
ブラウザ経由でアクセスしてエラーになる場合は、Webサーバ(roy)に
ログインし
/usr/local/apache2/logs/error_log
ファイルの
最後の方をtail -f
で参照する。
ssh roy # ←ログインパスワードを入れる tail -f /usr/local/apache2/logs/error_log : ↑動きっぱなしになるので C-c で止める↑
としておくと、アクセスするのと同時にエラーが出力される。 デバッグが終わったら tail を C-c で止め、 最後に roy からログアウトするのを忘れないこと。
HTML文書の form 要素内で、 ユーザからの入力を促すための主な要素を実例とともに示す。
以下の説明脇にある入力フォームに実際の値を入れて [送信] ボタンを押すと、この例にある入力名がどのように渡るかの結果が示される。 実際に、いろいろな値を入れて試してみること。
フォーム制御の詳細は HTMl Standard 4.10 フォーム が参考になる。
次のRubyプログラムはinput要素に値を入力してOKを押すと、 次の画面に進む、を繰り返すものである。
cgiloop.rb
(これと同時に cgiloop.css
も保存する)
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'cgi' c = CGI.new input = c["name"] myname = File.basename($0) # $0はプログラムのフルパス名、File.basename($0)するとファイル名部分のみ取り出す print <<~EOF Content-type: text/html; charset=utf-8 <!DOCTYPE html> <head><title>CGIループ</title> <link rel="stylesheet" type="text/css" href="cgiloop.css"> </head> <body> <h1>CGIループだよ</h1> EOF if !input.empty? then printf("<p class=\"shout\">%sさんの明日にいいことがありますように!</p>\n", input) end print <<~EOF <form action="#{myname}" method="POST"> <p>お名前をどうぞ:</p> <p><input type="text" name="name"> <input type="submit" value="OK"> <input type="reset" value="Reset"> </form> </body></html> EOF
このプログラムを ~/public_html/mycgi/
(またはcgi-scriptが有効になっているディレクトリ)に保存して
chmod +x cgiloop.rb
し、ブラウザでURLアクセスして
挙動を確かめよ。
input 要素の type="text" で名前を入力させる部分を type="checkbox" に変えて何かを入力させるものを作成し挙動を確認せよ。
同様に type="radio" に変えたものを作成し挙動を確認せよ。
select要素で複数の選択肢から1つを選ぶように変えたものを作成し挙動を確認せよ。
select要素で複数の選択肢から複数を選べるように変えたものを作成し挙動を確認せよ。