Reputation: 3559
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
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