preventing users from submitting data from form to mysql twice - php

I have a form where a user submits data from various text fields on my webpage to mysql database. Is there any code I can use were it will not let them submit/update the data again? e.g it will redirect them to a page saying sorry wwe have already received your data.
I have a unique number for each user if this helps. any help is appreciated.

Use tokens, it will avoid double submits and CSRFs.
Simply add tokens to an array, $_session most likely, and pop them when used.
Also, disable the submit button with JS after a submit.
You can also set a var in the session user that says he already performed an action, exampled uploaded his picture. Unset it if there is an error in your upload script for instance.

When you receive the post, query the database for the unique user number. If you get back a non-empty result, then display the error. Otherwise, save the data to the database.
The biggest thing you need to determine is what your unique identifier will be. It sounds as though you already have one (you mentioned unique user number?) Your unique identifier could be an email address, or even the full set of submitted data.
There are other ways to emulate this, such as setting a cookie on the user's machine, or disabling the submit button, but, none of these are completely under your control. The user could easily get past them if they tried. Therefore, determining a unique identifier and validating server side is probably the best way to do it.

The answer hugely depends on the reason for which user might send the data twice.
in case of an accident, there is one technique, and all other won't help you even a bit.
in case of intentional duplication the technique is completely different and again there is no general solution - everything depends on the certain scenario.
If you care to explain your certain case, you will get a proper solution.
For the most silly case of pressing "Reload" on a page with post results, you have to redirect browser using Location: HTTP header, e.g.
header("Location: ".$_SERVER['REQUEST_URI']);
exit;

Related

Passing values through URL or POST variable instead?

I'm implementing a message system (private messaging, if you will) and I'd like to be able to display the list of messages a user has by a text link so I don't need a button to open it. The message_id (unique value in the databse) would be passed through the URL. (something like www.example.com/message/view/16).Assuming I check to make sure the session of the userid matches the userid that the message is sent to, is this OK? To make it safer I could just append a random number and set that as as session, and then just check for that upon viewing.
Should I forget this idea and just stick with a submit button to view the message?
A POST request would not provide any more safety than a GET request: any half-decent web debugging tool can forge POST requests. You should simply never trust user-input data. Always double-check authorizations for safety!
That said, GET request semantics match what you're trying to do here.
The HTTP standard says that a GET request should be repeatable without any non-trivial consequence. For instance, it's adequate to view data with a GET request (and possibly do small things like incrementing a counter, since these are pretty trivial consequences). In fact, GETand HEAD are the two request methods that are considered "safe".
On the other hand, POST requests are expected to have non-trivial consequences, like sending a message or placing an order. Stuff that you don't want to perform twice accidentally. Most browsers these days also respect this by warning users when reloading a page would cause a POST request to be performed again.
Using GET values for viewing messages is much better idea, because assuming a user stays logged in, it would allow them to bookmark messages, etc.

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

Session questions

I am having trouble in understanding of how I need to do this:
Have list of items on my home page and when users click on that, I take them to a page where i ask for name and email id(both are optional fields) and when users hit submit, I will take them to other page where they get to see all the details. the reason for that name and emails fields are to store the ip address in mysql and also the url(has the item id and date) they are on.
To do this, i am having trouble in doing it in program.
I am thinking to start a session/store cookie once they hit submit. after that I want to store the ip address, item id, date and name/email(if they filled in) in mysql db
Store everything in the mysql db
Also, how can I avoid anyone going to the page directly(the one I show after they submit) ? Is there any way can I include some condition on that page and redirect them to this log in page ?
Please help me out.
regards
Since you set session variables when the user hits the submit buttons, you can test if one of those variables is set or not and redirect accordingly.
You can also do it with POST, use the page as an action to your form, and whenever someone accesses that page you test if $_POST variables (from the form) are set or not.
As the data seem to be necessary only for the immediate use, I think that a session is the right answer in this case.
If you would then use a database query, which data would you store to associate the data to the correct user? As you said, both the data you ask are optional; even in the case there would not be optional, how do you handle the case two different users report the same name and email (it could also be the same user using two different browsers).
For temporary data like that, the session is always the better choice (except few exceptions, maybe).
I was forgetting the other question.
Also in that case, I would use a session variable. Sessions variables are the solution for values that you want to keep between different forms, without the need to keep moving them between the server, and the client side.
For more information about sessions, see PHP: Sessions

Making form submissions unique using PHP and HTML

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....

How to know where a form came from?

I was wondering is there a way in PHP that you could tell where a form was submitted without using hidden fields or anything of the like where the user would only need to tamper with the html a little?
For example i am trying to work out if a form that was submitted was actually on my website or whether the form was saved offline and submitted that way.
An hidden field is not easily spoofed if it contains a UID (if you encrypt a time stamp you will be able to tell how long the user has been on the page)
Of course the user can enter whatever he wants in the field, but unless he can generate a valid UID, he can't make your php script believe it came from somewhere else.
You can also track a user's visited pages through $_SESSION and use that instead of the HTTP referrer (store each visited page in an array inside $_SESSION, and when your script is called, you simply check whether the last page was yours? Variation of that are possible depending on what you need).
You can attempt to use the referral header set in HTTP requests, do note however that not all browsers set these correctly, or users have them turned off, or that they are very easily spoofed.
Without a hidden field containing an unique identifier that is used to identify the form for that one single submission there is no good way of identifying whether the form is being forged or not.
I could be wrong but wouldn't the referrer header tell you this?
This gets you what you are after:
$referer = ($SERVER["HTTP REFERER"] == null);
This actually fetches it from the HTTP Header where it looks like this:
...
Referer: http://foobar.com/page.php
...
It is easy for anyone to spoof this but for most purposes it is reasonable.
Trivia: Referer should actually be spelt referrer which is the correct spelling but the spelling mistake made its way into the HTTP specification and has stuck since.
You can't really tell. Why would it matter? If you're trying to detect if someone has forged a request, you can't.
Amended: The green solution above does help some issues, but it doesn't address the question of if it came from your site, or if it was modified.

Categories