23

How to prevent multiple form submission on multiple clicks in PHP

Marcel
  • 231
  • 1
  • 2
  • 3
  • 1
    Since question is about server-side behavior (PHP), I'd recommend to look at the following question: http://stackoverflow.com/questions/218907/how-to-handle-multiple-submissions-server-side – Kel Jan 06 '11 at 10:49
  • 6
  • Is the javascript approach faster than autoclicker with > 1000 clicks per seconds? – 4 Leave Cover Feb 14 '17 at 02:28
  • Possible duplicate of [How to handle multiple submissions server-side](https://stackoverflow.com/questions/218907/how-to-handle-multiple-submissions-server-side) – Adam Jul 26 '19 at 14:19

8 Answers8

44

Use a unique token generated each time you display a form and which can be used only one time; it is also usefull to prevent CSRF and replay attacks. A little example :

<?php
session_start();

/**
 * Creates a token usable in a form
 * @return string
 */
function getToken(){
  $token = sha1(mt_rand());
  if(!isset($_SESSION['tokens'])){
    $_SESSION['tokens'] = array($token => 1);
  }
  else{
    $_SESSION['tokens'][$token] = 1;
  }
  return $token;
}

/**
 * Check if a token is valid. Removes it from the valid tokens list
 * @param string $token The token
 * @return bool
 */
function isTokenValid($token){
  if(!empty($_SESSION['tokens'][$token])){
    unset($_SESSION['tokens'][$token]);
    return true;
  }
  return false;
}

// Check if a form has been sent
$postedToken = filter_input(INPUT_POST, 'token');
if(!empty($postedToken)){
  if(isTokenValid($postedToken)){
    // Process form
  }
  else{
    // Do something about the error
  }
}

// Get a token for the form we're displaying
$token = getToken();
?>
<form method="post">
  <fieldset>
    <input type="hidden" name="token" value="<?php echo $token;?>"/>
    <!-- Add form content -->
  </fieldset>
</form>

Combine it with a redirect so you keep a perfect backward and forward behavior. See the POST / redirect / GET pattern for more information about the redirect.

Arkh
  • 8,416
  • 40
  • 45
6

You could disable the button after the first click (using JavaScript) and also have a check on the back-end (just in-case they disabled their JavaScript) which checks if they just recently submitted.

There are quite a few different ways of doing the check on the back-end. One way would be to set a session variable when they click it the first time, which can let the system know that it's processing. If they click a second, third or fourth time, then it can just check the session variable, and if that indicates that it's already been clicked, it won't process.

That's just one example - you could use that as a start.

xil3
  • 16,305
  • 8
  • 63
  • 97
5

I recommend against disabling the submit button, because in case of a temporary network issue (i.e. the request has not gone through at all), if the user chooses to abort the submission (Esc key/Stop button), he cannot submit again once network service has been restored, and instead will have to reload the page and fill in all the form entries again.

user562374
  • 3,817
  • 1
  • 22
  • 19
1

You could add something like this

<input type="hidden" name="form-token" value="someRandomNumber">

Then on the back-end, you have a save way of identifying multiple form submissions. This solution, of course, has some baggage since you have to delete form-tokens you know have finished processing, etc...

In most cases, a disabled form does the trick, for instance by either disabling the button or by adding return false to the form submit event (not sure if this works without jQuery though).

Mike
  • 2,567
  • 3
  • 23
  • 35
0

Can you just hide the button on click? It wouldn't effect form processing (as I know the problem is with immediately disabling the button) but it would essentially do the same thing. If you're really worried about it you could even just show another button that doesn't actually do anything. Might be an unconventional work-around, but a work-around nonetheless.

Carolyn
  • 21
  • 1
  • What if the user submits the form by pressing the enter key or by some built-in JavaScript in the application (e.g. `form.submit()`)? To assure the form isn't resubmitted simultaneously twice (or more times) one should have identifiers for the submissions and track their completeness. If you are to generate an ID, I'd suggest this API (https://api.cloudianos.com/genToken), known for providing unique (for medium- to short-periods) int + char strings. – undefined May 13 '19 at 11:21
0

I'm doing the following on the action.php

if($_SESSION && isset($_SESSION['already_submitted'])) {

  # If already submitted just redirect to thank you page

} else {

    # If first submit then assign session value and process the form
    $_SESSION['already_submitted'] = true;

    # Process form

}

Note: Always initiate your sessions in the header using session_start();

Robert Sinclair
  • 4,550
  • 2
  • 44
  • 46
0

if u are checking the value of the post with the name of submit button u have to change it or use it like that

<input type="hidden" name="submit1">
<button type="submit" onclick="this.form.submit(); this.disabled=true;">

if u r using it like that if(isset($_POST['submit1']){ // do my sql commands }

-2

You can as well prevent this by having a unique field like email/username or registration number. Then test then new field against the existing one in the DB, and if it matches, then the user has registered before, and form submission should stop, otherwise continue submitting form.

Blue
  • 22,608
  • 7
  • 62
  • 92