Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent user re-sending the form data?

Tags:

forms

php

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?

like image 869
Cyclone Avatar asked Oct 25 '11 23:10

Cyclone


2 Answers

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.

like image 87
aleemb Avatar answered Oct 27 '22 23:10

aleemb


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.

like image 41
Kai Qing Avatar answered Oct 28 '22 00:10

Kai Qing