2

私はこのコードでテストしています:

<?php
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');

if(filter_has_var(INPUT_POST, 'submit')) {

  $r = $db->query('SELECT * FROM test WHERE value="'.$_POST['value'].'"');
  $n = $r->rowCount();

  for ($i=0; $i<=10000000; $i++) {
    // do nothing
  }

  if  (!$n) {
    $db->query('INSERT INTO test (id, value) VALUES (NULL, "'.$_POST['value'].'")');
  }

}
?>

<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
  <input type="text" name="value" value="">
  <input type="submit" name="submit" value="Submit">
</form>

上記のフォームをsafariでテストする場合、送信ボタンをすばやくクリックすることで、同じ値をデータベースに複数回送信できます。

しかし、このコードでテストすると、次のようになります。

<?php
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');

if(filter_has_var(INPUT_POST, 'submit')) {

  for ($i=0; $i<=10000000; $i++) {
    // do nothing
  }

  $r = $db->query('SELECT * FROM test WHERE value="'.$_POST['value'].'"');
  $n = $r->rowCount();

  if  (!$n) {
    $db->query('INSERT INTO test (id, value) VALUES (NULL, "'.$_POST['value'].'")');
  }

}
?>

条件付きで機能し、送信ボタンをクリックしても同じ値を複数回送信できません。

最初のコードスニペットでデータベースの重複挿入が発生しないようにして、2番目のスニペットと同じように動作するようにする信頼できる方法はありますか?

4

1 に答える 1

2

通常、クライアント側のonsubmitハンドラーは偶発的な迅速な送信を防ぐのに役立ちますが、私は通常、_SESSION変数を使用するサーバー側のソリューションを選択します。配列のハッシュを作成し、$_POSTそれをセッション変数として保存してから、次に送信さ_POSTれたものをハッシュバージョンと比較します。

session_start();
//if this is the first time they've posted, just create a placeholder session var
if (!isset($_SESSION['repost_hash'])){$_SESSION['repost_hash']="";}

//if the post array is a duplicate, nullify the submission
if (isset($_POST) && md5(serialize($_POST)) == $_SESSION['repost_hash']){ 
   unset($_POST);
} else { //otherwise, if this is new data, update the stored hash
   $_SESSION['repost_hash'] = md5(serialize($_POST));
}
...

繰り返し送信を短時間だけ停止したい場合は、2番目の$_SESSION変数に最後のハッシュの時間を格納させることもできるので、1〜2秒後に期限切れにすることができます。

于 2012-12-05T03:12:22.460 に答える