Cyclone
Cyclone

Reputation: 15269

How to prevent user re-sending the form data?

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

Answers (6)

aleemb
aleemb

Reputation: 32085

There are two general approaches.

POST-REDIRECT-GET

First is the post-redirect-get pattern where the user fills out a form on signup.php which gets POSTed 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
...

NONCE

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

Chittaranjan Sethi
Chittaranjan Sethi

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

Iliya Kolev
Iliya Kolev

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

Kai Qing
Kai Qing

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

MrTrick
MrTrick

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:

  1. Check that $_SESSION['stopdupe'] exists, and matches the hidden field's value. (If not, ignore the post)
  2. Unset $_SESSION['stopdupe']
  3. Process the form as normal.

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

middus
middus

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

Related Questions