jpjp
jpjp

Reputation: 575

What are some methods to prevent double posting in a form? (PHP)

I want to prevent users from accidentally posting a comment twice. I use the PRG (post redirect get) method, so that I insert the data on another page then redirect the user back to the page which shows the comment. This allows users to refresh as many times as they want. However this doesn't work when the user goes back and clicks submit again or when they click submit 100 times really fast. I don't want 100 of the same comments.

I looked at related questions on SO and found that a token is best. But I am having trouble using it.

//makerandomtoken(20) returns a random 20 length char. 

<form  method="post" ... >
<input type="text" id="comments" name="comments" class="commentbox" /><br/>
<input type="hidden" name="_token" value="<?php echo $token=makerandomtoken(20); ?>" />
<input type="submit" value="submit" name="submit"  />
</form>

if (isset($_POST['submit']) && !empty($comments)) 
{
    $comments= mysqli_real_escape_string($dbc,trim($_POST['comments']));

    //how do I make the if-statment to check if the token has been already set once?
    if ( ____________){ 
        //don't insert comment because already clicked submit
    }
    else{
        //insert the comment into the database
    }
}

So I have the token as a hidden value, but how do I use that to prevent multiple clicking of submit.

METHODS: someone suggested using sessions. I would set the random token to $_SESSION['_token'] and check if that session token is equal to the $_POST['_token'], but how do I do that? When I tried, it still doesn't check

Upvotes: 2

Views: 3801

Answers (3)

Myco Claro
Myco Claro

Reputation: 483

you can do also in jquery it's very simple.

$(document).on('click', '.className', function(){
    $(this).css( 'pointer-events', 'none' );
});

Upvotes: 0

Artefacto
Artefacto

Reputation: 97805

If you want to prevent double submissions, you must store the state of "is submitted" versus "is not submitted". You have several options for where to keep this information.

  • Database - Add an hidden field with an autogenerated value that is unique (you can generate a short random string it and append the current time). This value can also be used to identify the conversation -- if you need a stateful web conversation. Add this value to the database and make it unique. Disadvantages: redundant storage in the database, reduced performance on comment insert, have to generate a unique string.
  • Session - Add the same hidden field with a value generated in a similar matter. When the user submits the form, save the value in the session if it's not there already. If it is, it's a double submission. Disadvantages: you still need to generate the unique token.
  • Browser - (1) Add some javascript to disable the submit button once it's clicked. (2) have an hidden field that starts with the value 0 and is changed to 1 when the user clicks the submit button. If the user clicks the button again, you check whether the value is 1 and abort if it is. Advantages: no unique string. Disadvantages: requires javascript to be enabled; you might require the string anyway to implement stateful web conversations.

Upvotes: 7

tc.
tc.

Reputation: 33592

I'd skip the whole random token thing and just store (a hash of) the comment in the session. If it matches the existing value stored in the session, then drop the comment. If not, let it through. Obviously there are problems:

  • It stops the user posting the same comment in different places. If this is a problem, store a hash of the comment and the id of the thing it's commenting on.
  • The user can press "back" and submit a different comment. I consider this a feature (it's better than dropping the comment because it matches the random token of a previous comment). Automatically interpreting this as a comment-edit is not easy.
  • It doesn't work if a user presses "submit" in alternate tabs. (I consider this unlikely, and it doesn't require the storage of multiple random tokens.)

You might want a random token to prevent XSRF anyway, but that's another issue (and in that case, you want to make sure that the random token is the same as "what it should be"; I'd store a long-lived one in the session).

Also, consider using prepared statements.

Upvotes: 0

Related Questions