Working with regenerating session id in PHP/CodeIgniter - php

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.

Related

PHP - Need to get the same thing using 3 very different id's from API

I need to be able to be able to get the same data from my database using 1 of 3 different ID's.
In this instance I am fetching shopping cart data using either a session_id (for guest users), account_id (for logged in users) or just by the cart's primary auto-incrementing key.
At the moment I have three GET API routes set up but I want to know if there's a more efficient way of accomplishing this
$router->get('carts/{id:i}', ['Controller\\CartController', 'getCartById']);
$router->get('carts/session-id/{sessionId:s}', ['Controller\\CartController', 'getCartBySessionId']);
$router->get('carts/account-id/{accountId:i}', ['Controller\\CartController', 'getCartByAccountId']);
A session_id is stored in a browser cookie with a TTL. A shopping cart will always have at least a session_id in the database but not always an account_id (signifying a guest user).
In this instance you are either logged in or a guest.
If the Cookie storing the session_id associated with a cart expires and you're not logged in we can assume that the cart has expired. If that guest user wants to add something to their cart again we will generate them a new one with a new session_id.
I think this chart explains things pretty well

Symfony4: How to transfer data to a new (logged in) session? e.g. shopping cart data

I want to allow guest visotors to store items in a shopping cart.
That cart should be taken into the new session, if that guest logs into an existing account.
Currently I save a session ID alongside cart data in my DB.
But as soon as a user logs into their account, the session ID is changed, so I don't have a way of moving the data from one session to the next.
What is the best way to (selectively) move data into a new session?
Try to check the documentation.
There are many type of session usage
https://symfony.com/doc/current/components/http_foundation/session_configuration.html

struggling to understand some cookie/database shopping cart concepts

I am trying to get my head around how to correctly implement a shopping cart based on saving a cookie with a unique identifier to identify a users shopping cart in the database whether the user is logged in or as shopping a guest. I've tried to look at as many examples as i can, but i am not understanding it clearly enough.
Here's how i have it so far:
[Guest user]
Create cookie with unique id when user adds item to cart
Check for existing cart associated with cookie ID in database
If cart does not exist, create entry in DB table 'cart_id' with the cookie ID as session identifier
create entry in DB table 'cart_items' with the cookie ID as an identifier
[Logged in user]
Check for existing cart in DB table 'cart_id' associated with username and cookie ID
If cart exists, rewrite new cookie ID with cookie ID from database
If cart does not exist, assign username ID to table 'cart_id' with users unique cookie ID
Here is where i am having troubles:, all the previous is well and good, assuming the user hadn't only decided to login after filling their cart which is where i am going wrong. Here's what i have:
Check for existing cart in DB table 'cart_id' associated with username and cookie ID
If cart does not exist, assign username to 'cart_id' table
If cart already exists, rewrite new cookie ID with existing cookie ID stored in database
rewrite 'new' cart items(items chosen while not logged in) with the users stored cookie ID
Check for duplicate cart items from existing cart and new cart items
If duplicate items are found, delete old items and replace with new item quantities
etc etc So basically i dont think it's going too well, though i currently works okay, it seems i am going a really crappy way about it.
How can i better handle a registered users shopping cart if they choose to log in after they have filled their shopping cart? Will i need to have a separate table for guest users and registered users, how can i transfer a guest shopping cart list to the registered users shopping cart if they log in after they pick their cart?
I think you're better off at storing every ordered item (or the whole shopping cart content) locally, either through localStorage or cookie.
The way you do it, you're doing too much request on your DB. Why? Because you're assuming a cookie is something reliable, and in fact, it is not. So all of your operations using "cookie ID" are for nothing if the user chooses to reset his browser / delete his cookies.
There are many ways a cookie can be destroyed, at least it's harder with localStorage.
I would say : store it locally, and if logged, sync what has been saved locally with what is on the DB. But don't store unlogged users shopping carts on the DB : eventually you'll end up with orphans (no more cookie present for some reason), and you won't be able to understand why.

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.

storing and loading cart in the database

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.

Categories