Refresh vs. Form Re-submission
September 16, 2005 10:54 AM
Form re-submission woes!
How can I catch page refreshes and prevent form values from being re-submitted?
I've read a lot on the subject and tried varying tactics to counteract the problem. From hidden form variables and plain old user education, no methodology has worked quite as well as I had anticipated upon implementation. However, a lot of sites seem fairly successful in protecting against this problem so there must be something I'm missing (well, more than one something).
What am I missing? Does anyone have any tried-and-true methods that they've used? If so, are their any caveats to your preferred method?
(This is particularly for Perl/PHP with Apache and/or IIS. I'm hoping for one solution that can be modularized for varying projects, but anything is appreciated.)
I've read a lot on the subject and tried varying tactics to counteract the problem. From hidden form variables and plain old user education, no methodology has worked quite as well as I had anticipated upon implementation. However, a lot of sites seem fairly successful in protecting against this problem so there must be something I'm missing (well, more than one something).
What am I missing? Does anyone have any tried-and-true methods that they've used? If so, are their any caveats to your preferred method?
(This is particularly for Perl/PHP with Apache and/or IIS. I'm hoping for one solution that can be modularized for varying projects, but anything is appreciated.)
The best way that sites prevent page refreshes from generating form resubmissions is by never landing the user on the form submission page as their final destination.
In other words: you have a page, page1.php, that displays a form. The user fills out the form and clicks submit, which sends them to page2.php to do the form submission processing. The form gets processed and the data gets munged however you're munging it, and then page2.php sends the user to page3.php (or back to page1.php, or wherever); the user never ends up on page2.php as their final destination.
As a better example, take a look at this very site -- when I click "Post Comment", I don't get sent immediately to this page, but after the site processes my comment, I end up on this page.
posted by delfuego at 11:05 AM on September 16, 2005
In other words: you have a page, page1.php, that displays a form. The user fills out the form and clicks submit, which sends them to page2.php to do the form submission processing. The form gets processed and the data gets munged however you're munging it, and then page2.php sends the user to page3.php (or back to page1.php, or wherever); the user never ends up on page2.php as their final destination.
As a better example, take a look at this very site -- when I click "Post Comment", I don't get sent immediately to this page, but after the site processes my comment, I end up on this page.
posted by delfuego at 11:05 AM on September 16, 2005
Easiest way would be to set a session cookie to one value when a form is displayed, and set it to a different value (or clear it entirely) after the form is submitted. Then your script can check for the existence of the cookie that means "the form was displayed" before processing the submission.
Alternatively, give a unique ID (in a hidden field) to each form you generate and don't accept multiple submisisons from the same form ID. This requires somewhat more work on the back-end because you have to store each processed form ID but should be somewhat more reliable.
posted by kindall at 11:09 AM on September 16, 2005
Alternatively, give a unique ID (in a hidden field) to each form you generate and don't accept multiple submisisons from the same form ID. This requires somewhat more work on the back-end because you have to store each processed form ID but should be somewhat more reliable.
posted by kindall at 11:09 AM on September 16, 2005
Well, there's also always AJAX for submission which would unbind the get/post of a form from any submissions. I'd also suggest if at all possible you deal gracefully with submissions that are 100% duplicates. There's usually no reason a comment form should ever accept a perfect dupe of any previous comment, for example. Simply discarding such things w/o comment would deal with 99% of your problems.
posted by phearlez at 11:21 AM on September 16, 2005
posted by phearlez at 11:21 AM on September 16, 2005
I think the unique ID is the best approach, even it if is a little more involved. Otherwise, there are some things you can do:
1) Use some JS to disable the submit button after a click. This way a user can't double click it.
2) Do what delfuego suggests and write a page that does nothing but process the data. After it is done processing, it should redirect to a useful spot. Use the Location header combined with the apropriate Status (302 I think)... don't do a crappy meta refresh tag inside HTML. Java servlets has sendRedirect, Perl's CGI.pm has redirect. I can't find anything for PHP, but you can construct a simple redirect function using a couple header calls.
posted by sbutler at 12:01 PM on September 16, 2005
1) Use some JS to disable the submit button after a click. This way a user can't double click it.
2) Do what delfuego suggests and write a page that does nothing but process the data. After it is done processing, it should redirect to a useful spot. Use the Location header combined with the apropriate Status (302 I think)... don't do a crappy meta refresh tag inside HTML. Java servlets has sendRedirect, Perl's CGI.pm has redirect. I can't find anything for PHP, but you can construct a simple redirect function using a couple header calls.
posted by sbutler at 12:01 PM on September 16, 2005
delfuego's solution is also called Post-Redirect-Get.
A lot of these answers are not really solving purephase's problem. purephase's problem has to do with users refreshing a page and choosing to resubmit the form data when their browser asks them. I suppose disallowing duplicate comments would indirectly solve the problem, but why shouldn't duplicate comments be allowed? I can think of plenty of situations where a user might want to post the same comment twice in the same thread.
The appropriate status code for the redirect is 303 (See Other), not 302 (Found). From the RFC for HTTP/1.1, describing 303 See Other:
A lot of these answers are not really solving purephase's problem. purephase's problem has to do with users refreshing a page and choosing to resubmit the form data when their browser asks them. I suppose disallowing duplicate comments would indirectly solve the problem, but why shouldn't duplicate comments be allowed? I can think of plenty of situations where a user might want to post the same comment twice in the same thread.
The appropriate status code for the redirect is 303 (See Other), not 302 (Found). From the RFC for HTTP/1.1, describing 303 See Other:
This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource.posted by bpt at 12:20 PM on September 16, 2005
Another vote here for hidden form field with a unique token. Javascript has issues, and other solutions may present you with a race-condition in terms of what came first, the redirect/response or the second click.
<form>
<input type=hidden name=key value=${guid}>
</form>
you can even have the ${guid} have a unique constraint in your database to really ensure that the form only gets submitted once. (Or just keep it as session state).
posted by H. Roark at 12:31 PM on September 16, 2005
<form>
<input type=hidden name=key value=${guid}>
</form>
you can even have the ${guid} have a unique constraint in your database to really ensure that the form only gets submitted once. (Or just keep it as session state).
posted by H. Roark at 12:31 PM on September 16, 2005
Good answers above. Unique tokens are the only foolproof way. But post-redirect-get means you will hardly ever need them.
In any event, it's something you have to do in your form-handling code. It's not magic you can turn on at the web server level (I get the feeling from the way you've phrased your question that you're hoping for a built-in solution).
posted by i_am_joe's_spleen at 2:21 PM on September 16, 2005
In any event, it's something you have to do in your form-handling code. It's not magic you can turn on at the web server level (I get the feeling from the way you've phrased your question that you're hoping for a built-in solution).
posted by i_am_joe's_spleen at 2:21 PM on September 16, 2005
Are you sure it's not an impatient user clicking on a submit a few times in a row?
A lot of users double click everything, just because that's how they do it.
I know some pretty simple javascript could be written to ignore button presses within x seconds between them, but I don't have it.
posted by easyasy3k at 2:33 PM on September 16, 2005
A lot of users double click everything, just because that's how they do it.
I know some pretty simple javascript could be written to ignore button presses within x seconds between them, but I don't have it.
posted by easyasy3k at 2:33 PM on September 16, 2005
« Older problem with page load delay in safari | And then I woke up and my pillow was missing. Newer »
This thread is closed to new comments.
posted by purephase at 10:56 AM on September 16, 2005