I am having a hard time with the cookie session driver in Laravel.
I have a simple form with a validation in place. This is my method for saving this form data:
The browser has limitation of cookie. It's too large for the browser to store the cookie while you use cookie
as the session driver. You can check the browser cookie limitation here http://browsercookielimits.iain.guru/
Recommendation:
Use redis
as the session driver.
Steps:
1.After installed Redis server, add the predis/predis
package:
composer require predis/predis
2.Change your configuration file config/database.php
:
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
The cookie session driver is not suitable for applications that must store any significant amount of data in the user's session. Browsers typically limit data stored in one cookie to around 4 KB (4096 bytes). As we found, we can easily exhaust this capacity by attempting to store a 1024-character-long string in the session cookie—the "Lorem ipsum..." string in the question contains only ASCII characters, and each ASCII character is represented using 4 bytes, so 1024 × 4 = 4096 bytes.
As we can see, we quickly begin to run out of space when we need to store additional items in one session cookie, such as the serialization metadata for PHP values, or when the data contains UTF-8 characters that consume more than 4 bytes per character. To continue to use cookies to store session data greater than 4 KB, we'd need to write a custom session driver that partitions session data across multiple cookies for each response and then reassembles them on each request. For good reason, no existing packages do this that I'm aware of. This brings me to my next point...
I want to strongly discourage the use of cookies for storing a full session (instead of just a session ID). This approach can expose security vulnerabilities, adds overhead to requests and responses (including requests for static assets on the same domain), risks desynchronizing data (right-click app tab → Duplicate to see what happers), complicates tests and debugging, and causes problems when storing certain kinds of data.
For the distributed application in the question, we have four options:
I think we can reasonably eliminate the fourth option. Unless we have a very good reason to avoid using the first three approaches, and for typical applications we usually don't, we cannot justify the amount of work, complexity, and overhead needed to build a system to transfer session data back and forth across HTTP when the first three options are standard, widely-accepted solutions.
Based on the information in the question, it sounds to me like you already understand the concepts and implications behind the other three options, so I won't elaborate on explanations for each one (but do comment to let me know if I should).
For applications without advanced infrastructure requirements, I recommend the third approach: sticky sessions. These are relatively easy to set up and usually require configuration on the load balancer so that once a client starts a session with an application server, the load balancer routes any subsequent requests to the same server until the session ends. For high-availability, we can combine this approach with the Redis session driver and Redis servers configured for master-slave replication between the datacenters, and, optionally, Redis Sentinel to automate failover. Redis suits session data well and offers better performance than a relational database. If we have multiple application instances at each data center, Redis provides a central location for session data for all instances at one site.
For completeness, and to directly answer the question, here's an overview for the development needed to create a cookie-based session driver that handles session data greater than 4 KB. Again, I recommend one of the other approaches described above:
First, we'll need to create a new class that implements PHP's SessionHandlerInterface (check out Laravel's cookie session handler for a starting point—we can probably extend this class).
The write()
method of this class will need to serialize the session $data
and then split the data into chunks smaller than 4 KB (for some browsers, less that 4093 bytes). Be sure to account for multibyte characters. Before splitting the data, we may also want to encrypt it if the session contains sensitive information or if we don't want clever users to mess with the values. Then, the method should add a new cookie for each chunk of the session data. Each cookie will need to contain the sequence in its name, and we can add an additional cookie that contains the number of chunks.
The read()
method will perform these operations in reverse. First, it will reassemble each chunk from the cookies in the request using the value of the cookie that contains the number of chunks, and then, optionally, decrypt the data if we encrypted it.
The destroy()
method should clear the contents of each cookie that contains a chunk.
Then we'll choose a name for the session driver, such as cookie-extended
, and, in a service provider's boot()
method, register it as an available driver using :
Session::extend('cookie-extended', ...);
We'll need to instruct the application, in config/session.php or in .env, to use the new driver for user sessions.
If you do decide to go down this path, be sure to test the implementation in every browser you plan to support, as different browsers impose their own limitations on the size and quantity of cookies. Even if we've increased the amount of session data we can store as cookies, we're still limited to the maximum number of cookies a browser will accept per domain.
As a final note, storing sessions in the database may not impact performance as much as you think. It could be worth measuring the actual load created by this simple solution before investing many hours optimizing for a concern that might not be a real issue.