Сеанси
HTTP – це протокол без статичних даних, але майже кожному додатку необхідно зберігати стан між запитами, наприклад, вміст кошика. Для цього і використовується сесія. Давайте подивимося
- як використовувати сесії
- як уникнути конфліктів імен
- як встановити термін дії
Під час використання сесій кожен користувач отримує унікальний ідентифікатор, який називається ID сесії, що передається в cookie. Він слугує ключем до даних сеансу. На відміну від cookie, які зберігаються на стороні браузера, дані сеансу зберігаються на стороні сервера.
Ми налаштовуємо сесію в конфігурації, при цьому важливим є вибір часу закінчення терміну дії.
Сесією керує об'єкт Nette\Http\Session,
який ви отримуєте, передаючи його за допомогою ін'єкції залежностей. У
презентаторах просто викликаємо $session = $this->getSession()
.
→ Встановлення та вимоги
Запуск сеансу
За замовчуванням Nette автоматично запускає сесію в той момент, коли ми
починаємо читати з неї або записувати в неї дані. Щоб запустити сесію
вручну, використовуйте $session->start()
.
PHP надсилає HTTP-заголовки, що впливають на кешування, під час запуску сесії, див. session_cache_limiter, і, можливо, cookie з ідентифікатором сесії. Тому завжди необхідно запускати сесію перед надсиланням будь-якого виводу в браузер, інакше буде викинуто виняток. Тому, якщо ви знаєте, що сесія буде використовуватися під час рендерингу сторінки, запустіть її вручну, наприклад, у презентаторі.
У режимі розробника Tracy запускає сесію, оскільки використовує її для відображення смуг перенаправлення і запитів AJAX у панелі Tracy.
Розділ
У чистому PHP сховище даних сесії реалізовано у вигляді масиву,
доступного через глобальну змінну $_SESSION
. Проблема полягає в
тому, що додатки зазвичай складаються з декількох незалежних частин, і
якщо всім доступний тільки один і той самий масив, рано чи пізно
відбудеться зіткнення імен.
Nette Framework вирішує цю проблему шляхом поділу всього простору на секції (об'єкти 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-запит файл cookie з ідентифікатором сесії?
regenerateId(): void
Генерує новий випадковий ідентифікатор сесії. Дані залишаються незмінними.
getId(): string
Повертає ідентифікатор сесії.
Конфігурація
Ми налаштовуємо сесію в конфігурації. Якщо ви пишете додаток, який не використовує DI-контейнер, використовуйте ці методи для конфігурації. Вони повинні бути викликані до запуску сесії.
setName (string $name): static
Встановлює ім'я cookie, яке використовується для передачі
ідентифікатора сесії. За замовчуванням використовується ім'я
PHPSESSID
. Це корисно, якщо ви запускаєте кілька різних додатків на
одному сайті.
getName(): string
Повертає ім'я сеансового файлу cookie.
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
Встановлює параметри для кукі. Значення параметрів за замовчуванням можна змінити в розділі configuration.
setSavePath (string $path): static
Встановлює каталог, у якому зберігаються файли сесій.
setHandler (\SessionHandlerInterface $handler): static
Встановлює користувацький обробник, див. документацію PHP.
Безпека насамперед
Сервер припускає, що він спілкується з одним і тим самим користувачем доти, доки запити містять один і той самий ідентифікатор сесії. Завдання механізмів безпеки – гарантувати, що така поведінка дійсно працює і що немає можливості підмінити або вкрасти ідентифікатор.
Саме тому Nette Framework правильно налаштовує директиви PHP для передавання ідентифікатора сесії тільки в cookies, для запобігання доступу з JavaScript і для ігнорування ідентифікаторів в URL. Ба більше, у критичні моменти, такі як вхід користувача в систему, він генерує новий ідентифікатор сесії.
Функція ini_set використовується для налаштування PHP, але, на жаль, її використання заборонено на деяких хостингах. Якщо це ваш випадок, спробуйте попросити хостинг-провайдера дозволити цю функцію для вас або хоча б правильно налаштувати його сервер.