Nette Documentation Preview

syntax
セッション
*****

<div class=perex>

HTTP は状態を持たないプロトコルですが、ほとんどのアプリケーションはリクエストをまたいで状態を保つ必要があります。買い物かごの中身などです。まさにそのためにセッションを使います。ここでは次のことをお見せします。

- セッションの使い方
- 名前の衝突を防ぐ方法
- 有効期限の決め方

</div>

セッションを使うと、それぞれの利用者はセッション ID と呼ばれる一意の識別子を受け取り、それがクッキーで運ばれます。これはセッションのデータへの鍵の役目を果たします。ブラウザ側に保存されるクッキーと違って、セッションのデータはサーバー側に保存されます。

セッションは[設定 |configuration#セッション]で設定します。とりわけ有効期限の時間の選び方が大事です。

セッションの管理は [api:Nette\Http\Session]オブジェクトが受け持ちます。これは [dependency injection |dependency-injection:passing-dependencies]で渡してもらえます。プレゼンターでは `$session = $this->getSession()` を呼ぶだけです。

→ [インストールと要件 |@home#インストール]


セッションを始める
=========

既定では、Nette はデータを読み書きしはじめた瞬間にセッションを自動的に始めます。セッションを手で始めるには `$session->start()` を使います。

PHP はセッションを始めるときに、キャッシュに影響する HTTP のヘッダー([php:session_cache_limiter]をご覧ください)と、場合によってはセッション ID のクッキーを送ります。ですからセッションは、ブラウザへ何かを出力する前に必ず始めなければなりません。そうしないと例外が投げられます。ですからページを描いているあいだにセッションを使うと分かっているなら、たとえばプレゼンターの中で、前もって手で始めてください。

開発モードでは Tracy がセッションを始めます。Tracy Bar でリダイレクトと AJAX のリクエストの帯を表示するのにセッションを使うからです。


区画
===

素の 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')` メソッドで調べられます。存在するすべての区画の名前の一覧は `$session->getSectionNames()` が返します。

区画そのものを扱うのは、`set()`、`get()`、`remove()` のメソッドでとても簡単です。

```php
// 変数を書き込みます
$section->set('userName', 'john');

// 変数を読み出します。なければ null を返します
echo $section->get('userName');

// 変数を取り除きます
$section->remove('userName');
```

区画のすべての変数を得るには `foreach` のループを使えます。

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


有効期限の決め方
--------

有効期限は区画ごとに、さらには変数ごとに決められます。利用者のログインを 20 分で切らしつつ、買い物かごの中身は覚えておくことができます。

```php
// この区画は 20 分で切れます
$section->setExpiration('20 minutes');
```

変数ごとに有効期限を決めるには、`set()` メソッドの第 3 パラメータを使います。

```php
// 変数 'flash' は 30 秒で切れます
$section->set('flash', $message, '30 seconds');
```

.[note]
セッション全体の有効期限([セッションの設定 |configuration#セッション]をご覧ください)は、区画や変数ごとに決めた時間と同じか、それより長くなければならないことを忘れないでください。

前に決めた有効期限を取り消すには `removeExpiration()` メソッドを使います。特定の変数の有効期限を消すには、その名前を渡します。`removeExpiration('flash')` のようにです。区画全体をすぐに取り除くには `remove()` メソッドを使います。


$onStart、$onBeforeWrite のイベント
-----------------------------

`Nette\Http\Session` オブジェクトには[イベント |nette:glossary#イベント] `$onStart` と `$onBeforeWrite` があるので、セッションが始まったあとや、ディスクに書き込まれて終わる前に呼ばれるコールバックを足せます。

```php
$session->onBeforeWrite[] = function () {
	// セッションにデータを書き込みます
	$this->section->set('basket', $this->basket);
};
```


セッションの管理
========

セッションを管理する `Nette\Http\Session` クラスのメソッドの一覧です。

<div class=wiki-methods-brief>


start(): void .[method]
-----------------------
セッションを始めます。


isStarted(): bool .[method]
---------------------------
セッションは始まっていますか。


close(): void .[method]
-----------------------
セッションを終わらせます。セッションはスクリプトの実行の終わりに自動的に終わります。


destroy(): void .[method]
-------------------------
セッションを終わらせて消します。


exists(): bool .[method]
------------------------
HTTP のリクエストにセッション ID のクッキーが入っていますか。


regenerateId(): void .[method]
------------------------------
新しい無作為なセッション ID を生成します。データはそのまま残ります。


getId(): string .[method]
-------------------------
セッション ID を返します。

</div>


設定
---

セッションは[設定 |configuration#セッション]で設定します。DI コンテナを使わないアプリケーションを書いているなら、設定にはこれらのメソッドを使います。セッションを始める前に呼ばなければなりません。

<div class=wiki-methods-brief>


setName(string $name): static .[method]
---------------------------------------
セッション ID を運ぶクッキーの名前を設定します。標準の名前は `PHPSESSID` です。同じウェブサイトでいくつかの違うアプリケーションを動かしているときに役立ちます。


getName(): string .[method]
---------------------------
セッション ID を運ぶクッキーの名前を返します。


setOptions(array $options): static .[method]
--------------------------------------------
セッションを設定します。PHP のすべての[セッションのディレクティブ |https://www.php.net/manual/en/session.configuration.php](camelCase の形で。たとえば `session.save_path` は `savePath` と書きます)と [readAndClose |https://www.php.net/manual/en/function.session-start.php#refsect1-function.session-start-parameters]を設定できます。


setExpiration(?string $expire): static .[method]
------------------------------------------------
セッションが切れるまでの無操作の時間を設定します。


setCookieParameters(string $path, ?string $domain=null, ?bool $secure=null, SameSite|string|null $samesite=null): static .[method]
----------------------------------------------------------------------------------------------------------------------------------
クッキーのパラメータを設定します。パラメータの既定値は[設定 |configuration#セッションのクッキー]で変えられます。


setSavePath(string $path): static .[method]
-------------------------------------------
セッションのファイルを保存するディレクトリを設定します。


setHandler(\SessionHandlerInterface $handler): static .[method]
---------------------------------------------------------------
独自のハンドラを設定します。[PHP のドキュメント |https://www.php.net/manual/en/class.sessionhandlerinterface.php]をご覧ください。

</div>


安全第一
====

サーバーは、リクエストに同じセッション ID が伴っている限り、同じ利用者とやり取りしていると考えます。安全のしくみの仕事は、それが本当にそのとおりであり、識別子が盗まれたりすり替えられたりしないようにすることです。

ですから Nette Framework は PHP のディレクティブを正しく設定し、セッション ID をクッキーだけで運び、JavaScript から触れないようにし、URL の中の識別子は無視します。さらに利用者のログインのような大事な瞬間には、新しいセッション ID を生成します。

.[note]
PHP の設定には `ini_set` 関数を使いますが、残念ながらホスティングによってはその使用を禁じています。あなたのホスティングがそうなら、その関数を使えるようにしてもらうか、少なくともサーバーをきちんと設定してもらえるよう相談してみてください。

セッション

HTTP は状態を持たないプロトコルですが、ほとんどのアプリケーションはリクエストをまたいで状態を保つ必要があります。買い物かごの中身などです。まさにそのためにセッションを使います。ここでは次のことをお見せします。

  • セッションの使い方
  • 名前の衝突を防ぐ方法
  • 有効期限の決め方

セッションを使うと、それぞれの利用者はセッション ID と呼ばれる一意の識別子を受け取り、それがクッキーで運ばれます。これはセッションのデータへの鍵の役目を果たします。ブラウザ側に保存されるクッキーと違って、セッションのデータはサーバー側に保存されます。

セッションは設定で設定します。とりわけ有効期限の時間の選び方が大事です。

セッションの管理は Nette\Http\Sessionオブジェクトが受け持ちます。これは dependency injectionで渡してもらえます。プレゼンターでは $session = $this->getSession() を呼ぶだけです。

インストールと要件

セッションを始める

既定では、Nette はデータを読み書きしはじめた瞬間にセッションを自動的に始めます。セッションを手で始めるには $session->start() を使います。

PHP はセッションを始めるときに、キャッシュに影響する HTTP のヘッダー(session_cache_limiterをご覧ください)と、場合によってはセッション ID のクッキーを送ります。ですからセッションは、ブラウザへ何かを出力する前に必ず始めなければなりません。そうしないと例外が投げられます。ですからページを描いているあいだにセッションを使うと分かっているなら、たとえばプレゼンターの中で、前もって手で始めてください。

開発モードでは Tracy がセッションを始めます。Tracy Bar でリダイレクトと AJAX のリクエストの帯を表示するのにセッションを使うからです。

区画

素の PHP では、セッションのデータの保管場所は大域変数 $_SESSION で触れる配列として作られています。困るのは、アプリケーションがふつう多くの独立した部分から成っていて、そのすべてがひとつの配列しか使えないなら、遅かれ早かれ名前の衝突が起きることです。

Nette Framework はこの問題を、空間全体を区画(Nette\Http\SessionSectionのオブジェクト)に分けることで解決します。それぞれの部分は一意の名前を持つ自分の区画を使うので、衝突は起きません。

区画はセッションから取り出します。

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

プレゼンターでは getSession() にパラメータを渡すだけです。

// $this はプレゼンターです
$section = $this->getSession('unique name');

区画があるかどうかは $session->hasSection('unique name') メソッドで調べられます。存在するすべての区画の名前の一覧は $session->getSectionNames() が返します。

区画そのものを扱うのは、set()get()remove() のメソッドでとても簡単です。

// 変数を書き込みます
$section->set('userName', 'john');

// 変数を読み出します。なければ null を返します
echo $section->get('userName');

// 変数を取り除きます
$section->remove('userName');

区画のすべての変数を得るには foreach のループを使えます。

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

有効期限の決め方

有効期限は区画ごとに、さらには変数ごとに決められます。利用者のログインを 20 分で切らしつつ、買い物かごの中身は覚えておくことができます。

// この区画は 20 分で切れます
$section->setExpiration('20 minutes');

変数ごとに有効期限を決めるには、set() メソッドの第 3 パラメータを使います。

// 変数 'flash' は 30 秒で切れます
$section->set('flash', $message, '30 seconds');

セッション全体の有効期限(セッションの設定をご覧ください)は、区画や変数ごとに決めた時間と同じか、それより長くなければならないことを忘れないでください。

前に決めた有効期限を取り消すには removeExpiration() メソッドを使います。特定の変数の有効期限を消すには、その名前を渡します。removeExpiration('flash') のようにです。区画全体をすぐに取り除くには 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 のリクエストにセッション ID のクッキーが入っていますか。

regenerateId(): void

新しい無作為なセッション ID を生成します。データはそのまま残ります。

getId(): string

セッション ID を返します。

設定

セッションは設定で設定します。DI コンテナを使わないアプリケーションを書いているなら、設定にはこれらのメソッドを使います。セッションを始める前に呼ばなければなりません。

setName(string $name): static

セッション ID を運ぶクッキーの名前を設定します。標準の名前は PHPSESSID です。同じウェブサイトでいくつかの違うアプリケーションを動かしているときに役立ちます。

getName(): string

セッション ID を運ぶクッキーの名前を返します。

setOptions(array $options)static

セッションを設定します。PHP のすべてのセッションのディレクティブ(camelCase の形で。たとえば session.save_pathsavePath と書きます)と readAndCloseを設定できます。

setExpiration(?string $expire)static

セッションが切れるまでの無操作の時間を設定します。

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

クッキーのパラメータを設定します。パラメータの既定値は設定で変えられます。

setSavePath(string $path)static

セッションのファイルを保存するディレクトリを設定します。

setHandler(\SessionHandlerInterface $handler)static

独自のハンドラを設定します。PHP のドキュメントをご覧ください。

安全第一

サーバーは、リクエストに同じセッション ID が伴っている限り、同じ利用者とやり取りしていると考えます。安全のしくみの仕事は、それが本当にそのとおりであり、識別子が盗まれたりすり替えられたりしないようにすることです。

ですから Nette Framework は PHP のディレクティブを正しく設定し、セッション ID をクッキーだけで運び、JavaScript から触れないようにし、URL の中の識別子は無視します。さらに利用者のログインのような大事な瞬間には、新しいセッション ID を生成します。

PHP の設定には ini_set 関数を使いますが、残念ながらホスティングによってはその使用を禁じています。あなたのホスティングがそうなら、その関数を使えるようにしてもらうか、少なくともサーバーをきちんと設定してもらえるよう相談してみてください。