PHP - WEB - 11. セッションの詳細
引き続きセッションについて学習していきましょう。Webアプリケーションにおいてユーザとの一連のやりとりの間で発生するデータを保存するにはセッションという仕組みを使います。PHPにおいて、セッションを利用するためには予め session_start
関数を呼び出した後、 $_SESSION
変数にアクセスします。それでは、このときWebブラウザとWebサーバ間のHTTP通信ではどのようなデータのやりとりが行われているのでしょうか。ここでは具体的なHTTP通信のやりとりを中心に見ていくことにします。
Cookie
一般的にセッションはその内部でCookieという仕組みを使います。CookieとはHTTPのクライアント(Webブラウザ)上に少量のデータを保存する仕組みです。もともとHTTPの通信ではWebサーバからWebブラウザ上のコンピュータに対してファイルを作成したり、削除したりといった操作は禁止されています。これを許可してしまうとWebサーバから、Webブラウザを使っている利用者のコンピュータを自由に操作できてしまうためです。そのような背景においてCookieはWebサーバからWebブラウザ上にデータを残すことのできる例外的な仕組みです。
CookieはPHPの連想配列のようにキーと値の組み合わせでデータを管理します。ただし、 Cookieには様々な制約があります。たとえば1つのキーに指定可能な値には、少量のデータ(数KB程度)しか保存できないようになっています。
Cookieへのデータの保存
WebサーバからWebブラウザ上のCookieにデータを保存するためにはHTTPレスポンスに Set-Cookie
ヘッダを付与します。具体的には次のようなヘッダフィールドです。
Set-Cookie: Key1=Value1; path=/
レスポンスの中に上記のような Set-Cookie
ヘッダが存在する場合、Webブラウザは Cookieに Key1
というキーと Value1
という値のペアを保存します。
Cookie上のデータの送信
Cookieに保存されたデータは、Cookieを作成した同一ドメインへのリクエスト時に、自動的にリクエストのヘッダフィールド( Cookie
ヘッダ)に含まれるようになります。
Cookie: Key1=Value1
あるドメインによってCookieに保存されたデータは、別のドメインへのリクエストに含まれることはありません。
PHPプログラムの開発(セッションの仕組み)
ここではさきほどのログイン処理でのやりとりをもとに、実際にどのようなデータ通信が発生して、 Cookieへのアクセスが発生するのかを確認してみましょう。またここではChromeを起動する際にシークレットモードで起動することにします。これはわかりやすくWebブラウザ上のCookieを空の状態にして動作確認するためです。
MacでChromeをシークレットモードで起動するには
cmd + shif + n
キーをタイプします。Windowsの場合はctrl + shift + n
キーをタイプします。
ビルトインWebサーバを起動した状態で、Webブラウザからログイン画面( login.html
)にアクセスします。
http://localhost:8000/login.html
ログイン画面が表示されるのでデベロッパーツール(Networkタブ)を開いた状態でIDに Andy
、パスワードに secret
と入力してログインボタンをクリックしましょう。そうするとログイン処理( login.php
)へのHTTP通信と、リダイレクト後のメニュー画面表示処理( menu.php
)へのHTTP通信2つのキャプチャーが取得できます。
ここではまずログイン処理( login.php
)のレスポンスを確認してみましょう。
次のようなHTTPレスポンスを確認できるでしょう。
HTTP/1.1 302 Found
Host: localhost:8000
Date: Mon, 17 Aug 2020 13:20:29 GMT
Connection: close
X-Powered-By: PHP/7.3.11
Set-Cookie: PHPSESSID=1j49ibl7m223hh6k28pmf4s1un; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: menu.php
Content-type: text/html; charset=UTF-8
このレスポンスはメニュー画面表示処理へのリダイレクトを指示しているので、ステータスコードは 302
、また Location
ヘッダには遷移先である menu.php
が指定されています。このとき Cookie
にデータを保存する Set-Cookie
ヘッダが付与されている点に注意してください。
Set-Cookie: PHPSESSID=1j49ibl7m223hh6k28pmf4s1un; path=/
この Set-Cookie
ヘッダによって、 Cookieに PHPSESSID
キーで 1j49ibl7m223hh6k28pmf4s1un
という値が保存されます。この PHPSESSID
という名前のキーはセッションIDと呼ばれるものです。この場合、ユーザのセッションID( PHPSESSID
)は 1j49ibl7m223hh6k28pmf4s1un
となり、Webサーバ上でユーザのセッションを識別する用途に利用します。
セッションを実現するために必要なネットワーク上のやりとりはセッションIDに限定されます。 $_SESSION
変数に保存した "id"
や "time"
キー、またそれぞれのキーに紐づく値は、セッションIDと関連付けられてサーバサイドに保存されます。
さいごにHTTPレスポンスになぜ、このような Set-Cookie
ヘッダが付与されたのかという疑問が残ります。これはログイン処理( login.php
)において session_start
関数を呼び出しているためです。PHPでは session_start
関数を呼び出すことで、セッションの管理に必要なHTTPレスポンス(この場合 Set-Cookie
ヘッダ)を生成するようになっています。
Set-Cookie
ヘッダの挙動を上手く動作確認できない場合は、Chromeを一度閉じて、改めてシークレットモードで動作を確認してください。
以上の結果としてログイン処理( login.php
)のレスポンスを受け取ったWebブラウザはCookieに PHPSESSID
キーと 1j49ibl7m223hh6k28pmf4s1un
のような値を保持することになります。
続いてChromeのデベロッパーツール(Networkタブ)から、リダイレクト時のメニュー画面表示処理( menu.php
)へのリクエストも確認しておきましょう。
次のような通信データを確認できるでしょう。
GET /menu.php HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6)...省略
Accept: text/html,application/xhtml+xml,application/xml;q=0.9...省略
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8000/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=1j49ibl7m223hh6k28pmf4s1un
このリクエストはさきほどの Set-Cookie
ヘッダを受信した際のドメインと同一ドメインへのリクエストに該当するので、リクエストには Cookie
ヘッダが付与されているのがわかります。
Cookie: PHPSESSID=1j49ibl7m223hh6k28pmf4s1un
WebブラウザからWebサーバに送信される Cookie
ヘッダはPHPから参照可能となります。またサーバ上にはユーザ(セッションID)に紐づくセッション情報が複数存在します。メニュー画面の表示処理( menu.php
)において、 session_start
関数を呼び出すことで、このセッション情報の一覧の中から送信されたセッションID( PHPSESSID
)に紐づく1件のセッション情報を識別できるようになります。このようにして $_SESSION
変数が利用できるようになります。
まとめ
- 一般的にセッションはCookieを使って実装されている
- Cookieはクライアント(Webブラウザ)上に少量のデータを保存する仕組み
- PHPはセッションを開始するとCookieにセッションIDを保存し、セッションに保存したデータそのものはサーバサイドに保存する