roy > naoya > 基礎プログラミングII > (8)CGI[2]
(8) CGI[2]
[1]入力フォームの構成部品について
入力フォームを作成する場合、まずform要素を使用する。<form></form>の間にラジオボタンや入力フィールドを配置し、<form>内に指定した方法でCGIスクリプトに引き渡す。
form要素については既に説明済みであるが、念のため再掲する。
<form method="メソッド" action="./スクリプト"> </form>
となる。メソッドの部分はGETまたはPOSTのどちらかを指定する。GETは最大で255文字までしか送ることができない。項目数が多い場合や長い文章を入力させる場合はPOSTを指定する。ここではPOSTを使うものとして説明を続ける。
スクリプトの部分は入力データの引渡し先である。このソースを見ると、./kakaku.rbとなっており(./は同一ディレクトリをあらわすので)、cgi-binディレクトリの中にあるkakaku.rbがデータを受け取って処理をしていることがわかる。
<form></form>の間に配置するフォームの構成部品について、まずは外観を示し、その後説明を加える。
1行のテキスト入力フィールド:
チェックボックス(複数選択可):
ラジオボタン(ひとつのみ選択可):
プルダウンメニュー:
送信ボタン:
リセットボタン:
これらの構成部品はinput要素、textarea要素、select要素を用いて作成することができる。textarea要素は複数行のテキスト入力フィールドの作成に用い、select要素はプルダウンメニューの作成に用いる。それ以外の部品は全てinput要素で作成し、type属性で区別する。
部品名 |
要素名 |
type属性 |
---|---|---|
1行のテキスト入力フィールド |
input |
text |
チェックボックス |
input |
checkbox |
ラジオボタン |
input |
radio |
複数行のテキスト入力フィールド |
textarea |
不要 |
プルダウンメニュー |
select |
不要(選択肢はoption属性を使用) |
送信ボタン |
input |
submit |
リセットボタン |
input |
reset |
[2]1行のテキスト入力フィールド
input要素を利用し、type属性としてtextを指定する。
<input type="text" name="namae" size="40" maxlength="40">
- <input>に対する</input>は不要。
- name属性はCGIスクリプトに引き渡す際のkeyとして使用するため、必ず指定しなければならない。入力した値がkey(ここではnamae)に対応するvalueとなる。
- size属性は左右の幅であり文字数で指定する。
- maxlength属性は入力できる最大文字数であり、これも文字数で指定する。
- size属性とmaxlength属性はなくても良い。
maxlength属性を5とすると入力できる文字数が最大5文字となる。
size属性を5とすると入力フィールドの幅が狭くなる。
[3]チェックボックス(複数選択可)
input要素を利用し、type属性としてcheckboxを指定する。
<input type="checkbox" name="cbx" value="1">チキンカレー
チキンカレー
- <input>に対する</input>は不要。
- name属性はCGIスクリプトに引き渡す際のkey、value属性はvalueとして使用するため、必ず指定しなければならない。
- 通常は、チェックボックスは単独では使用せず、複数の項目から該当するものを全て選択するような場合に用いることが多い。このため、複数のチェックボックスのname属性は全て異なる名称にする。チェックをつけた項目のvalueがプログラムに引き渡される(チェックされていない項目のvalueをプログラム内で取り出すとnilになる)。
- checked属性を追加し、checked="checked"と書くことで、その項目を最初から選ばれた状態にすることができる。
3つ目のチェックボックスのみchecked="checked"を追加
チキンカレー
シーフードカレー
野菜カレー
[4]ラジオボタン(ひとつのみ選択可能)
input要素を利用し、type属性としてradioを指定する。
<input type="radio" name="rd" value="20代">20代
20代
- <input>に対する</input>は不要。
- name属性はCGIスクリプトに引き渡す際のkey、value属性はvalueとして使用するため、必ず指定しなければならない。
- ラジオボタンは単独では使用せず、複数の項目から1つを選択する際に用いることが多い。name属性は全て同一にする。
- name属性を同一にしない場合、複数項目が選択できてしまう。
- checked属性を追加し、checked="checked"と書くことで、その項目を最初から選ばれた状態にすることができる。
3つ目のチェックボックスのみchecked="checked"を追加
20代
30代
40代
左側はname属性をいずれもageとした場合(1つしか選択できない)。右側はname属性を順番にage1、age2、age3とした場合(3つとも選択できてしまう)。
20代
30代
40代
20代
30代
40代
[5]複数行のテキスト入力フィールド
textarea要素を利用する。type属性は不要。
<textarea rows="3" cols="30" name="youbou"></textarea>
- <textarea>に対する</textarea>が必要。
- name属性はCGIスクリプトに引き渡す際のkeyとして使用するため、必ず指定しなければならない。入力した値がkeyに対応するvalueとなる。
- rows属性で行数、cols属性では幅を1行当たりの文字数で指定する。
- <textarea></textarea>間にテキストを挿入すると、フィールド内にその文字が表示される。
rowsを2、colsを10にした場合
<textarea></textarea>間に「感想をお願いします」と入れた場合
[6]プルダウンメニュー
select要素を利用する。各選択肢にはoption要素を利用する。type属性は不要。
<select name="age">
<option>10代</option>
<option>20代</option>
<option>30代</option>
<option>40代</option>
<option>50代</option>
</select>
- <select>に対する</select>が必要。
- <select></select>間にoption要素を用いて選択肢を記述する。
- name属性はCGIスクリプトに引き渡す際のkeyとして使用するため、必ず指定しなければならない。opetion要素の中でユーザが実際に選択した値がkeyに対応するvalueとなる。
- select要素に対してsize属性で行数を指定すると、プルダウンメニューではなく、リストボックスとして表示される。
select要素にsize属性で、size="3"と指定した場合
[7]送信ボタン
input要素を利用し、type属性としてsubmitを指定する。
<input name="ok" type="submit" value="OK">
- <input>に対する</input>は不要。
- value属性はボタンに表示する名称となる。
- name属性は送信ボタンが単独の場合は不要。送信ボタンが複数ある場合、これがCGIスクリプトに引き渡す際のkeyとなる(単独の場合はこのボタンを押すとCGIスクリプトにデータが引き渡されるのみであるが、複数の送信ボタンがある場合は、データをCGIスクリプトに引き渡すことに加え、どの送信ボタンを押したかという情報が伝達される)。
value属性を「送信する」にした場合
[8]リセットボタン
input要素を利用し、type属性としてresetを指定する。
<input name="ng" type="reset" value="reset">
- <input>に対する</input>は不要。
- value属性はボタンに表示する名称となる。
- このボタンを押すと、form要素内に記述した(選択した)値がリセットされる。
- name属性は実質的には不要(つけても良いが意味がない)。
value属性を「やっぱりやめる」にした場合
[9]CGIスクリプトの応用(処理の切替)
先週は入力した値に基づいて計算を行い、結果を表示するCGIスクリプトについて見てきた。今週は一歩進んで、入力した値により出力を切り替える例を作成してみよう。つまりif文を用いて結果を切り替える。
今回はラジオボタン(これ→)やチェックボックス(これ→)が追加されている。上述の通りこれらのパーツはいずれもいずれもinput要素で作成できる。パーツの使い分けはtype属性で指定している。
- type="text":1行の入力フィールド
- type="radio":ラジオボタン
- type="checkbox":チェックボックス
- type="submit":送信ボタン
- type="reset":リセットボタン
この入力フォームは実際には以下のように書かれている(入力フォームの部分のみ)。
<html> <head><title>購入ページ</title></head> <body> <form method="POST" action="./shinri.rb"> <p class="item">氏名: <input type="text" name="name" maxlength="40"><br> 性別: <input type="radio" name="rd" value="男性">男性 <input type="radio" name="rd" value="女性">女性 <input type="radio" name="rd" value="不明">どちらでもない<br> 以下の各項目について当てはまるものに全てチェックをつけてください。<br> <input type="checkbox" name="box1" value="1"> いろいろ勉強して自分を深めたい<br> <input type="checkbox" name="box2" value="1"> 社会に出て成功したいと思う<br> <input type="checkbox" name="box3" value="1"> いつも何か目標を持っている<br> <input type="checkbox" name="box4" value="1"> 手がけたことは最善を尽くしたい<br> <input type="submit" name="ok" value="OK"> <input type="reset" name="ng" value="reset"> </p> </form> </body> </html>
shinri.htmlのform要素のaction属性を見ると、入力データをshinri.rbに引き渡していることが分かる。shinri.rbは入力データを受け取り、処理をして結果のHTML文書を出力するCGIスクリプトである。前回のkakaku.rbと同じく、変数cのハッシュ値として入力値を取り出しているが、if文が追加されているため若干構造が複雑になっている。このプログラムではチェックをした項目数に応じてif文でメッセージを変化させている。
#!/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" namae = c["name"] seibetsu = c["rd"] q1 = c["box1"] q2 = c["box2"] q3 = c["box3"] q4 = c["box4"] point = q1.to_i + q2.to_i + q3.to_i + q4.to_i print "<html> <head><title>診断結果</title></head> <body>\n" print "<h1>#{namae}さん(#{seibetsu})の診断結果</h1>\n" print "<p>あなたがチェックをした項目数は#{point}個です。</p>\n" print "<p>" if point == 4 print "やる気満々ですね。このまま頑張って!\n" elsif point == 3 print "結構頑張り屋さんですねえ。この調子で。\n" elsif point == 2 print "うーん。まあまあですかねえ\n" elsif point == 1 print "うーん。うーん。もうちょっとやる気見せましょう。\n" else print "やる気ないですね。\n" end print "</p>\n" print "</body>\n" print "</html>\n"
[10]出席課題
shinri.htmlでは4つのチェックボックスが設置されており、チェックした数に応じて異なるメッセージが表示されるようCGIスクリプトが書かれている。チェックボックスをあと2つ追加し(=htmlファイルを作成して内容を書き換え)、チェックした項目数に応じて異なるメッセージが表示されるように変更してみよう(=shinri.rbを改良する)。
うまく実行できたら、入力フォームURL(http://roy.e.koeki-u.ac.jp/~学籍番号/cgi-bin/◯◯.html)を報告する。
制限時間は授業中に指示する。出席点は2点。提出要領は下記の通り。
- 提出先:課題提出用メールアドレス
- メールのSubject:attend09
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目にURLを記載し、その他感想等を記載する。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:Mewによるメールの送り方はMewコマンドを参照
[11]CGIスクリプトでa要素やimg要素を使用する際の""の取り扱い
タグを記載する場合<a href="hoge.html">トップページ</a>や<img src="hoge.jpg">のように""を使用する場合がある。これらをCGIスクリプト(Rubyプログラム)の中で記載する場合
print"<a href="hoge.html">トップページ</a>\n"
というようにprint ""で周囲をくくる必要があるため、""の中に""が入り込むという状況になる。この場合どれがprintの"でどれがa要素の"なのかが不明確になり、うまく取り扱うことができない。そのためprint""の""以外で""を使用する場合は"の手前に\(バックスラッシュ)をつけて区別する。
""の取り扱い
<a>や<img>を使用する場合、内部で使用する"の手前には\をつける。
print"<a href=\"hoge.html\">トップページ</a>\n"
[12]ファイルのアクセス権について
CGIスクリプトとして働くRubyプログラムは、cgi-binディレ クトリに保存した上で、ktermより次のコマンドを入力しなければ正しく動かすことが出来なかった。
sime{c1xxxxx}% chmod 755 ◯◯.rb[Return] または sime{c1xxxxx}% chmod +x ◯◯.rb[Return]
chmodコマンドはファイルへのアクセス権を設定するコマンドである。では、その後の755は何を意味するのだろうか。これを理解するためには、まずアクセス権について理解する必要がある。
ファイルのアクセス権
ktermを使い、lsコマンドに引数-laをつけ、ディレクトリ内のファイル一覧を表示してみよう。どのディレクトリで行っても構わない。コマンドを入力すると、ファイル名以外に-rw-r--r--というような不思議な記号が表示されることが確認できる。
sime{c1xxxxx}% ls -la[Return] drwxr-xr-x 2 naoya st2005 512 9月 29日 19:10 ./ drwxr-xr-x 13 naoya st2005 1024 9月 29日 16:03 ../ -rw-r--r-- 1 naoya st2005 46 9月 24日 16:09 .htaccess -rw-r--r-- 1 naoya st2005 3743 9月 29日 19:10 10-access.htm -rw-r--r-- 1 naoya st2005 5934 2月 15日 2008年 10-css.htm -rw-r--r-- 1 naoya st2005 2319 2月 15日 2008年 10-image.htm -rw-r--r-- 1 naoya st2005 4828 9月 29日 19:06 10-open.htm -rw-r--r-- 1 naoya st2005 22966 9月 29日 18:42 10.htm -rw-r--r-- 1 naoya st2005 22501 9月 24日 16:19 9.htm -rwxr-xr-x 1 naoya st2005 807 9月 24日 16:45 kakaku.rb* -rw-rw-rw- 1 naoya st2005 144 9月 29日 19:06 open-cgi.dat -rwxr-xr-x 1 naoya st2005 887 9月 29日 19:01 open-cgi.rb*
これが各ファイルのアクセス権を示したものである。先頭は、「-」または「d」となっているが、これはファイルとディレクトリを区別するもので、「-」はファイル、「d」はディレクトリとなる。
先頭の1桁を除外すると、残りは9桁である。これは3桁×3つに分割することができる。最初の3桁は自分自身(u)のアクセス権、次の3桁は自分と同一グループのユーザー(g)のアクセス権、最後の3桁は他のユーザー(o)のアクセス権である。
u (User) | g (Group) | o (Other) | ||||||
---|---|---|---|---|---|---|---|---|
r | w | x |
r | w | x |
r | w | x |
ここで、rはReadの略であり読み込む権利を、wはWriteの略であり編修する権利を、xはeXecuteの略で実行する権利を表している。r、w、xと表示されている場合はその権利があり、-の場合はその権利がないという意味になる。
ファイルを作成した直後のアクセス権の設定は、rw-r--r--となっているが、これは次のような意味となる。
- 自分(u):r(読み込み)とw(編集)のみ可
- グループ(g):r(読み込み)のみ可
- 他人(o):r(読み込み)のみ可
CGIスクリプトとして使用するRubyプログラムは、自分だけでなく他人が使用する可能性があるため、gやoに実行する権利を与える必要があるし、CGIの中でopenメソッドを使ってファイルの読み書きをする場合は、gやoにファイルを読み込む権利や編修する権利を与える必要がある。
アクセス権の変更方法[1] ビットパターンによる指定
u, g, oそれぞれについて3種類の権利を設定することができる。許可する場合を1、許可しない場合を0とした場合、u, g, oそれぞれについて000, 001, 010, 011, 100, 101, 110, 111という8種類の組み合わせが想定できる。これを3桁の2進数と見なし、10進数に直した値を使って指定しようとする方法である。
組み合わせ | r(Read) | w(Write) | x(eXecute) | 10進数 |
---|---|---|---|---|
000 | - | - | - | 0 |
001 | - | - | OK | 1 |
010 | - | OK | - | 2 |
011 | - | OK | OK | 3 |
100 | OK | - | - | 4 |
101 | OK | - | OK | 5 |
110 | OK | OK | - | 6 |
111 | OK | OK | OK | 7 |
sime{c1xxxxx}% chmod 755 hoge.rb[Return]
この場合、hoge.rbに対して、Userはr,w,xいずれも許可、GroupとOtherはr,xのみ許可という設定をしていることになる。
アクセス権の変更方法[2] シンボルを用いて指定
ユーザーを表すu, g, oと、アクセス権を表すr, w, xを組み合わせて指定する方法である。例を示しながら説明する。
sime{c1xxxxx}% chmod u+x hoge.rb[Return] #=>Userにx(eXecute)を追加
sime{c1xxxxx}% chmod o-r hoge.rb[Return] #=>Otherからr(Read)を除去
sime{c1xxxxx}% chmod +x hoge.rb[Return] #=>User、Group、Otherにx(eXecute)を追加
sime{c1xxxxx}% chmod -w hoge.rb[Return] #=>User、Group、Otherからw(Write)を除去
[13]CSSを切り替える
以下は、色占いのCGIである。いずれかの色を選んだ上で「占う」ボタンを押すと、占い結果が表示されるが、その際に背景色を選択色にするということを考えてみる。
背景色の変更はbody要素に対してCSSのbackground-colorプロパティを指定すれば良い。CSSによるスタイルの指定にはいくつかの方法があるが、ここでは<head></head>内に記載する方法を示す。
入力フォーム
<form method="POST" action="./color.rb">
<p>占いです。今の気分を表す色を選んでね。</p>
<p>
<input type="radio" name="color" value="red">赤
<input type="radio" name="color" value="blue">青
<input type="radio" name="color" value="green">緑
</p>
<p>
<input type="submit" name="ok" value="占う">
<input type="reset" name="ng" value="やめておく">
</p>
</form>
使用しているのはラジオボタンである。ラジオボタンはいずれか1つしか選択することができないようにするため、name属性を3つともcolorに指定している。選択した色をvalue、colorをkeyとしてcolor.rbに引き渡される。
CGIスクリプト(color.rb)
#!/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" select = c["color"] print "<html>\n" print "<head>\n" print "<title>診断結果</title>\n" print "<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n" print "<style type=\"text/css\">\n" print "<!--\n" if select == "red" print "body {background-color: #ff0000}\n" uranai = "元気いっぱいですね" elsif select == "blue" print "body {background-color: #0000ff}\n" uranai = "落ち込んでいますね" elsif select == "green" print "body {background-color: #00ff00}\n" uranai = "目が疲れていますね" end print "-->\n" print "</style>\n" print "</head>\n" print "<body>\n" print "<h1>診断結果</h1>\n" print "<p>あなたが選んだのは#{select}です。#{uranai}。</p>\n" print "</body>\n" print "</html>\n"
CSSを使用する場合、<head></head>内に
<meta http-equiv="Content-Style-Type" content="text/css">
と書く必要がある。
Rubyプログラムの中に書くため、print""をつけ、""内で使用されている"はバックスラッシュをつけて
print "<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n"
となる。
CSSのスタイル自体は
<style type="text/css"> <!-- body {background-color: #ff0000} --> </style>
で指定されている。color.rbではbody {background-color: #ff0000}の部分をif文でくくり、条件に応じて色を変更している。
外部CSSファイルを呼び出す
CSSによるデザインの指定を行う場合、上述の通り<head></head>内に具体的に書いてもよいが、別にファイルを作成しておいても良い。この場合拡張子がcssのテキストファイルを作成しておき、<head></head>内には<style></style>で具体的に指定するかわりに
<link rel="stylesheet" href="hoge.css" type="text/css">
として呼び出すこともできる。これにより、hoge.cssに記載したスタイルが呼び出したhtmlファイルに適用される。
CSSファイルのサンプル(2010.css; このページで使用しているCSS)
CSSのプロパティの詳細についてはGoogle等で「CSS プロパティ」をキーワードにして検索してみること。
[14]openメソッドと組み合わせる
通常のプログラムと同じように、openメソッドを使って外部のファイルからの読み込みや、書き出しをすることができる。
入力フォーム(choice.html)
<form method="POST" action="./open-cgi.rb"> <p> 猫と犬のどちらが好きですか?<br> <input type="radio" name="choice" value="cat">猫 <input type="radio" name="choice" value="dog">犬<br> <input type="submit" name="ok" value="投票"> <input type="reset" name="ng" value="リセット"> </p> </form>
質問にはラジオボタンを用いている。2つのラジオボタンを同時に選択することが出来ないよう、name属性をchoiceに統一している。選択したボタンに対応するvalue属性の値がkeyであるchoiceに対応するvalueとして、CGIスクリプト(open-cgi.rb)に送られる。
CGIスクリプト(open-cgi.rb)
#!/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" data = c["choice"] cat = 0 dog = 0 open("open-cgi.dat","r+:utf-8") do |hoge| while line = hoge.gets if /cat/ =~ line cat += 1 elsif /dog/ =~ line dog += 1 end end if data == "cat" cat += 1 hoge.printf("%s\n",data) elsif data == "dog" dog += 1 hoge.printf("%s\n",data) end end print"<html> <head><title>結果発表</title></head> <body>\n" print"<h1>投票数:#{cat+dog}</h1>\n" print"<table border=1>\n" print"<tr><td>猫</td><td>" 1.upto(cat) do |i| if i%50 == 0 print"■<br>" else print"■" end end printf(" %d</td></tr>\n",cat) print"<tr><td>犬</td><td>" 1.upto(dog) do |i| if i%50 == 0 print"■<br>" else print"■" end end printf(" %d</td></tr></table>\n",dog) print"</body>\n" print"</html>\n"
入力フォームで選択されたデータは、ハッシュ変数cのkeyとvalueという形で取り出されている。その後、openメソッドを用いて、open-cgi.datを開いている。モードはr+とし、読み込みも書込みも出来るようにしている。open-endの中で、まず、while-endを使ってファイル内の値を順番にとりだし、これまでの得票数をcatとdogにそれぞれ代入しておき、その下のif-endで今回の得票の加算と、ファイルへの書込みを行っている。
HTMLへの結果出力時には、1票を■1つで表現し、それぞれ得票数を示している。演算子%は割り算の余りという意味であり、50で割ったときの余りが0の場合のみ<br>をつけることで、50票ずつ折り返して表示できるようにしている。
このCGIをうまく動かすためには、事前にopen-cgi.datを作成しておく必要がある。その上で、自分以外の第三者がこのファイルへの読み書きができるようファイルのアクセス権限を変更する必要がある。具体的にはktermでchomodコマンドを使用して次のように入力する。
sime{c1xxxxx}% chmod 666 open-cgi.dat[Return]
[15]データを永続させる(PStoreクラス)
[16]CGIでのPStoreの利用
[17]レポート課題
問題(10点満点):shinri.rbを改良し、合計得点に応じて結果出力のページの見栄えを変化させる。具体的には合計得点のpointの値に応じて、CSSを変化させる。color.rbでは背景色のみ変化させているが、文字色や文字の大きさ、挿入する画像など自由に設定してよい。
- 提出先:課題提出用メールアドレス
- 提出期限:第1提出期限、第2提出期限を設定
- メールのSubject:課題7
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
- データを入力するWebページのURL
- 作成したプログラム(CGIスクリプト)
- プログラムの説明
- 感想
- 採点基準:期限内提出点(2点)、メールの体裁(1点)、プログラム(3点)、CSSのデザイン(2点)、説明(2点)
- プログラムの説明:何をするCGIなのか、Webページの入力フォームから受け取った値をどのように処理しているのかについて
- わかりにくい説明や、Webページを単にコピー&ペーストしただけの説明は減点することがある。一度読み直してから提出すること。
- 驚異的に良くできているレポートについては満点を超える得点をつけることがある。
- よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする
Tips:Mewによるメールの送り方はMewコマンドを参照