41
...
?>
<input type="hidden" name="unique_id" value="<?php echo $unique_id; ?>">
</form>
Then, when processing, look for this ID:
$unique_id = $dbh->quote($_GET['unique_id']);
$sth = $dbh->query("SELECT * FROM database WHERE unique_id = $unique_id");
if ($sth->numRows( )) {
// already submitted, throw an error
} else {
// act upon the data
}
9.6.3 Discussion
For a variety of reasons, users often resubmit a form. Usually it's a slip-of-the-mouse: double-
clicking the Submit button. They may hit their web browser's Back button to edit or recheck
information, but then they re-hit Submit instead of Forward. It can be intentional: they're
trying to stuff the ballot box for an online survey or sweepstakes. Our Solution prevents the
nonmalicious attack and can slow down the malicious user. It won't, however, eliminate all
fraudulent use: more complicated work is required for that.
The Solution does prevent your database from being cluttered with too many copies of the
same record. By generating a token that's placed in the form, you can uniquely identify that
specific instance of the form, even when cookies is disabled. When you then save the form's
data, you store the token alongside it. That allows you to easily check if you've already seen
this form and record the database it belongs to.
Start by adding an extra column to your database table —
unique_id
— to hold the
identifier. When you insert data for a record, add the ID also. For example:
$username = $dbh->quote($_GET['username']);
$unique_id = $dbh->quote($_GET['unique_id']);
$sth = $dbh->query("INSERT INTO members ( username, unique_id)
VALUES ($username, $unique_id)");
By associating the exact row in the database with the form, you can more easily handle a
resubmission. There's no correct answer here; it depends on your situation. In some cases,
you'll want to ignore the second posting all together. In others, you'll want to check if the
record has changed, and, if so, present the user with a dialog box asking if they want to
update the record with the new information or keep the old data. Finally, to reflect the second
form submission, you could update the record silently, and the user never learns of a problem.
All these possibilities should be considered given the specifics of the interaction. Our opinion is
there's no reason to allow the deficits of HTTP to dictate the user experience. So, while the
third choice, silently updating the record, isn't what normally happens, in many ways this is