PHPの$_SESSION変数:初心者向けガイド

まえがき

PHPプログラミングにおける$_SESSIONスーパーグローバル変数は、ユーザーのセッション情報を管理するために使用されます。
この記事では、$_SESSIONの基本的な使い方とセッションの効果的な管理方法を紹介します。

$_SESSION変数の基本

$_SESSIONは、ウェブサーバー上でユーザーごとにセッションデータを保持するためのPHPのスーパーグローバル配列です。
主にユーザー認証や設定情報の保持に使われます。

セッションの開始

セッションを使用する前に、session_start()関数を呼び出してセッションを開始する必要があります。

<?php
session_start();

データの保存とアクセス

$_SESSION配列にデータを保存し、その後アクセスすることができます。

データの保存

<?php
$_SESSION['username'] = 'JohnDoe';

データへのアクセス

<?php
echo $_SESSION['username']; // 出力: JohnDoe

セッションデータの管理

セッションを通じて保存されたデータは、ウェブサイトの異なるページ間で共有され、ブラウザが閉じられるまで(またはセッションが明示的に終了されるまで)持続します。

セッションの終了

セッションを終了するには、session_destroy()関数を使用します。

<?php
session_destroy();

実際の動作を確認してみよう

ここからはdocker composeを使用して$_SESSION変数の実際の動作を確認してみましょう。

1. プロジェクトのディレクトリを作成

ターミナルで以下のコマンドを実行して、新しいディレクトリを作成します。

mkdir php-session-test
cd php-session-test

2. docker-compose.yml の作成

docker-compose.yml を作成し、以下の内容を記述します。

version: '3.8'

services:
  php:
    image: php:8.2-fpm
    container_name: php-container
    volumes:
      - ./html:/var/www/html
  nginx:
    image: nginx:latest
    container_name: nginx-container
    ports:
      - "8080:80"
    volumes:
      - ./html:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

3. Nginx の設定ファイルを作成

nginx ディレクトリを作成し、default.conf を作成します。

mkdir nginx
server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

4. 商品をカートに入れる PHP を作成

html ディレクトリを作成し、商品をカートに入れる簡単な PHP ファイルを作成します。

mkdir html
<?php
session_start();

// カートが未初期化なら空の配列で初期化
if (!isset($_SESSION['cart'])) {
    $_SESSION['cart'] = array();
}

// GETパラメータによる処理
if (isset($_GET['action'])) {
    $action = $_GET['action'];

    if ($action === 'clear') {
        // セッションの破棄(カートのリセット)
        $_SESSION = array();
        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();
        // 再度セッションを開始してカートを初期化
        session_start();
        $_SESSION['cart'] = array();
    } elseif (($action === 'add' || $action === 'remove') && isset($_GET['id'])) {
        $productId = $_GET['id'];

        if ($action === 'add') {
            // 既にカートにあるなら数量を増やす、無ければ新規追加
            if (isset($_SESSION['cart'][$productId])) {
                $_SESSION['cart'][$productId]++;
            } else {
                $_SESSION['cart'][$productId] = 1;
            }
        } elseif ($action === 'remove') {
            if (isset($_SESSION['cart'][$productId])) {
                $_SESSION['cart'][$productId]--;
                // 数量が0以下なら削除
                if ($_SESSION['cart'][$productId] <= 0) {
                    unset($_SESSION['cart'][$productId]);
                }
            }
        }
    }

    // GETパラメータの再送信を防ぐためリダイレクト
    $redirectUrl = strtok($_SERVER["REQUEST_URI"], '?');
    header("Location: " . $redirectUrl);
    exit;
}

// 表示用変数の準備

// カートの内容(HTML)
if (empty($_SESSION['cart'])) {
    $cartContent = "<p>カートは空です。</p>";
} else {
    $cartContent = "<ul>";
    foreach ($_SESSION['cart'] as $id => $quantity) {
        $idEscaped = htmlspecialchars($id, ENT_QUOTES, 'UTF-8');
        $quantityEscaped = htmlspecialchars($quantity, ENT_QUOTES, 'UTF-8');
        $removeLink = '<a href="?action=remove&id=' . urlencode($id) . '">削除</a>';
        $cartContent .= "<li>商品ID: {$idEscaped} 数量: {$quantityEscaped} {$removeLink}</li>";
    }
    $cartContent .= "</ul>";
}

// 商品一覧(HTML)
$productList = <<<EOT
<ul>
    <li>商品1 <a href="?action=add&id=1">カートに追加</a></li>
    <li>商品2 <a href="?action=add&id=2">カートに追加</a></li>
    <li>商品3 <a href="?action=add&id=3">カートに追加</a></li>
</ul>
EOT;

// セッションリセット用リンク
$clearLink = '<p><a href="?action=clear">セッションを破棄(カートをリセット)</a></p>';

// ヒアドキュメントを使用してHTML出力(変数埋め込みのみ)
$html = <<<HTML
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>カートサンプル</title>
</head>
<body>
    <h1>カートの内容</h1>
    {$cartContent}

    <h2>商品一覧</h2>
    {$productList}

    {$clearLink}
</body>
</html>
HTML;

// HTMLを出力
echo $html;

5. フォルダ構成の確認

ここまでで下記のフォルダ構成になっていればOKです。

$ tree php-session-test/
php-session-test/
├── docker-compose.yml
├── html
│   └── index.php
└── nginx
    └── default.conf

2 directories, 3 files

6. Docker Compose を起動

php-session-testフォルダで以下のコマンドを実行して、コンテナを起動します。

docker-compose up -d

7. ブラウザで確認

コンテナを起動後、ブラウザで http://localhost:8080 にアクセスすると、カートの内容が表示される画面が現れます。

カート内容画面

各商品の「カートに追加」リンクをクリックすると、その商品がカートに追加されます。

カートに商品を追加

また、「セッションを破棄」リンクをクリックすると、現在のセッションが破棄され、新しいセッションが作成されます。

セッション破棄後のカート内容画面

これで、セッションが破棄されるまでカートの情報が保持され続けることが確認できるかと思います。

8. セッションIDを確認する

ところで、セッションの開始やセッションの終了など、ユーザーとセッションの紐づけはどうやっているのでしょうか?
その仕組みは非常にシンプルで、ユーザーの端末には「セッションID」がCookieとして保存されています。

このセッションIDは、ブラウザの開発者ツールを使えば簡単に確認できます。
以下の手順で確認してみましょう:

  1. ブラウザ上で F12キー を押して「開発者ツール」を開き、「Application」タブを選択します。
  2. 左側のペインで「Storage」→「Cookies」を展開し、対象のURL(例:http://localhost:8080)をクリックします。
  3. 右側のペインに「PHPSESSID」という項目が表示され、その 「Value」 が現在のセッションIDとなります。
    セッションID

この状態で、「セッションを破棄」のリンクを押下すると、セッションIDが更新されることが確認できます。

9. セッション名を変更する

Cookieに「PHPSESSID」という名称で保存されていることが分かりましたが、このままではセッションIDがどの項目で保存しているのか簡単に分かってしまいます。
セキュリティ対策としてこのセッション名は変更することが可能です。

セッション名を変更する方法は2つあります。

  • session_name関数を使用する
  • php.iniファイルのsession.nameを変更する

それぞれの変更のやり方を見ていきましょう。

session_name関数を使用する

この方法では、session_start 関数を呼び出す前に session_name 関数を使って、任意のセッション名を設定します。たとえば、セッション名を MYSESSID に変更する場合は以下のように記述します。

// セッション開始前にセッション名を変更
$previous_name = session_name('MYSESSID');
session_start();

ここで、session_name 関数は元々設定されていたセッション名(通常は PHPSESSID)を返します。
なお、session_start 関数を呼び出す前に毎回この関数を実行する必要があります。

この方法のメリットは、コード上で簡単にセッション名を変更できるため、環境ごとに柔軟な設定が可能な点です。

実際に session_name 関数を使用してセッション名を変更すると、下記のようにセッション名が変わっていることが確認できます。

セッション名を変更する

なお、以前のPHPSESSIDという名前はそのまま残るため、Cookieの管理状況に注意してください。

php.iniファイルのsession.nameを変更する

もう一つの方法は、PHPの設定ファイルである php.ini を直接編集してセッション名を変更する方法です。
ただ、php.iniを持ってくるのは手間がかかるため、php フォルダ内に custom-php.ini というファイルを作成し、以下の内容を記述して現在の設定を上書きします。

mkdir php
session.name = MYSESSID_FROMINI

上記ファイルを読み込むためにdocker-compose.ymlの9行目を追記します。

version: '3.8'

services:
  php:
    image: php:8.2-fpm
    container_name: php-container
    volumes:
      - ./html:/var/www/html
      - ./php/custom-php.ini:/usr/local/etc/php/conf.d/custom-php.ini
  nginx:
    image: nginx:latest
    container_name: nginx-container
    ports:
      - "8080:80"
    volumes:
      - ./html:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

ここまでで下記フォルダ構成になっていればOKです。

$ tree php-session-test/
php-session-test/
├── docker-compose.yml
├── html
│   └── index.php
├── nginx
│   └── default.conf
└── php
    └── custom-php.ini

3 directories, 4 files

設定を変更した後、下記コマンドでコンテナを再起動することで設定が反映されます。

$ docker-compose down
$ docker-compose up -d

これでセッション名が「MYSESSID_FROMINI」に変更されているはずです。
Cookieを削除する必要はありませんが、一旦最初の状況に戻して検証するため、保存されているCookieを削除して確認してみましょう。
Cookieの削除は「Application」タブの各項目を選択し「Del」キーを押下すると削除できます。

Cookieのセッション名を削除

削除後、F5キーで更新すると項目名が「MYSESSID_FROMINI」に変わっていることが確認できます。

Cookieのセッション名をMYSESSID_FROMINIに変更

もし変わっていなかったら、先ほど追加したsession_name関数がindex.phpファイルに残っていないか確認してみてください。

この方法は、サーバ全体で統一したセッション名を使用したい場合に有効です。

以下は、文章全体の流れや表現を改善した例です。参考にしてください。

セキュリティ対策について

今回説明した内容は、あくまで $_SESSION スーパーグローバル変数の基本的な使い方にすぎません。
実際にWebサービスを公開する際は、より高度なセキュリティ対策が必要です。
セッションのセキュリティは非常に奥深いテーマであり、ひとつの専門書が必要なほどの知識が求められます。

最低限、以下の公式ドキュメントには目を通し、しっかりと内容を理解しておくことが重要です。
PHPマニュアル > 関数リファレンス > セッション処理

まとめ

  • 基本的なセッション管理
    $_SESSION 変数を利用したカート機能の実装方法を通して、セッションの開始、操作、破棄の基本について解説しました。

  • セッションIDとCookie
    ブラウザの開発者ツールを使って、どのようにセッションIDがCookieとして保存され、管理されているかを解説しました。

  • セッション名の変更
    セキュリティ強化のために、session_name() 関数や php.ini(またはカスタム設定ファイル)を利用して、デフォルトのセッション名を変更する方法を解説しました。

  • セキュリティ対策の重要性
    セッションの管理はWebアプリケーションの根幹をなす部分であり、セッションIDの再生成やCookieのセキュリティ設定など、さらに多くの対策が必要です。
    そのため、公式ドキュメントをはじめとした信頼できる情報源で、セキュリティ対策を十分に学ぶことが大切です。

これらの知識を活かし、実際のWebサービス開発時にはセッションの管理とセキュリティ強化に努めてください。


スポンサーリンク

共有

もふもふ

プロフィール

著者
もふもふ
プログラマ。汎用系→ゲームエンジニア→Webエンジニア→QAエンジニア。開発からテストまで一通り経験し、実際に詰まった点や検証結果を技術ブログとしてまとめています。