[PHPのはじめ方] Part16: セッションとクッキーの管理

Webアプリケーションの状態を維持する方法を学ぼう!

Webサイトを見ていると、「ログイン状態が維持される」「カートに入れた商品が残っている」といった経験があると思います。これは、HTTPというプロトコルが基本的に「ステートレス(状態を持たない)」であるため、何もしなければサーバーは前のリクエストと次のリクエストが同じユーザーからのものだと認識できないからです。

この問題を解決し、ユーザーごとの情報(状態)を維持するために使われるのがクッキー (Cookie)セッション (Session) です。今回は、PHPでこれらをどのように扱っていくのかを学びましょう!

🍪 クッキー (Cookie) とは?

クッキーは、Webサーバーからの指示で、ユーザーのブラウザ(クライアント側)に保存される小さなテキストファイルです。サーバーはHTTPレスポンスヘッダーを通じてクッキーを送信し、ブラウザはそれを保存します。次回以降、同じサーバーにリクエストを送る際に、ブラウザは保存されているクッキーをHTTPリクエストヘッダーに含めて送信します。これにより、サーバーはユーザーを識別したり、以前の設定を読み込んだりできます。

クッキーの主な用途

  • ログイン状態の維持: 「次回から自動的にログインする」機能など。
  • ユーザー設定の保存: 言語設定、テーマ設定など。
  • ショッピングカート: ログインしていなくてもカートの中身を保持する。
  • トラッキング: ユーザーのサイト内での行動履歴を追跡する(広告などで利用)。

PHPでのクッキー操作

クッキーの設定: setcookie()

PHPでクッキーを設定するには setcookie() 関数を使います。この関数は、HTTPヘッダーを送信するため、HTMLが出力される前(<!DOCTYPE html> や他のPHP出力よりも前)に呼び出す必要があります。

<?php
// クッキーを設定する例
$cookie_name = "user_preference";
$cookie_value = "dark_mode";
$expire = time() + (86400 * 30); // 86400秒 = 1日 なので、30日間有効
$path = "/"; // サイト全体で有効
// $domain = "example.com"; // 必要であればドメイン指定
// $secure = true; // HTTPS接続の場合のみ送信
// $httponly = true; // JavaScriptからのアクセスを禁止

setcookie($cookie_name, $cookie_value, $expire, $path); // , $domain, $secure, $httponly);

// より現代的なオプション指定 (PHP 7.3+)
/*
setcookie($cookie_name, $cookie_value, [
    'expires' => $expire,
    'path' => $path,
    // 'domain' => $domain,
    // 'secure' => $secure,
    // 'httponly' => $httponly,
    // 'samesite' => 'Lax' // CSRF対策: Strict, Lax, None
]);
*/
?>
<!DOCTYPE html>
<html>
<head>
    <title>クッキー設定</title>
</head>
<body>
    <p>クッキーを設定しました。</p>
</body>
</html>
ポイント: setcookie() の引数には、名前、値、有効期限、パス、ドメイン、Secure属性、HttpOnly属性、SameSite属性などを指定できます。セキュリティ向上のため、HttpOnlySameSite 属性の利用を検討しましょう。

クッキーの取得: $_COOKIE

ブラウザから送信されたクッキーは、PHPのスーパーグローバル変数 $_COOKIE (連想配列) を使ってアクセスできます。この変数は、スクリプトのどこからでも利用可能です。

<?php
// $_COOKIE を使う前に setcookie() を実行する必要はない

if(isset($_COOKIE["user_preference"])) {
    $preference = htmlspecialchars($_COOKIE["user_preference"], ENT_QUOTES, 'UTF-8'); // XSS対策
    echo "ユーザー設定: " . $preference . " が読み込まれました。";
} else {
    echo "ユーザー設定のクッキーは見つかりませんでした。";
}
?>
注意: $_COOKIE の内容はユーザーが改ざんできる可能性があるため、必ずバリデーションやサニタイズ(例: htmlspecialchars())を行ってください。

クッキーの削除

クッキーを削除するには、setcookie() を使って有効期限を過去の日時に設定します。名前やパスなどの他の引数は、設定時と同じものを指定する必要があります。

<?php
// 'user_preference' クッキーを削除
$expire = time() - 3600; // 1時間前
$path = "/";
setcookie("user_preference", "", $expire, $path);

// またはオプション配列で
/*
setcookie("user_preference", "", [
    'expires' => $expire,
    'path' => $path,
]);
*/
?>
<!DOCTYPE html>
<html>
<head>
    <title>クッキー削除</title>
</head>
<body>
    <p>クッキーを削除しました(次のリクエストから反映されます)。</p>
</body>
</html>

クッキーの注意点

  • 容量制限: ブラウザごとに保存できるクッキーの総数や、1つのドメインあたりのクッキー数、1つのクッキーのサイズに制限があります(通常4KB程度)。
  • セキュリティ: クッキーはクライアント側に保存されるため、盗まれたり改ざんされたりするリスクがあります。機密情報は直接保存しないようにしましょう。
  • プライバシー: トラッキングクッキーなどはプライバシーに関わるため、利用にはユーザーの同意が必要になる場合があります(GDPRなど)。

🔑 セッション (Session) とは?

セッションは、ユーザーに関する情報をサーバー側に一時的に保存する仕組みです。ユーザーがサイトにアクセスすると、PHPは一意なID(セッションID)を生成します。このセッションIDは通常、クッキーを使ってユーザーのブラウザに保存されます(URLパラメータで渡すことも可能ですが、セキュリティ上推奨されません)。

ユーザーがサイト内でページを移動するたびに、ブラウザはセッションIDをサーバーに送信します。サーバーはそのIDを使って、対応するセッションデータ(ユーザー名、カートの中身など)をサーバー側のストレージ(ファイルやデータベースなど)から読み込みます。これにより、ユーザーごとの状態を安全に管理できます。

セッションの主な用途

  • ログイン状態の管理: ログインしたユーザーの情報をサーバー側で安全に保持する。
  • 一時的なデータの保持: 複数ページにまたがるフォーム入力内容、エラーメッセージなど。
  • ユーザーごとの設定: クッキーでも可能だが、より機密性の高い情報や大量のデータを扱う場合。

PHPでのセッション操作

セッションの開始: session_start()

セッションを利用するには、まず session_start() 関数を呼び出す必要があります。これは、既存のセッションを再開するか、新しいセッションを開始します。setcookie() と同様に、この関数もHTMLなどの出力よりも前に呼び出す必要があります。

<?php
// セッションを開始 (または再開)
session_start();
?>
<!DOCTYPE html>
<html>
<head>
    <title>セッション開始</title>
</head>
<body>
    <p>セッションが開始されました。</p>
</body>
</html>
ポイント: セッションを利用する全てのPHPページの冒頭session_start() を呼び出すようにしましょう。

セッション変数の設定と取得: $_SESSION

セッションが開始されると、スーパーグローバル変数 $_SESSION (連想配列) が利用可能になります。この配列に値を追加したり、読み取ったりすることで、セッションデータを操作します。

<?php
session_start();

// セッション変数を設定
$_SESSION["username"] = "Taro Yamada";
$_SESSION["email"] = "taro@example.com";
$_SESSION["login_time"] = time();

echo "ようこそ、" . htmlspecialchars($_SESSION["username"], ENT_QUOTES, 'UTF-8') . "さん!<br>";

// セッション変数を取得
if (isset($_SESSION["email"])) {
    echo "登録メールアドレス: " . htmlspecialchars($_SESSION["email"], ENT_QUOTES, 'UTF-8') . "<br>";
}

// セッション変数の一部を削除 (unset)
unset($_SESSION["login_time"]);

// セッション変数の一覧表示 (デバッグ用)
echo "<pre>";
print_r($_SESSION);
echo "</pre>";
?>

セッションの破棄

セッションを終了させたい場合(ログアウト時など)は、いくつかの手順を踏みます。

  1. セッション変数を全て削除: session_unset() を使うか、$_SESSION = array(); で空にします。
  2. セッションを破棄: session_destroy() を呼び出し、サーバー上のセッションデータを削除します。
  3. セッションIDクッキーを削除 (推奨): クライアント側に残っているセッションIDのクッキーも削除します。
<?php
session_start();

// 1. セッション変数をすべて削除
$_SESSION = array();
// または session_unset();

// 2. セッションクッキーを削除 (推奨)
// セッション名を取得 (デフォルトは 'PHPSESSID')
$session_name = session_name();
// クッキーのパラメータを取得
$cookie_params = session_get_cookie_params();

// クッキーを削除するために過去の時間を設定
setcookie(
    $session_name,
    '',
    time() - 42000,
    $cookie_params["path"],
    $cookie_params["domain"],
    $cookie_params["secure"],
    $cookie_params["httponly"]
);

// 3. セッションを破棄
session_destroy();
?>
<!DOCTYPE html>
<html>
<head>
    <title>ログアウト</title>
</head>
<body>
    <p>ログアウトしました。セッションは破棄されました。</p>
    <p><a href="session_check.php">セッション状態を確認</a></p> <!-- 確認用ページへのリンク -->
</body>
</html>

セッションの注意点

  • session_start() の位置: 必ず出力の前(HTMLタグ、空白、他のPHP出力よりも前)に記述します。
  • サーバーリソース: セッションデータはサーバー側に保存されるため、アクティブなセッションが多いとサーバーのリソース(ディスク容量、メモリ)を消費します。不要になったセッションは適切に破棄しましょう。
  • セキュリティ: セッションIDが漏洩すると、第三者にセッションを乗っ取られる(セッションハイジャック)可能性があります。HTTPS通信の利用や、定期的なセッションIDの再生成(session_regenerate_id(true))が重要です。

🤔 クッキーとセッションの使い分け

クッキーとセッションはどちらも状態維持に使われますが、特徴が異なります。状況に応じて適切に使い分けることが重要です。

特徴 クッキー (Cookie) 🍪 セッション (Session) 🔑
データ保存場所 クライアント (ブラウザ) サーバー
データ容量 小さい (通常 4KB 程度) 比較的大きい (サーバーのディスク/メモリ容量による)
セキュリティ 低い (改ざん・盗聴のリスクあり) 比較的高い (データはサーバー側にある)
有効期限 任意に設定可能 (ブラウザを閉じても維持できる) ブラウザを閉じるまで、またはサーバー側で設定した有効期限まで
サーバー負荷 低い 高い (セッション管理が必要)
主な用途例 自動ログイン、設定保存、トラッキング ログイン状態管理、ショッピングカート、一時データ保持

使い分けのヒント

  • 機密性の高い情報(ユーザーID、個人情報など)は、セッションで管理する。
  • ログイン状態は、セッションで管理するのが一般的(セッションIDはクッキーで保持)。
  • 「次回から自動ログイン」のような機能は、安全な方法(例:推測されにくいトークン)でクッキーに保存する。
  • サイトの表示設定(テーマ、言語など)のような、機密性が低く、長期間保持したい情報はクッキーが適している場合がある。
  • 一時的なフォーム入力内容やエラーメッセージなどはセッションが便利。

🛡️ セキュリティに関する考慮事項

セッションとクッキーは便利ですが、セキュリティリスクも伴います。以下の点に注意して安全なWebアプリケーションを構築しましょう。

  • HTTPSの利用: 通信経路を暗号化し、クッキー(特にセッションIDクッキー)の盗聴を防ぎます。setcookie()secure 属性を true に設定しましょう。
  • HttpOnly属性: クッキーに HttpOnly 属性を付けると、JavaScriptからのアクセスが禁止され、クロスサイトスクリプティング(XSS)によるクッキー盗難のリスクを軽減できます。setcookie()httponly 属性を true に設定するか、php.inisession.cookie_httponly を有効にします。
  • SameSite属性: クロスサイトリクエストフォージェリ(CSRF)攻撃を緩和するために、クッキーに SameSite 属性(Strict, Lax, None)を設定します。PHP 7.3以降で setcookie() のオプション配列で指定可能です。
  • セッションIDの再生成: ログイン成功時など、ユーザーの権限レベルが変わるタイミングで session_regenerate_id(true) を呼び出し、セッションIDを新しいものに変更します。これにより、セッション固定攻撃(Session Fixation)のリスクを軽減できます。引数に true を指定すると、古いセッションファイルも削除されます。
  • セッションタイムアウト: 一定時間操作がない場合にセッションを自動的に無効にするタイムアウトを設定します。
  • CSRF対策: フォーム送信時に推測困難なトークン(CSRFトークン)を埋め込み、サーバー側で検証することで、意図しないリクエストの実行を防ぎます。
  • クッキーの内容の検証: クッキーに保存された値を利用する際は、改ざんされていないか検証する仕組み(例: HMAC署名)を導入することも検討します。
セッションとクッキーのセキュリティは非常に重要です。常に最新の脅威と対策方法について情報を収集し、適切な対策を講じるように心がけましょう。

まとめ

今回は、PHPにおけるセッションとクッキーの管理方法について学びました。

  • クッキーはクライアント側にデータを保存する仕組み。
  • セッションはサーバー側にデータを保存する仕組み(セッションIDはクッキーで管理することが多い)。
  • setcookie() でクッキーを設定・削除、$_COOKIE で取得。
  • session_start() でセッションを開始、$_SESSION でデータを操作、session_destroy() などで破棄。
  • それぞれの特性を理解し、セキュリティに配慮しながら適切に使い分けることが重要。

セッションとクッキーを使いこなすことで、ユーザーにとってより便利でインタラクティブなWebアプリケーションを構築できます。特にログイン機能などでは必須の知識となります。

次は、いよいよPHPの強力な機能である「オブジェクト指向プログラミング」に進みます!クラスやオブジェクトの概念を学び、より構造化されたコードを書く方法を身につけましょう。💪