Nette Http 3.1: mnohem chytřejší sessions
Nette vždy přistupovalo k session opatrným způsobem. Spouštělo je automaticky až když je uživatel potřeboval, aby šetřilo serverové prostředky. Nová verze 3.1 tuto filozofii posouvá ještě dál a přináší vylepšení, která dělají práci se sessions ještě efektivnější.

Kdy se session automaticky spouští?
- když se do ní zapisuje
- když se z ní čte a zároveň prohlížeč poslal cookie se session ID
Protože pokud cookie neexistuje, nemusíme session spouštět, abychom věděli, že v ní žádná data nejsou. Tedy i bez spuštění může Nette vrátit například obsah nákupního košíku jakožo prázdný atd.
Celý tento mechanismus má určitá úskalí, která nová verze 3.1.5 řeší.
Pozdní start
V celém procesu správy session jsou důležité tři prvky: identifikátor session (ID) obsažený v cookie, který posílá prohlížeč, odpovídající soubor na disku nebo záznam v databázi obsahující data session, a session ID, které server posílá prohlížeči při prvním spuštění session (aby si ho uložil jako cookie).
S automatickým spouštěním souvisí problém pozdního nastartování
session, tedy v situaci, kdy už byl odeslán ze serveru výstup a nelze už
posílat HTTP hlavičky. Při spuštění session se totiž musí odeslat cookie
se session ID, ale také hlavičky Pragma
a Expires
,
což po odeslání výstupu není možné. Aby se tomuto problému
předcházelo, Nette při nastavení „autoStart: smart“ (což je výchozí
hodnota) automaticky spustilo session při startu aplikace, pokud existovalo
cookie se session ID. Což se mění, viz níže.
Přístup k datům
K datům v session sekci se často přistupuje podobně jako k proměnným:
$section = $session->getSection('unique name');
$section->userName = 'john';
echo $section->userName;
Kvůli specifickému technickému rysu PHP je však operace
echo $section->userName
detekována jako zápis. To
znamená, že i když pouze chceme přečíst data (třeba obsah košíku
pomocí $cart = $section->cart
), PHP to vyhodnotí jako zápis a
nastartuje session, i když cookie neexistuje. Tím přicházíme o výhodu
efektivního autostartu, který měl spouštět session pouze když je to
skutečně potřeba.
Tento problém lze obejít pomocí syntaxe ArrayAccess, která správně rozlišuje mezi čtením a zápisem:
$section['userName'] = 'john';
echo $section['userName']; // jde o operaci čtení
Nicméně syntaxe ArrayAccess může být pro uživatele příliš magická a
někdy nefunguje tak, jak by se mohlo očekávat (např.
$section['cart'][] = $item
generuje notice Indirect
modification of overloaded element has no effect).
Proto v posledních verzích řady 3.1 i 3.0 najdete pro přístup
k datům srozumitelnou sadu metod set()
, get()
a
remove()
, které nemají nevýhody předchozích přístupů a
správně fungují s autostartem session.
Pomocí set()
lze nastavit i expiraci:
$section->set('flash', $message, '30 seconds');
Používání těchto metod se tak stává preferovaným přístupem k datům v sessions. Nette je interně všude používá.
Autostart, když existuje cookie
Nette nově upravuje chování v situaci, když uživatel posílá v cookie ID, kterému neodpovídá žádný soubor na disku nebo záznam v databázi. Dříve Nette v takové situaci vygenerovalo nové ID a vytvořilo nový session soubor, aby předešlo možnému podvržení ID ze strany útočníka. Nyní místo toho Nette cookie smaže a soubor vůbec nevytváří. A to proto, aby se na disku nevytvářely prázdné soubory, pokud útočník záměrně session ID podvrhává.
Nová konfigurace autoStart
V konfiguračním souboru může volba autoStart
nově nabývat
hodnot always
a never
. První z nich zapíná session
vždy hned po startu a je totožná s variantou true
. Novinkou je
never
, která zcela vypíná automatické startování a session se
zapne jen tehdy, pokud sami zavoláte $session->start()
.
Výchozí variantou zůstává smart
, jejíž chování se ale od
verze 3.1 mění, jak jsem zmiňoval v úvodu. Už nezapíná session
automaticky po startu ale učiní tak až v případě čtení nebo zápisu.
Totožné chování má od verze 3.1 i hodnota false
.
Ve starší řadě v3.0 se naopak mění výchozí nastavení ze
smart
na false
, což vypíná autostart po
spuštění.
Události $onStart, $onBeforeWrite
A nakonec objekt Nette\Http\Session
má nově události
$onStart
a $onBeforeWrite
, můžete tedy přidat
callbacky, které se vyvolají po startu session nebo před jejím zápisem na
disk a následným ukončením. Tyto události jsou užitečné především pro
ladění a detekování míst v kódu, kde dochází k automatickému
spuštění session, což vám pomůže optimalizovat práci se session.
$session->onBeforeWrite[] = function () {
// zapíšeme data do session
$this->section->set('basket', $this->basket);
};
Při testování nového chování nezapomeňte, že ve vývojářském režimu startuje session Tracy, protože ji používá pro zobrazování pruhů s přesměrováním a AJAXovými požadavky v Tracy Baru. Od verze 2.9 už Tracy session nevyužívá, a to právě proto, aby bylo možné lépe ladit fungování session.
Chcete-li odeslat komentář, přihlaste se