Reputation: 15269
I got a POST
form, and it does send the data to the same file, and if use hit the back button in his browser, he can easily just re-send the data, and it'll be still read.
Is there any way to avoid such behaviour?
Upvotes: 5
Views: 9302
Reputation: 32085
There are two general approaches.
First is the post-redirect-get
pattern where the user fills out a form on signup.php
which gets POST
ed to submit.php
which on successful completion sends back a REDIRECT
to thanks.php
. The browser sees the redirect response and issues a GET for thanks.php
. This works because without the redirect, hitting refresh would reload submit.php
causing a re-post form data warning and the POST
request to be double issued. The redirect solves this problem.
signup.php
-----------
...
<input type="text" name="email">
...
submit.php
----------
...
if ($_POST) {
// process data
header('Location: thanks.php');
}
...
thanks.php
----------
...
Thanks
...
The second approach is to embed a nonce
key in the form. This approach has the added benefit of preventing CSRF attacks as well. The approach here is to inject a hidden guid in your form:
<input type="nonce" value="<?= uniqid(); ?>">
The server will need to keep track of all nonce keys issues (in a database or something) and when it receives a form, it will process the form and delete the nonce key from the database. If the user resubmits the form a second time, the nonce key won't exist and the server can handle that by ignoring or issuing a warning.
Upvotes: 4
Reputation: 442
In First Page use one session variable and assign the value to 1. Example:
<form name="frm1" method="post">
<?php $_SESSION['resend_chk']=1; ?>
<input type="text" name="a" />
<input type="submit" name="submit">
</form>
In second page:
if(isset($_REQUEST['submit'])
{
if($_SESSION['resend_chk']==1)
{
insert to db OR and any transaction
$_SESSION['resend_chk']=0;
}
}
It will insert once or the transaction will happen once in db and the value of session variable will change, next time when we try to resend the data it will not do any transaction because the value of session variable is already changed.
Upvotes: 0
Reputation: 11
That works for me. I use smarty, but it can be done without smarty too. It's only an idea. Modify it as you wish.
The HTML form:
<form action="submit_file.php" method="POST">
<input type="hidden" name="submit_edit" value="1">
<input type="text" name="data"/>
</form>
The php in globals.php
if (count($_POST) > 0) {
if (isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1'
&& time() - $_SESSION['last_request_time'] < 100
&& count($_SESSION['last_request']) > 0
&& serialize($_SESSION['last_request']) == serialize($_POST)) {
$oSmarty->assign('display_time_alert', '1');
unset($_POST['submit_edit']);
unset($_REQUEST['submit_edit']);
} else {
$_SESSION['last_request_time'] = time();
$_SESSION['last_request'] = $_POST;
}
}
And this in head.tpl
{literal}
<script>
function showTimeAlert(){
alert('{/literal}{tr var="Cannot send the same request twice"}{literal}');
}
{/literal}
{if isset($display_time_alert) AND $display_time_alert eq '1'}
showTimeAlert();
{/if}
{literal}
</script>
{/literal}
Finaly the submit_file.php
require_once("globals.php");
if(isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1')){
//record data
}
$oSmarty->dysplay(some.tpl);//in some.tpl is included head.tpl
Upvotes: 1
Reputation: 18833
The link Levi sent will answer for you. But in case you want an alternative, here is how I do it...
User posts to a class, like yours. same file. In the beginning of the class I do post processing. For this example I will make it very simple...
<?php
session_start();
//set form vars ahead of time so you can pre-populate the value attr on post
$form = array(
'name' => '',
'email' => ''
);
if(!empty($_POST))
{
//do some kind of validation...
$errors = array();
if(trim($_POST['name']) == '')
$errors[] = 'Please enter your name';
if(empty($errors))
{
$_SESSION['message'] = 'Thank you for participating';
header('location: /form.php'); // same file
exit;
}
else
{
// set the form vars to the post vars so you don't lose the user's input
$form['name'] = $_POST['name'];
$form['email'] = $_POST['email'];
$message = '<span style="color:red">';
foreach($errors AS $error)
{
$message .= $error."<br />";
}
$message .= '</span>';
$_SESSION['message'] = $message;
}
}
if(isset($_SESSION['message']))
{
echo $_SESSION['message'];
unset($_SESSION['message']);
}
?>
<form id="some_form" action="" method="post">
<fieldset>
<label for="name">Name</label> <input type="text" name="name" value="<?php echo $form['name']; ?>" />
<br /><br />
<label for="email">Email</label> <input type="text" name="email" value="<?php echo $form['email']; ?>" />
<br /><br />
<input type="submit" name="submit" value="Submit" />
</fieldset>
</form>
Now you can refresh over and over and not submit the form twice.
Edited to show further example. Obviously your validation and error handling should be a bit more sophisticated than this, but this should get you in the right direction.
Upvotes: 3
Reputation: 1957
When you send the form, push a random number into a $_SESSION['stopdupe']
value, and into a hidden field.
When receiving the form for processing:
$_SESSION['stopdupe']
exists, and matches the hidden field's value. (If not, ignore the post)$_SESSION['stopdupe']
This way, if a user presses the submit button twice, the second request will not be processed.
Another helpful trick is to use the onSubmit
javascript event on the form to disable the button, so the user can't easily submit it multiple times.
Upvotes: 1
Reputation: 9121
You cannot 100% prevent this if the user wants to do it, however to avoid this happening by accident, look into Post/Redirect/Get.
Upvotes: 3