Avoid resending forms on php pages - php

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.

Related

PHP - return the same page with changes

I have html page where you can insert some information and then submit this form, which will change information in database. I do it normally, that submit button call php file in server.
But what I want, is that this php file will return to me the same html page of which I sent request, with modified changes. e.g: there will be "Database update successfully" text added etc.
How can I do it without AJAX ?
Thanks
In the PHP file, do a call to the header() function to redirect the user. For example:
header('Location: url.php');
To change the content of that page they are redirected to, you could pass something in the URL that your page will check for. For example:
header('Location: url.php?submitted=1');
There are other ways to implement this, but this seems the most straightforward to me. Note that you don't want to call header() until the end of your submission page.
Use POST/REDIRECT/GET
Excerpt:
The user submits the form
This is pretty straight forward. The user completes the form and submits it by pressing the submit button or enter on their keyboard.
We store the form data in a session
After processing the data we discover an error so we need to redisplay the form with an error message but we also want to populate
it with their data so they don't have to refill the entire form just
to fix potentially one little mistake. So we store their data in a
session ($_SESSION). Session variables carry over from page-to-page
for as long as the session is valid or until they are deleted. This is
an ideal place to put their information since redirecting will cause
their information to be immediately discarded by the server.
We redirect the user back to the same page using a 303 redirect
Once we have saved the user's information in their session we need to redirect them back to the same page. In order for this to work
properly we need to use a 303 redirect. This means we need to send a
303 header with our redirect. A 303 redirect will cause the browser to
reload the page without the initial HTTP POST request to be
resubmitted. This includes when the user uses the back or refresh
buttons.
We re-populate the form using the data stored in the session
When the page is sent to the user we re-populate it with their information we saved in their session.
Only by generating the whole page in CGI first, unless you go through some horribly convoluted method of getting value of one of the fields to be set to document.innerHTML or something like that in Javascript. But you'll go through hell to get the quoting issues resolved. Use AJAX, it was created for precisely this purpose and exactly to avoid the utter hell associated with what you need.
Alternatively: the "modified piece" of the page may be an iframe, and you can set the target attribute of the form, so that the PHP returns only the iframe content.

Stop page from resending forms on refresh [duplicate]

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.

Does this protect me against page reload and the back button?

Further to my previous question, here's what I decided to implement; it may not be pure P-R-G, but it seems ok. Care to comment?
The form.php has an action; let's call it validate.php.
validate.php is never seen by the user; if validates all $_GET and, if valid writes it to database and generates the HTML of a confirmation page / if not valid, it generates the HTML of an error page explaining what is wrong.
Whichever HTML is generated get stored in a $_SESSION variable and then validate.php does a header('Location: <as appropriate>);
Finally a page called submitted.php of invalid_input.php (in case the user reads the URL) consists only of echo $_SESSION['form_html'];
That seems to me like is proff against both page reload and back button problems.
Or did I goof by trying to reinvent the wheel?
Firstly, you're better off storing the form data, which means you can perform the validation again. It will also be less html. The problem with the method you're employing now is that it doesn't protect against multiple tabs, since $_SESSION is universal to a browser session.
One way I've used to prevent against duplicate submission (without PRG) is to generate a unique id for every page load (where a form is involved). When I generate that unique id, I add it to a $_SESSION['form_unique_ids'] array, and I include it as a hidden field in every form I generate. Then before I take action on a form submission, I check to see if that unique id is in the session. If it is, this is the first time that form has been submitted, and I remove it from the session. That way if I try to resubmit that page, I will know because that id is not in the session not to process the results.
This could be extended so that instead of storing a single id, you use the id as the key in the array, and let the value be the result of the transaction. Then:
If there are errors, you store the $_POST data as well. Then, redirect to original_form.php?id=unique_id and display the validation results. You can either store them or recalculate them there.
If there is success, store the success message and redirect to success_page.php?id=unique_id. Display the success message prominently there. If you like, you can remove it from the page.
You have the option of removing the session data when you display it, but that would mean if they refreshed the edit page they'd lose the validation messages and saved form data. I'd rather find a way to get rid of data that is old enough that they're not likely to need it anymore.
Anyway, some of those ideas might be useful. Then again, maybe it's way too much effort for the problem. Your call :)
As long as you use a php redirect at the end of your validate you cannot reload or back button into the validate.php

Monitoring for postbacks with PHP?

I have a PHP page with content that my users can view. When this page receives a POST request from a certain external URL, I'd like to redirect the user to another page.
The problems I'm' having are:
How can I monitor the page for requests being sent in an efficient way?
How can I actually redirect them since header() doesn't work.
Thanks.
For the second question, header() will work if you use it before you output any information to the page. However, if you echo, print, or have HTML before it, it will give an error.
Edit: In response to Toad's comment, then you'd have to do as Aaron Harun suggested. Have the page save the $_POST data to the database or a file (make sure you sanitize it!), just like you would with any $_POST data. You would then need to use AJAX to get a response from a second PHP page that simply checks for the existence of updated data from wherever you saved it. If the response comes back true, then you redirect using a JavaScript redirect.
The only other way to do it without using AJAX would be to refresh the page using an HTML meta refresh element at timed intervals to check if $_POST data has been received. HTML would perform the refresh, PHP would do the checking, and you could use either for the redirect.
You can use an AJAX script to "ping" the server intermittently to see if there have been any changes. If there are, redirect the user with JavaScript.
It's pretty much the only way.
we can put this snippet to check the post request
if($_POST['flag']==1) {
header("location:newpage.php");
exit();
}
But If you want to check the request regularly without user interaction than you will have to use AJAX

Prevent Back button from showing POST confirmation alert

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

Categories