Sessions

HTTP is a stateless protocol, but almost every application needs to keep state between requests, e.g. content of a shopping cart. This is what a session is used for. Let's see

  • how to use sessions
  • how to avoid naming conflicts
  • how to set expiration

When using sessions, each user receives a unique identifier called session ID, which is passed in a cookie. This serves as the key to the session data. Unlike cookies, which are stored on the browser side, session data is stored on the server side.

We configure session in configuration, the choice of expiration time is important.

The session is managed by the Nette\Http\Session object, which you get by passing it using dependency injection. In presenters simply call $session = $this->getSession().

Installation and requirements

Starting Session

By default, Nette will start a session automatically the moment we start reading from it or writing data to it. To manually start a session, use $session->start().

PHP sends HTTP headers affecting caching when starting the session, see session_cache_limiter, and possibly a cookie with the session ID. Therefore, it is always necessary to start the session before sending any output to the browser, otherwise an exception will be thrown. So if you know that a session will be used during page rendering, start it manually before, for example in the presenter.

In developer mode, Tracy starts the session because it uses it to display redirection and AJAX requests bars in the Tracy Bar.

Section

In pure PHP, the session data store is implemented as an array accessible via a global variable $_SESSION. The problem is that applications normally consist of a number of independent parts, and if all have only one same array available, sooner or later a name collision will occur.

Nette Framework solves the problem by dividing the entire space into sections (objects Nette\Http\SessionSection). Each unit then uses its own section with a unique name and no collisions can occur.

We get the section from the session manager:

$section = $session->getSection('unique name');

In the presenter it is enough to call getSession() with the parameter:

// $this is Presenter
$section = $this->getSession('unique name');

The existence of the section can be checked by the method $session->hasSection('unique name').

The section itself is very easy to work with using the set(), get() and remove() methods:

// variable writing
$section->set('userName', 'franta');

// reading a variable, returns null if it does not exist
echo $section->get('userName');

// variable removing
$section->remove('userName');

It's possible to use foreach cycle to obtain all variables from section:

foreach ($section as $key => $val) {
	echo "$key = $val";
}

How to Set Expiration

Expiration can be set for individual sections or even individual variables. We can let the user's login expire in 20 minutes, but still remember the contents of a shopping cart.

// section will expire after 20 minutes
$section->setExpiration('20 minutes');

The third parameter of the set() method is used to set the expiration of individual variables:

// variable 'flash' expires after 30 seconds
$section->set('flash', $message, '30 seconds');

Remember that the expiration time of the whole session (see session configuration) must be equal to or higher than the time set for individual sections or variables.

The cancellation of the previously set expiration can be achieved by the method removeExpiration(). Immediate deletion of the whole section will be ensured by the method remove().

Events $onStart, $onBeforeWrite

Object Nette\Http\Session has events $onStart a $onBeforeWrite, so you can add callbacks that are called after the session starts or before it is written to disk and then terminated.

$session->onBeforeWrite[] = function () {
	// write data to the session
	$this->section->set('basket', $this->basket);
};

Session Management

Overview of methods of the Nette\Http\Session class for session management:

start(): void

Starts a session.

isStarted(): bool

Is the session started?

close(): void

Ends the session. The session ends automatically at the end of the script.

destroy(): void

Ends and deletes the session.

exists(): bool

Does the HTTP request contain a cookie with a session ID?

regenerateId(): void

Generates a new random session ID. Data remain unchanged.

getId(): string

Returns the session ID.

Configuration

We configure session in configuration. If you are writing an application that does not use a DI container, use these methods to configure it. They must be called before starting the session.

setName(string $name): static

Sets the name of the cookie which is used to transmit the session ID. The default name is PHPSESSID. This is useful if you run several different applications on the same site.

getName(): string

Returns the name of session cookie.

setOptions(array $options)static

Configures the session. It is possible to set all PHP session directives (in camelCase format, eg write savePath instead of session.save_path) and also readAndClose.

setExpiration(?string $time)static

Sets the time of inactivity after which the session expires.

setCookieParameters(string $path, string $domain=null, bool $secure=null, string $samesite=null)static

Sets parameters for cookies. You can change the default parameter values in configuration.

setSavePath(string $path)static

Sets the directory where session files are stored.

setHandler(\SessionHandlerInterface $handler)static

Sets custom handler, see PHP documentation.

Safety First

The server assumes that it communicates with the same user as long as requests contain the same session ID. The task of security mechanisms is to ensure that this behavior really works and that there is no possibility to substitute or steal an identifier.

That's why Nette Framework properly configures PHP directives to transfer session ID only in cookies, to avoid access from JavaScript and to ignore the identifiers in the URL. Moreover in critical moments, such as user login, it generates a new Session ID.

Function ini_set is used for configuring PHP, but unfortunately, its use is prohibited at some web hosting services. If it's your case, try to ask your hosting provider to allow this function for you, or at least to configure his server properly.

version: 4.0 3.x 2.x