I have designed a user profile form, a long form which is quite complicated.
Before the user can submit and save it, the form needs to be validated.
Here is the question:
When the form is saved into the DB, there are multiple tables involved.
Now I would like to introduce a function called "Save Form" which internally doesn't validate the form and just save whatever the user entered.
There are potential issues, such as:
Q1> How to save temporary data?
Q2> What should I do if the user saves the temporary data
without submitting the form and then quit.
This feature looks like the Draft feature provided by Gmail.
You could create a session for the fields you're interested in saving. For example
$this_form = array(
'field1' = 'value',
'field2' = 'value2',
);
Then save this to a session:
$_SESSION['this_form'] = $this_form;
If you want to be really lazy you could just save the $_POST or $_GET variable in the session.
$_SESSION['my_post'] = $_POST;// or $_GET depending on your form.
And Of course, you know not to do anything with these until you validate them and do the usual inoculations.
You can retread the saved session variable later simply by calling it.
i.e.
echo $_SESSION['this_form']['field1'];
Once you are done with the session you can delete it with the unset command:
i.e.
unset $_SESSION['this_form']
There are also session functions that you can use:
PHP Session Functions
Q1> How to save temporary data?
There are a couple ways you could do this. You could save it to a different table. You could also (probably more popular) save it to the same table as the completed profiles, but flag it as incomplete via a column for this purpose. This column could be named complete. If the profile is not complete, it would be set to 0 or false. If it is complete, it would be set to 1 or true. You can then query based on it.
You could then "validate" the data via whatever procedure is required and set the column to 1 or true as needed.
Q2> What should I do if the user saves the temporary data without
submitting the form and then quit. This feature looks like the Draft
feature provided by Gmail.
The answer above should serve this purpose as well.
If you need to reload the data and allow the user to continue filling out the incomplete form, you will need to get some sort of identifier for them to allow this. You could do this by setting a cookie, or by some sort of unique identifier they would enter at the top of the form - such as SSN, phone #, student ID #, etc (or a combination).
If you are looking for a feature like Gmail's draft feature, you will need to implement some sort of AJAX call that automatically fire's every X seconds/minutes to automatically save the data.
Related
Is there a way to ensure the $_POST data my code received came from my form and not an outside influence. Basically I don't want someone to be able to spoof a $_POST to a universally available page such as account creation. The account creation page is accessible by any user, but I want to ensure only the data submitted by my account_creation form is what gets processed.
The only thing I could think of was initiating a $_SESSION, and then supplying the session_id to the form using a hidden input. Upon $_POST the value of the hidden input would then be matched against the current session_id.
If there is a better method to achieve this result? If there is I look forward to hearing it.
You cannot ensure that data came from a form. A POST request is just a POST request, it can be generated in any number of ways. An HTML form is just one of those ways that's very user friendly. Your server needs to validate whether the data received via the POST request is valid or not and whether to act on it or not.
Having said that, there are things that can help you to restrict and validate the data that is being submitted. First of all, require that a user is logged in using (session) cookies. That eliminates random requests by anonymous users. Secondly, you can embed a token as a hidden field into the form which you also save into the user's session. The POST request needs to contain that token in order to be valid. The token is simply a pseudo-random string.
You can enhance this by preparing a hash of the form fields that you expect the user to submit. If the form value should be read-only, you can include the value into the hash as well. E.g.:
$rand = md5(mt_rand());
$hash = sha1('lastname:firstname:email:' . $rand);
$_SESSION['rand'] = $rand;
$_SESSION['hash'] = $hash;
// on form submit:
$keys = array_keys($_POST);
$checkHash = sha1(join(':', $keys) . ':' . $_SESSION['rand']);
if ($checkHash != $_SESSION['hash']) {
die('Form submission failed token validation');
}
That's just a quick example, you'll probably want to sort the keys alphabetically to make sure you'll get the same hash etc. It demonstrates the concept of the user needing to have a unique token for each request though which prevents tempering with forms and submitting more or less data than wanted.
This still does not mean that a user actually used your form to submit the data though.
$ref = $_SERVER['HTTP_REFERER'];
if($ref !== 'some site path/index.php')
{
die("Access Denied!");
}
This should prevent most people from posting data to your database from an outside influence.
Slightly better is to add additional validation such as user_agent, user_ip and some other $_SERVER vars - those are the two I use.
So, create the unique ID (or Session ID) as you describe, but add a little extra validation that the agent and ip also match. Not fool proof, but adds another little layer of security.
Edit: I should add that you don't send the user agent back; keep that server side and silently validate against the returned session id.
Also, if a submission fails validation, never reveal that back to the user as to why - that way a cheat doesn't know how your tracking them. You can also add "5 invalids and you're out" tracking, but you need to sort of login for that.
Using the session ID is certainly one way of doing it. But there are other options most (if not all) of which involve adding some data as a hidden field.
Use a CAPCHA. That will always be unique to each page load and therefore make it mandatory to use your form.
Generate random data and store it in the DB (or just the $_SESSION variable) and check it once the form is submitted.
Option one is the one I recommend for a user creation form as it pulls double duty. It stops automated submission of your own form, while ensuring that the $_POST data is coming from your own form.
This is a standard pattern pattern to prevent XSRF. Essentially it is the similar to what you mentioned. Server creates a random token when form is rendered for the user. It is tied to a browser cookie for the user. On form submission it is posted back to the server. Server then compares the token with what was issued and form action is performed only after a successful match.
There's a lot of good mentions of putting a unique value in the form and matching to the stored value in the server side session. Do that, but also think about what happens when a user uses the back button and possibly tries to submit the form twice, or they open a second browser window(same session!), or they use multiple forms on your site.
Don't create crazy bugs by not thinking your system through.
I'm trying to create a form with 3 steps:
fill the form
check if data is correct (show input)
thank you
With an advice of some people here (regarding my previous question) I've changed my way of doing it from mainly PHP + js-validation to mainly js + PHP process data.
I need an advice with how to deal with this now.
Previously I've had a PHP if/else that determined which step to show and kept data in $_SESSION for 2nd step and possible corrections back in 1st step.
Now I'm wondering if I really need two ajax calls (first to process data in order to show it - 2nd form step uses $_SESSION to display data input in 1st step; second to generate e-mail and pdf with given data - same $_SESSION as step2).
Maybe a good solution would be to put data with javascript into 2nd step aswell and use $_SESSION only in the final processing and generating.
What's the common/your approach to this problem?
Here's the normal flow:
User loads page with form on it. Fills it out. Submits it.
You can validate every field as they fill it out (instant feedback which is nice from a user's perspective) or validate using the onSubmit event (in jquery $('#formID').submit). You don't allow them to submit if it doesn't pass, return false from the submit function.
In case they don't have JS enabled (you can try to prevent them from using it w/o JS but in reality they can just use curl -d "value1=foo&value2=foo2&value3=foo3" http://example.org/page/ to get around you) you have to validate the data on the server, too. JS isn't enough.
If it doesn't pass server validation, you can redirect them back to the form using the Location: http://example.org header or echo the form again in the server-side code. If it does pass, you can use it (insert it into db, echo it, email it, whatever).
You save the data in your database and add it to $_SESSION. You echo the data they just entered along with a button "Download PDF" or some such.
They click "Download PDF".
You have all the information you need to create and PDF. You don't have anything to validate but you need to use the $_SESSION information to create the PDF. You should test the $_SESSION to make sure they have valid input from the previous pages or else someone can mimic a post to the page and generate a PDF (perhaps blank though). I generally avoid using data from a $_SESSION as anything but state information -- I'll write to a db on post data (after scrubbing) but if it's in $_SESSION it usually is just stuff that tells me who they are and stores other information about configuration, etc. In your case, I'd have written to a DB in step one and now would use some ID from $_SESSION to pull that record and create the PDF to send it.
I think all of your validation can be easily done in step one and then you separate step 2 into delivery based on the validity of step one.
This is inside a PHP website form.
An example is like:
First page:
-Username:
-Password
Second page:
-Email
-[Checkbox]
Thirdpage:
-Contact Details
-Address
Fourth page:
Review all of the above forms in hard copy but with a back and forward command so that the user does not loose any information when switching between these pages.
Please post.
You could use cookies and do your own sessions with MySQL too. I like doing it like that because the data is easier to access if necessary.
Or you can pass the previous variables to the next page though hidden form elements.. but that can get messy.
You Have to use session. I like Zend_Session.
If you want users to be able to come back later and complete the form (assuming you have some kind of login system, or a way to recognize users), you could still save the data into a database. Make another table, temp_submissions. Keep data in it until the user completes the form and commits the data they send. Once committed, clear the data out of the temp_submissions folder and insert it into the "permanent" table. It may not be practical in this case, or total overkill, but it's an alternative to sessions and cookies.
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
I am trying to to solve a problem where I need to pass large arrays of data to another page, this is my scenario:
The user input his/her gmail login information inside a form, I then send this information to an ajax page where i authenticate and fetch all the contacts, if the login is invalid they can try again but if it authenticated I need to send them to the next page where I parse all the emails and check if they match any users on the site.
Method 1 (didn't work):
Store all the data inside a session, this only work if the array is small as there is a size limit for the sessions.
Method 2 (didn't work):
Add an hidden input with javascript and then submit the form (also with javascript).
As it turns out you can't submit the form and return true (change page) unless the user triggers the event.
So how should I go on, should I just skip the ajax authentication and send them back to the previous page if it didn't work or is there some workaround to my problem?
Why don't you store the data in a database, MySQL, or SQLite if MySQL is not available to you. In there, you would store a serialized version of your array linked to the users session id.
The MySQL table I'm thinking of:
id | session_id | data
http://php.net/manual/en/function.serialize.php on how to serialize your array.
If you are able to fetch the data again on the next page, you could do that instead of passing it between pages.
Since you are using jQuery you can submit the data directly or as a hidden element on the form without a user click. Assuming the second submission is via AJAX you can:
$("#mydiv").load("secondpage.php", {email1: 'blah'}, function(){
alert("Submitted everything nicely");
});
Depending on your webserver, but session variables do not typically have a size restriction. Apache+PHP you could handle extremely large sizes, instead you should care about
http://ca.php.net/manual/en/ini.core.php#ini.memory-limit. In addition, PHP.ini carries session.size variable that you could adjust. I am not sure how it did not work for you; you used $_SESSION, right?
Finally, to make a better persisting yet fast (faster than Database) volatile storage I would recommend using Danga's memcached. It is very stable, widely used and has wrappers for every possible language flavor.