storing and loading cart in the database - php

I am coding a E-commerce website/admin interface for a client. They are doing some B2B so they want the cart to be saved/loaded from database so if the user close his browser and reopen it the cart is intact.
The application is using the Zend Framework and I've been looking to the Zend_Session_SaveHandler_DbTable. So I can save the session in the database easily what about the reverse case I want to load the database in session.
Also it would be nice if can load that cart items only when the users reopen the browser not on every page since it would have some performance impact.
Any advices ?
Kind of sub question: I suppose Zend_Session is using $_SESSION so everything is based on the php session id, is there any possibilities to change what it is using has id.
I am thinking of generating my unique id and pushing this to client with cookies.
NOTE 2: the user is able to build some cart not being logged so I cannot rely on the login process ....

The first thing you need to do is work out how to make sessions persist beyond the user closing their browser. Check the Zend_Session configuration part of the manual:
http://framework.zend.com/manual/en/zend.session.global_session_management.html
see the part on the 'remember_me_seconds' option. Once you have this working, anything you store in the session will be available when the user comes back another day.
As for storing the cart in the session, I would suggest creating a 'Cart' class which contains this information. You could then either store the whole object in the session or store the data in a 'carts' table in your database and merely store the ID of the cart in the user's session. Then on subsequent visits you just have to check for the existence of the ID and load the Cart up if it's present.

I had same problem as you when I wanted to store column settings for grid before two weaks.
And I didnt have whole session in DB. I just check session if there is something in the cart. If there is nohing in session, load from db. And on every change of basket save to db of course.
And I used serialized array from Session_Namespace::to_array() method. not whole Session_Namespace because of I cant load it back.
You can use flag which eill tell you, that you try load from db once, for instance that there is no cart in db same in session and you dont want try to load cart every request.

Related

How can I identify a guest user for a time longer than session usually exists

I know, that I can use \Session::getId(). But it changes form time to time. Maybe I do not understand the sessions. As I know it starts when php runs and it is deleted when php code is finished. On the other hand I read that session id is stored in cookie and when a user open your site again, the session 'restores'. So why in my case the session id expires so quickly. How can I get the 'session id' that does not change at least for a month and that is used by shopping carts?
Update: The question becomes a little confusing because I do not want how call some things and do not know how these things work.
I want to know how I can identify a guest user and get its unique id for some period of time (longer than sessions usually exist). In the result I want to have function someFunction which could do the following:
$guestId = someFunction();
$dbRow = Model::findByGuestIdOrNew($guestId);
// now $dbRow contains all previosly save info about a guest user,
// of it does not exists, create new row by `$guestId`.
It seems to me that there is some unique id of session, which exists for time longer than session. This thought came to me when I've seen that in most cart packages cart items are saved directly to session. I really do not know how long these packages store cart items, but I think this time is even longer than a week. This period of time for lifetime of cart was defined by me while working with such shopping platforms: shopify and bigcommerce. I know they store cart item longer than a week. So I want to know how they identify a guest user before he creates an account. Also It will be a useful information to know how long most 'shopping cart' packages store cart items.
Laravel implements a custom way of handling sessions, but the logic is the same as the one described by the PHP Sessions Documentation. Here's an excerpt from that documentation that pretty much explains the logic behind it:
Sessions are a simple way to store data for individual users against a unique session ID. This can be used to persist state information between page requests. Session IDs are normally sent to the browser via session cookies and the ID is used to retrieve existing session data. The absence of an ID or session cookie lets PHP know to create a new session, and generate a new session ID.
So your understanding of how sessions use IDs is right, but there is a another component to sessions that defines how long they last. Sessions expire after a predefined period of time, which in the case of Laravel, can be set in the config/session.php file:
'lifetime' => 120,
The above default value means that the session will expire after 120 minutes of inactivity from the user. There is also the option to expire the session when the user closes the browser, thus forcing a new session to be generated when he opens the browser again, by setting:
'expire_on_close' => true,
You should read the Laravel Sessions Documentation for more insight into how Laravel handles sessions, and also read the comments from the config/session.php file which explain what each configuration option does and what values it can take.
The above explained how sessions work in PHP and Laravel, so in your case to make the session last for a whole month you could set the lifetime value to:
'lifetime' => 60*24*30 // 60 minutes x 24 hours x 30 days = 43200 minutes
But that seems like a really long time to keep a session, especially if the session also contains authentication info. If you want to persist the contents of a shopping cart I suggest you store them in the database and when the user logs in the next time just populate the session from the database.
For example the Cartalyst Cart library (which happens to have really nice Laravel integration) handles all the logic behind a shopping cart, while offering a nice sync method that allows you to add the cart items stored in the database to your current session. You could do the following to restore a cart from the database:
// Get the items from the database
$items = CartItem::where('user_id', Auth::id())->get();
// Sync the items with the session cart
Cart::sync($items);
The above assumes you have a cart_items table that has a CartItem model attached, and that you're using the Laravel Authentication to handle users sessions, but as you can see it leads to a very easy to implement solution.

Shopping cart persistence: $_SESSION or browser cookie?

On an e-commerce site with no username/login to persist cart data, would it be better to use the PHP $_SESSION variable or a browser cookie to persist items in the shopping cart? I am leaning toward $_SESSION since cookies can be disabled, but would like to hear thoughts from you.
Thank you in advance for your consideration.
Neither
No large sites would dare store a user's cart in a session or cookie - that data is just to valuable.
What customers are buying, when they select items, how many they purchase, why they don't finish the checkout, etc.. are all very, very important to your business.
Use a database table to store this information and then link it to the user's session. That way you don't lose the information and you can go back and build statistics based on users carts or solve problems with your checkout process.
Log everything you can.
Database Schema
Below is a simplified example of how this might look at the database level.
user {
id
email
}
product {
id
name
price
}
cart {
id
product_id
user_id
quantity
timestamp (when was it created?)
expired (is this cart still active?)
}
You might also want to split the cart table out into more tables so you can track revisions to the cart.
Sessions
Normal PHP Sessions consist of two parts
The data (stored in a file on the server)
A unique identifier given to the user agent (browser)
Therefore, it's not $_SESSION vs $_COOKIE - it's $_SESSION + $_COOKIE = "session". However, there are ways you can modify this by using a single encrypted cookie which contains the data (and therefore you don't need an identifier to find the data). Another common approach is to store the data in memcached or a database instead of the filesystem so that multiple servers can access it.
What #Travesty3 is saying is that you can have two cookies - one for the session, and another that is either a "keep me logged in" cookie (which exists longer than the session cookie), or a copy of the data inside separate cookie.
As pointed out by Xeoncross, it is very important to store any possible information for analysis. So one should not entirely rely on sessions and cookies.
A possible approach is-
Use sessions if not logged in
If the user is not logged in, you can store and retrieve the cart items and wishlist items from session using $_SESSION in PHP
Use database when logged in
If the user is logged in then you can consider one of the two options -
Store the cart item or wishlist item in database alone
Store the cart item or wishlist item in database as well as in session (This will save some of your database queries)
When user logs in
When the user logs in, get all the cart items and wishlist items from the session and store it in the database.
This will make the data persistent even if the user logs out or changes the machine but till the user has not logged in, there is no way to store the information permanently so it will not be persistent.
Getting required data
Whenever you are trying to access cart or wishlist do the following check -
If the user is not logged in then look into session
If the user is logged in, query database if you are storing in the database alone, otherwise you can just look into sessions if you are keeping session updated along with the database
I would store it in a SESSION. My wish list is rather long, and I am afraid that it will not fit in the 4K storage that a COOKIE may occupy. It forces you set the session time out to a longer period.
note: there are some countries (like the Netherlands, where I am) that have very strict policies about cookies, and you may be forced by legislation to use Sessions.
Some points to help:
Cookies:
info is persisted untill the cookie expires (what can be configured by you);
tend to slow down the communication between server and client, since it has to be exchanged between the two in every request/response;
its an insecure form of storing data and easy to sniff;
they also have a limit to store data.
Session:
all information is persisted in the server, thus not been exchanged with the client.
because it is not shared across the network, its a bit more secure;
all info is lost when the session ends;
If you are hosting in a shared host, you may have problems with session ending in the middle of a operation due to a push on the resources by any of the sites hosted on the same server.
I would personally go with sessions, since I'm assuming to be a small/meddium auddience page. If it grows, you would be better with a simple DB structure to store this data, with a maintenance plan to get ridge of unnecessary data (eg: clients that choose some products but don't do the checkout).
You might consider using both.
The drawback with $_SESSION is that the session is cleared when the browser is closed.
Use sessions, but attempt to populate the $_SESSION data from a cookie, if it's available.
I would use a session. If a user has cookies disabled then the session won't be able to start as the session ID is stored on the user's machine in a cookie.
There are some settings you may want to look at in order to attempt to keep the sessions for longer.
Prevent the session cookie from being deleted when the user closes their browser by running session_set_cookie_params() with the lifetime parameter set. This function needs to run before session_start()
You may also want to extend how often sessions are cleared from the server by modifying the session garbage collection settings session.gc_probability, session.gc_divisor, session.gc_maxlifetime either in php.ini or using ini_set()
If you have other websites running on the server and you modify the above garbage collection settings you will need them set in php.ini so they apply to all websites, or if you are using ini_set() then you might also look at saving these sessions to a different directory than other websites by modifying session_save_path(). Again this is run before session_start(). This will prevent the garbage collection of other websites clearing up your extended sessions for one particular site.
I would also recommend setting the following session settings in php.ini session.entropy_file = /dev/urandom, session.entropy_length = 256, session.hash_function = sha512. That should give you a cryptographically strong session ID with an extremely tiny chance of collisions.
And make sure you have an SSL cert on your site to prevent man in the middle attacks against your session ID.
Obviously a user could still decide to manually clear all their cookies which will take the session ID cookie with it but that's a risk I'd be prepared to take. If I was halfway through a shopping cart system and hadn't checked out, I wouldn't go and clear my cookies. I still think sessions are better than just using plain cookies.
The data is secure enough so long as you are the only website that has access to your sessions directory and your session ID is strong. And by extending the server's session storage time your data can persist on the server.
There are further measures you could employ to make your sessions even stronger. Regenerate your session ID every 20 minutes, copying the data over. Also record session IDs against IP addresses in a database and check to see if a particular IP address attempts to send more than X number of session IDs in a given time to prevent someone trying to brute force a session ID.
You could also store the data in a database linked by the session ID, instead of in a session file on the server. However this is still reliant on a session ID which is stored in a cookie and could disappear at any time. The only way to truly be sure that a user doesn't lose their cart is by having them login first and storing in a database.

E-commerce project with users cart

I want to create an e-commerce project online. I have this issue :
if the user is not logged in, then the selected products will be automatically added to a default cart under the name of guest001, guest002 etc where guestxxx is a default user.
if the user signs up, then the system will automatically check in his carts data to add it to his new account
when the user then wants to add new products to cart, they will be added directly to his cart.
My questions are :
Should I be using cookies to store the data in the user's machine, so it will be used by the system once the user creates his account? or should I use server side session data?
Should I be creating a default client (guestxxx) in the database once the unknown user adds something to his cart, or just create a cookie to store the data without the need to create a guest user?
I just have little suggestion for you.
If you are using Codeigniter Framework you can use Library Cart Class
or you want make code yourself.
According to my experience. I was used session for store cart while users checkout I add his cart into my database.
Disadvantage of using it while browser is closed your guest cart will start from default (no cart),
If you use cookie for it while browser is closed your guest cart will keep exist. ( store in browser ). But I think you can use both of it. Use cookie for keep cart data and use session for processing cart in your PHP Code. because Cookie is stored in browser, malicious user can do malicious activity of it.
For client i think you can use session or cookie rather than add his data into database
Hope it can help you. I just know little about it.

Working with regenerating session id in PHP/CodeIgniter

I'm using CodeIgniter's Session class to manage my sessions for a cart/checkout system. The session data is being stored in the database and the session id is stored in a cookie. All cart information is retrieved via AJAX and is kept in the session, along with the session id.
Right now I am using the session id that PHP/CodeIgniter generates as a way to keep track of users. Users do not log in to the site and the store and the cart/checkout system are on different domains so this is the only thing that is tying them to their cart that is stored in the session/database. I use this session id in hidden fields on forms and as a parameter in links so that it gets sent to the server on any request (add item, remove item, view cart, etc...)
CodeIgniter lets you set a time for regenerating the session id, right now I have it set to 10 minutes. I had it at the default but that was too short because if the user sat at the page for too long, the session id that was dynamically written to the links and forms would be out of date and no longer tied to their cart data.
This is obviously not a great solution. What is the best way to allow for regenerating session ids at a lower interval but still keep users tied to their cart data even if the user waits 10+ minutes (without a page refresh) to do an action?
Don't use the session id's in the database. The cart should persist across sessions, so you need to store the cart in relation to the user, not the session. I also would not be putting the session id in fields as a hidden field. The benefit of sessions is you can store them server side.
Store the cart in the database, don't load the whole thing into session.
Method #1
A user can be given an "active" cart in the database.
User -> (has many) Cart
This cart is then updated by adding items to it
/cart/add/{id} -> Verify prices / quantities
This cart is not linked to the session, the session is only controlling which user is logged in. When they checkout the cart is set from "active" to "ordered" and a new "active" (but empty) cart is created. Carts will persist in the database between sessions, and a full history can be made available.
Method #2
Store the entire cart in session, not backed against the database. This would make some things simpler (adding / removing items aren't DB operations) but it also won't persist across sessions. When a user checks out write the cart to the database.

What is the best way to deal with sessions when the user may stay logged in, but a session key needs to be updated, because of another update?

I'm working a site where users could technically stay logged in forever, as long as they never close their browser (and therefore never get a new session key). Here's what I could see happening: a user leaves a browser open on computer A. The then use computer B, login and change their name which is stored in the session. They logout of B, but A is still logged in and still has their old name stored in the session. Therefore, their name won't be updated till the next time they logout manually or they close their browser and open it again and are logged in through the remember me function.
Name is a simple example, but in my case the subscription level of their account is stored in the session and can be changed.
How do you deal with this?
A few ideas that I have are:
After a period of 10 minutes or more, the session data get's reloaded. It might be exactly 10 minutes if the user is highly active as the function will get triggered right at the 10 minute point or it could be after 2 hours if the user leaves and comes back and then triggers the functionality.
Store as little information as possible in the session and load the rest from the DB on every page call. (I really don't like this idea.)
Use database sessions and use the same session on all the computers. I like this, but I could see it getting confusing when something like search criteria are stored in the session--the same criteria would show up on both browsers/comptuers.
For information, even such as the user's name or username/email address, store it in the session, but for other information that would heavily affect their abilities on the site, don't store it in the session and load when needed (attempt to only do it once per instance).
Are there other better methods?
--
Another option: 5. Use database session and when an update is made load the user's other sessions (just unserialize), change the relevant information and save them back to the database.
I would go either with number 1 or number 4. If you store the time of the last update of the information, you could even ask on every request whether the date has been updated.
Don't store information likely to change in the session, if you're looking at scenarios like the one you outline. Just get over your dislike of loading user data with every page - it's by far the best idea.
I'm guessing you don't want to load the data from the database because you're concerned about performance issues somehow. Before you try out any of the other solutions, you might want to test how long it takes to actually load a users data from the database, then check that against your number of users - chances are you won't see any performance problems due to loading user profiles on every page.
Regards
I'd go with option 6: only store userid and session specific stuff (search criteria) in his session and put the rest into APC/xcache (memcached if you're using multiple servers).
this way you'll only have to go to the database the first time (and after the cache expires) and you can still share any data between users sessions.
Normally you should do 2), but you don't like it.
maybe you can use sessions stored in db.
when a user change his name, put into all sessions from that user the information "refresh userdata".
on the next request the userdata is reloaded again into the session and is cached there.
this can be done be reusing your loaduserdata function which called at login.
php session_set_save_handler() - also read comments
php session_decode() - to read the username from the session to store it additionally to the sessiondata. usefull for easily to find the users sessions for updating.
[edit]
don't forget:
when you are updating all the sessions while the page is generated (between session_start and session_write_close) you changes maybe lost.

Categories