Sessions
HTTP je bezestavový protokol, nicméně takřka každá aplikace potřebuje stav mezi požadavky uchovávat, například obsah nákupního košíku. Právě k tomu slouží session neboli relace. Ukážeme si,
- jak používat sessions
- jak předejít jmenným konfliktům
- jak nastavit expiraci
Při použití sessions každý uživatel obdrží jedinečný identifikátor nazývaný session ID, který se předává v cookie. Ten slouží jako klíč k session datům. Na rozdíl od cookies, které se uchovávají na straně prohlížeče, jsou data v session uchovávána na straně serveru.
Session nastavujeme v konfiguraci, důležitá je zejména volba doby exipirace.
Správu session má na starosti objekt Nette\Http\Session,
ke kterému se dostanete tak, že si jej necháte předat pomocí dependency injection. V presenterech stačí jen zavolat
$session = $this->getSession()
.
Start session
Nette ve výchozím nastavení automaticky zahájí session automaticky ve chvíli, když z ní začneme číst nebo do ní
zapisovat data. Ručně se session zahájí pomocí $session->start()
.
PHP odešle při spuštění session HTTP hlavičky ovlivňující kešování, viz session_cache_limiter, a případně i cookie se session ID. Proto je nutné vždy session nastartovat ještě před odesláním jakéhokoliv výstupu do prohlížeče, jinak dojde k vyhození výjimky. Pokud tedy víte, že v průběhu vykreslování stránky se bude používat session, nastartujte ji ručně předtím, třeba v presenteru.
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.
Sekce
V čistém PHP je datové úložiště session realizováno jako pole dostupné přes globální proměnnou
$_SESSION
. Problém je v tom, že aplikace se běžně skládají z celé řady vzájemně nezávislých částí a
pokud všechny mají k dispozici jen jedno pole, dříve nebo později dojde ke kolizi názvů.
Nette Framework problém řeší tak, že celý prostor rozděluje na sekce (objekty Nette\Http\SessionSection). Každá jednotka pak používá svou sekci s unikátním názvem a k žádné kolizi již dojít nemůže.
Sekci získáme ze session:
V presenteru stačí použít getSession()
s parametrem:
Ověřit existenci sekce lze metodou $session->hasSection('unikatni nazev')
.
Se samotnou sekcí se pak pracuje velmi snadno pomocí metod set()
, get()
a
remove()
:
Pro získání všech proměnných ze sekce je možné použít cyklus foreach
:
Nastavení expirace
Pro jednotlivé sekce nebo dokonce jednotlivé proměnné je možné nastavit expiraci. Můžeme tak nechat vypršet přihlášení uživatele za 20 minut, ale přitom si nadále pamatovat obsah košíku.
Pro nastavení expirace jednotlivých proměnných slouží třetí parametr metody set()
:
Nezapomeňte, že doba expirace celé session (viz konfigurace session) musí být stejná nebo vyšší než doba nastavená u jednotlivých sekcí či proměnných.
Zrušení dříve nastavené expirace docílíme metodou removeExpiration()
. Okamžité zrušení celé sekce
zajistí metoda remove()
.
Události $onStart, $onBeforeWrite
Objekt Nette\Http\Session
má 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.
Správa session
Přehled metod třídy Nette\Http\Session
pro správu session:
start(): void
Zahájí session.
isStarted(): bool
Je session zahájená?
close(): void
Ukončí session. Session se automaticky ukončí na konci běhu skriptu.
destroy(): void
Ukončí a smaže session.
exists(): bool
Obsahuje HTTP požadavek cookie se session ID?
regenerateId(): void
Vygeneruje nové náhodné session ID. Data zůstávají zachované.
getId(): string
Vrátí session ID.
Konfigurace
Session nastavujeme v konfiguraci. Pokud píšete aplikaci, která nepoužívá DI kontejner, slouží ke konfiguraci tyto metody. Musí být volány ještě před spuštěním session.
setName(string $name): static
Nastaví název cookie, ve které se přenáší session ID. Standardní název je PHPSESSID
. Hodí se
v případě, kdy v rámci jednoho webu provozujete několik odlišných aplikací.
getName(): string
Vrací název cookie, ve které se přenáší session ID.
setOptions(array $options): static
Konfiguruje session. Lze nastavovat všechny PHP session
direktivy (ve formátu camelCase, např. místo session.save_path
zapíšeme savePath
) a také readAndClose.
setExpiration(?string $time): static
Nastaví dobu neaktivity po které session vyexpiruje.
setCookieParameters(string $path, ?string $domain=null, ?bool $secure=null, ?string $samesite=null): static
Nastavení parametrů pro cookie. Výchozí hodnoty parametrů můžete změnit v konfiguraci.
setSavePath(string $path): static
Nastaví adresář, kam se ukládají soubory se session.
setHandler(\SessionHandlerInterface $handler): static
Nastavení vlastního handleru, viz dokumentace PHP.
Bezpečnost především
Server předpokládá, že komunikuje stále s tímtéž uživatelem, dokud požadavky doprovází stejné session ID. Úkolem bezpečnostních mechanismů je zajistit, aby tomu tak doopravdy bylo a nebylo možné identifikátor odcizit nebo podstrčit.
Nette Framework proto správně nakonfiguruje PHP direktivy, aby session ID přenášel pouze v cookie, znepřístupnil jej JavaScriptu a případné identifikátory v URL ignoroval. Navíc v kritických chvílích, jako je třeba přihlášení uživatele, vygeneruje session ID nové.
Pro konfiguraci PHP se používá funkce ini_set, kterou bohužel některé hostingy zakazují. Pokud je to případ i vašeho hostéra, pokuste se s ním domluvit, aby vám funkci povolil nebo alespoň server nakonfiguroval.