2015-09-20 208 views
1

我運行一個網站的青少年體育項目,具有日程安排,積分榜,並使用該操作存儲在MySQL數據庫中數據的簡單的PHP腳本成績報告。防止意外多PHP表單提交

一個玩遊戲後,冠軍教練將訪問成績報告形式,針對特定遊戲,輸入信息,並點擊提交更新相應的時間表和積分榜。然後他們會自動重定向到他們來自的時間表頁面。

然而,一個賽季中,教練會無意中重複提交比分(有時會創造多達三或四個實例),這不會影響在賽程上發佈的結果,但會將數據放到排名榜上重擊。我不確定這是如何完成的,但我試圖解決這個問題。

我一直在這裏讀了儘可能和網絡,並認爲我需要實現某種形式的代幣系統報告的腳本,但我不知道該如何準確地編寫代碼?任何建議在這裏將非常感激。這裏是腳本本身:

<?php 

// Connect to the database: 
require ('../mysqli_connect.php'); 

// Validate the school: 
if (empty($_POST['school'])) { 
echo "You forgot to enter your school.<br>"; 
$validate = 'false'; 
} elseif ($_POST['school'] != $_POST['away_team'] && $_POST['school'] != $_POST['home_team']) { 
echo "Your school does not match one of the two on file for this game.<br>"; 
$validate = 'false'; 
} else { 
$school = mysqli_real_escape_string($db, trim($_POST['school'])); 
$validate = 'true'; 
} 

// Validate the password: 
if (empty($_POST['pass'])) { 
echo "You forgot to enter your password.<br>"; 
$validate = 'false'; 
} else { 
$pass = mysqli_real_escape_string($db, trim($_POST['pass'])); 
$validate = 'true'; 
} 

// Validate the away score: 
if (!isset($_POST['away_score'])) { 
echo "You forgot to enter the away score.<br>"; 
$validate = 'false'; 
} elseif (!is_numeric($_POST['away_score'])) { 
echo "You entered an invalid score for the away team.<br>"; 
$validate = 'false'; 
} else { 
$away_score_confirm = mysqli_real_escape_string($db, trim($_POST['away_score'])); 
$validate = 'true'; 
} 

// Validate the home score: 
if (!isset($_POST['away_score'])) { 
echo "You forgot to enter the home score.<br>"; 
$validate = 'false'; 
} elseif (!is_numeric($_POST['$home_score']) && $_POST['$home_score'] < 0) { 
echo "You entered an invalid score for the home team.<br>"; 
$validate = 'false'; 
} else { 
$home_score_confirm = mysqli_real_escape_string($db, trim($_POST['home_score'])); 
$validate = 'true'; 
} 

// Determine the winner and loser, and set variables: 
if ($_POST['away_score'] > $_POST['home_score']) { 
$winner = mysqli_real_escape_string($db, trim($_POST['away_team'])); 
$winner_score = mysqli_real_escape_string($db, trim($_POST['away_score'])); 
$loser = mysqli_real_escape_string($db, trim($_POST['home_team'])); 
$loser_score = mysqli_real_escape_string($db, trim($_POST['home_score'])); 
$tie = 'no'; 
} else if ($_POST['away_score'] < $_POST['home_score']) { 
$winner = mysqli_real_escape_string($db, trim($_POST['home_team'])); 
$winner_score = mysqli_real_escape_string($db, trim($_POST['home_score'])); 
$loser = mysqli_real_escape_string($db, trim($_POST['away_team'])); 
$loser_score = mysqli_real_escape_string($db, trim($_POST['away_score'])); 
$tie = 'no'; 
} else if ($_POST['away_score'] == $_POST['home_score']) { 
$tie = 'yes'; 
$tie1 = mysqli_real_escape_string($db, trim($_POST['away_team'])); 
$tie2 = mysqli_real_escape_string($db, trim($_POST['home_team'])); 
$tie_score = mysqli_real_escape_string($db, trim($_POST['away_score'])); 
} 

// Declare remaining hidden inputs as variables: 
$league = $_POST['league']; 
$table = mysqli_real_escape_string($db, $_POST['table']); 
$game_id = mysqli_real_escape_string($db, $_POST['game_id']); 
$sport = $_POST['sport']; 

// Declare remaining hidden inputs as variables: 
$standings_league = $table . "_standings"; 

// If all conditions are met, process the form: 
if ($validate != 'false') { 
$q1 = "SELECT school_id FROM user_schools WHERE (school_name='$school' AND pass='$pass')"; 
$r1 = mysqli_query($db, $q1); 
$num = mysqli_num_rows($r1); 
if ($num == 1) { 
    // Get the game ID: 
    $q2 = "SELECT $game_id FROM $table"; 
    $r2 = mysqli_query($db, $q2); 
    // Get the row for the game ID: 
    $row = mysqli_fetch_array($r2, MYSQLI_NUM); 
    // Perform an UPDATE query to modify the game scores: 
    $q3 = "UPDATE $table SET home_score='$home_score_confirm', away_score='$away_score_confirm' WHERE game_id=$row[0]";   
    $r3 = mysqli_query($db, $q3); 
    if (mysqli_affected_rows($db) == 1) { 
     $confirm = 'true'; 
    } else { 
     $confirm = 'false'; 
    } 

    // Update the winning team in the standings: 
    $q4 = "SELECT school_id FROM $standings_league WHERE school_name='$winner'"; 
    $r4 = mysqli_query($db, $q4); 
    // Get the row for the school: 
    $row2 = mysqli_fetch_array($r4, MYSQLI_NUM); 
    $q5 = "UPDATE $standings_league SET games=games + 1, win=win + 1, pts_for=pts_for + '$winner_score', pts_against=pts_against + '$loser_score' WHERE school_id=$row2[0]"; 
    $r5 = mysqli_query($db, $q5); 
    $q6 = "UPDATE $standings_league SET pct=(win/games), avg_for=(pts_for/games), avg_against=(pts_against/games) WHERE school_id=$row2[0]"; 
    $r6 = mysqli_query($db, $q6);   

    // Update the losing team in the standings: 
    $q7 = "SELECT school_id FROM $standings_league WHERE school_name='$loser'"; 
    $r7 = mysqli_query($db, $q7); 
    // Get the row for the school: 
    $row3 = mysqli_fetch_array($r7, MYSQLI_NUM); 
    $q8 = "UPDATE $standings_league SET games=games + 1, loss=loss+1, pts_for=pts_for + '$loser_score', pts_against=pts_against + '$winner_score' WHERE school_id=$row3[0]"; 
    $r8 = mysqli_query($db, $q8); 
    $q9 = "UPDATE $standings_league SET pct=(win/games), avg_for=(pts_for/games), avg_against=(pts_against/games) WHERE school_id=$row3[0]"; 
    $r9 = mysqli_query($db, $q9); 

    if ($confirm != 'false') { 
     header('Location: schedules_' . $sport . '_' . $league . '.html?league=' . $league .'&table=' . $table); 
    } else { 
     echo "The scores could not be reported due to a system error. Apologies for the inconvenience. If this problem continues, please contact us directly."; 
    } 

} else { 
    echo "Your school and password combination do not match those on file for this game."; 
}  
} 

mysqli_close($db); 

?> 

回答

2

我的猜測是,這些教練只需單擊提交按鈕多次,而窗體正在等待服務器的響應。你可以首次點擊後,用JS禁用(或隱藏)按鈕:

var button = document.querySelector('input[type=submit]'); // Use whatever selector is appropriate here 

button.addEventListener('click', function(ev) { 
    if (!button.classList.contains('submitting')) { // If this is our first click... 
     button.className += ' submitting'; 
    } else { // Otherwise prevent submission 
     ev.preventDefault(); 
    } 
}); 

如果您有jQuery的提供給你,你也可以只處理通過JS整個提交過程並阻止它。

你應該意識到呈現某種反饋到屏幕上,讓用戶知道提交正在進行中的,那將有助於減輕一些按鈕搗碎爲好。

2

一個解決方案是爲表單添加一個唯一值,並在其提交時將值添加到會話中。如果他們點擊提交按鈕一次(可能發生的事情)更多,它只會接受一個submition

例子:

<form> 

    <input type="hidden" name="submit_id" value="<?php echo mt_rand(); ?>"> 

    // rest of the form 

</form> 

php文件recieving:

<?php 

    session_start(); 

    if (isset($_POST['submit_id'])) { 

    if (!isset($_SESSION['submit_id'])) { 
     $_SESSION['submit_id'] = array(); 
    } 

    if (!in_array($_POST['submit_id'], $_SESSION['submit_id'])) { 

     // validate posted values 

     // when data is valid, register form as submitted 
     $_SESSION['submit_id'][] = $_POST['submit_id']; 

     // add the submitted form data to database 

    } 
    else { 
     echo 'Your data has already been submitted'; 
    } 

    } 
2

我不想閱讀你的代碼,所以我會建議一個策略。

我同意@relic。你的教練可能是雙擊按鈕。

如果可以假設在同一秒不同的用戶決不會屈服於兩種形式,那麼你就可以「過濾」你的表只接受一個對於任何給定的第二項。爲(新)秒列創建索引,並使其唯一。如果一個條目已經在那一秒退出,這將防止將行插入到該表中。

如果這會導致衝突,你可以引入強制每個條目是在表中的其他字段的組合唯一的限制。這稱爲複合鍵(SQL)。您制定了類似於此遊戲和用戶的方式,只能有一個得分註冊。

的MySQL:

create table scores (game_id int, user_id int, score int); 
alter table scores add unique index uniq_gus (game_id, user_id, score); 
insert into scores (game_id, user_id, score) values (1, 1, 10); 
insert into scores (game_id, user_id, score) values (1, 1, 10); 
ERROR 1062 (23000): Duplicate entry '1-1-10' for key 'uniq_gus' 

此外,您可能希望避免重複提交(假設的jQuery):

(function($){ 

var btn = $('button[type="submit"]'); 

btn.click(function(event){ 
    event.preventDefault(); 
    btn.attr('disabled','disabled'); 
    $.ajax({ 
     url: 'http://foo.bar/form-endpoint.php', 
     success: function (data, status, xhr) { 
      btn.removeAttr('disabled'); 
     }, 
    }) 
}) 

})(jQuery);