Tracking information over many pages for a website - php

I have a sort of vague question that you guys are perfect for answering. I've many times come across a point where I've had a form for my user to fill out where it consisted of many different pages. So far, I've been saving them in a session, but I'm a little worried about that practice since a session could expire and it seems a rather volatile way of doing it.
I could see, for example, having a table for temporary forms in SQL that you save to at the end of each page. I could see posting all the data taken so far to the next page. Things along those lines. How do you guys do it? What's good practice for these situations?

Yes, you can definitely save the intermediate data in the database, and then flip some bit to indicate that the record is finished when the user submits the final result. Depending on how you are splitting up the data collection, each page may be creating a row in a different table (with some key tying them together).
You may also want to consider saving the data in a more free-form manner, such as XML in a single column. This will allow you to maintain complex data structures in a simple data schema, but it will make querying the data difficult (unless your database supports xml column types, which most modern enterprisey databases do).
Another advantage to storing the interim data in the database is that the user can return to it later if he wishes. Just send the user an email when he starts, with a link to his work item. Of course, you may need to add whatever security layers on top of that to make sure someone else doesn't return to his work item.
Storing the interim data in the DB also allows the user to skip around from one page to another, and revisit past pages.
Hidden fields are also a good approach, but they will not allow the user to return later.
I would avoid storing large data structures in session, since if the user doesn't invalidate the session explicitly, and if you don't have a good mechanism for cleaning up old sessions, these expired sessions may stick around for a long time.
In the end, it really depends on your specific business needs, but hopefully this gives you something to think about.

I would stick with keeping the data in the session as it is more or less temporary at this stage: What would you do if a user does not complete the forms? You would have to check the SQL table for uncompleted data regularly making your whole application more complex.
By the way, there is a reason for session expiring namely security. And you can define yourself when the session expires.

Why not just pass things along in hidden parameters?

Ahh, good question.
I've found that a great way to handle this (if it's linear). The following will work especially well if you are including different content (pages) into one PHP page (MVC, for example). However, if you need to go from URL to URL, it can be difficult, because you cannot POST across a redirect (well, you can, but no browsers support it).
You can fill in the details.
$data = array();
//or//
$data = unserialize(base64_decode($_POST['data']));
// add keys to data
// serialize
$data = base64_encode(serialize($data));
<input type="hidden" name="data" value="<?= htmlspecialchars($data, ENT_QUOTES); ?>" />

Related

Database storage vs Cookies - To store form data

Good day to all,
I have a form with around 90 to 100 fields, divided into sub forms, which are loaded using ajax each time a form has to be displayed. but i would like to retain the data on the form fields every time a subform is loaded(lets say on an accidental page refresh or even if the user is switching between sub forms). What is the best way that this can be done.
I was thinking that i can store it in cookies or lets say in the database. But, storing it in the database would mean that i would have to query for the fields data every time a sub form is loaded. And again, if it was cookies, it has to read the data stored in the cookie files. I need some help with deciding what is the most efficient way, more in terms of speed.
What is the best way among these, or is there any other possibility to retain the fields data in the sub forms, every time they are loaded (which are loaded via AJAX each time.)
I am working with PHP and Codeigniter framework.
Thanks!!
A form like that needs to be durably stored. I would consider session state to smooth out the sub form loads, with writes to the database whenever the user updates something of consequence. Personally, I would start with a database-only solution, and then add session state if performance is an issue.
Cookies aren't meant to store large amounts of data. Even if it were possible, they bloat the request considerably (imagine 100 form fields all being transmitted with every request).
Local storage in the browser is also an option, though I would consider other options first.
I would first simplify it by using serialize:
$data = serialize(array_merge($_POST,$olddata));
Then that may be enough for you, but it's now super easy to store it anywhere since it is just a string. To reform it into its original state:
$data = unserialize($data);
.. wherever you end up pulling it from - database,session,etc..
Prose of database
It can also access from other computer too
You can store far far more data then cookie
Cones
If you retrive data by ajax it coukd cose more load on server
Cookie
Faster than database no query , fetch and all process .
Cones
Limited amount of space
However you can use local storage
So answer is database storage

What is the best way to store a column sort order on website?

Here is what my table looks like: http://jsfiddle.net/Draven/kGtx7/14/
Each header cell is clickable to be able to sort by that field and by ASC / DESC.
I want to be able to store that sorting option somewhere, so it get's remembered, but am not sure the best way to do that.
Here are the options I was thinking...
Making sort_field and sort_order fields in the users table
Making a new table that has their userid along with sort_field, and sort_order fields
Or Cookies, but I assume this is the worst option
I don't think we are clear on what you want, but I think you are wanting something like this:
Step 1: Run a query than will populate the sorting values into 2 session variables.
Step 2: Do something like this code.
$sortHeadClicked = $_SESSION['headClicked']
$sortReturnDirection = $_SESSION['returnDirection']
//TODO: validate data before query
if ($result = $mysqli->query("SELECT * FROM table ORDER BY $sortHeadClicked $sortReturnDirection))
{
//TODO: Get results
}
Step 3: Smile like your awesome
Alternatively, you could use some sort of sub select query.
NOTE: This is the simplistic logic so they won't be remember with this example. However, you can put the gets into session variables if you only want them to be remember temporarily
However, if you want these remembered permanently, you need two columns in your user's table where you would either puts them into sessions or use a subselect query
This is left up to interpretation, but each case would have its own uses.
1) Adding two fields to your users table will make the calls to retrieve these values easier but it is a much uglier approach to the problem than..
..2) Relational databases are built to be used as such. I'm not sure in terms of performance, but I do know that using the power of relational databases can make your db easier to navigate and understand/manipulate. While you may need some more complex calls (ie joins and whatnot), I believe the tradeoff is worth it.
and 3) Cookies are a very meh solution. They could be used in temporary cases, but if you are trying to save info for later, cookies can easily be deleted or not even enabled, at which point your site can suffer drastically.
Actually, using a cookie to store the user session id and then keeping session data in a database, flat file, or memcached is pretty common way to solve this. It would help to set up a reusable mechanism for this, like registry of sorts, that you can retrieve per user values at will. This only works if you have a user login of course. Otherwise there is no point in storing that data, as the users identity will be lost once they end the session (close the browser window). Most web apps will use cookies to identify you. If you delete that cookie, it forgets you and you are logged out.
Your first solution will suffer if you ever want to add another per user "preference" as you'd need to modify the underlying table.
Have a look at Zend Session for ideas if you are using PHP. If not the concepts still apply.
To save the sorting order to their profile, make the table inside a form and have the sortable field names be inputs. When they click one of the field names (sort by Location, for example), have the form's action run a PHP snip that updates a field in their profile on the database.
Alternately, if able to use ajax, you could simply add the database updating to an ajax call and skip the form.
I'm afraid that depends on your needs. How I see this problem:
good if you must share this settings between browsers, PCs, in
case if user delete cookies in browser. But it is not flexible - if
you will need to add another table, you will also add two additional
fields
the same as 1 in term of how it is shared between computers, browsers etc, but it is more flexible. You may add a column with table name easily.
If this setting is not so important and you may allow to loose setting in some cases. This solution is simplest, but it may not work for you

Why should I not insert serialized arrays into my database field?

I just saw the first comment to this question Inserting into a serialized array in PHP and it made me wonder why? Especially seeing that when you use database managed sessions (database based session handling) that is exactly what happens, the session handler inserts a serialized array into a database field.
There's nothing wrong with this in certain contexts. Session management is definitely one of those instances where this would be deemed acceptable. The thing to remember is that if you ever find yourself trying to relate data between the serialized data and any fields in your database you've made a huge design flaw and unfortunately this is something that I have seen people try to do.
Take any "never do x" with a grain of salt as almost any technique can be the correct one in certain circumstances. The advice is usually directed towards noobies who are very apt to misunderstand proper usage and code themselves into a very nasty corner.
How certain are you that you'll never want to get at that data from any platform other than PHP?
I don't know about PHP's form of serialization, but the default binary serialization format from every platform I do know about is inoperable with other platforms... typically it's not a good idea to data encoded for just a single frontend into a database.
Even if you don't end up using any other languages, it means the database itself isn't going to know anything about the information - so you won't be able to query on it etc. Maybe that's not a problem in your case - but it's definitely something to bear in mind.
The main argument against serialized data is that serialized data are hard to search through and impossible to do so efficiently i.e., without retrieving the records in the first place.
Depends on the data. By storing a language-specific data structure in a field you're tied to that language and you're also giving up anything the DB can give you. You won't have indexes on specific fields, can't run simple updates, can't extract partial data, can't have data check, referential integrity and so on.

quantity of data that should be stored in session

Assumption
I understand that it's not good to store to much data and it is needed to be as simple.
State today
Now I use as minimum needed and using simple data types (int and strings)
mainly for storing user's id and to tell if he is logged in.
must of my functions are static or singleton that has to be built each post/get.
I have trouble to representing the current state and changing it.
and get a largely static site.
most of state representing goes into javascript .
Target
for the other hand if I'll create a object that represent the entire website it will be much easier for me to maintain user's input , including database interaction.
simple question, how much data should be stored there?
example
One of the things i want to implement is
objects that relate to Database tables,
Let's take a page for a "car.update()".
Now if i store an object for it, that extends a connection to the Database with methods
for CRUD.
When I handle a post back from that page with details i could just put them in properties needed and call the update method.
situation now: I need to create a new object with that details and make an static update
Another example
storing previous search result and filter it using new data
In many cases the ideal amount would be none. Store the username in a cookie along with an HMAC hash used to verify the cookie was created by your site, and get everything else from the database (or cache) as needed. This makes it easy to load balance across servers because any server can handle any request and there's no state that needs to be shared between them.
This approach wouldn't be appropriate for banking or other top-security uses because if someone gets your cookie they connect as you. But for sites where you're not doing anything super critical it's great. The risk can also be mitigated somewhat by adding an expiration mechanism to your cookie handling. See chubbards great answer related to another HMAC question for more info.
note you can switch the way PHP stores data using session_set_save_handler. Then you don't have to change the calls and you improve performances/maintenance with the efficiency of database.
The minimum would be the user I.D.—assuming it is a logging in type of interface. But it is often helpful to include the most common aspects of that, like the user's permission and other items which are stored in the database, but are frequently referenced when constructing pages.
You shouldn't store an enormous amount of data, but you can without problems store some user-information if it helps you server you pages faster.
But if you want to build a more dynamic website, you will probably retreive more and more data from the database. So when you're connecting to a database after all, you could skip storing all kinds of information in the session, because you can just as well get them from the database. Most databases (including MySQL) have a quite efficient query cache that will make repeated queries lightning fast.
So in that case you'll need to save little more than the userid and maybe a small amount of flags.

PHP - Is this a good method to prevent re-submission?

This is related to preventing webform resubmission, however this time the context is a web-based RPG. After the player defeats a monster, it would drop an item. So I would want to prevent the user from hitting the back button, or keep refreshing, to 'dupe' the item-drop.
As item drop is frequent, using a DB to store a unique 'drop-transaction-id' seems infeasible to me. I am entertaining an idea below:
For each combat, creating an unique value based on the current date-time, user's id and store it into DB and session. It is possible that given a userid, you can fetch the value back
If the value from session exists in the DB, then the 'combat' is valid and allow the user to access all pages relevant to combat. If it does not exist in DB, then a new combat state is started
When combat is over, the unique value is cleared from DB.
Values which is 30mins old in the DB are purged.
Any opinions, improvements, or pitfalls to this method are welcomed
This question is very subjective, there's things you can do or can not do, depending on the already existing data / framework around it.
The solution you've provided should work, but it depends on the unique combat/loot/user data you have available.
I take it this is what you think is best? It's what I think is best :)
Get the userID, along with a unique piece of data from that fight. Something like combat start time, combat end time, etc
Store it in a Database, or what ever storage system you have
Once you collect the loot, delete that record
That way if the that userID, and that unique fight data exists, they haven't got their loot.
And you are right; tracking each piece of loot is too much, you're better off temporarily storing the data.
Seems like a reasonable approach. I assume you're storing the fact that the player is in combat somewhere anyway. Otherwise, they can just close their browser if they want to avoid a fight?
The combat ending and loot dropping should be treated as an atomary operation. If there is no fight, there can't be any dropping loot.
That depends on your game design: Do you go more in the direction of roguelikes where only turns count, and therefore long pauses in between moves are definitely possible (like consulting other people via chatroom, note: in NetHack that is not considered cheating)? Can users only save their games on certain points or at any place? That makes a huge difference in the design, e.g. making way for exploits similar to the one Thorarin mentions.
If your game goes the traditional roguelike route of only one save, turn basement and permadeath, then it would be possible to save the number of the current turn for any given character along with any game related information (inventory, maps, enemies and their state), and then check against that at any action of the player, therefore to prevent playing the turn twice.
Alternatively you could bundle everything up in client side javascript, so that even if they did resubmit the form it would generate an entirely new combat/treasure encounter.

Categories