#!/usr/local/bin/perl #---------------------------------------# # 多者択一クイズCGI # バージョン 1.2 # 制作 HAL # URL http://www.harukitchen.com/ #--------------------------------------# #-----------------------------------------------------# # 設定項目 #-----------------------------------------------------# $ANS_NUM=6;#最大何択にさせるか(問題作成時) $TITLE = 'クイズ ゲームキッズ';#タイトル $stylefile = '../../style.css';#スタイルシート $HOME_URL = '../../';#HomeURL $thisurl = './';#このCGI $logfile = './quiz.txt';#問題ファイル $memfile = './member.txt';#参加者ファイル $maxmissnum = 5;#この回数を間違うとゲームオーバー #正解のカラー $CORRECT_COLOR = 'ff0000'; #間違いのカラー $BAD_COLOR = '0000ff'; #--携帯設定--# $usehand = 0;#PCでも携帯画面にする(yes=1,no=0) $IHOME_URL = '../../i/゙';#ホームURL #-----------------------------------------------------# # 設定は以上まで #-----------------------------------------------------# #1.2 問題を重複しないようにランダムで作成 #1.1 回答にチェックしなかった時に正解になるバグ修正 &form;#フォーム情報 $lockdir = './lock/';#ロック用ディレクトリ unless($ENV{HTTP_USER_AGENT} =~ /Mozilla/){$usehand=1;}#携帯端末からのアクセスの場合 &GetNowDate; &head;#ヘッダ #圧縮情報を分割 if( $in{seed} ){ ($in{mymissnum},$in{anssum},$in{line},$in{start}) = split(/-/,$in{press}); }else{ ($in{mymissnum},$in{anssum},$in{line},$in{start},$in{seed}) = split(/-/,$in{press}); } #分岐 if($in{action} eq 'try'){&try;} elsif($in{action} eq 'new'){&new;} elsif($in{action} eq 'do_new'){&do_new;} elsif($in{action} eq 'lookmem'){&lookmem;} elsif($in{action} eq 'regist'){&regist;&lookmem;} else{&top;} &foot;#フッタ #ヘッダ sub head{ if(!$usehand){ print<<"HEAD"; Content-type: text/html <html> <head> <meta http-equiv="content-type" content="text/html; charset=shift_jis"> <title>$TITLE</title> <link rel="stylesheet" href="$stylefile"> </head> <body> <a href="$HOME_URL">Home</a> <center> <h1>$TITLE</h1> <p>[ <a href="$thisurl">始めから</a> | <a href="$thisurl?action=new">問題作成</a> | <a href="$thisurl?action=lookmem">成績ランキング</a> ]</p> HEAD } #携帯ヘッダ else{ print<<"HHEAD"; Content-type: text/html <html> <head><title>$TITLE</title></head> <body> <a href="$IHOME_URL">Home</a>&gt;$TITLE HHEAD } } #フッタ sub foot{ if(!$usehand){ print<<"FOOT"; <p align="right"> <small><a href="http://www.harukitchen.com/">(CGI)はるキッチン</a></small> </p> </body> </html> FOOT }else{ if(!$in{action}){print '<p align="right"><a href="http://www.harukitchen.com/i/">(CGI)はるキッチン</a></small></p>';} print "</body></html>"; } } #トップページ sub top{ open(IN,$logfile) or &openerror($logfile); @logs = <IN>; close(IN); $num = scalar(@logs); $seed_str = sprintf( "%04d%02d%02d", $gl_year, $gl_month, $gl_day ); print<<"MSG"; <table><tr><td> <ul> <li>多者択一クイズです。 <li>問題は全部で$num問あります。 <li>$maxmissnum回間違うとゲームオーバーです。 <li>ゲームオーバー時に成績を登録します。 <li>問題を作成する時は、上の「問題作成」で行えます。 <li>以下のSeedの数値によって問題の順番がランダムで決まります。 </ul> <div align="center"> <form action="$thisurl" method="GET"> <input type="hidden" name="action" value="try"> Seed:<input type="text" name="seed" value="$seed_str" size=10> <input type="submit" value="クイズ スタート"> </form> </div> </td></tr></table> MSG } #-----------------------------------------------------# # 現在の日時取得 #-----------------------------------------------------# sub GetNowDate{ #グローバル変数 ( $gl_sec, $gl_min, $gl_hour, $gl_day, $gl_month, $gl_year ) = localtime( time ); $gl_year += 1900; $gl_month++; } #トライページ sub try{ #ファイルの読み込み open(IN,$logfile) or &openerror($logfile); @logs = <IN>; close(IN); #前回の答え合わせ if($in{press}){ local($no,$question,$correct,@ans)=split(/<>/,$logs[$in{line}]); if($in{ans} == $correct){ print "<p><font size=5 color=\"#$CORRECT_COLOR\">正解!</font><br>\n"; }else{ print "<p><font size=5 color=\"#$BAD_COLOR\">間違い!</font><br>\n"; $in{mymissnum}++; } }else{print "<p> <br>\n";$in{start}=time;}#初めての問題の時 #ステータス $correctnum = $in{anssum}-$in{mymissnum}; if($in{anssum}){ $per = sprintf("%4.2f",($correctnum*100)/$in{anssum}); }else{ $in{anssum}=0; $per = 0; } if(!$in{mymissnum}){$in{mymissnum} = 0;} $passtime = time-$in{start}; print<<"STATUS"; <table border=1> <tr><th>問題数</th><th>正解数</th><th>間違い数</th><th>正解率</th><th>経過時間</th></tr> <tr><td align="right">$in{anssum}</td><td align="right">$correctnum</td> <td align="right">$in{mymissnum}</td><td align="right">$per</td> <td align="right">$passtime秒</td></tr> </table> STATUS if($in{mymissnum} >= $maxmissnum || $in{anssum} == scalar(@logs) ){ print "<h2>ゲームオーバー<br>成績を登録します。</h2>\n"; &registform; }else{ $in{anssum}++; #問題を重複しないようにランダムで出題 #$in{anssum}が問題数 srand( $in{seed} ); #順列作成 @q_array = (); for( $i = 0; $i < scalar(@logs); $i++ ){ push( @q_array, $i ); } #一応表示 #foreach(@q_array){print "$_<br>";}; #print "<br>"; #並び替え for( $i = 0; $i < scalar(@logs); $i++ ){ $rand = int( rand( scalar(@logs) - $i ) ) + $i; $temp = $q_array[ $i ]; $q_array[ $i ] = $q_array[ $rand ]; $q_array[ $rand ] = $temp; } #一応表示 #foreach(@q_array){print "$_<br>";}; #今回の問題 $thistime = $q_array[ $in{anssum} ]; chomp $logs[ $thistime ]; ($no,$question,$correct,@ans)=split(/<>/,$logs[ $thistime ]); print<<"QUIZ"; <form action="$thisurl" method="GET"> <table border=1 width="60%"> <tr><th>$question</th></tr> <tr><td align="center"> <table><tr><td> <span style="font-size:20pt"> QUIZ #選択肢 for($i=1;$i<scalar(@ans)+1;$i++){ print "<input type=\"radio\" name=\"ans\" value=$i>$ans[$i-1]<br>\n"; } print<<"QUIZ"; </span> </td></tr></table> <input type="hidden" name="action" value="try"> <input type="hidden" name="press" value="$in{mymissnum}-$in{anssum}-$thistime-$in{start}-$in{seed}"> <input type="submit" value="答える"> </td></tr> </table> </form> QUIZ } } #成績登録 sub regist{ if(!$in{name}){&error("名前が入力されていません");} if(!$in{key}){&error("パスワードが入力されていません");} $in{correctnum} = $in{anssum}-$in{mymissnum}; $in{per} = sprintf("%4.2f",($in{correctnum}*100)/$in{anssum}); #同じ名前の人物がいないかチェック open(IN,$memfile) or &openerror($memfile); @mems = <IN>; close(IN); $flag=0;$i=0; foreach(@mems){ &linesplit($_); #同じ名前の時、同一人物かどうか if($name eq $in{name}){ #キーが合ってるか? if($pass eq crypt($in{key},$pass)){ $flag=1; $prev = $i;#添字取得 last; }else{$flag=2;last;} } $i++; } #キーを暗号化 $xx = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./"; $salt = substr($xx,int(rand(64)),1); $salt .= substr($xx,int(rand(64)),1); $enckey = crypt($in{key},$salt); #成績登録 #新規の場合 if($flag == 0){ if(!mkdir($lockdir,0755)){&error("同時アクセスが起こりました。");} $flag2 = 0; open(OUT,">$memfile"); foreach(@mems){ &linesplit($_); if(!$flag2 && $in{per} > $per){ print OUT "$in{name}<>$in{msg}<>$enckey<>$in{url}<>$in{anssum}<>$in{correctnum}<>$in{mymissnum}<>$in{per}<>$in{passtime}\n"; $flag2 = 1; } print OUT $_; } #最下位の場合 if(!$flag2){print OUT "$in{name}<>$in{msg}<>$enckey<>$in{url}<>$in{anssum}<>$in{correctnum}<>$in{mymissnum}<>$in{per}<>$in{passtime}\n";} close(OUT); rmdir($lockdir); print "<p>成績を記録しました。</p>\n"; } #更新の場合 elsif($flag == 1){ if(!mkdir($lockdir,0755)){&error("同時アクセスが起こりました。");} open(OUT,">$memfile"); $j = 0;$flag2 = 0; foreach(@mems){ &linesplit($_); if($flag2==0 && $in{per} > $per){ print OUT "$in{name}<>$in{msg}<>$enckey<>$in{url}<>$in{anssum}<>$in{correctnum}<>$in{mymissnum}<>$in{per}<>$in{passtime}\n"; $flag2 = 1; } if($j == $prev){;}#前のデータを削除 else{print OUT $_;} $j++; } #最下位の場合 if(!$flag2){print OUT "$in{name}<>$in{msg}<>$enckey<>$in{url}<>$in{anssum}<>$in{correctnum}<>$in{mymissnum}<>$in{per}<>$in{passtime}\n";} close(OUT); rmdir($lockdir); print "<p>成績を更新しました。</p>\n"; } #名前が重複していた場合 elsif($flag == 2){ print "その名前で既に登録されています。他の名前で登録して下さい。"; &registform; exit; } } #問題作成ページ sub new{ print<<"FORM"; <h2>問題を追加します。</h2> <form action="$thisurl" action="$thisurl" method="post"> <b>問題</b><br><textarea name="question" cols=55 rows=5></textarea><br><br> <b>選択肢</b><br> 正解をチェックして下さい。<br> 未記入の欄は、選択肢になりません。<br> FORM for($i=1;$i<$ANS_NUM+1;$i++){ print "<input type=\"radio\" name=\"newans\" value=$i><input type=\"text\" name=\"ans$i\" size=50><br>\n"; } print<<"FORM"; <input type="hidden" name="action" value="do_new"><p> <input type="submit" value="登録"> </form> FORM } #問題追加 sub do_new{ if(!$in{question}){&error("問題を入力して下さい。");} if(!$in{newans}){&error("正解をチェックして下さい。");} open(IN,$logfile) or &openerror($logfile); @logs = <IN>; close(IN); #同じ問題がないかチェック foreach(@logs){ local($no,$q) = split(/<>/,$_); if($q eq $in{question}){&error("同じ問題が登録されています。");} } #MAXNOを取得 $maxno=1; for($i=0;$i<scalar(@logs);$i++){ ($no)=split(/<>/,$logs[$i]); if($maxno<$no){$maxno=$no;} } $maxno++; if(!mkdir($lockdir,0755)){&error("同時アクセスが起こりました。");} open(OUT,">$logfile"); print OUT "$maxno<>$in{question}<>$in{newans}"; for($i=1;$i<$ANS_NUM+1;$i++){ $str = sprintf("ans%d",$i); print OUT "<>$in{$str}"; } print OUT "\n"; print OUT @logs; close(OUT); rmdir($lockdir); print "<p>問題を追加しました。</p>\n"; } #成績を見るページ sub lookmem{ open(IN,$memfile) or &openerror($memfile); @dat=<IN>; close(IN); chop(@dat); $sum = scalar(@dat); print "<h2>上位$sum人の成績表\</h2>\n" ."<table border=1 cellspacing=0 cellpadding=3>\n" ."<tr><th>順位</th><th>名前</th><th>正解数</th><th>正解率</th><th>タイム</th><th>コメント</th></tr>\n"; $rank=1;$prev=1;$i=0; foreach(@dat){ &linesplit($_); $i++; if($prev > $per){$rank = $i;} $prev = $per; print "<tr><td align=\"right\">$rank</td>" ."<td align=\"right\">$name</td>" ."<td align=\"right\">$correctnum</td><td align=\"right\">$per</td><td align=\"right\">$time</td><td>$msg</td></tr>\n"; } print "</table>\n"; } #成績登録フォーム sub registform{ if(!$passtime){$passtime=$in{passtime};} print<<"GAMEOVER"; <form action="$thisurl" action="$thisurl" method="post"> 名前とパスワード欄は必須項目です。<br> 2回目以降のチャレンジの時は、前回と同じパスワードを使用して下さい。<br> 成績が更新されます。<br> <table border=1> <tr><td>なまえ</td><td><input type="text" name="name" size=40></td></tr> <tr><td>パスワード</td><td><input type="password" name="key" size=8></td></tr> <tr><td>コメント</td><td><input type="text" name="msg" size=40></td></tr> </table> <input type="hidden" name="press" value="$in{mymissnum}-$in{anssum}-$rand-$in{start}-$in{seed}"> <input type="hidden" name="passtime" value=$passtime> <input type="hidden" name="action" value="regist"> <br> <input type=submit value="登録"> </form> GAMEOVER } #ログ形式通り分割して変数に格納 sub linesplit{ ($name,$msg,$pass,$url,$qnum,$correctnum,$missnum,$per,$time) = split(/<>/,$_[0]); chomp($time); } #フォーム情報 sub form{ local($buffer,@pairs); $ENV{REQUEST_METHOD} =~ tr/A-Z/a-z/;#大文字を小文字に if($ENV{REQUEST_METHOD} eq 'post'){ read(STDIN,$buffer,$ENV{CONTENT_LENGTH}); }else{$buffer = $ENV{QUERY_STRING};} @pairs = split(/&/,$buffer); foreach(@pairs){ local($key,$value) = split(/=/,$_); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; $value =~ s/&/&amp;/g; $value =~ s/"/&quot;/g; $value =~ s/</&lt;/g; $value =~ s/>/&gt;/g; $value =~ s/\r\n/\n/g; $value =~ s/\n/<br>/g; $in{$key} = $value; } } sub openerror{print "$_[0]がオープン出来ません。";&foot;exit;}#オープンエラー sub error{print "$_[0]\n";&foot;exit;}#エラー