この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:8
ページ更新者:atom
更新日時:2026-06-11 07:12:00

タイトル: セッション
SEOタイトル: 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 + トークン) は両者必要。