Upgrade to Pro — share decks privately, control downloads, hide ads and more …

セッションで遊んでみた

gallu
February 28, 2024

 セッションで遊んでみた

gallu

February 28, 2024
Tweet

More Decks by gallu

Other Decks in Technology

Transcript

  1. Slimいいよ!! PHPセッション楽しいよ!  「PHPのセッションサポート機能」(ってマニュアルに書い てある)、お世話になっている人も多いのではないか? と 思われます  Laravel使うと「Laravelのセッション」なのであんまり……という 人もいるかと思いますがキニスンナ

     普通に使う分には割と慣れっこな気がしますが、「ちょっ と奇妙な事」も割と耐えられるので、そんなこんなを見て いきましょう!!  お題は3つ。5分なんでサクサクいきます(笑
  2. 前提) セッションって?  大雑把には「ステートレスなHTTPで、ステートを保存す る」用途のあんなこんな  Cookieと似てる  Cookieは「RFCで定義された」機能 

    昔は「ネスケが提案実装した」localだったんですけどねぇ  2000年に出てるRFC 2965には出てきているので、まぁ古参  セッションは「共通の定義はない」  のでまぁ「どの」セッションか? でいろいろとお話が変わる  今回は「PHPという言語が提供しているセッション処理 https://www.php.net/manual/ja/book.session.php 」
  3. Cookieとセッションの大まかな違い  データの置き場所  Cookieは「HTTPのリクエストとレスポンス」の通信でやりとりし て、データはユーザ側に保存されます  セッションは「どこにあるかは実装次第」。でもまぁサーバ上に あることが「多い」かなぁ 

    データ量の制限とか  Cookieが保証しているのは「Cookieごとに少なくとも4096バイ ト」「ドメインごとに少なくとも50のCookie」「合計で少なくとも 3,000のクッキー」 by RFC 6265  セッションは「実装次第」。Cookieよりは多い事が多いと思う
  4. 本題1) 複数ドメインで同じセッション  ニーズ  ゲーム作ってるんですが(過去のリニューアル込みで)  www.example.com でメインのユーザ管理 

    game1.example.com とか game2.example.com とかでそれぞれ個別 にゲーム  全体で「同じユーザ」として管理したい  けどまぁ開発の都合もあって、ドメインは切り分けたい  ので「wwwでユーザ登録しぃの、ログインしてもらいぃの」 した後で「個々のゲームを楽しんでもらいたい」  認可情報は「セッションに入れる(事が多い)」から、まぁ「違うド メインで同じセッション使えると具合がよいなぁ」と
  5. 大まかな実装指針  session_set_cookie_params() 関数つかって「domainを指 定する」  今回の場合 example.com を対象ドメインにする 

    後は普通にセッションを開始して書いたり読んだりする  かいつまんでいくつかコードを書いておきます  後で資料公開するのでその時に落ち着いて読んでください(笑  Blogにもうちょっと詳細がありますので、こちらもよかったら  https://gallu.hatenadiary.jp/entry/2024/02/13/174635
  6. コード(一部)  common.php <?php // common.php declare(strict_types=1); // ob_start(); //

    ざっくりセッション設定 session_set_cookie_params([ 'lifetime' => 0, 'samesite' => 'Strict', // 'secure' => true, // テスト環境なのでhttpsになってないからコメントアウト 'httponly' => true, 'domain' => 'example.com', ]); ini_set('session.use_strict_mode', 1); // セッション開始 session_start();
  7. <?php // hoge/read.php, foo/read.php declare(strict_types=1); require __DIR__ . '/../common.php'; //

    セッション情報の表示 var_dump($_SESSION); var_dump(session_id()); <?php // hoge/write.php declare(strict_types=1); require __DIR__ . '/../common.php'; // セッションへの書き込み $_SESSION['hoge'] = 'hoge value'; // echo 'ok'; <?php // foo/write.php declare(strict_types=1); require __DIR__ . '/../common.php'; // セッションへの書き込み $_SESSION['foo'] = 'foo value'; // echo 'ok';
  8.  結果(例)  うんいけてるいけてる  セッションIDが「同じ」なので、ちゃんと「同じセッション見てる」 事がわかる  ゲーム保存データ本体はまた別のこと考えてますがチャンス があったらまたどこかで

    http://hoge.example.com/read.php array(2) { ["hoge"]=> string(10) "hoge value" ["foo"]=> string(9) "foo value" } string(32) "f4a57c3d4dc2e0fe4f4fb4b167d4dcd2" http://foo.example.com/read.php array(2) { ["hoge"]=> string(10) "hoge value" ["foo"]=> string(9) "foo value" } string(32) "f4a57c3d4dc2e0fe4f4fb4b167d4dcd2"
  9. 余談) セッションとCookieのテスト方法  ブラウザの、シークレットモードとかプライベートブラウジ ングとか(火狐だとプライベートウィンドウ、Chromeだと シークレットウィンドウ)を使うと楽です  開いた瞬間、「まっさらな状態」からstartできるので  「全部のシークレットウィンドウを閉じる」とCookieも完全に消

    えるので、またまっさらからテストし直せます  ブラウザの開発ツール(F12)も便利なので積極的に使い ましょう!  先日、学校の生徒さんから「開発ツールで初めて通信のイ メージがついた」って言われたので、来年度は授業でももっと 積極的に使おうかと思ってます!!
  10. 本題2)セッションの寿命(GC)の実験  この辺割と「なんとなく」触っているので、実験してみたく なった  ところでGCって……  ガベジコレクタ ? 

    ガベージコレクタ ?  ガーベジコレクタ ?  ガーベッジコレクタ ?  面倒だから「ジーシー」「ガベコレ」って言うことが増えた(笑
  11. コード <?php declare(strict_types=1); error_reporting(-1); ob_start(); ini_set('session.gc_maxlifetime', 5); // 5秒 //

    1/1の確率で破棄 ini_set('session.gc_probability', 1); ini_set('session.gc_divisor', 1); session_start(); echo "5秒を見切ってみましょう<br>¥n"; if (false === isset($_SESSION['time'])) { echo "一見さんですね?"; } else { $t = (hrtime(true) - $_SESSION['time']) / 1e9; echo "前回アクセスから {$t} 秒経過しています。¥n"; } $_SESSION['time'] = hrtime(true);
  12. 動かしてみた 一見さんですね? 前回アクセスから 1.859404099 秒経過しています。 前回アクセスから 4.374510851 秒経過しています。 前回アクセスから 10.326877074

    秒経過しています。 一見さんですね? 前回アクセスから 0.69189565 秒経過しています。 前回アクセスから 4.530781299 秒経過しています。 前回アクセスから 5.74658378 秒経過しています。 一見さんですね? 前回アクセスから 5.400823442 秒経過しています。 前回アクセスから 3.952103308 秒経過しています。 前回アクセスから 6.470162867 秒経過しています。 一見さんですね?
  13. コード class JokeSessionHandler implements SessionHandlerInterface { const COOKIE_NAME = "joke";

    // 一部省略。省略メソッドは return true; 程度の実装 #[¥ReturnTypeWillChange] public function read(string $id) { return $_COOKIE[self::COOKIE_NAME] ?? ''; } public function write(string $id, string $data): bool { setcookie(self::COOKIE_NAME, $data); return true; } public function destroy(string $id): bool { setcookie(self::COOKIE_NAME, '', time() - 1); return true; } }
  14. <?php declare(strict_types=1); ob_start(); class JokeSessionHandler implements SessionHandlerInterface { (略) }

    session_set_save_handler(new JokeSessionHandler()); session_start(); var_dump($_SESSION); $_SESSION['rand'] = random_int(0, 9999); $_SESSION['rand2'] = random_int(0, 9999); $_SESSION['rand3'] = random_int(0, 9999); var_dump($_SESSION); var_dump( session_encode() );
  15. 結果  一回目  array(0) { }  array(3) {

    ["rand"]=> int(6045) ["rand2"]=> int(9493) ["rand3"]=> int(5557) } string(38)  "rand|i:6045;rand2|i:9493;rand3|i:5557;"  Set-Cookie: joke=rand%7Ci%3A6045%3Brand2%7Ci%3A9493%3Brand3%7Ci% 3A5557%3B
  16.  二回目  array(3) { ["rand"]=> int(6045) ["rand2"]=> int(9493) ["rand3"]=>

    int(5557) }  array(3) { ["rand"]=> int(7301) ["rand2"]=> int(4857) ["rand3"]=> int(9676) } string(38)  "rand|i:7301;rand2|i:4857;rand3|i:9676;"  Cookie: PHPSESSID=3cec75116c097a73f89d52c5bfe78a13; joke=rand%7Ci%3A6045%3Brand2%7Ci%3A9493%3Brand3%7Ci% 3A5557%3B  Set-Cookie: joke=rand%7Ci%3A7301%3Brand2%7Ci%3A4857%3Brand3%7Ci% 3A9676%3B
  17.  ちゃんと「Cookieに保存されたセッション」ができました!!!  多分、ほぼなんの用途もありませんが  まぁ真面目な話「保存データを暗号化する」とかやれば、 うっすらと使い道がないわけでもなく  write側で暗号化、read側で復号すればいい 

    「サーバ側の資源を使わない」のは、マジで割と強い  Laravelにも「cookie」ってセッションの設定があるし  もしかしたら、どこかで使える、かも?  「絶対にない」を言い切るのは難しいwww