後期第02回 - oddmutou/jugyo-2026kyototech GitHub Wiki

授業の最初に

  • シラバスの説明
  • AWS Academyの新しいクラスへの参加
  • その新しいクラスのLabのAWSアカウント上でEC2インスタンス作成
    • 「インターネットからのHTTPトラフィックを許可」を有効化するのを忘れずに
  • 新しいEC2インスタンス内で環境構築
    • vimのインストール、.vimrc設定
    • screenのインストール、.screenrc設定
    • docker, docker compose, buildx の導入

セッション

セッションとは、おもにコンピュータにおける一連の操作の流れのことを指します。

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://18.234.43.222/enshu1.php

実装例: https://github.com/oddmutou/jugyo-2026kyototech/commit/06b1082d0325e4118e39faf81d88ad7549749e4a

演習2

セッション別の、アクセスカウンタに加えて、前回のアクセス日時を表示するようにしてみましょう。

動作例: http://18.234.43.222/enshu2.php

実装例: https://github.com/oddmutou/jugyo-2026kyototech/commit/f2857dbd47f4706be39aabbdb161f2cbc2c683cb

追加演習

追加の演習です。物足りないひとはやってください。全体で説明は行いません。助言、解説が必要な人は授業中に個別に聞いてください。

追加演習1

「カウンタをリセットする」ボタンを作ってください。押すと、そのセッションのカウントだけを0にしてください。

追加演習2

全セッション合計のカウンタも同画面に実装してみてください。セッション別のカウントに加えて、「サイト全体で何回アクセスされたか」を表示する型式にしてください。

追加演習3

セッションの有効期限を実装してみてください。有効期限がきたら、自動的にセッションに保存しているデータが全て消えるようにしてみてください。

まずは有効期限を30秒として作ってみると、動作確認しやすいでしょう。(実際のWebサービスでセッションの有効期限が30秒だったらめちゃくちゃおかしいとは思いますが、…。)

追加演習4

セッションに名前を覚えさせてみてください。適当に名前入力フォームを用意して、一度記入したら、次回以降のアクセス時に「こんにちは、XXさん」といったように表示させてみてください。

追加演習5

セッション情報を自ら全て破棄するボタンを作ってみてください。追加演習1と違って、何らかの値をリセットするのではなく、セッションデータを消してください。redis-cliでKEYSを叩いて、データが消えていることを確認してください。