お御籤とお告げ/Perl/CGIの基礎講座
【環境条件】
Eclipse 4.4(ルナ)
XAMPP 1.8.3
Perlは既にインストール済み
CGIを使用する時は、必ずApachを起動する
【おみくじの】
最初に表示される画面の左上にあるのは管理者用の仕掛けです。パスワードを入力して 「設定」 ボタンをクリックすると、設定画面が開かれて、お御籤の出る確率を、例えば、「大吉」 を 30%、「凶」 を 10% などと任意に設定することができます。
1.おみくじ画面
![](https://blogimg.goo.ne.jp/user_image/7e/28/79009cc96d0ad1fc26536752de75ca86.jpg)
・「籤引き」ボタンを押す
2.お告げ画面
画面の 「籤引き」 ボタンを押すと、画面がめまぐるしく変わり、その後で 「お告げ」 の画面が現われます。バックグランドミュージックの変化や画面がめまぐるしく変わる動きは、最初の画面の中に仕掛けてある javascript で制御しています。画面が20回切り替わった後で、「お告げ」 の画面が表示されます。
![](https://blogimg.goo.ne.jp/user_image/6e/92/566ac52d8584e4da17ba849251a21bd4.jpg)
【スクリプト】
この御神籤のスクリプトは、omikuji.cgiがメインで、そのスクリプトからlibrary.plとOmikuji.plを読み込んでる。
◆omikuji.cgi
1.#!/usr/local/bin/perl
2.
3.require 'library.pl';#ライブラリーの読み込み
4.require 'Omikuji.pl';#パッケージの読み込み
5.
6.$thisfile = 'omikuji.cgi';
7.$pass = '0123';
8.$bg_img = 'img/pur6b.gif';
9.$font_family = 'AR勘亭流H, HG創英角ポップ体';
10.$m_dir = 'mid';
11.$music_draw = 'babels.mid';
12.@music1 = ('yuuki.mid', 'bee.mid', 'bop_on.mid');
13.@music2 = ('avinion.mid', 'l_coucou.mid', 'fly_free.mid');
14.
15.#---- 基本プログラム ----
16.&decode;
17.if ($in{'mode'} eq 'otuge') { &otuge; }
18.elsif ($in{'mode'} eq 'admin') { &admin; }
19.elsif ($in{'mode'} eq 'write') { &write; }
20.else { &omikuji; }
21.exit;
22.
23.#---- お御籤を引く画面 ----
24.sub omikuji {
25. $n1 = int(rand 3);
26. $music = "$m_dir/$music1[$n1]";
#スタイルシート設定
27. $css = <<END;
28.#div0 { position:absolute; top:16px; left:16px; }
29.#div1 { font-size:20pt; font-weight:bold; margin-top:50px; }
30.#div2 { position:absolute; top:170px; width:100%; font-size:150pt; }
31.#div1, #div2 { text-align:center; font-family:$font_family; }
32.h1 { color:#006400; font-size:30pt; }
33.b { color:red; }
34..s1 { width:6em; height:32px; font-weight:bold; font-size:12pt;
35. background:#800000; color:white; margin-top:50px; }
36.END
# javascript の設定
37. $java = <」と出るか、「<b>大凶</b>」と出るか、
71. 今日の運勢を占います!!!</p>
72.<p>下のボタンを押してください</p>
73.<form action="$thisfile" method="post">
74.<input type="hidden" name="mode" value="otuge">
75.<input type="button" value="籤引き" class="s1" onclick="chng()">
76.</form>
77.</div>
78.<div id="div2"></div> ←囲った部分をブロックレベル要素としてグループ化している。
79.<p id="p1"><embed hidden="true" src="$music"></p>
80.</body>\n</html>
81.END
82.}
83.
84.#---- お告げの画面 ----
85.sub otuge {
86. &Omikuji::drawKuji($n1, $kuji, $text);
87. $n2 = int($n1/2); if ($n2>2) { $n2=2; }
88. $music = "$m_dir/$music2[$n2]";
89. $css = <<END;
90.div { text-align:center; font-family:$font_family;
91. font-size:20pt; font-weight:bold; margin-top:50px; }
92.h1, b { color:red; font-size:30pt; }
93.form { margin-top:50px; }
94.input { width:6em; height:32px; font-weight:bold; font-size:12pt;
95. background:#800000; color:white; }
96.END
97. &header('お告げ', $css, '');
98. print <<END;
99.<body background="$bg_img">
100.<div>
101.<h1>お告げ</h1>
102.<p>今日の運勢は <b>$kuji</b> です。</p>
103.<p>$text</p>
104.<form action="$thisfile">
105.<input type="submit" value="戻る">
106.</form>
107.</div>
108.<p><embed hidden="true" src="$music"></p>
109.</body>\n</html>
110.END
111.}
112.
113.#---- お告げの設定画面 ----
114.sub admin {
115. if ($in{'pw'} ne $pass) { &error('パスワードが違います'); }
116. @kuji = &Omikuji::getKuji;
117. @data = &Omikuji::readData;
118. $max = @kuji * 10;
119. $css = <<END;
120.div { text-align:center; font-family:$font_family;
121. font-size:20pt; font-weight:bold; margin-top:50px; }
122.h1 { color:#006400; font-size:30pt; }
123..s1 { width:6em; height:32px; font-weight:bold; font-size:12pt;
124. background:#800000; color:white; margin-top:50px; }
125.END
126. &header('お告げの設定', $css, '');
127. print <<END;
128.<body background="$bg_img">
129.<div>
130.<h1>お告げの設定</h1>
131.<p>合計が $max になるように設定してください</p>
132.<form action="$thisfile" method="post">
133.<input type="hidden" name="mode" value="write">
134.<table>
135.END
136. for ($i=0; $i<@kuji; $i++) {
137. print <<END;
138.<tr><td>$kuji[$i]</td>
139.<td><input type="text" size=6 name="k$i" value="$data[$i]">
140.</td></tr>
141.END
142. }
143. print <<END;
144.</table>
145.<input type="submit" value="設定" class="s1">
146.</form>
147.</div>\n</body>\n</html>
148.END
149.}
150.
151.#---- 設定の保存処理 ----
152.sub write {
153. $max = 0;
154. foreach (sort keys %in) {
155. if (/k([0-9])/) { $data[$1] = $in{$_}; $max += 10; }
156. }
157. $ret = &Omikuji::writeData(@data);
158. if ($ret==0) { &error("合計が $max ではありません"); }
159. &omikuji;
160.}
161.
162.#---- エラー表示画面 ----
163.sub error {
164. $css = <<END;
165.div { text-align:center; font-family:$font_family;
166. font-size:20pt; font-weight:bold; margin-top:50px; }
167.h1 { color:#006400; font-size:30pt; }
168.input { width:6em; height:32px; font-weight:bold; font-size:12pt;
169. background:#800000; color:white; margin-top:50px; }
170.END
171. &header('設定エラー', $css, '');
172. print <<END;
173.<body background="$bg_img">
174.<div>
175.<h1>ERROR !</h1>
176.<hr width=600 size=2 noshade>
177.<p>$_[0]</p>
178.<hr width=600 size=2 noshade>
179.<input type="button" value="戻る" onclick="history.back();">
180.</div>
181.</body>\n</html>
182.END
183. exit;
184.}
●●● 解説 ●●●
・外部ファイルの呼び込み
【omikuji.cgi】
1.#!/usr/local/bin/perl
2.
3.require 'library.pl';#ライブラー
4.require 'Omikuji.pl';#パッケージ
ライブラリーとパッケージを呼び込んでる。ところで、ライブラリとパッケージの違いは、変数の扱い方が違います。ライブラリと呼び出し側とで、互いの変数をグローバルに扱えるのに対して、パッケージの場合は独立性が強く、変数は別々に管理されるため、呼び出し側では相手の変数を気にする必要はありません。
6.$thisfile = 'omikuji.cgi';
7.$pass = '0123';
8.$bg_img = 'img/pur6b.gif';
9.$font_family = 'AR勘亭流H, HG創英角ポップ体';
10.$m_dir = 'mid';
11.$music_draw = 'babels.mid';
→初期設定用の変数と配列です。 $pass は管理者用のパスワードです。 $bg_img は背景画像、$font_family は表示用字体です。
12.@music1 = ('yuuki.mid', 'bee.mid', 'bop_on.mid');
13.@music2 = ('avinion.mid', 'l_coucou.mid', 'fly_free.mid');
→楽曲の指定、$m_dir はこれらの楽曲ファイルの所在を示すディレクトリです。これらの楽曲ファイルを omikuji.cgi と同じディレクトリに置く場合は、カレントディレクトリを示す 「. 」 を使い $m_dir = '.' と指定します
【library.pl】
1.#---- フォームデータ取得 ----
2.sub decode {
・・・
16.}
・・・
41.#---- HTMLヘッダー部の出力 ----
42.sub header {
・・・
66.}
67.1; ←ライブラリーの場合
【Omikuji.pl】
#package とは、
「名前空間」 を宣言する言葉です。「この名前で、次から記述する変数名、サブルーチン名などを管理せよ」 と宣言しているのです。このため、パッケージ内で使われる変数名などは、呼び出し側とは異なる別な 名前空間 で管理されることなります。
1.package Omikuji; #パッケージ名の宣言(名前空間)をする
#コンストラクタ設定
2.sub BEGIN {
3. $datafile = 'omikuji.dat';
4. @kuji = ('大吉', '中吉', '小吉', '吉', '末吉', '凶');←6要素の配列
5. @text = (
6. '何をしても絶好調な一日。新しいことにチャレンジを!',
7. '良いことが起きます。早朝東の空にUFOが見られるかも?',
8. 'ちょっとした幸運あり。道で小銭が拾えるかも?',
9. 'ツキが廻ってきます。但しギャンブルに手をだすと転落。',
10. '運気上昇の兆しあり。トイレで読書すると吉に転ずる?',
11. '災厄の日。入浴すると吉、湯船で眠るとそのまま沈む。');←6要素の配列
12. $max = 6;
13.}
14.sub getKuji { return @kuji; }
15.sub writeData {
16. $sum=0;
17. foreach (@_) { $sum += $_; }
18. if ($sum != $max * 10) { return 0; }
19. else {
20. $data = join(",", @_);←区切り文字列を挟みながら、文字列を連結し、連結した文字列をスカラー変数
21. open(OUT, ">$datafile");
22. print OUT "$data\n";
23. close(OUT);
24. return 1;
25. }
26.}
27.sub readData {
28. if (-e $datafile) {
29. open(IN, $datafile);
30. $data = <IN>;
31. close(IN);
32. chomp $data;←改行を取り除く関数
33. @val = split(/,/, $data);←指定した区切り文字で文字列を分解して配列を作成する
34. }
35. return @val;
36.}
37.sub drawKuji {
38. @val = &readData;
39. if (@val) {
40. $rr = int(rand($max * 10));
41. for ($n1=0, $dd=0; $n1<$max; $n1++) {
42. $dd += $val[$n1];
43. if ($rr < $dd) { last; }
44. }
45. } else {
46. $n1 = int(rand $max);
47. }
48. $_[0] = $n1;
49. $_[1] = $kuji[$n1];
50. $_[2] = $text[$n1];
51.}
52.return 1;← パッケージの場合
・パッケージ内サブルーチンの呼び出し
→スクリプトomikuji.cgiからパッケージ内のサブルーチンを呼び出すには、86行目のように書く&Omikuji::drawKuji($n1, $kuji, $text);→ &パッケージ名::サブルーチン名; として呼び出さなければなりません。この書き方はPerl5での書き方で、Perl4では &パッケージ名'サブルーチン名; となっています。
■ パッケージ Omikuji.plについて
1.package Omikuji;←パッケージ宣言
2.sub BEGIN {
$datafile = 'omikuji.dat';
・・・・・・・
13.}
までは、コンストラクタと呼ばれる初期処理の部分、$datafile として管理者が 「お告げ」 の出る確率を設定するデータファイルを、また @kuji と @text という夫々6つの要素を持つ2つの配列を定義しています。
14.sub getKuji { return @kuji; }
パッケージ内で定義した配列 @kuji を返します。呼び出し側で、これを配列、または変数で受け取れば、配列 @kuji そのもの、または @kuji の要素数が渡されます。
15.sub writeData {・・・}のサブルーチンは
管理人が設定したデータをデータファイルに書き込むための処理ルーチンです。渡された引数の合計を計算して、$max の10倍とならない場合は、エラーを示すために 0 を返して終了します。合計が正しい場合には、join 関数を使って引数を区切り記号 「, 」 で繋ぎ合わせて(20行目)、それを $datafile に書き出し、成功を示す 1 を返します。ファイルに書き込まれるデータは "20,10,10,5,5,10" のような形の1行の文字列です
27.sub readData {・・・}のサブルーチンは
$datafile が存在すれば、これを読み取りモードで開きます。このファイルには1行しか書いてないので、これを $data という変数に代入してファイルを閉じます。末尾の改行記号を取り去った後、split 関数で、「, 」 で区切られたデータを分解して配列 @val に取り込み、この配列を返します
37.sub drawKuji{・・・}のサブルーチンは
お御籤を引いた人への 「お告げ」 を演算するルーチンです
先ず、readData サブルーチンを呼び出し、データファイルに書かれているデータを配列 @val で受け取ります
データが存在する場合には、
$max を10倍した数以下の乱数($max が 6 のときは 0~59)を $rr にセットします(40行目)。41~44行目の for ループでは、まわる度に、配列 @val の要素を加算した $dd と 乱数 $rr とを比較して、$rr < $dd の条件が成り立てば、last; で for ループを抜け出します。ループを抜けたときの $n1 は、このような処理の結果、単なる乱数ではなく重み付けされた値になっています
45.} else {
46. $n1 = int(rand $max);
47. }
→データが存在しなければ @val は偽となり、46行目の演算で、乱数による均等確率で $n1 の値をセットします。
48. $_[0] = $n1;
49. $_[1] = $kuji[$n1];
50. $_[2] = $text[$n1];
51.}
この $n1 と、配列 @kuji と @text の夫々から $n1 番目の文字列を取り出して、第1~第3引数にセットします(48~50行目)。
◆omikuji.cgi の基本プログラム
15.#---- 基本プログラム ----
16.&decode;
→decode サブルーチンが生成するハッシュ %in にある筈の キー mode の値 $in{'mode'} を調べている。次のif文で、値にあった処理をする。
17.if ($in{'mode'} eq 'otuge') { &otuge; }
18.elsif ($in{'mode'} eq 'admin') { &admin; }
19.elsif ($in{'mode'} eq 'write') { &write; }
20.else { &omikuji; }←最初の画面に成る
21.exit;
→最初に表示される 「お御籤を引く画面」 は、omikuji サブルーチンで作られます。
■ お御籤を引く画面
23.#---- お御籤を引く画面 ----
24.sub omikuji {
25. $n1 = int(rand 3);
26. $music = "$m_dir/$music1[$n1]";
27. $css = <<END;
・・・
36.END
37. $java = <<END;
・・・
57.END
58. &header('おみくじ', $css, $java);
59. print <<END;
60.<body id="bg" background="$bg_img">
・・・
80.</body>\n</html>
81.END
→25行目の $n1 = int(rand 3); で、$n1 に 0~2 の乱数が代入されます。
26行目で、この$n1を使って変数 $music に楽曲ファイルをセットします。 $m_dir と @music1 は、前節で説明したように、このスクリプトの冒頭で定義してあり、$n1 が 0 であれば、$music は "mid/yuuki.mid" というような文字列となります。
→27.$css = <<END;から36.ENDはスタイルシートの文字列を $css に設定。
→37.$java = <<END;から57.ENDは javascript の記述を $java に設定。
これらの変数を引数にして、58行目で library.pl 内の header サブルーチンを使って HTML のヘッダー部分を出力する。
→59.print <このHTML は、javascript を使って 「籤引き」 というボタンを押すと、画面がめまぐるしく変わり、せきたてるようなバックグランドミュージックが鳴り出し、20回表示を変えた後に、「お告げ」 の画面に切り替わるようになっています
【JavaScriptについて】
・getElementById→任意のHTMLタグで指定したIDにマッチするドキュメント要素を取得するメソッドです。
◆ javascript の仕掛けの説明
21.function chng() {
22. if (n1==0) {
DynamicHTML(<a href="https://eng-entrance.com/what-is-dom">DOM</a>)
23.document.getElementById("div0").style.visibility = "hidden";#可視属性の変更
24.document.getElementById("div1").style.visibility = "hidden";#可視属性の変更
25.document.getElementById("bg").style.backgroundImage = "none";
26. document.getElementById("p1").innerHTML =
27. '<embed hidden="true" src="mid/babels.mid">';
28. }
29. var i = n1++ % 4;
30. document.getElementById("div2").innerText = mj[i];
31. document.fgColor = fc[i];
32. document.bgColor = bc[i];
33. if (n1chng()関数が起動されます。n1が0であるため、先ず23~27行目が順に実行されます。ここの処理は1回だけ行われます。
→23行目にある。getElementById("div0").style.visibility とは id="div0" と設定した40~46行目のdiv要素を特定する記述で、このstyle要素のvisibilityプロパティを "hidden" と設定して、見えないように隠している。ここは、管理者が設定画面を開くためのフォームを含んでいる部分です。
40.<div id="div0">
フォーム0
41.<form action="omikuji.cgi" method="post">
42.<input type="hidden" name="mode" value="admin">
43.<input type="password" size=12 name="pw">
44.<input type="submit" value="設定">
45.</form>
46.</div>
→24行のdocument.getElementById("div1").style.visibility = "hidden";も同様で、idに設定された"div1"要素をスタイルシートに現れないようにしている。
47.<div id="div1">
48.<h1>おみくじ</h1>
49.<p>「<b>大吉</b>」と出るか、「<b>大凶</b>」と出るか、
50. 今日の運勢を占います!!!</p>
51.<p>下のボタンを押してください</p>
フォーム1
52.<form action="omikuji.cgi" method="post">
53.<input type="hidden" name="mode" value="otuge">
54.<input type="button" value="籤引き" class="s1" onclick="chng()">
55.</form>
56.</div>
→25行のdocument.getElementById("bg").style.backgroundImage = "none";はbody 要素の背景画像を非表示に変更している。
→26行のdocument.getElementById("p1").innerHTML = '<embed hidden="true" src="mid/babels.mid">';→.innerHTMLプロパティを使って、58行の
<embed hidden="true" src="mid/yuuki.mid">
で、最初に鳴り出す楽曲を設定されたものを、別な楽曲に変更している。ただし、「babels.mid」「yuuki.mid」ファイルが無いのでならない。
→29.var i = n1++ % 4;は、n1%4の演算結果を i に代入した後で、変数 n1 はインクレメントされます。この演算では、n1 を4で割った剰余が変数 i に代入されるので、i は 0~3 の何れかの値となります。
→30行目では、id="div2" と設定した57行目の内の文字を、配列 mj の添え字としてこの i を使って、mj[i] とします。同様にして、31, 32行目では、画面の文字色と背景色を、fc[i] と bc[i] に変更しています。
→33行の if (n1<20) { timer = setTimeout("chng()", 250); } は、変数 n1 が20に達するまで、このchng()関数自身が 250msec 毎に再帰的に呼び出されます。呼び出されるたびに、30~32行目で画面の文字、文字色、背景色が変更され、めまぐるしく変化する画面が表示されることになります。
→n1が20に達すると、34行目の clearTimeout(timer); でタイマーがクリアされ、 document.forms[1].submit(); が実行されます。HTML内のフォームは、forms というコレクション(配列)で管理されています。この HTML には2つのフォームがあり、現われた順に forms[0]、forms[1] ・・・ として識別されます。従って、この記述は、2番目に現われる 52~55行目の 「籤引き」 ボタンのあるフォームを指定して、このフォームのデータを submit() メソッドで送信するように命じていることになります。送信先は、52行目の form タグの action 属性で指定されている omikuji.cgi で、53行目の隠し input タグの記述で mode=otuge というデータが送られます。従って、この命令で 「お告げの画面」 に切り替わります。
■ お告げの画面
84.#---- お告げの画面 ----
85.sub otuge {
86. &Omikuji::drawKuji($n1, $kuji, $text);
87. $n2 = int($n1/2); if ($n2>2) { $n2=2; }
88. $music = "$m_dir/$music2[$n2]";
89. $css = <
91. font-size:20pt; font-weight:bold; margin-top:50px; }
92.h1, b { color:red; font-size:30pt; }
93.form { margin-top:50px; }
94.input { width:6em; height:32px; font-weight:bold; font-size:12pt;
95. background:#800000; color:white; }
96.END
97. &header('お告げ', $css, '');
98. print <<END;
99.<body background="$bg_img">
100.<div>
101.<h1>お告げ</h1>
102.<p>今日の運勢は <b>$kuji</b>です。</p>
103.<p>$text</p>
104.<form action="$thisfile">
105.<input type="submit" value="戻る">
106.</form>
107.</div>
108.<p><embed hidden="true" src="$music"></p>
109.</body>\n</html>
110.END
111.}
→86行目で Omikuji.pl の drawKuji サブルーチンを &Omikuji::drawKuji($n1, $kuji, $text); で呼び出し、ありがたいお告げを頂いています。お告げが 「大吉」 の場合には、$n1=0、$kuji='大吉'、$text='何をしても絶好調な ・・・ ' とセットされます
→87行目では、6種類のお告げを3種類の楽曲に割り当てるため、$n2 = int($n1/2); の処理をしています。 if ($n2>2) { $n2=2; } の処理は、Omikuji.pl が6種類以上のお告げを出せるように修正される場合もあり得ることを配慮した処理です
→88行目では、冒頭で定義された $m_dir と @music を使って、この画面で使う楽曲ファイルを $music という変数にセットしています。
あとは一気呵成に HTML 文を出力します。 89~96行目でスタイルシートを $css に設定して、97行目で &header('お告げ', $css, ''); として HTML のヘッダー部分を出力し、98~110行目で HTML の body 部分を出力しています。
◆「お告げの設定画面」 を表示する admin サブルーチンのスクリプト
113.#---- お告げの設定画面 ----
114.sub admin {
115. if ($in{'pw'} ne $pass) { &error('パスワードが違います'); }
116. @kuji = &Omikuji::getKuji;
117. @data = &Omikuji::readData;
118. $max = @kuji * 10;
スタイルシート
119. $css = <<END;
120.div { text-align:center; font-family:$font_family;
121. font-size:20pt; font-weight:bold; margin-top:50px; }
122.h1 { color:#006400; font-size:30pt; }
123..s1 { width:6em; height:32px; font-weight:bold; font-size:12pt;
124. background:#800000; color:white; margin-top:50px; }
125.END
126. &header('お告げの設定', $css, '');
<HTML>を出力する
127. print <<END;
128.<body background="$bg_img">
129.<div>
130.<h1>お告げの設定</h1>
131.<p>合計が $max になるように設定してください</p>
フォームを作る
132.<form action="$thisfile" method="post">
133.<input type="hidden" name="mode" value="write">
134.<table>
135.END
136. for ($i=0; $i<@kuji; $i++) {
137. print <<END;
138.<tr><td>$kuji[$i]</td>
139.<td><input type="text" size=6 name="k$i" value="$data[$i]">
140.</td></tr>
141.END
142. }
143. print <<END;
144.</table>
145.<input type="submit" value="設定" class="s1">
146.</form>
147.</div>\n</body>\n</html>
148.END
149.}
→115行目で、「お御籤を引く画面」 から送られてくるパスワードをチェックして、正しくない場合は error サブルーチンに飛ばします。正しければ、116行目に進みます。
→116行目の @kuji = &Omikuji::getKuji; で、Omikuji.pl 内の配列 @kuji を受け取ります。
→117行目では @data = &Omikuji::readData; で、データファイルから読み出したデータを受け取ります。データファイルが存在しなければ、@data は空の配列となります。
→118行目の$max = @kuji * 10;では、配列 @kuji の要素数を10倍した値が $max に代入されます。6種類のお告げのときは $max = 6 * 10 の演算です
→119~125行目でスタイルシートの文字列を $css に設定し、126行目でこの $css を使って HTML のヘッダー部分を出力します。127行目以降で HTML の body 部分を出力しています。
→136~142行目のfor ループを使って、テーブルの各行2列を出力しています。ここでも @kuji が要素の数として扱われていることに注意してください。このようにスクリプトを記述しておけば、Omikuji.pl でお御籤の種類を増やしたとしても影響を受けなくなります。
→この画面のフォームは、132~146行目で生成する form 要素です。管理者が入力したデータは、139行目の生成する input タグから送られ、k0=20、k1=10 ・・・ のような形になります
■ 設定の保存処理
管理者の入力を保存処理する write サブルーチンを下に示します。「お告げの設定画面」 から送られてきた k0=20、k1=10 ・・・ のようなデータは、decode サブルーチンによって、ハッシュ %in に、キー 'k0' の値として 20、キー 'k1' の値として 10 ・・・ などと格納されています
151.#---- 設定の保存処理 ----
152.sub write {
153. $max = 0;
154. foreach (sort keys %in) {
155. if (/k([0-9])/) { $data[$1] = $in{$_}; $max += 10; }
156. }
157. $ret = &Omikuji::writeData(@data);
158. if ($ret==0) { &error("合計が $max ではありません"); }
159. &omikuji;
160.}
→これらのデータは、154~156行目の foreach ループで処理されます。154行目の (sort keys %in) は、ハッシュ%in からキーだけを配列として取り出し、それをソートした配列です。 foreach ループでは、この配列から1つずつ要素を取り出し、155行目で処理します。
→155行目では、取り出した$_ を対象に、正規表現 での /k([0-9])/ パターンにマッチするかどうかを調べます。 'k0'、'k1' のようなキーだけがマッチして、( ) で囲まれた部分は、特殊な変数 $1 に格納されます。
→従って、キー 'k0' が取り出されたときには、$data[$1] = $in{$_}; は、$data[0] = $in{'k0'}; となり、このようにして配列 @data に管理者が入力したデータが格納されます。また、該当するキーが見付かるたびに、$max には10 が加算され、キーが6個見付かれば、ループを抜けたときには、60になっています。
→157行目の $ret = &Omikuji::writeData(@data); で、Omikuji.pl 内の writeData サブルーチンを使ってデータファイルへの書き込みを行います。戻り値 $ret が 0 となるのは、データの合計が正しくなかったためで、この場合は158行目で error 処理を行います。データの合計値が正しければ書き込み成功の 1 が返り、この場合は omikuji サブルーチンに処理を移します。
■ エラー表示画面
エラー画面を表示する error サブルーチンのスクリプト
162.#---- エラー表示画面 ----
163.sub error {
164. $css = <<END;
165.div { text-align:center; font-family:$font_family;
166. font-size:20pt; font-weight:bold; margin-top:50px; }
167.h1 { color:#006400; font-size:30pt; }
168.input { width:6em; height:32px; font-weight:bold; font-size:12pt;
169. background:#800000; color:white; margin-top:50px; }
170.END
171. &header('設定エラー', $css, '');
172. print <
$_[0]
で出力されます。→179行目の 「戻る」 ボタンをクリックすると、onclick="history.back();" で、この画面の前に表示されていた画面に戻ります。 history とは javascript のオブジェクトで、このオブジェクトのメソッド back() は、前の画面に戻る動作を引き起こします。
この画面を表示させたあとは、呼び出し元に戻らないように、サブルーチンの最後に exit; を実行して、プログラムを終結させます。