27.

PHP セッション完全ガイド

編集
この記事の要点
  • session_start() でセッション開始、$_SESSION["key"] で読み書き
  • 識別は Cookie (PHPSESSID)、保存先は ファイル / Redis / Memcached / DB から選択
  • ログイン直後は session_regenerate_id(true) 必須 (セッション固定化攻撃対策)
  • Cookie 属性: HttpOnly / Secure / SameSite=Lax/Strict
  • SPA / API は JWT (Stateless) を選ぶことが多いが、CSRF / トークン失効を考えるとセッションが優位な場面も多い

基本: セッションの開始と読み書き

// 必ず HTML 出力前に呼ぶ
session_start();

// 書き込み
$_SESSION['user_id'] = 123;
$_SESSION['name']    = 'taro';
$_SESSION['cart']    = ['apple' => 2, 'banana' => 1];

// 読み込み
$id = $_SESSION['user_id'] ?? null;

// 削除
unset($_SESSION['cart']);

// 全クリア
$_SESSION = [];

// セッション破棄 (ログアウト)
session_unset();
session_destroy();
setcookie(session_name(), '', time() - 3600, '/');  // Cookie も消す

動作原理

  1. クライアントが初回アクセス → サーバが セッション ID を発行
  2. Set-Cookie: PHPSESSID=abc123... でブラウザに渡す
  3. 以降のリクエストでブラウザが Cookie を送信
  4. サーバは ID をキーにセッションストア (ファイル等) から状態を取得
  5. $_SESSION 経由で読み書き → リクエスト終了時に書き戻し

保存先の選択 (php.ini / ini_set)

; php.ini
session.save_handler = files                           ; デフォルト
session.save_path    = "/var/lib/php/sessions"

; Redis
session.save_handler = redis
session.save_path    = "tcp://127.0.0.1:6379?auth=password"

; Memcached
session.save_handler = memcached
session.save_path    = "127.0.0.1:11211"

; ライフタイム (秒)
session.gc_maxlifetime = 1440

; Cookie 設定
session.cookie_lifetime = 0          ; 0 = ブラウザ閉じるまで
session.cookie_secure   = 1          ; HTTPS のみ
session.cookie_httponly = 1          ; JS から読めなくする
session.cookie_samesite = "Lax"      ; CSRF 対策
session.use_strict_mode = 1          ; ★ 未知の ID 拒否 (セッション固定化対策)
session.use_only_cookies = 1         ; URL 経由禁止

保存先別の比較

保存先速度マルチサーバ用途
files (デフォルト)速いX (NFS は不可)単一サーバの小規模
Redis超速O★ 推奨。標準的
Memcached超速Oキャッシュ兼用
DB遅めO永続化必要なとき

セキュリティ: 必ずやること

// 1. ログイン直後にセッション ID を再生成 (セッション固定化対策)
function login(string $email, string $password): bool {
    $user = User::findByEmail($email);
    if (!$user || !password_verify($password, $user->password_hash)) {
        return false;
    }
    // ★ ここが超重要
    session_regenerate_id(true);   // 古い ID を破棄
    $_SESSION['user_id'] = $user->id;
    $_SESSION['logged_in_at'] = time();
    return true;
}

// 2. CSRF トークン
$_SESSION['csrf'] ??= bin2hex(random_bytes(32));

// HTMLフォームに埋め込み
?>
<input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
<?php

// POST 検証
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
    http_response_code(419);
    exit('CSRF token mismatch');
}

// 3. セッション固定タイマー
if (isset($_SESSION['logged_in_at']) && time() - $_SESSION['logged_in_at'] > 7200) {
    session_destroy();
    redirect('/login?expired=1');
}

Cookie 属性詳解

属性意味推奨
HttpOnlyJavaScript から document.cookie で読めない★ 必須 (XSS 対策)
SecureHTTPS でしか送信しない★ 本番必須
SameSite=Strictクロスサイト全拒否強い保護だが UX 影響
SameSite=Laxトップ遷移は許可、リソース送信は不可★ 標準推奨
SameSite=None制限なし (Secure 必須)3rd party Cookie 必須なとき
DomainCookie 有効ドメインサブドメイン共有時のみ指定
PathCookie 有効パス通常 /
// session_start で Cookie 属性を一括指定 (PHP 7.3+)
session_set_cookie_params([
    'lifetime' => 0,
    'path'     => '/',
    'domain'   => '.example.com',
    'secure'   => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();

Laravel のセッション

// config/session.php
return [
    'driver'     => env('SESSION_DRIVER', 'redis'),    // file / cookie / database / redis / memcached
    'lifetime'   => env('SESSION_LIFETIME', 120),       // 分
    'expire_on_close' => false,
    'encrypt'    => true,
    'cookie'     => 'myapp_session',
    'secure'     => env('SESSION_SECURE_COOKIE', true),
    'http_only'  => true,
    'same_site'  => 'lax',
];

// .env
SESSION_DRIVER=redis
SESSION_LIFETIME=120
SESSION_SECURE_COOKIE=true

// コントローラで
session(['user_id' => 1]);
session('user_id');
session()->forget('user_id');
session()->flush();

// フラッシュ (次のリクエストまで)
session()->flash('message', '保存しました');

// CSRF (自動)
// → form に @csrf を入れるだけで Laravel が検証

Symfony / SPA / JWT との比較

方式状態サーバスケール失効用途
セッション (Cookie)サーバ持ち共有ストア必要即時 (削除)★ Web アプリ標準
JWT (Bearer)クライアント水平展開容易困難 (期限まで有効)SPA / API / モバイル
OAuth Access Tokenクライアント同上サーバ側で revoke 可外部連携
Refresh Token + Session両方柔軟OK本格 API

セッション関連のよくあるトラブル

症状原因対処
セッションが保持されないCookie が送られない / Domain ミスDevTools で Cookie 確認、Domain 修正
"Cannot send session cookie - headers already sent"session_start 前に出力済BOM 削除、空白除去、output_buffering ON
HTTPS で消えるsecure=true で HTTP アクセスHTTPS 統一 or secure を環境変数化
ロードバランサ越しで切れるfiles ストアで別サーバへ振分Redis 等の共有ストアへ
サイズエラーセッションに巨大データ格納最小限に。データは DB 参照キーだけ

FAQ

Q: セッションと Cookie の違いは?
A: Cookie はブラウザ保存。セッションはサーバ保存 (識別子だけ Cookie 経由)。秘密情報はセッション側に持つのが安全。

Q: ログアウトで何を呼ぶ?
A: session_unset() + session_destroy() + setcookie(session_name(), '', time()-3600, '/') の 3 点セット。

Q: SPA で JWT と Cookie セッション、どちらが安全?
A: HttpOnly Cookie セッションのほうが XSS 耐性が高い。JWT を localStorage に置くのは XSS で漏洩する。CSRF 対策 (SameSite + トークン) は両者必要。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ