Сесии

HTTP е протокол без статични данни, но почти всяко приложение трябва да съхранява състояние между заявките, напр. съдържанието на количка за пазаруване. Именно за това е сесията. Нека разгледаме

  • как да използвате сесиите
  • как да избегнете конфликти на имена
  • как да зададете дата на изтичане на срока на валидност

Когато се използват сесии, на всеки потребител се дава уникален идентификатор, наречен идентификатор на сесия, който се предава на “бисквитката”. Той служи като ключ към данните за сесията. За разлика от “бисквитките”, които се съхраняват от страна на браузъра, данните за сесията се съхраняват от страна на сървъра.

Настройваме сесията в конфигурацията, като изборът на време на изтичане е важен.

Сесията се управлява от обекта Nette\Http\Session, който получавате, като го предавате чрез инжектиране на зависимости. В презентаторите наричаме $session = $this->getSession().

Монтаж и изисквания

Стартираща сесия

По подразбиране Nette автоматично стартира сесия в момента, в който започнем да четем от нея или да записваме данни в нея. За да стартирате сесия ръчно, използвайте $session->start().

PHP изпраща HTTP хедъри, които влияят на кеширането, когато сесията започне, вж. session_cache_limiter и евентуално бисквитка с идентификатор на сесията. Затова винаги трябва да стартирате сесията, преди да изпратите какъвто и да е изход към браузъра, в противен случай ще бъде хвърлено изключение. Затова, ако знаете, че сесията ще се използва по време на визуализирането на страницата, стартирайте я ръчно, например в презентатора.

В режим за разработчици Tracy стартира сесията, тъй като я използва за показване на ленти за пренасочване и AJAX заявки в панела Tracy.

Раздел

В чистия език PHP съхранението на данни за сесията се реализира като масив, достъпен чрез глобалната променлива $_SESSION. Проблемът се състои в това, че приложенията обикновено се състоят от няколко независими части и ако всички разполагат само с един и същ масив, рано или късно ще се стигне до колизии на имена.

Рамката на Nette решава този проблем, като разделя цялото пространство на секции (обекти Nette\Http\SessionSection). В този случай всяка част използва свой собствен раздел с уникално име и не се получават колизии.

Получаваме дяла от мениджъра на сесии:

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

Всичко, което трябва да направите в презентатора, е да извикате getSession() с параметъра:

// $this - Представящ
$section = $this->getSession('unique name');

Съществуването на дяла може да се провери по метода $session->hasSection('unique name').

Самият дял е много лесен за работа с помощта на методите set(), get() и remove():

// писане на променлива
$section->set('userName', 'franta');

// четене на променливата, връща null, ако не съществува
echo $section->get('userName');

//премахване на променлива
$section->remove('userName');

Можете да използвате цикъла foreach, за да извлечете всички променливи от секцията:

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

Как да зададете дата на изтичане

Срокът на валидност може да бъде зададен за отделни раздели или дори за отделни променливи. Можем да позволим на потребителския вход да изтече след 20 минути, но да запазим съдържанието на кошницата.

// срокът на действие на раздела изтича след 20 минути
$section->setExpiration('20 minutes');

Третият параметър на метода set() се използва за задаване на датата на изтичане на срока на валидност на отделните променливи:

// променливата 'flash' изтича след 30 секунди
$section->set('flash', $message, '30 seconds');

Не забравяйте, че времето на изтичане на цялата сесия (вж. Конфигурация на сесията) трябва да е равно или по-голямо от времето, зададено за отделните секции или променливи.

Отмяна на предварително зададено време на изтичане може да се осъществи чрез метода removeExpiration(). Незабавното изтриване на цял раздел се осигурява от метода remove().

Събития $onStart, $onBeforeWrite

Обектът Nette\Http\Session има събития $onStart и $onBeforeWrite, така че можете да добавите обратни извиквания, които ще бъдат извикани след стартирането на сесията или преди тя да бъде записана на диска и след това завършена.

$session->onBeforeWrite[] = function () {
	// запис на данни в сесията
	$this->section->set('basket', $this->basket);
};

Управление на сесиите

Преглед на методите на класа Nette\Http\Session за управление на сесии:

start(): void

Стартира сесията.

isStarted(): bool

Работи ли сесията?

close(): void

Приключва сесията. Сесията приключва автоматично в края на скрипта.

destroy(): void

Приключва и изтрива сесията.

exists(): bool

Съдържа ли HTTP заявката “бисквитка” с идентификатор на сесията?

regenerateId(): void

Генерира нов случаен идентификатор на сесия. Данните остават непроменени.

getId(): string

Връща идентификатора на сесията.

Конфигурация

Конфигурираме сесията в конфигурацията. Ако пишете приложение, което не използва DI-контейнер, използвайте тези методи, за да го конфигурирате. Те трябва да бъдат извикани преди стартирането на сесията.

setName(string $name): static

Задава името на “бисквитката”, използвана за предаване на идентификатора на сесията. Името по подразбиране е PHPSESSID. Това е полезно, ако използвате няколко различни приложения в един и същи сайт.

getName(): string

Връща името на “бисквитката” на сесията.

setOptions(array $options)static

Конфигурира сесията. Могат да се задават всички директиви на PHP сесията (във формат camelCase, напр. запишете savePath вместо session.save_path), както и readAndClose.

setExpiration(?string $time)static

Задава времето за неактивност, след което сесията се затваря.

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

Задава параметрите за бисквитките. Настройките по подразбиране могат да бъдат променени в раздела за конфигурация.

setSavePath(string $path)static

Задава директорията, в която се съхраняват файловете на сесиите.

setHandler(\SessionHandlerInterface $handler)static

Задава персонализирания манипулатор, вижте документацията на PHP.

Сигурността на първо място

Сървърът приема, че комуникира с един и същ потребител, докато заявките съдържат един и същ идентификатор на сесията. Предизвикателството пред механизмите за сигурност е да се гарантира, че това поведение действително работи и че няма начин да се подмени или открадне идентификаторът.

Ето защо Nette Framework правилно конфигурира директивите на PHP да предават идентификаторите на сесията само на бисквитките, да предотвратяват достъпа от JavaScript и да игнорират идентификаторите в URL адресите. Освен това в критични моменти, като например влизане на потребител, той генерира нов идентификатор на сесията.

Функцията ini_set се използва за конфигуриране на PHP, но за съжаление някои уеб хостове не я разрешават. Ако вашият случай е такъв, опитайте се да помолите доставчика си на хостинг да разреши тази функция или поне да конфигурира правилно своя сървър.

версия: 4.0