後期第02回 - oddmutou/jugyo-2025kyototech GitHub Wiki
セッション
セッションとは、おもにコンピュータにおける一連の操作の流れのことを指します。
https://wa3.i-3-i.info/word1791.html
HTTPリクエスト/レスポンスをそれぞれ単独でみると、状態を持たない(ステートレスな)通信です。そのため、複数のHTTP通信、つまり複数の画面遷移にまたがって一連の操作を行いたい場合は、セッション機能をアプリケーションで実装する必要があります。
現代のWebアプリケーションにおいてはほぼ必須の機能であるため、Webアプリケーションで利用されることの多い言語にはだいたいセッション用の仕組みが用意されていたり、有志が既に高品質なセッション用のライブラリを作っていたりします。また、Webフルスタックフレームワーク(RailsやLaravel等)にもそういった機能が組み込まれていることが多いです。PHPも標準でセッション管理用の仕組みがあります。
そのため、実際の業務でセッションの仕組みをイチから作ることは稀で、セッションについて軽く設定するだけで済ますことが多いと思いますが、この授業においては、セッションについての理解を深めるために一度独自で簡単なセッション機能を実装してもらえればと思います。
セッションを独自実装してみる
セッション毎の値は、サーバー内部のファイルやRDBMS、KVSに保存させます。商業サービスではスケーラビリティや速度を考慮しKVSに保存させることが多いです。この授業では、KVSの一つであるRedisを使います。
各ブラウザ(みなさんのパソコンやスマホのブラウザ)に振るセッションIDは、PHP側で生成します。セッションIDが予測できるとセッションが乗っ取られる(セッションハイジャック)危険性が生まれてしまうため、セキュアな疑似乱数を用い予測不可能な値にしましょう。
また、セッションIDは、ブラウザのCookiに保存してあげましょう。
セッション値の保存は、 session-セッションID といったキーとして、Redisに保存しましょう。
値は連想配列にしておくと、複数の値を扱うことができますね。
前回の授業の演習課題3と同様に、redisには文字列しか保存することができないので、配列などを保存したいときはJSONに変換してから保存しましょう。
つまりRedisへの保存前には json_encode() で連想配列をJSONに変換し、Redisから読み取った値は json_decode() でJSONから連想配列に変換するということですね。
実装例
// セッションIDの取得(なければ新規で作成&設定)
$session_cookie_name = 'session_id';
$session_id = $_COOKIE[$session_cookie_name] ?? base64_encode(random_bytes(64));
if (!isset($_COOKIE[$session_cookie_name])) {
setcookie($session_cookie_name, $session_id);
}
// 接続 (redisコンテナの6379番ポートに接続)
$redis = new Redis();
$redis->connect('redis', 6379);
// redisにセッション変数を保存しておくキーを決めておきます。
$redis_session_key = "session-" . $session_id;
// 既にセッション変数(の配列)が何かしら格納されていればそれを、なければ空の配列を $session_values変数に保存。
$session_values = $redis->exists($redis_session_key)
? json_decode($redis->get($redis_session_key), true)
: [];
// 値の保存
// 例として、username は kitagawaと保存
// $session_valuesにセットした上で、redisに保存。
$session_values["username"] = "kitagawa";
$redis->set($redis_session_key, json_encode($session_values));
// 値の取得
// $session_values変数の中身は連想配列なので、素直に値の取得ができますね。
$result = $session_values["username"];
演習
演習1
セッション別のアクセスカウンタを作りましょう。
このセッションでの 5回目 のアクセスです! みたいに表示しましょう。
動作例: http://54.210.191.33/enshu1.php
実装例: https://github.com/oddmutou/jugyo-2025kyototech/commit/3113d0d34227412b9ca6d389cbd290aea267a196
演習2
アクセスカウンタに加えて、前回のアクセス日時を表示するようにしてみましょう。
動作例: http://54.210.191.33/enshu2.php
実装例: https://github.com/oddmutou/jugyo-2025kyototech/commit/5ddb06a14ac83e4dfd77c2c4bacda3fb40472675