Nette Documentation Preview

syntax
Сеанси
******

<div class=perex>

HTTP - це протокол без статичних даних, але майже кожному додатку необхідно зберігати стан між запитами, наприклад, вміст кошика. Для цього і використовується сесія. Давайте подивимося

- як використовувати сесії
- як уникнути конфліктів імен
- як встановити термін дії

</div>

Під час використання сесій кожен користувач отримує унікальний ідентифікатор, який називається ID сесії, що передається в cookie. Він слугує ключем до даних сеансу. На відміну від cookie, які зберігаються на стороні браузера, дані сеансу зберігаються на стороні сервера.

Ми налаштовуємо сесію в [конфігурації |configuration#Session], при цьому важливим є вибір часу закінчення терміну дії.

Сесією керує об'єкт [api:Nette\Http\Session], який ви отримуєте, передаючи його за допомогою [ін'єкції залежностей |dependency-injection:passing-dependencies]. У презентаторах просто викликаємо `$session = $this->getSession()`.

→ Встановлення [та вимоги |@home#Installation]


Запуск сеансу .[#toc-starting-session]
======================================

За замовчуванням Nette автоматично запускає сесію в той момент, коли ми починаємо читати з неї або записувати в неї дані. Щоб запустити сесію вручну, використовуйте `$session->start()`.

PHP надсилає HTTP-заголовки, що впливають на кешування, під час запуску сесії, див. [php:session_cache_limiter], і, можливо, cookie з ідентифікатором сесії. Тому завжди необхідно запускати сесію перед надсиланням будь-якого виводу в браузер, інакше буде викинуто виняток. Тому, якщо ви знаєте, що сесія буде використовуватися під час рендерингу сторінки, запустіть її вручну, наприклад, у презентаторі.

У режимі розробника Tracy запускає сесію, оскільки використовує її для відображення смуг перенаправлення і запитів AJAX у панелі Tracy.


Розділ .[#toc-section]
======================

У чистому PHP сховище даних сесії реалізовано у вигляді масиву, доступного через глобальну змінну `$_SESSION`. Проблема полягає в тому, що додатки зазвичай складаються з декількох незалежних частин, і якщо всім доступний тільки один і той самий масив, рано чи пізно відбудеться зіткнення імен.

Nette Framework вирішує цю проблему шляхом поділу всього простору на секції (об'єкти [api:Nette\Http\SessionSection]). При цьому кожна частина використовує свій власний розділ з унікальним ім'ям, і колізії не виникають.

Ми отримуємо розділ від менеджера сесій:

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

У презентері достатньо викликати `getSession()` з параметром:

```php
// $this - доповідач
$section = $this->getSession('unique name');
```

Існування розділу можна перевірити методом `$session->hasSection('unique name')`.

Із самим розділом дуже легко працювати, використовуючи методи `set()`, `get()` і `remove()`:

```php
// запис змінної
$section->set('userName', 'franta');

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

// видалення змінної
$section->remove('userName');
```

Можна використовувати цикл `foreach` для отримання всіх змінних із секції:

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


Як встановити термін дії .[#toc-how-to-set-expiration]
------------------------------------------------------

Термін дії може бути встановлений для окремих розділів або навіть окремих змінних. Ми можемо дозволити логіну користувача закінчитися через 20 хвилин, але при цьому зберегти вміст кошика.

```php
// термін дії розділу закінчується через 20 хвилин
$section->setExpiration('20 minutes');
```

Третій параметр методу `set()` використовується для встановлення терміну дії окремих змінних:

```php
// змінна 'flash' закінчується через 30 секунд
$section->set('flash', $message, '30 seconds');
```

.[note]
Пам'ятайте, що час закінчення терміну дії всієї сесії (див. [конфігурацію сесії |configuration#Session]) має дорівнювати або бути більшим за час, встановлений для окремих секцій або змінних.

Скасування раніше встановленого терміну дії може бути досягнуто за допомогою методу `removeExpiration()`. Негайне видалення всього розділу забезпечується методом `remove()`.


Події $onStart, $onBeforeWrite .[#toc-events-onstart-onbeforewrite]
-------------------------------------------------------------------

Об'єкт `Nette\Http\Session` має [події |nette:glossary#Events] `$onStart` і `$onBeforeWrite`, тому ви можете додати зворотні виклики, які будуть викликатися після початку сеансу або перед тим, як вона буде записана на диск і потім завершена.

```php
$session->onBeforeWrite[] = function () {
	// записуємо дані в сесію
	$this->section->set('basket', $this->basket);
};
```


Управління сесіями .[#toc-session-management]
=============================================

Огляд методів класу `Nette\Http\Session` для керування сеансами:

<div class=wiki-methods-brief>


start(): void .[method]
-----------------------
Запускає сеанс.


isStarted(): bool .[method]
---------------------------
Чи запущено сеанс?


close(): void .[method]
-----------------------
Завершує сеанс. Сеанс завершується автоматично наприкінці сценарію.


destroy(): void .[method]
-------------------------
Завершує та видаляє сесію.


exists(): bool .[method]
------------------------
Чи містить HTTP-запит файл cookie з ідентифікатором сесії?


regenerateId(): void .[method]
------------------------------
Генерує новий випадковий ідентифікатор сесії. Дані залишаються незмінними.


getId(): string .[method]
-------------------------
Повертає ідентифікатор сесії.

</div>


Конфігурація .[#toc-configuration]
----------------------------------

Ми налаштовуємо сесію в [конфігурації |configuration#Session]. Якщо ви пишете додаток, який не використовує DI-контейнер, використовуйте ці методи для конфігурації. Вони повинні бути викликані до запуску сесії.

<div class=wiki-methods-brief>


setName(string $name): static .[method]
---------------------------------------
Встановлює ім'я cookie, яке використовується для передачі ідентифікатора сесії. За замовчуванням використовується ім'я `PHPSESSID`. Це корисно, якщо ви запускаєте кілька різних додатків на одному сайті.


getName(): string .[method]
---------------------------
Повертає ім'я сеансового файлу cookie.


setOptions(array $options): static .[method]
--------------------------------------------
Налаштовує сесію. Можна встановити всі [директиви сесії |https://www.php.net/manual/en/session.configuration.php] PHP (у форматі camelCase, наприклад, написати `savePath` замість `session.save_path`), а також [readAndClose |https://www.php.net/manual/en/function.session-start.php#refsect1-function.session-start-parameters].


setExpiration(?string $time): static .[method]
----------------------------------------------
Встановлює час бездіяльності, після якого сесія завершується.


setCookieParameters(string $path, string $domain=null, bool $secure=null, string $samesite=null): static .[method]
------------------------------------------------------------------------------------------------------------------
Встановлює параметри для кукі. Значення параметрів за замовчуванням можна змінити в розділі [configuration |configuration#Session-Cookie].


setSavePath(string $path): static .[method]
-------------------------------------------
Встановлює каталог, у якому зберігаються файли сесій.


setHandler(\SessionHandlerInterface $handler): static .[method]
---------------------------------------------------------------
Встановлює користувацький обробник, див. [документацію PHP |https://www.php.net/manual/en/class.sessionhandlerinterface.php].

</div>


Безпека насамперед .[#toc-safety-first]
=======================================

Сервер припускає, що він спілкується з одним і тим самим користувачем доти, доки запити містять один і той самий ідентифікатор сесії. Завдання механізмів безпеки - гарантувати, що така поведінка дійсно працює і що немає можливості підмінити або вкрасти ідентифікатор.

Саме тому Nette Framework правильно налаштовує директиви PHP для передавання ідентифікатора сесії тільки в cookies, для запобігання доступу з JavaScript і для ігнорування ідентифікаторів в URL. Ба більше, у критичні моменти, такі як вхід користувача в систему, він генерує новий ідентифікатор сесії.

Функція ini_set використовується для налаштування PHP, але, на жаль, її використання заборонено на деяких хостингах. Якщо це ваш випадок, спробуйте попросити хостинг-провайдера дозволити цю функцію для вас або хоча б правильно налаштувати його сервер. .[note]

Сеанси

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, але, на жаль, її використання заборонено на деяких хостингах. Якщо це ваш випадок, спробуйте попросити хостинг-провайдера дозволити цю функцію для вас або хоча б правильно налаштувати його сервер.