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
Related
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.
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 have a form, in whmcs that I want user to only be able to submit once, so they cant submit it and refresh to resubmit... I was thinking about unsetting $_POST or redirecting, but neither would work in this situation, how would I generate a key and make it so its only usable once? Can't use mysql.
Why not store a random key in the session? That's how most CRSF token systems work: When loading the form, generate the key and save it in the session and include it in the form. When submitting, compare the keys and delete the saved key.
If you just don't want the user to accidentally resubmit a successfully submitted form, the link from #zerkms' comment is what you want: http://en.wikipedia.org/wiki/Post/Redirect/Get
The most common way to avoid double-posting is to do
header('location: /'.$your_url_here);
after you complete your actions. So you just redirect to the same page, but without $_POST.
Set a session or cookie when the form has been submitted and check if it exists beforehand.
You could also store information in a database such as their IP and browser if you wanted a permanent check, but this has it's own problems so your never going to stop someone 100% of the time.
I realize this is an old question but I recently had the same problem. None of the Post/Redirect/Get solutions appear to work on WHMCS if you want to stay on the productdetails page (for example) even if you are switching to another smarty template file after POST. Probably because it needs $_POST[id'] and that goes away after a refresh. So the closest I could get was having it go back to the products list page which is not what I want and probably not what the original poster wants.
The solution I finally came up with was to add a $_SESSION[submitted] variable after the form was submitted. You will have to figure out the logic yourself depending on what you are doing.
My Logic goes something like:
if ($_SESSION['submitted'] == 1 && !isset($_POST['somecustomkey'])) {
unset($_SESSION['submitted']);
}
That is at the top and resets the "submitted" session key if your POST form data does not exist.
Then add a check before you write the info to your database or whatever.
if ($_SESSION['submitted'] != 1) {
//Do some stuff with $_POST form data
$_SESSION['submitted'] = 1;
}
I think this fits in well with the intended purpose of $_SESSION and easy to implement.
I'm currently developing a page where the user fills out a form, and when submitted they are taken to the next page. When on the next page, I want to have it so that if the user went back to the previous page using the back button, or hit refresh, the submission will not be saved into the DB.
Now I recall reading somewhere that if you had a way to make each submission unique, this issue is averted, but after screwing around for hours on end, for the life of me I cannot recall how this could be done (using PHP), so long story short has anyone ran into this, and if so, what was your solution?
Use the Post/Redirect/Get pattern to avoid this problem. See also Redirect After Post.
Another way is to generate an identifier using uniqid and include it in the form as a hidden input. On submission, store that identifier in a database column marked with a UNIQUE index. This will cause subsequent submissions to throw a SQL error, which your application can handle gracefully.
You can add any confirmation on the second page.
By adding any confirmation box or any button....
by which you can confirm that whether user want to save it or not....
and if you don't want any confirmation...then you can delete the last record....by using managing session...but it is not good practice to fire the query very soon and delete in that kind..
so best way will be by adding any confirmation msg....
I want to ask a best practice question.
Suppose I have a form in php with 3 fields say name, email and comment.
I submit the form via POST. In PHP I try and insert the date into the database.
Suppose the insertion fails.
I should now show the user an error and display the form filled in with the data he previously inserted so he can correct his error. Showing the form in it's initial state won't do.
So I display the form and the 3 fields are now filled in from PHP with echo or such. Now if I click refresh I get a message saying "Are you sure you want to resend information?".
OK.
Suppose after I insert the data I don't carry on but I redirect to the same page but with the necessary parameters in the query string. This makes the message go away but I have to carry 3 parameters in the query string.
So my question is:
How is it better to do this? I want to not carry around lots of parameters in the query string but also not get that error. How can this be done? Should I use cookies to store the form information.
Your first scenario seems the most valid.
i.e.
User submits the form
Some problem prevents submission, so form is re-displayed
If user "refreshes" they see the usual message about re-sending information (although their most likely path of progression is to re-submit the form that you are kindly re-populating for them).
The "Are you sure you want to resend information?" message is perfectly valid in the event of someone refreshing the page after a form submission, so don't write code to specifically break this behaviour.
I think generally people would temporarily store the submitted data in a session variable, and send the data back to the client.
Maybe it is besides the point but you mentioned "wrong dates", and I think many would say you should arrange things so that the user cannot unintentionally send you wrong dates.