session_start() / $_SESSION / session_destroy()
| 対応: | PHP 4(2000) |
|---|
セッションを開始し、サーバー側でユーザーごとのデータを保持します。ログイン状態の管理やショッピングカートなど、ページをまたいでデータを保持したい場合に使用されます。
構文
// セッションを開始する session_start($options); // セッション変数に値を保存・取得する $_SESSION['key'] = $value; // セッションを破棄する session_destroy(); // セッションIDを再生成する session_regenerate_id($delete_old_session); // セッションIDを取得する session_id($id); // セッションCookieのパラメータを設定する session_set_cookie_params($options);
関数一覧
| 関数 | 概要 |
|---|---|
| session_start($options) | セッションを開始します。既にセッションが開始されている場合は何もしません。引数で『cookie_lifetime』『cookie_secure』などのオプションを指定できます。 |
| $_SESSION | セッション変数を格納するスーパーグローバル配列です。この配列に値を保存すると、同じユーザーの次のリクエストでもデータが利用できます。 |
| session_destroy() | セッションに関連付けられたデータをすべて破棄します。セッション変数は即座には消えないため、併せて『$_SESSION = []』で空にしてください。 |
| session_regenerate_id($delete_old) | セッションIDを新しく生成し直します。引数に『true』を指定すると古いセッションファイルも削除されます。 |
| session_id($id) | 引数なしで現在のセッションIDを返します。引数を指定するとセッションIDを設定できます。 |
| session_set_cookie_params($options) | セッションCookieのパラメータを設定します。『session_start()』の前に呼び出す必要があります。 |
サンプルコード
『session_start()』はすべてのページの先頭で1回だけ呼び出してください。
session_start.php
<?php
// セッションを開始する
session_start();
// セッション変数にデータを保存する
$_SESSION['username'] = '桐生一馬';
$_SESSION['favorite_song'] = 'ばかみたい';
$_SESSION['login_time'] = time();
echo $_SESSION['username']; // 『桐生一馬』と出力される
echo $_SESSION['favorite_song']; // 『ばかみたい』と出力される
// セッション変数の存在を確認する
if (isset($_SESSION['username'])) {
echo "ログイン中: " . $_SESSION['username'];
}
// セッションIDを確認する
echo session_id(); // 『abc123def456...』のようなIDが出力される
// セキュリティ対策としてセッションCookieを適切に設定する
session_set_cookie_params([
'lifetime' => 0, // ブラウザを閉じるまで有効
'path' => '/',
'domain' => '',
'secure' => true, // HTTPS接続でのみCookieを送信する
'httponly' => true, // JavaScriptからCookieにアクセスできなくなる
'samesite' => 'Lax' // CSRF対策としてSameSite属性を設定する
]);
session_start(); // ← 本来はページ先頭でこの1回のみ呼び出す
// ログイン成功時にセッションIDを再生成する
session_regenerate_id(true); // 古いセッションファイルも削除される
$_SESSION['user_id'] = 1;
// ログアウト処理の完全な実装
$_SESSION = []; // セッション変数をすべて空にする
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(
session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
); // セッションCookieを削除する
}
session_destroy(); // セッションデータを破棄する
php session_start.php 桐生一馬 ばかみたい ログイン中: 桐生一馬 abc123def456789ghijk012345lmnop
実践パターン: ログイン処理の完全実装
以下のサンプルでは、次のユーザーテーブルを使用します。パスワードは『password_hash()』でハッシュ化して保存してください。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) DEFAULT 'user'
);
-- パスワード『secret123』のハッシュ値(password_hash()で生成)
INSERT INTO users (email, password_hash, role) VALUES
('kiryu@dojima-family.jp', '$2y$10$xxxxx...', 'admin');
テーブルの内容を確認します。
SELECT * FROM users; +----+------------------------+--------------------------------------------------------------+-------+ | id | email | password_hash | role | +----+------------------------+--------------------------------------------------------------+-------+ | 1 | kiryu@dojima-family.jp | $2y$10$xxxxx... | admin | +----+------------------------+--------------------------------------------------------------+-------+ 1 row in set
sample_login.php
<?php
// ログイン処理の完全な実装パターン
// 1. セッションCookieの設定は session_start() より前に行う
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
// 2. CSRFトークンを確認する(フォームから送信されたトークンと比較)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
http_response_code(403);
exit('Forbidden');
}
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
// 3. DBでユーザーを認証する
$pdo = new PDO('mysql:host=localhost;dbname=sample_db;charset=utf8mb4', 'root', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email LIMIT 1");
$stmt->execute([':email' => $email]);
$user = $stmt->fetch();
// password_verify() でハッシュ値と照合する
if ($user && !password_verify($password, $user['password_hash'])) {
$user = false;
}
if ($user) {
// 4. ログイン成功時はセッションIDを必ず再生成する(セッション固定攻撃対策)
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['role'] = $user['role'];
$_SESSION['login_time'] = time();
header('Location: /dashboard.php');
exit;
} else {
$_SESSION['error'] = 'メールアドレスまたはパスワードが違います。';
}
}
// 5. フォーム表示時にCSRFトークンを発行する
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
curlコマンドで動作確認します。以下のシェルスクリプトでログインフォームの取得からログインリクエストの送信までを実行します。
sample_login_test.sh
#!/bin/bash # 1. ログインフォームを表示してCSRFトークンを取得する CSRF=$(curl -c cookie.txt -s http://localhost/login.php \ | grep -o 'value="[^"]*"' | head -1 | cut -d'"' -f2) echo "CSRFトークン: $CSRF" # 2. ログインリクエストを送信する curl -b cookie.txt -c cookie.txt -s -D - \ -d "email=kiryu@dojima-family.jp&password=secret123&csrf_token=$CSRF" \ http://localhost/login.php
sh sample_login_test.sh CSRFトークン: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 HTTP/1.1 302 Found Location: /dashboard.php Set-Cookie: PHPSESSID=new_session_id; path=/; secure; HttpOnly; SameSite=Lax
ログインに成功すると302リダイレクトが返され、セッションIDが再生成された新しいCookieが発行されます。認証に失敗した場合は同じページに戻り、『$_SESSION["error"]』にエラーメッセージが格納されます。
よくあるミス1: 出力後のsession_start()
セッション開始前に何かを出力すると『headers already sent』エラーになります。
<?php // NG: セッション開始前に何かを出力すると『headers already sent』エラーになる echo "こんにちは"; // HTMLや空白でも同様です。 session_start(); // エラー: Cannot send session cookie - headers already sent
<?php // OK: session_start() はページの最先頭(出力より前)で呼び出す session_start(); echo "こんにちは";
よくあるミス2: session_destroy()だけのログアウト
『session_destroy()』だけではセッション変数がメモリ上に残り続けます。ログアウト処理には3ステップが必要です。
<?php // NG: session_destroy() だけではセッション変数が残る session_destroy(); echo $_SESSION['username']; // まだ参照できてしまいます。
<?php
// OK: 変数の消去・Cookieの削除・データ破棄の3ステップが必要
$_SESSION = [];
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
}
session_destroy();
よくあるミス3: セッションID未再生成
ログイン後にセッションIDを再生成しないと、セッション固定攻撃の危険があります。
<?php // NG: ログイン後にセッションIDを再生成しないとセッション固定攻撃の危険がある $_SESSION['user_id'] = $user['id']; // セッション固定攻撃のリスクあり
<?php // OK: ログイン直後に必ず再生成する session_regenerate_id(true); $_SESSION['user_id'] = $user['id'];
よくあるミス4: session_start()の二重呼び出し
require/include で読み込んだファイルで再度 session_start() を呼ぶとエラーになります。
<?php // NG: require/include で読み込んだファイルで再度 session_start() を呼ぶとエラーになる // common.php: session_start(); // login.php: require 'common.php'; session_start(); // Warning: session already started
<?php
// OK: session_status() で状態を確認してから開始する
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
『PHP_SESSION_NONE』(未開始)の場合のみ『session_start()』が実行されます。複数のファイルから呼ばれる可能性がある共通ファイルでは、この書き方を使ってください。
概要
『session_start()』はPHPのセッション管理を開始する関数で、サーバー側にユーザーごとのデータ領域を確保します。セッション固定攻撃を防ぐため、ログイン成功時には必ず『session_regenerate_id(true)』でセッションIDを再生成してください。
セッションCookieには『secure』『httponly』『samesite』属性を設定することが重要です。『httponly』を有効にするとJavaScriptからCookieにアクセスできなくなり、XSS攻撃によるセッションハイジャックを防止できます。
ログアウト時は、セッション変数の消去・セッションCookieの削除・セッションデータの破棄の3つをすべて行ってください。『session_destroy()』だけでは『$_SESSION』の中身は残り続けるため不十分です。Cookieの操作については『setcookie()』も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。