Form inserting twice in the bank (F5)

Asked

Viewed 6,297 times

14

I have a great form that update and insert at various points when submitted. However, if in the time interval of this process the user presses F5, he duplicates the insertion record the number of times he presses the key.

Utilise: PHP with CodeIgniter, MySQL with Lumine.

  • Just after you submit the form and press F5, does it duplicate the data? If that’s the case, it’s not about your code, it’s about the native process of browsers submitting a form.

  • 1

    You could show us the executed SQL code when submitting the form?

  • I understand Cesar Miguel. At any time of the processing, if I press F5, the data will duplicate... :\

  • Unfortunately not Paul. But it would be an Insert into common SQL.

  • 1

    Finished operation? was successfully performed? redirect the user to a successful page and clear SESSION and CACHE if you use them

  • try adding the autocomplete="off" property to the < form element >

Show 1 more comment

4 answers

10


By default, the F5 updates your page, and if you just submit form information, it will normally ask for a confirmation:

Captura de Tela

It is normal that if you click resubmit the same information is sent again, it is a native behavior of browsers.

However, you should check if there is a record with the same PrimaryKey (normally the ID) and if there is you should give UPDATE instead of INSERT.

  • I understood Paulo. But in this case, how to perform a check of this in a huge system? There is something that can be done in the Framework?

  • 1

    SQL is SQL, PHP is PHP. They are different things, but you can do the following, before anything, with the form data in hand, make a select in the bank with the id that the form is sending, check if the ID already exists, if it already exists, of UPDATE, if no, use INSERT, but you must (when loading the form) use a Generator or make a max() in the id’s to know which one is bigger, and add +1, so that whenever the user opens a new form page is creating a new record instead of changing.

  • Beauty Paul... In fact needs to streamline the process... I managed to realize Bruno’s suggestion straight in my Framework. Everything ok. Thank you very much! :-)

  • Thank you so much @Zuul ! Really the image is very useful!

6

I suggest you use a token and redirect users to another page (302) after processing the form. This way the same data will not be sent multiple times when pressing F5.

<?php
if($_SERVER['REQUEST_METHOD'] === 'POST' &&
   isset($_POST['field1']) && isset($_POST['token']) &&
   $_POST['token'] === $_SESSION['form_token']) {
   // Insert ...
   unset($_SESSION['form_token']);
   header('X-PHP-Response-Code: 302');
   header('Location: /index.php');
   return;
}
$token = bin2hex(openssl_random_pseudo_bytes(32));
$_SESSION['form_token'] = $token;
?>
<form method="POST">
  <input type="text" name="field1">
  <input type="hidden" name="token" value="<?php echo $token ?>">
</form>

5

As a developer, you should always think of the worst possible scenario and always take into account the inexperience (to be nice) of users.

You may have some JS that interrupts some repeat action of that request (F5, for example), but you should also consider that user who actually has some knowledge in the subject matter and for example navigates with minimum JS enabled (like me) which would potentially nullify your alleged "protection".

And this is where the server-side check comes in. You have two options and both can be implemented in parallel:

  • Accept multiple inserts, but allow the user to view transactions made and, if applicable, remove some duplicity on their own, as in a Shopping Cart that has an overview of orders before making the purchase.

  • Distinguish if a request is a resubmission or a reload by storing in a Session a hash of all form information and only enter in fact if it is really a submission.

This second alternative is very simple, just store in the session an MD5 hash of everything you have in the form:

<?php

session_start();

if( $_SERVER['REQUEST_METHOD']=='POST' ) {

    $hash = md5( implode( $_POST ) );

    if( isset( $_SESSION['hash'] ) && $_SESSION['hash'] == $hash ) {

        // Refresh! Não faz nada ou re-exibe o formulário preenchido

    } else {

        $_SESSION['hash']  = $request;

        // Submissão legítima! Insere ;)
    }
}

?>

<form action="" method="post">

    <input type="text" name="field" value="value" />
    <input type="submit" name="send" value="send" />
</form>
  • 1

    Thank you very much Bruno. I did a little different but under this same concept. Thanks! :-)

3

One option is you redirect the user to another page other than the one you use to "save" the form, you can do this with header.

header("Location: http://www.seusite.com.br/cadastroEfetuado.php");

This new page will not be able to resend the form again.

As a hint: create a file of the type salvaForm.php this file only processes the form and send to another page.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.