This question already has answers here:
How to prevent form resubmission when page is refreshed (F5 / CTRL+R)
(21 answers)
Closed 5 years ago.
I'm wondering if there is a way to stop pages from resending html forms when you refresh.
You could send a Location header to a different URL in your script that is processing the form input. This new URL will be available for the browser without the need to send form data.
It is principally impossible to stop a client (browser) over which you have no control, from doing something. It is however possible - and in your case quite easy - to harden your app against this:
When you show the form, create a random token, store it in the session and add it to the form as a hidden field
When you receive the filled-out form, check the token against the session, if it doesn't match ignore the data, if it does match clear the token from the session and process the data
Any headers or other tricks may or may not work with browsers and people refreshing WITHOUT MALICE, but they definitly won't help against an attacker.
Use Post/Redirect/Get: http://en.wikipedia.org/wiki/Post/Redirect/Get
in PHP process the form in code, then instead of outputting anything put this header('Location: http://www.example.com/foo.php'); (obviously replacing the url) and do the display on another page. If you need to pass anything to that page then use the query string and $_GET[]
I don't believe that there is a good way to do this. The way we have accomplished this in the past was to have a last_modified date and a minimum time between posts. If you haven't waited an hour say, the post would be rejected.
The only trick I know is to have the form submit return a page with a link that you click via javascript (meta refresh, whatever) to get you to a third page.
The idea being that the thing you end up refreshing when you hit F5 is the link page not the form submit page.
In my quest to solve this, I have been taking a bit of a different approach. In a self developed MVC environment I redirected the page twice. After making sure that the data is submitted to the database, I redirect it to
header("Location: http:// .... /redirect/blogcomment
This will call to my "redirect" class and the "blogcomment" method. Here it will get redirected again to the "referer".
public function blogcomment() {
$ref = $_SERVER['HTTP_REFERER'];
$page = "Location: " . $ref . "#commentform";
header($page);
}
This clears the POST array and by adding an anchor tag just in front of the form fields, I jump right back to that location. Of course I also gain a lot of freedom in customizing my redirect. So far it works like a charm.
Double load... i.e. redirecting the page back to itself is bad practice. Try debugging an app that does this and it makes it much more awkward to realize thi is happening. For the love of god people, if you have to php submit a form, send it to a separate script first, then back if you want to remove a refresh sending the form again, much easier to debug!
try doing :
unset( $_POST );
as last command.
Related
I am working on a my site to allow users to take test so they can see how much they know of a particular subject. I am running into a little problem though. Once a user submits the test for grading, how do I prevent them from going back to the test page? I am on a Mac with Safari running and when I click the back button in my web browser after I submit the test it leaves all of the answers I answered filled out. I want it do this: When a user submits a test and they click the back button in their web browser it redirects them to the main test page.
I am using PHP and MYSQL. I even have the test pages setup so that the user must come from a certain url (I am using HTTP_REFERER) and I have tried other stuff such as sessions but I cannot seem to figure this out. Any help is greatly appreciated.
You don't stop them.
Instead change your application so that it still works even if they go back. You can embed a unique number in a hidden field on the page and if they resubmit the same test twice you can detect it and display an appropriate error message. You should also think about what should happen if they modify the unique number.
If you don't want people to post different answers once they have already answered, all you have to do is check, in the script that accepts the test for grading, that the user has never submitted the test before. If you don't, a clever student will always be able to to circumvent your protection by sending an appropriate request directly to that script.
If you don't want people to see previous answers (for instance, if you have two people grade their tests on the same computer), consider using AJAX on the test page to submit the answers and then erase them from the fields. This way, most browsers will not remember the answers and the back button will not un-erase data that was erased by JavaScript.
At the top of the grade page, put the following:
session_start();
$_SESSION['testcomplete'] = 'yes';
Then at the top of each page of the test, put this:
session_start()
if ($_SESSION['testcomplete'] == 'yes') {
header("Location:cheater.php");
}
You could simulate there being no page to go back to. From one page, generate each test page using jQuery, and provide no way to go back, only forward. The back button would take them to the page before they ever launched the test, and you could allow them to launch the test again and generate the right part where they should be. This would be pretty easy, if you haven't gone too far in development the current way.
You could run javascript that clears out all the answers. You might also just allow one submission so that subsequent submissions don't get processed. HTTP_REFERER is usually sent, but can be spoofed and forged by an altered browser.
On the top of the script POST-ing the answers, do a check whether you have the test results in the database for the current user for this test. If you do, redirect to results.
if(get_test_results($user)){
$test_url = get_test_url($user);
header( "Location: $test_url" ) ;
}
Disabling the back button is not a good idea.
I was facing a similar problem making an online examination myself
what I did is
I provided a session variable such that if the user pastes the previous page's URL in the address bar then on loading the page the page is automatically forwards to the next desired page. Whether the page whose URL was mentioned is the being visited the first time or being revisited is determined by the value of the session variable
If the user instead of loading the page does a go back via the browser button the it automatically redirects to the next page in history as :
javascript:window.history.forward(1);
Hope this helps :)
http://www.htmlgoodies.com/tutorials/buttons/article.php/3478911/Disabling-the-Back-Button.htm you should be able to do it in javascript.
I am working on a my site to allow users to take test so they can see how much they know of a particular subject. I am running into a little problem though. Once a user submits the test for grading, how do I prevent them from going back to the test page? I am on a Mac with Safari running and when I click the back button in my web browser after I submit the test it leaves all of the answers I answered filled out. I want it do this: When a user submits a test and they click the back button in their web browser it redirects them to the main test page.
I am using PHP and MYSQL. I even have the test pages setup so that the user must come from a certain url (I am using HTTP_REFERER) and I have tried other stuff such as sessions but I cannot seem to figure this out. Any help is greatly appreciated.
You don't stop them.
Instead change your application so that it still works even if they go back. You can embed a unique number in a hidden field on the page and if they resubmit the same test twice you can detect it and display an appropriate error message. You should also think about what should happen if they modify the unique number.
If you don't want people to post different answers once they have already answered, all you have to do is check, in the script that accepts the test for grading, that the user has never submitted the test before. If you don't, a clever student will always be able to to circumvent your protection by sending an appropriate request directly to that script.
If you don't want people to see previous answers (for instance, if you have two people grade their tests on the same computer), consider using AJAX on the test page to submit the answers and then erase them from the fields. This way, most browsers will not remember the answers and the back button will not un-erase data that was erased by JavaScript.
At the top of the grade page, put the following:
session_start();
$_SESSION['testcomplete'] = 'yes';
Then at the top of each page of the test, put this:
session_start()
if ($_SESSION['testcomplete'] == 'yes') {
header("Location:cheater.php");
}
You could simulate there being no page to go back to. From one page, generate each test page using jQuery, and provide no way to go back, only forward. The back button would take them to the page before they ever launched the test, and you could allow them to launch the test again and generate the right part where they should be. This would be pretty easy, if you haven't gone too far in development the current way.
You could run javascript that clears out all the answers. You might also just allow one submission so that subsequent submissions don't get processed. HTTP_REFERER is usually sent, but can be spoofed and forged by an altered browser.
On the top of the script POST-ing the answers, do a check whether you have the test results in the database for the current user for this test. If you do, redirect to results.
if(get_test_results($user)){
$test_url = get_test_url($user);
header( "Location: $test_url" ) ;
}
Disabling the back button is not a good idea.
I was facing a similar problem making an online examination myself
what I did is
I provided a session variable such that if the user pastes the previous page's URL in the address bar then on loading the page the page is automatically forwards to the next desired page. Whether the page whose URL was mentioned is the being visited the first time or being revisited is determined by the value of the session variable
If the user instead of loading the page does a go back via the browser button the it automatically redirects to the next page in history as :
javascript:window.history.forward(1);
Hope this helps :)
http://www.htmlgoodies.com/tutorials/buttons/article.php/3478911/Disabling-the-Back-Button.htm you should be able to do it in javascript.
Is there a way to avoid reprocessing forms when I refresh php pages? I'd like to prevent resending forms when refreshing links to php files with an insert function in them. For example, I am processing a series of notes written by users at the top of each page for a new note. Besides the obvious creating a separate php file with a header function is there another way to do it?
Use the Post-Redirect-Get Pattern.
Accept a Post request
Process the data
Issue a redirect response
Accept a Get request
Issue a 200 response
If you need to display data from the submitted stuff, then include a row id or similar in (for example) the query string of the URL you redirect to.
The best way would be to do a header("location: form.php"); call after you process the form. That would redirect you back to the form page, and if you refresh, the browser wont resend the form data.
Alternatively, you could check to see if you already processed the data received, but that would still give you the browser warning message that you are going to resend the data.
You might do both, just in case someone uses the back button and accidentally clicks Submit again.
Just set some flag when you process the form first time so you could check for it and abort reprocessing later on. Session variable or cookie will work fine.
You could put a nonce into the page that is only allowed to be used once so that if you see the same nonce come in you don't do the insert of the page.
I redirect users to a new page after processing of the form.
The form is a POST-request to do-something.php. I check the input data and if it validates I process the data and perform a redirect to do-something.php?somethingdone. So the user can hit F5 w/o resending the POST request.
I tried to use header("Location:..."), $_POST = array(), unset($_POST), but (idk why) they didn't work in my php page.
So, what I did, I just used
echo '< script>window.location.replace("http://.../this.php")</script>'
😂 it works very good! Maybe it is not a good idea, I am learning PHP for the 4th week.
I am working on a my site to allow users to take test so they can see how much they know of a particular subject. I am running into a little problem though. Once a user submits the test for grading, how do I prevent them from going back to the test page? I am on a Mac with Safari running and when I click the back button in my web browser after I submit the test it leaves all of the answers I answered filled out. I want it do this: When a user submits a test and they click the back button in their web browser it redirects them to the main test page.
I am using PHP and MYSQL. I even have the test pages setup so that the user must come from a certain url (I am using HTTP_REFERER) and I have tried other stuff such as sessions but I cannot seem to figure this out. Any help is greatly appreciated.
You don't stop them.
Instead change your application so that it still works even if they go back. You can embed a unique number in a hidden field on the page and if they resubmit the same test twice you can detect it and display an appropriate error message. You should also think about what should happen if they modify the unique number.
If you don't want people to post different answers once they have already answered, all you have to do is check, in the script that accepts the test for grading, that the user has never submitted the test before. If you don't, a clever student will always be able to to circumvent your protection by sending an appropriate request directly to that script.
If you don't want people to see previous answers (for instance, if you have two people grade their tests on the same computer), consider using AJAX on the test page to submit the answers and then erase them from the fields. This way, most browsers will not remember the answers and the back button will not un-erase data that was erased by JavaScript.
At the top of the grade page, put the following:
session_start();
$_SESSION['testcomplete'] = 'yes';
Then at the top of each page of the test, put this:
session_start()
if ($_SESSION['testcomplete'] == 'yes') {
header("Location:cheater.php");
}
You could simulate there being no page to go back to. From one page, generate each test page using jQuery, and provide no way to go back, only forward. The back button would take them to the page before they ever launched the test, and you could allow them to launch the test again and generate the right part where they should be. This would be pretty easy, if you haven't gone too far in development the current way.
You could run javascript that clears out all the answers. You might also just allow one submission so that subsequent submissions don't get processed. HTTP_REFERER is usually sent, but can be spoofed and forged by an altered browser.
On the top of the script POST-ing the answers, do a check whether you have the test results in the database for the current user for this test. If you do, redirect to results.
if(get_test_results($user)){
$test_url = get_test_url($user);
header( "Location: $test_url" ) ;
}
Disabling the back button is not a good idea.
I was facing a similar problem making an online examination myself
what I did is
I provided a session variable such that if the user pastes the previous page's URL in the address bar then on loading the page the page is automatically forwards to the next desired page. Whether the page whose URL was mentioned is the being visited the first time or being revisited is determined by the value of the session variable
If the user instead of loading the page does a go back via the browser button the it automatically redirects to the next page in history as :
javascript:window.history.forward(1);
Hope this helps :)
http://www.htmlgoodies.com/tutorials/buttons/article.php/3478911/Disabling-the-Back-Button.htm you should be able to do it in javascript.
I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
Since application is built in such way that going Back is a quite common operation, this is really annoying to end users.
Basically, I would like to do it the way this page does:
http://www.pikanya.net/testcache/
Enter something, submit, and click Back button. No warning, it just goes back.
Googling I found out that this might be a bug in Firefox 3, but I'd like to somehow get this behavior even after they "fix" it.
I guess it could be doable with some HTTP headers, but which exactly?
See my golden rule of web programming here:
Stop data inserting into a database twice
It says: “Never ever respond with a body to a POST-request. Always do the work, and then respond with a Location: header to redirect to the updated page so that browser requests it with GET”
If browser ever asks user about re-POST, your web app is broken. User should not ever see this question.
One way round it is to redirect the POST to a page which redirects to a GET - see Post/Redirect/Get on wikipedia.
Say your POST is 4K of form data. Presumably your server does something with that data rather than just displaying it once and throwing it away, such as saving it in a database. Keep doing that, or if it's a huge search form create a temporary copy of it in a database that gets purged after a few days or on a LRU basis when a space limit is used. Now create a representation of the data which can be accessed using GET. If it's temporary, generate an ID for it and use that as the URL; if it's a permanent set of data it probably has an ID or something that can be used for the URL. At the worst case, an algorithm like tiny url uses can collapse a big URL to a much smaller one. Redirect the POST to GET the representation of the data.
As a historical note, this technique was established practice in 1995.
One way to avoid that warning/behavior is to do the POST via AJAX, then send the user to another page (or not) separately.
I have been using the Session variable to help in this situation. Here's the method I use that has been working great for me for years:
//If there's something in the POST, move it to the session and then redirect right back to where we are
if ($_POST) {
$_SESSION['POST']=$_POST;
redirect($_SERVER["REQUEST_URI"]);
}
//If there's something in the SESSION POST, move it back to the POST and clear the SESSION POST
if ($_SESSION['POST']) {
$_POST=$_SESSION['POST'];
unset($_SESSION['POST']);
}
Technically you don't even need to put it back into a variable called $_POST. But it helps me in keeping track of what data has come from where.
I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
Your reasoning is wrong. If the request is without side effects, it should be GET. If it has side effects, it should be POST. The choice should not be based on the number of parameters you need to pass.
As another solution you may stop to use redirecting at all.
You may process and render the processing result at once with no POST confirmation alert. You should just manipulate the browser history object:
history.replaceState("", "", "/the/result/page")
See full or short answers