2015-09-20 212 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);