Sessions

HTTP is a stateless protocol, but almost every application needs to store states between requests, e.g. content of a shopping cart. And exactly for that the session (or relation) is. We will show you,

  • how to use sessions
  • how to avoid naming conflicts
  • set expiration
  • secure against vulnerability

When using sessions, each user who visits a web page receives a unique identifier called Session ID, which is passed by cookies. It serves as a key for session data. Unlike cookies, which are stored at browser side, session data are stored at server side.

Sections

In pure PHP is session data storage implemented as an array, which is accessible via global variable $_SESSION. The problem is, that applications are usually composed of several independent parts and if every part can use the same array, you'll have to solve naming conflicts sooner or later.

Nette Framework solves this problem by division of the session space into sections (objects Nette\Http\SessionSection). So then every part of a program uses its own section with a unique name and no collision can occur.

Let's start with a session manager, which is an object of class Nette\Http\Session. We can access this service directly from presenter:

// $this stands for presenter
$session = $this->getSession();
$mySection = $this->getSession('mySection');

Or we can require it using Dependency Injection, in our case in constructor:

use Nette;

class MyService {

    /** @var Nette\Http\Session */
    private $session;

    /** @var Nette\Http\SessionSection */
    private $sessionSection;

    public function __construct(Nette\Http\Session $session)
    {
        $this->session = $session;

        // get section by identifier 'mySection':
        $this->sessionSection = $session->getSection('mySection');
    }

}

We can use a method hasSection('myCounter') for checking an existence of a section.

There is no need to start or close that session, it's done automatically by framework itself. But we can start it manually by calling $session->start(). If we call that start() method more times, nothing happens and it will have no effect. You can also modify this behaviour in configuration.

And then it's really simple to work with that section:

// variable writing
$section->userName = 'franta'; // or $section['userName'] = 'franta';

// variable reading
echo $section->userName; // or echo $section['userName'];

// variable cancellation
unset($section->userName);  // unset($section['userName']);

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

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

Example: Visit Counter

We will start with an example of a visit counter, which shows how many times did user display a page.

$section = $session->getSection('myCounter');
$section->count++; // increment counter by one
echo "You displayed this page $section->count ×";

Accessing a non-existent variable generates no error (variable has a null value). It could be undesirable behaviour in some cases and that's why there is a possibility to change it:

$section->warnOnUndefined = true;

How to Set Expiration

Very useful feature is the possibility to set its own expiration time for every section or variable. So we can let expire user's login, but still remember a content of a shopping cart.

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

// variable $section->a will expire after 10 seconds
$section->setExpiration(10, 'a');

Besides a relative time in seconds one can use a UNIX timestamp or a textual form. Interesting is a value of 0, which sets an expiration time to the moment when the user closes his browser:

// variable $section->password will expire when a user closes a browser
$section->setExpiration(0, 'password');

Remember that the expiration time of a whole session (see session configuration) has to be the same or greater than the time which was set for the separate sections or variables.

Cancellation of a previously set expiration can be achieved by calling removeExpiration() method. Imediate cancellation of the whole section is handled by the remove() method.

Session Configuration

Configuration of a session must be done before using it. The best place to do it is a config.neon. Read more on session configuration.

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 behaviour really works and that there is no possibility to substitute or steal an identifier.

That's why Nette Framework properly cofigures 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.

Known Limitations

In browser Chrome in the “System” section Continue running background apps when Google Chrome is closed., this option is default enable. It causes the cookie that has a set expiration to close the browser, cookie still lives. Section with expiration 0, when you close the browser is not removed.