読む前の注意事項:
- コードがそれほど素晴らしいものではないことは承知しています。私の古い作品にコメントしないでください;)
- mysql_query が非推奨であることは承知しています。現時点での更新は、この質問の範囲内ではありません
質問の背景
今日、古い Web サイトから興味深いバグ レポートを受け取りました。このバグが発生するとは予想していなかったので、非常に心配しています。
ページはシンプルです。元のロードでは、データベースへの mysql クエリをループした後にテーブルが表示されます。これらの各行には、次のリンクが表示されます。
url.com/items.php?use=XXX&confirm=0
XXXitems table
は、データベース内の項目の ID に関連しています。confirm=0 には次のコードがあります。
if(isset($_GET['use'])){
$id=@mysql_real_escape_string($_GET['use']);
if(isset($_GET['confirm'])){
$confirm=@mysql_real_escape_string($_GET['confirm']);
if($confirm==0){
// show a confirm button of YES / NO for them
// to click which has 1 for confirm
ユーザーは [はい] をクリックすると、次の場所に転送されます。
url.com/items.php?use=XXX&confirm=1
コードelse
は、次のチェックを行う上記のコードから に移動します。
if($id<1){
echo "<p class='error-message'>An error has occurred.</p>";
print "<p class='center'><a href='http://www.url.com/items.php'>[Back]</a></p>";
include("inc/ftr.php");
exit();
}
if(empty($id)){
echo "<p class='error-message'>An error has occurred.</p>";
print "<p class='center'><a href='http://www.url.com/items.php'>[Back]</a></p>";
include("inc/ftr.php");
exit();
}
$quantity = 0;
$result=@mysql_query("SELECT * FROM inventory WHERE item_id=$id AND u_id=$user_id");
$num_rows=@mysql_num_rows($result);
$r=@mysql_fetch_array($result);
$quantity=$r['quantity'];
if($num_rows==0){
echo "<p class='error-message'>You do not own any of these.</p>";
print "<p class='center'><a href='http://www.url.com/items.php'>[Back]</a></p>";
include("inc/ftr.php");
exit();
}
if($quantity<1){
echo "<p class='error-message'>You don't have any of these left!</p>";
print "<p class='center'><a href='http://www.url.com/items.php'>[Back]</a></p>";
include("inc/ftr.php");
exit();
}
$result=@mysql_query("SELECT * FROM items WHERE id=$id");
$r=@mysql_fetch_array($result);
$type=$r['type'];
$item_name=$r['item_name'];
上記は、関連するチェックを実行して ID が存在することを確認し、データベースにクエリを実行して在庫から現在の数量を取得し、0 を下回っていないことを確認します。0 を下回っている場合は、その時点でページをブロックします。
この後のコードは、データベースからアイテムの数量を削除し、アイテムの「効果」を実装します。更新が実行されると仮定しましょう。
問題:
私がここで抱えている実際の問題は、ユーザーがページを複数回更新すると、実際にはupdate
クエリを実行できるが、実際には数量のチェックをスキップできることです。更新クエリは何度も実行されますが、エラー メッセージがないため、数量のチェックは一度しか実行されません。今日の例は、インベントリに3 つのアイテムがあり、f5 を約 100 回押したときです。エラーメッセージが表示されることなく、クエリの更新を16回実行することができました。数秒待ってからもう一度 f5 キーを押すと、それらのアイテムがないというエラー メッセージが表示されます。
コーディングに時間を無駄にしたくないので、次の解決策はオプションではありません。
- すべてのクエリが処理される前に複数の送信を防ぐために ajax 呼び出しを作成します。
- MVC 構造を実装し、複数の送信を防ぐ別のページにユーザーをリダイレクトする
誰かがこのバグの理由を (関連する読み物で) 説明したり、それを解決するための解決策を提供したりできれば、それは素晴らしいことです! ありがとう!