ooXei1sh
ooXei1sh

Reputation: 3559

php mysql prevent duplicate inserts from rapid form submits

I'm testing with this code:

<?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>

When testing the above form in safari I am able to submit the same value into my database multiple times by rapidly clicking the submit button.

But, when I test with this code:

<?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'].'")');
  }

}
?>

The conditional works and I'm unable to submit the same value multiple times no matter how fast I click the submit button.

Is there a reliable way to prevent duplicate database inserts from occurring with the first code snippet so that it behaves just like the second snippet?

Upvotes: 2

Views: 1435

Answers (1)

Ben D
Ben D

Reputation: 14509

Generally a client side onsubmit handler can help stop accidental rapid-submissions, but I usually opt for a server side solution using _SESSION variables. Just create a hash of the $_POST array, store it as a session variable, and then compare the next submitted _POST to the hashed version:

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));
}
...

If you only want to stop repeat-submissions for a short period of time, you can also have a second $_SESSION variable store the time of the last hash, so you can expire it after a second or two.

Upvotes: 3

Related Questions