(1) user, on page “A”, submits form to page “B”
(2) page “B” processes the form and creates the response to show the user.
*page “B” **does not display anything** to the user.*
(3) page “B” saves the response (say, using `$_SESSION`), and then redirects the user to page “C” (e.g., `header( “Location: http://example.com/pageC” );`).
(4) page “C” gets the response (e.g., from `$_SESSION`) and displays it to the user.
When the user, on page “C”, clicks on the [Back] button, their browser will go back to page “A” (where the original form is). It won’t go to page “B”, and won’t ask the user to submit the form again, because page “B” had no output, and is not in the browser’s history.
*(I use “page A”, “B”, and “C” here for clarity, but the form submission/redirect could just as easily be handled on a single page.)*
Another alternative is to use a “token” with your forms. Note that this is not as user-friendly as the redirect method above, but it’s a good idea for other reasons, and you can combine the two approaches for best results.
(1) before showing the form to the user, generate an arbitrary, unique string. This is a “token.”
(2) put the “token” in a hidden form field.
also, save the “token” in the user’s session, along with the time it was created.
(3) when the form is submitted, check the “token” before processing it. The token **must**:
… be present
… match the token you saved in the session
… have been created recently (e.g., in the last 30 min.)
(You want the token to match so you know that the form was submitted from one you actually provided – not one a spammer copied and used in a script.
(You want it to have been created recently so you can be reasonably sure that it’s the same person you actually gave the form to).
Next, delete the token info from the session. This way, you can never get a duplicate response (the re-submission will have a token that doesn’t match any records in your session, and so you know to ignore it).
If the “token” passed the tests, you can proceed normally and process the form.