Nette Http 3.1: much smarter sessions
Nette has always approached sessions with caution. It started them automatically only when the user needed them, in order to conserve server resources. The new version 3.1 takes this philosophy even further and brings improvements that make working with sessions even more efficient.

When are sessions automatically started?
- when writing to them
- when reading from them and the browser has sent a cookie with the session ID
Because if the cookie doesn't exist, we don't need to start the session to know there's no data in it. So even without starting, Nette can return for example the shopping cart content as empty, etc.
This entire mechanism has certain pitfalls that the new version 3.1.5 addresses.
Late initialization
In the entire session management process, three elements are important: the session identifier (ID) contained in the cookie sent by the browser, the corresponding file on disk or database record containing session data, and the session ID that the server sends to the browser when first starting the session (so it can store it as a cookie).
The automatic startup is related to the problem of late session
initialization, which occurs when output has already been sent from the server
and HTTP headers can no longer be sent. When starting a session, you need to
send a cookie with the session ID, as well as the Pragma
and
Expires
headers, which is not possible after sending output. To
prevent this problem, with the setting “autoStart: smart” (which is the
default value), Nette automatically started the session at application startup
if a cookie with session ID existed. This is changing, see below.
Accessing Data
Data in a session section is often accessed similarly to variables:
$section = $session->getSection('unique name');
$section->userName = 'john';
echo $section->userName;
However, due to a specific technical feature of PHP, the operation
echo $section->userName
is detected as a write. This
means that even when we only want to read data (like cart contents using
$cart = $section->cart
), PHP evaluates it as a write and starts
the session, even if the cookie doesn't exist. This eliminates the advantage of
efficient autostart, which was supposed to start sessions only when truly
necessary.
This problem can be bypassed using ArrayAccess syntax, which correctly distinguishes between reading and writing:
$section['userName'] = 'john';
echo $section['userName']; // this is a read operation
However, ArrayAccess syntax might be too magical for users and sometimes
doesn't work as expected (e.g., $section['cart'][] = $item
generates a notice Indirect modification of overloaded element has no
effect).
Therefore, in the latest versions of both 3.1 and 3.0 series, you'll
find a clear set of methods set()
, get()
, and
remove()
for accessing data, which don't have the disadvantages of
previous approaches and work correctly with session autostart.
Using set()
, you can also set expiration:
$section->set('flash', $message, '30 seconds');
Using these methods thus becomes the preferred approach to data in sessions. Nette uses them internally everywhere.
Autostart When Cookie Exists
Nette has updated its behavior in situations where a user sends an ID in a cookie that doesn't correspond to any file on disk or database record. Previously, Nette would generate a new ID and create a new session file to prevent possible ID spoofing by an attacker. Now, instead of that, Nette deletes the cookie and doesn't create a file at all. This is to prevent empty files from being created on disk if an attacker deliberately spoofs session IDs.
New autoStart Configuration
In the configuration file, the autoStart
option can now take the
values always
and never
. The first one turns on the
session always right after start and is identical to the true
variant. The new option is never
, which completely turns off
automatic starting, and the session is only turned on if you call
$session->start()
yourself. The default option remains
smart
, but its behavior changes from version 3.1, as I mentioned
in the introduction. It no longer turns on the session automatically after start
but does so only when reading or writing. The value false
has
identical behavior from version 3.1.
In the older v3.0 series, the default setting is conversely changing from
smart
to false
, which turns off autostart after
launch.
Events $onStart, $onBeforeWrite
Finally, the Nette\Http\Session
object now has events
$onStart
and $onBeforeWrite
, so you can add callbacks
that are triggered after session start or before it's written to disk and
subsequently closed. These events are particularly useful for debugging and
detecting places in code where automatic session startup occurs, which helps you
optimize session work.
$session->onBeforeWrite[] = function () {
// we'll write data to the session
$this->section->set('basket', $this->basket);
};
When testing the new behavior, remember that in development mode, Tracy starts the session because it uses it to display redirection bars and AJAX requests in the Tracy Bar. From version 2.9, Tracy no longer uses sessions, precisely to better debug session functionality.
Sign in to submit a comment