2016-10-10 6 views
0

私は、ローカルWebブラウザから新しい質問を受け付ける、perl cgiでクイズフォームを作成する必要があります。それぞれの質問の挿入は状態テーブルで更新する必要があり、最後にデータベースに存在する質問の数と各セッションに挿入される新しい質問を表示する必要があります。私のデータベースとしてフォームとMysqlを使用し、localhostで実行します。新しいクエスチョンを追加しようとすると、それをテーブルに入れる唯一のことは質問です。何も追加されません。 URLの値がサーバーに渡されているのがわかりますが、データはSQLステートメントに決して送られません。助けてください。Perl cgiがmysqlにハッシュを渡さない

#! /usr/bin/perl 
#use strict; 
#use warnings; 
#use diagnostics; 
print "Content-type: text/html\n\n"; 

if ($ENV{"REQUEST_METHOD"} eq "POST") { 
    read(STDIN, $datastring, $ENV{"CONTENT_LENGTH"});  
} 
elsif (exists $ENV{"REQUEST_METHOD"}) {  # data from GET transaction (or HEAD or other) 
    $datastring = $ENV{"QUERY_STRING"}; 
} 
else { 
    print "Offline execution detected\n"; 
    print "Please enter some data.\n"; 
    $datastring = <>; 
    chomp $datastring; 
    print "== data accepted == HTML output follows ==\n\n"; 
} 

###decode###################################################### 
$datastring =~s/%0D%0A/\n/g;      #step to deal with line 
                #breaks in text areas 
@nameValuePairs = split(/&/, $datastring);   #step 1 
foreach $pair (@nameValuePairs) { 
    ($name, $value) = split(/=/, $pair);    #step 2 
    $name =~tr/+/ /;         #step 3 
    $name =~s/%([\da-fA-F]{2})/pack("C",hex($1))/eg; #step 3 
    $value =~tr/+/ /;         #step 3 
    $value =~s/%([\da-fA-F]{2})/pack("C",hex($1))/eg; #step 3 

    if(exists $formHash{$name}) {      #improved step 4, 
    $formHash{$name} = $formHash{$name}.";".$value; #now handles multiple 
    }             #select menus 
    else { 
    $formHash{$name} = $value; 
    } 
} 
###done decoding############################################### 

### global variables ########################################## 
use DBI; 
$dbhandle = DBI->connect("DBI:mysql:databasexx", "idyy", "passzz") 
    or &errorPage("Can't connect to database". DBI->errstr()); 
$file_life_span = 1.0/24; # in days (so is 1 hours) 
$time_out = 1.0/24; 
$time_out = 1.0/24; # in days 
$cache_limit = 300; 
$state_table_name = "stable"; # name of state table 
$quiz_table_name = "qtable";  # name of quiz table 
%stateHash=(); 
### end of global variables ##################################### 

### app logiC################################################### 
if($formHash{"request"} eq "menu") { 
    &menu; 
} 
elsif($formHash{"request"} eq "add") { 
    &add; 
} 
elsif($formHash{"request"} eq "add2") { 
    &add2; 
} 
elsif($formHash{"request"} eq "list") { 
    &list; 
} 
else { 
    &welcome; 
} 
### end app logiC################################################ 

################################################################## 
sub welcome{ 
my $sessionID = &get_long_id_db($dbhandle, $state_table_name, $cache_limit, $file_life_span); 
$qnumber=1; 
%stateHash = ("qnumber"=>$qnumber); 
&write_state_db($dbhandle, $state_table_name, $sessionID, %stateHash); 

print <<PAGE; 
<html><head><title>Welcome</title></head> 
    <body> 
    <h2>Welcome</h2> 
    <form action="$ENV{SCRIPT_NAME}" method="GET"> 
    <input type="hidden" name="qnumber" value="$qnumber"> 
    <input type="hidden" name="id" value="$sessionID"/> 
    <input type="hidden" name="request" value="menu"> 
    <input type="submit" value="Main Menu"> 
    </form> 
</body> 
</html> 
PAGE 
} 

################################################################## 
sub menu{ 
    my $sessionID = $formHash{"id"}; 
    my $qnumber = $fromHash{"qnumber"}; 
print <<PAGE; 
<html><head><title>Menu</title></head> 
    <body> 
    <form action="$ENV{SCRIPT_NAME}" method="GET"> 
    <input type="hidden" name="qnumber" value="$qnumber"/> 
    <input type="hidden" name="id" value="$sessionID"/> 
    List the questions.<br> 
    <button type="submit" name="request" value="list">List Questions</button> 
    <br><br> 
    Add a question.<br> 
    <button type="submit" name="request" value="add">Add Question</button> 
    <br><br> 
    </form> 
</body> 
</html> 
PAGE 
} 

################################################################## 
sub add{ 
    my $sessionID = $formHash{"id"}; 
    my $qnumber = $fromHash{"qnumber"}; 
    $sql = "SELECT * from $quiz_table_name"; 
    $qObj = $dbhandle -> prepare($sql); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> fetchall_arrayref(); # Fetch all rows, no need to use them 
    my $number_of_questions = $qObj->rows(); 
    $qObj -> finish(); 

print <<PAGE; 
<html><head><title>Add Question</title></head> 
    <body> 
    There are $number_of_questions in the database now.<br> 
    This will be your $qnumber question this session. 
    <form action="$ENV{SCRIPT_NAME}" method="GET"> 
    <input type="hidden" name="qnumber" value="$qnumber"/> 
    <input type="hidden" name="id" value="$sessionID"/> 
    <input type="hidden" name="request" value="add2"> 
    <br/> 
    Enter the Question.<br> 
    <INPUT TYPE="text" NAME="question" VALUE="Question"><br> 
    Correct Answer.<br> 
    <INPUT TYPE="text" NAME="answer" VALUE="Answer"><br> 
    Choce #1.<br> 
    <INPUT TYPE="text" NAME="choice1" VALUE="1"><br> 
    Choce #2.<br> 
    <INPUT TYPE="text" NAME="choice2" VALUE="2"><br> 
    Choce #3.<br> 
    <INPUT TYPE="text" NAME="choice3" VALUE="3"><br> 
    Choce #4.<br> 
    <INPUT TYPE="text" NAME="choice4" VALUE="4"><br> 
    Choce #5.<br> 
    <INPUT TYPE="text" NAME="choice5" VALUE="5"><br> 
    <br/> 
    <input type="submit" value="Submit"> 
    </form> 
</body> 
</html> 
PAGE 
} 

################################################################## 
sub add2{ 
    my $sessionID = $formHash{"id"}; 
    my $qnumber = $fromHash{"qnumber"}; 
    my $question = $formHash{"question"}; 
    my $answer = $fromHash{"answer"}; 
    my $choice1 = $fromHash{"choice1"}; 
    my $choice2 = $fromHash{"choice2"}; 
    my $choice3 = $fromHash{"choice3"}; 
    my $choice4 = $fromHash{"choice4"}; 
    my $choice5 = $fromHash{"choice5"}; 
    $stateHash{"qnumber"}++; # The next question number. 
    &write_state_db($dbhandle, $state_table_name, $sessionID, %stateHash); 
    $sql = "INSERT INTO $quiz_table_name(question, answer, choice1, choice2, choice3, choice4, choice5) VALUES(?,?,?,?,?,?,?)"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare"); 
    $qObj -> execute($question, $answer, $choice1, $choice2, $choice3, $choice4, $choice5) or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> finish(); 
    $request = menu; 
} 

################################################################## 
sub list { 
    my $sessionID = $formHash{"id"}; 
    my $qnumber = $fromHash{"qnumber"}; 
print <<PAGE; 
    <html><head><title>List Questions</title></head> 
    <body> 
    <h2>List Questions</h2><br/> 

    <style> 
    table, th, td { 
    border: 1px solid black; 
    } 
    th { 
    text-align: left; 
    } 
    </style> 
    <table> 
    <tr><th>Number</th><th>Question</th><th>Answer</th><th>Choice 1</th><th>Choice 2</th><th>Choice 3</th><th>Choice 4</th><th>Choice 5</th></tr> 
PAGE 
    # DEFINE A MySQL QUERY 
    $sql = "SELECT qnumber, question, answer, choice1, choice2, choice3, choice4, choice5 FROM $quiz_table_name"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare"); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    my $arry_ref = $qObj->fetchall_arrayref(); 
    $qObj -> finish(); 
    foreach my $row(@$arry_ref) 
    { 
     my ($qnumber, $question, $answer, $choice1, $choice2, $choice3, $choice4, $choice5) = @$row; 
     print "<tr><th>$qnumber</th><th>$question</th><th>$answer</th><th>$choice1</th><th>$choice2</th><th>$choice3</th><th>$choice4</th><th>$choice5</th></tr>"; 
    } 
    # PRINT THE RESULTS 
    print <<BOTTOM; 
    </table> 

</body> 
</html> 
<form action="$ENV{SCRIPT_NAME}" method="POST"> 
<input type="hidden" name="qnumber" value="$qnumber"/> 
<input type="hidden" name="id" value="$sessionID"/> 
<input type="hidden" name="request" value="menu"> 
<input type="submit" value="Main Menu"> 
    </form> 
</body> 
</html> 
BOTTOM 
} 


################################################################# 
################################################################# 
# end app logic functions 
# begin toolkit functions 
################################################################# 
################################################################# 

################################################################# 
sub write_state_db { 
    my ($dbhandle, $table_name, $sessionID, %states) = @_; 
    ### add the updated last-modified time to the front of the incoming state hash 
    my $currtime = time; 
    my @updates = ("last_modified = '$currtime'"); 
    foreach $key (keys %states){ 
    push @updates, "$key = '$states{$key}'"; 
    } 

    ### update the state record 
    $sql = "UPDATE $table_name set " . join(",", @updates) . " WHERE id = '$sessionID'"; 
    $qObj = $dbhandle -> prepare($sql); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> finish(); 
} 

################################################################# 
sub read_state_db { 
    my ($dbhandle, $table_name, $sessionID, $time_out, 
     $time_out_function, $time_out_message) = @_; ### $time_out is in days 

    ### read the desired state record into the query object 
    $sql = "SELECT * FROM $table_name WHERE ID = '$sessionID'"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare."); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    my $rowhashref = $qObj->fetchrow_hashref(); 
    $qObj -> finish(); 

    if(! $rowhashref) { ### $rowhashref is an empty reference, which means no such id... 
    &errorPage("No such session."); 
    } 
    my %hash = %$rowhashref; ### get the actual hash containing the state record 
    ### timeout test 
    if(($time_out > 0) && ($hash{"last_modified"} < time - $time_out*24*60*60)){ 
    ### timed out... 
    if($time_out_function) { 
     &$time_out_function($time_out_message); 
      exit; 
    } 
     else{ 
     &errorPage("Your session has timed out"); 
    } 
    } 
    ### touch the record 
    $sql = "UPDATE $table_name SET last_modified = " . time . " WHERE ID = '$sessionID'"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare."); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> finish(); 
    ### only need to return the actual state data 
    delete $hash{"id"}; 
    delete $hash{"last_modified"}; 
    return %hash;   
} 

################################################################# 
sub get_long_id_db { 
    my ($dbhandle, $table_name, $cache_limit, $file_life_span) = @_; 

    ### count number of sessions 
    my $sql = "SELECT id FROM $table_name"; 
    my $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare."); 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> fetchall_arrayref(); 

    if($qObj->rows() >= $cache_limit) {  ### Need to police table? 
    my $expiredtime = int(time - $file_life_span*24*60*60); ### in seconds ### 
    $qObj -> finish(); 

    ### police the table 
    $sql = "DELETE FROM $table_name WHERE last_modified < $expiredtime"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare.");; 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> finish(); 

    ### count number of sessions again 
    $sql = "SELECT id FROM $table_name";   
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare.");; 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 
    $qObj -> fetchall_arrayref(); 

    if($qObj->rows() >= $cache_limit) { ### still over limit? 
     # should generate e-mail message to warn administrator 
     &errorPage("Site busy. Please try again later."); 
    } 
    } 
    $qObj -> finish(); 

    my $id = &generate_random_string(32); 
    my $currtime = time; 

    ### create new state record 
    $sql = "INSERT INTO $table_name (id, last_modified) values ('$id', $currtime)"; 
    $qObj = $dbhandle -> prepare($sql) or &errorPage("Can't prepare.");; 
    $qObj -> execute() or &errorPage("Can't execute " . $qObj->errstr()); 

    return $id; 
} 

################################################################# 
sub generate_random_string { 
    my $n = $_[0]; 
    my $result = ""; 
    my @chars = (0..9, 'a'..'z', 'A'..'Z'); 
    my $which; 
    for($i = 1 ; $i <= $n ; $i++) { 
    $which=int rand 62; 
    $result = $result . $chars[$which]; 
    } 
    return $result; 
} 

################################################################# 
sub errorPage { 
my $message = $_[0]; # the incoming parameter, store in localized variable 
print<<ALL; 
<html> 
<head> 
    <title>Error encountered</title> 
</head> 
<body> 
    <h1>Error Encountered</h1> 
    <h3>$message</h3> 
    Please try again, or report the problem to the webmaster. 
</body> 
</html> 
ALL 
exit; 
} 
+9

'strict'、' warnings'、 'diagnostics'プラグマを有効にします。彼らが文句を言うことを修正してください。 [デバッガ](http://perldoc.perl.org/perldebug.html)または適切に配置されたプリントステートメントを使用して、コードの挿入箇所で何が起こっているのかを知ることができます期待している)。問題が見つかった場合は、状況が正しく見えるようになるまで後方に向かって作業し、再び間違って見えるように転送します。これらの2つの州の間の領域はあなたのバグの場所です。 –

+6

CGIを*行う必要がある場合は、[CGIモジュールを使用してください](http://perldoc.perl.org/CGI.html)。このコードは、1990年代初めのスタイルです。 – tadman

答えて

5

質問はデータベースにそれを作る唯一のものであるという理由は、あなたが存在しない%fromHashから、他のすべての値を取得しているということです。 ではなく、%formHashにデータを入れます。

これは、strictプラグマが捕まえる(多くの!)タイプの問題の1つです。 use strictおよびuse warningsでありません。はコメントアウトしてください。 これまであなたがPerlを学んでいるとき、少し難しいように思えるかもしれませんが、実際にはあなたの親友です。経験豊富なPerlプログラマであっても、私がに非常にまれにしか書かれていない正確な理由を知っている非常にまれな場合を除き、私は常にを有効にしています。また

  • &であなたのサブ呼び出しを接頭しないでください。それは時代遅れのPerl 4-ismです。 Perl 5では、おそらく分からない副作用があります。
  • 既にCGIを使用している場合は、手作業で行うのではなく、フォーム/パラメータデコード(paramメソッド)を処理させます。実際のプロダクションコードでは、CGIの代わりにDancerやMojoliciousなどの適切なWebフレームワークを使用すると言いますが、CGIの選択はあなたの割り当てによって決定されたと仮定します)。
  • このコードSQLインジェクション攻撃に対して脆弱です。これは通常、私が大事にしていることですが、これは言語を学ぶための入門的な課題であるため、Webプログラミングをやり続けるかどうかを調べるためのものとして言及します。このような攻撃からPerlコードを保護する方法の例を含め、SQLインジェクションの詳細については、Bobby Tablesを参照してください。
10

これは、あなたが学校やカレッジで学んでいることを意味するので、これは「課題」と言われて大変心配しています。私はこのコードのどれがあなたの教師から与えられたのか、またインターネットから日付情報を読みとることからどれくらい一緒に畳んだのか分かりませんが、これはPerlで少なくとも15のWebアプリケーションを書くスタイルです年を切った

  • 最近では、CGIを使用してPerlでWebアプリケーションを作成していません。最新のPerl WebアプリケーションはPSGI and Plackに基づいています。
  • CGIを使用してWebアプリケーションを作成することを主張している場合、CGI moduleは90年代半ば以降使用されており、より簡単に使用できます。特に、手書きやバグのフォーム解析コードではなく、param()関数を使用する必要があります。
  • 生のHTMLをPerlプログラムに入れることをお勧めして以来、15年が経ちました。代わりにtemplating engineを使用してください。

ウェブ特有のものの外には、古いソースから学習していることを示す別のものがあります。サブルーチンコールの

  • アンパサンドはPerl 5のは、1994年にリリースされたので、必要に応じて、彼らはほとんどの人がほとんどの時間をそれらを使用するべきではありません意味「興味深い」効果のカップルを持っていません。
  • 最近のほとんどのデータベースアクセスは、使用している未加工のDBIの上にラッパーであるDBIx::Classを使用して書かれています。あなたのコードに含まれているSQLインジェクションの脆弱性からあなたを保護します。

最後に、あなたのコードにuse strictをコメントアウトしていないと、あなた自身が問題を見つけたでしょう。それはあなたの変数を宣言することを強要し、%formHash%fromHashと間違って入力しているという事実が(多くの)間違いの中にあったはずです。

あなたがここで学んでいることは、このコースが役に立たないことに非常に近い、職場であなたにとって有用なPerlからは遠いです。あなたの大学の誰かがこのコースの質を向上させることに興味があるなら、私はできるだけお手伝いします。

+0

ここでは、いくつかのテクノロジー、特にDBIx :: Classを誇張していると思います。 SQLインジェクションからあなたを守ることができるのはDBIです(ただし、あなたが賢明に使っている場合のみ)。私が心配しているのは、それほどよく知らない人に誤った方向に向かう、敵対的かつむしろ役に立たない怒りです。それはあなたが怒っているポスターではありません。 –

+0

@briandfoy:私はDBIがSQLインジェクションからあなたを守ることができますが、あなたはそれを正しく使う方法を知る必要があることに同意します。しかし、DBICを使用するデフォルトの方法は、あなたがそれを考えなくてもあなたを保護します。私の答えを読んで、私は本当に怒りを見ません。私は彼らが何を学んでいるのか心配しており、コースを改善するのに役立つと言っています。私はOPが私が彼に怒っているとは思わないと本当に願っています。それは真実から遠いです。 –

関連する問題