Seje

HTTP je brezstanje protokol, vendar skoraj vsaka aplikacija potrebuje ohranjati stanje med zahtevami, na primer vsebino nakupovalne košarice. Prav temu služijo seje ali relacije. Pokazali si bomo,

  • kako uporabljati seje
  • kako preprečiti konflikte imen
  • kako nastaviti potek

Pri uporabi sej vsak uporabnik prejme edinstven identifikator, imenovan ID seje, ki se prenaša v piškotku. Ta služi kot ključ do podatkov seje. Za razliko od piškotkov, ki se shranjujejo na strani brskalnika, se podatki v seji shranjujejo na strani strežnika.

Sejo nastavljamo v konfiguraciji, pomembna je zlasti izbira časa poteka.

Upravljanje sej ima na skrbi objekt Nette\Http\Session, do katerega pridete tako, da si ga pustite predati s pomočjo dependency injection. V presenterjih je dovolj le poklicati $session = $this->getSession().

Namestitev in zahteve

Zagon seje

Nette v privzeti nastavitvi samodejno zažene sejo samodejno v trenutku, ko iz nje začnemo brati ali vanjo zapisovati podatke. Ročno se seja zažene s pomočjo $session->start().

PHP ob zagonu seje pošlje HTTP glave, ki vplivajo na predpomnjenje, glej session_cache_limiter, in po potrebi tudi piškotek z ID-jem seje. Zato je treba vedno sejo zagnati še pred pošiljanjem kakršnega koli izpisa v brskalnik, sicer pride do sprožitve izjeme. Če torej veste, da se bo med izrisovanjem strani uporabljala seja, jo zaženite ročno prej, na primer v presenterju.

V razvijalskem načinu sejo zažene Tracy, ker jo uporablja za prikazovanje trakov s preusmeritvami in AJAX zahtevami v Tracy Baru.

Sekcije

V čistem PHP je podatkovno skladišče seje realizirano kot polje, dostopno preko globalne spremenljivke $_SESSION. Problem je v tem, da se aplikacije običajno sestojijo iz cele vrste medsebojno neodvisnih delov in če imajo vsi na voljo le eno polje, prej ali slej pride do kolizije imen.

Nette Framework problem rešuje tako, da celoten prostor razdeli na sekcije (objekte Nette\Http\SessionSection). Vsaka enota nato uporablja svojo sekcijo z edinstvenim imenom in do nobene kolizije več ne more priti.

Sekcijo dobimo iz seje:

$section = $session->getSection('unikatno ime');

V presenterju je dovolj uporabiti getSession() s parametrom:

// $this je Presenter
$section = $this->getSession('unikatno ime');

Preveriti obstoj sekcije je mogoče z metodo $session->hasSection('unikatno ime').

S samo sekcijo se nato dela zelo enostavno s pomočjo metod set(), get() in remove():

// zapis spremenljivke
$section->set('userName', 'franta');

// branje spremenljivke, vrne null če ne obstaja
echo $section->get('userName');

// preklic spremenljivke
$section->remove('userName');

Za pridobitev vseh spremenljivk iz sekcije je mogoče uporabiti zanko foreach:

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

Nastavitev poteka

Za posamezne sekcije ali celo posamezne spremenljivke je mogoče nastaviti potek. Lahko tako pustimo poteči prijavo uporabnika čez 20 minut, vendar si pri tem še naprej zapomnimo vsebino košarice.

// sekcija poteče po 20 minutah
$section->setExpiration('20 minutes');

Za nastavitev poteka posameznih spremenljivk služi tretji parameter metode set():

// spremenljivka 'flash' poteče že po 30 sekundah
$section->set('flash', $message, '30 seconds');

Ne pozabite, da mora biti čas poteka celotne seje (glej konfiguracija seje) enak ali daljši od časa, nastavljenega pri posameznih sekcijah ali spremenljivkah.

Preklic prej nastavljenega poteka dosežemo z metodo removeExpiration(). Takojšen preklic celotne sekcije zagotovi metoda remove().

Dogodka $onStart, $onBeforeWrite

Objekt Nette\Http\Session ima dogodke $onStart in $onBeforeWrite, lahko torej dodate povratne klice, ki se sprožijo po zagonu seje ali pred njenim zapisom na disk in posledičnim zaključkom.

$session->onBeforeWrite[] = function () {
	// zapišemo podatke v sejo
	$this->section->set('basket', $this->basket);
};

Upravljanje sej

Pregled metod razreda Nette\Http\Session za upravljanje sej:

start(): void

Zažene sejo.

isStarted(): bool

Je seja zagnana?

close(): void

Zaključi sejo. Seja se samodejno zaključi na koncu izvajanja skripta.

destroy(): void

Zaključi in izbriše sejo.

exists(): bool

Ali HTTP zahteva vsebuje piškotek z ID-jem seje?

regenerateId(): void

Generira nov naključni ID seje. Podatki ostanejo ohranjeni.

getId(): string

Vrne ID seje.

Konfiguracija

Sejo nastavljamo v konfiguraciji. Če pišete aplikacijo, ki ne uporablja DI vsebnika, služijo za konfiguracijo te metode. Morajo biti poklicane še pred zagonom seje.

setName (string $name): static

Nastavi ime piškotka, v katerem se prenaša ID seje. Standardno ime je PHPSESSID. Koristno je v primeru, ko v okviru enega spletnega mesta poganjate več različnih aplikacij.

getName(): string

Vrača ime piškotka, v katerem se prenaša ID seje.

setOptions (array $options)static

Konfigurira sejo. Lahko nastavljate vse PHP direktive seje (v formatu camelCase, npr. namesto session.save_path zapišemo savePath) in tudi readAndClose.

setExpiration (?string $time)static

Nastavi čas neaktivnosti, po katerem seja poteče.

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

Nastavitev parametrov za piškotek. Privzete vrednosti parametrov lahko spremenite v konfiguraciji.

setSavePath (string $path)static

Nastavi imenik, kamor se shranjujejo datoteke s sejo.

setHandler (\SessionHandlerInterface $handler)static

Nastavitev lastnega obravnavalnika, glej dokumentacija PHP.

Varnost na prvem mestu

Strežnik predpostavlja, da komunicira vedno z istim uporabnikom, dokler zahteve spremlja isti ID seje. Naloga varnostnih mehanizmov je zagotoviti, da je temu res tako in da ni mogoče identifikatorja ukrasti ali podtakniti.

Nette Framework zato pravilno konfigurira PHP direktive, da ID seje prenaša samo v piškotku, ga onemogoči JavaScriptu in morebitne identifikatorje v URL-ju ignorira. Poleg tega v kritičnih trenutkih, kot je na primer prijava uporabnika, generira nov ID seje.

Za konfiguracijo PHP se uporablja funkcija ini_set, ki jo na žalost nekateri gostitelji prepovedujejo. Če je to primer tudi vašega gostitelja, se poskusite z njim dogovoriti, da vam funkcijo dovoli ali vsaj strežnik konfigurira.

različica: 4.0