【PHP8.x】session_set_save_handler関数の使い方

session_set_save_handler関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

session_set_save_handler関数は、PHPのセッションの保存と管理方法をカスタマイズするために使用される関数です。通常、PHPのセッションデータはWebサーバーのファイルシステムにファイルとして保存されますが、この関数を利用することで、セッションデータをデータベースやMemcached、Redisなどの外部ストレージに保存するよう、その処理を切り替えることができます。

具体的には、セッションの開始、終了、データの読み込み、データの書き込み、セッションの破棄、そして古いセッションデータの削除(ガベージコレクション)といった、セッションに関連する主要な操作を処理するための独自の関数群(またはクラスのメソッド)を登録します。これらのカスタムハンドラを登録することで、アプリケーションの特定の要件や、複数のWebサーバー間でセッション情報を共有する必要がある分散環境において、より柔軟で効率的なセッション管理を実現できます。

この関数は、session_start()関数が呼び出される前に設定する必要があります。引数には、オープン、クローズ、リード、ライト、デストロイ、ガベージコレクションの各操作に対応するコールバック関数を順番に指定します。成功した場合は真(true)、失敗した場合は偽(false)を返します。この機能は、大規模なシステムや高可用性が求められるシステムで、セッション管理の自由度を高めるために広く活用されています。

構文(syntax)

1<?php
2
3// SessionHandlerInterface を実装したオブジェクトを引数に指定します。
4// ここでは匿名クラスを使用してその場で実装していますが、通常のクラスとして定義することも可能です。
5$customSessionHandler = new class implements SessionHandlerInterface {
6    public function open(string $path, string $name): bool {
7        // セッションを開くための処理を記述します。
8        return true;
9    }
10
11    public function close(): bool {
12        // セッションを閉じるための処理を記述します。
13        return true;
14    }
15
16    public function read(string $id): string|false {
17        // 指定されたIDのセッションデータを読み込む処理を記述します。
18        // データが存在しない場合は空文字列を、エラーの場合は false を返します。
19        return '';
20    }
21
22    public function write(string $id, string $data): bool {
23        // 指定されたIDにセッションデータを書き込む処理を記述します。
24        return true;
25    }
26
27    public function destroy(string $id): bool {
28        // 指定されたIDのセッションデータを破棄する処理を記述します。
29        return true;
30    }
31
32    public function gc(int $max_lifetime): int|false {
33        // 有効期限切れのセッションデータを削除するガベージコレクション処理を記述します。
34        // 削除されたセッション数を整数で返します。
35        return 0;
36    }
37
38    // 必要に応じて、以下のPHP 7.0以降で追加されたオプションメソッドも実装できます。
39    // public function create_sid(): string { return ''; }
40    // public function validate_sid(string $id): bool { return true; }
41    // public function update_timestamp(string $id, string $data): bool { return true; }
42};
43
44// カスタムセッションハンドラを設定します。
45// 第二引数は、シャットダウン時にセッションハンドラを登録するかどうか (デフォルト true)。
46session_set_save_handler($customSessionHandler, true);

引数(parameters)

callable $open, callable $close, callable $read, callable $write, callable $destroy, callable $gc, ?callable $create_sid = null, ?callable $validate_sid = null, ?callable $update_timestamp = null

  • callable $open: セッションIDの読み込みまたは新規作成を行うハンドラー関数
  • callable $close: セッションのクローズ処理を行うハンドラー関数
  • callable $read: 指定されたセッションIDのデータを読み込むハンドラー関数
  • callable $write: 指定されたセッションIDにデータを書き込むハンドラー関数
  • callable $destroy: 指定されたセッションIDのセッションデータを破棄するハンドラー関数
  • callable $gc: セッションIDのガベージコレクション(不要なセッションの削除)を行うハンドラー関数
  • ?callable $create_sid: 新しいセッションIDを生成するハンドラー関数 (オプション)
  • ?callable $validate_sid: セッションIDの有効性を検証するハンドラー関数 (オプション)
  • ?callable $update_timestamp: セッションのタイムスタンプを更新するハンドラー関数 (オプション)

戻り値(return)

bool

セッション保存ハンドラーとして、指定されたコールバック関数が正常に設定されたかどうかを真偽値で返します。成功した場合は true、失敗した場合は false が返されます。

サンプルコード

PHP 8.4 session_set_save_handlerでカスタムセッションを実装する

1<?php
2declare(strict_types=1);
3
4/**
5 * PHPのカスタムセッションハンドラの基本例
6 *
7 * このコードは、`session_set_save_handler` を使用して、
8 * PHPのセッションデータをメモリ上に一時的に保存する方法を示します。
9 * システムエンジニアを目指す初心者の方へ:
10 * 通常、PHPはセッションデータをファイルに保存しますが、この機能を使うと、
11 * データベースやキャッシュシステム(例:Redis、Memcached)など、
12 * 好きな場所にセッションを保存できるようになります。
13 * 各メソッドは、セッションのライフサイクル(開始、読み込み、書き込み、終了など)
14 * の特定の段階でPHPによって呼び出されます。
15 */
16class MyCustomSessionHandler
17{
18    /**
19     * @var array<string, array{data: string, timestamp: int}>
20     * セッションデータをメモリ上に保持する配列。
21     * キーはセッションID、値はセッションデータと最終更新タイムスタンプの配列です。
22     */
23    private static array $sessionStorage = [];
24
25    /**
26     * セッションが開かれる際に呼び出されます。
27     * ここでデータベース接続の確立など、セッション保存に必要な初期化を行います。
28     */
29    public function open(string $path, string $name): bool
30    {
31        // メモリ上に保存するため、特別な初期化は不要
32        return true;
33    }
34
35    /**
36     * セッションが閉じられる際に呼び出されます。
37     * ここでデータベース接続のクローズなど、終了処理を行います。
38     */
39    public function close(): bool
40    {
41        // メモリ上に保存するため、特別なクリーンアップは不要
42        return true;
43    }
44
45    /**
46     * 指定されたセッションIDのデータを読み込みます。
47     */
48    public function read(string $id): string
49    {
50        if (isset(self::$sessionStorage[$id])) {
51            $session = self::$sessionStorage[$id];
52            // PHPのデフォルト設定 (session.gc_maxlifetime) を使用して有効期限をチェック
53            if ($session['timestamp'] + (int)ini_get('session.gc_maxlifetime') < time()) {
54                unset(self::$sessionStorage[$id]); // 期限切れセッションを削除
55                return '';
56            }
57            return $session['data'];
58        }
59        return '';
60    }
61
62    /**
63     * 指定されたセッションIDにデータを書き込みます。
64     */
65    public function write(string $id, string $data): bool
66    {
67        self::$sessionStorage[$id] = [
68            'data' => $data,
69            'timestamp' => time(), // 最終更新日時を記録
70        ];
71        return true;
72    }
73
74    /**
75     * 指定されたセッションIDのセッションを破棄します。
76     * `session_destroy()` が呼び出された際に使用されます。
77     */
78    public function destroy(string $id): bool
79    {
80        unset(self::$sessionStorage[$id]);
81        return true;
82    }
83
84    /**
85     * ガベージコレクション (GC) 処理。
86     * 古い(有効期限切れの)セッションデータを削除します。
87     * PHPの設定に基づき、不定期に呼び出されます。
88     */
89    public function gc(int $max_lifetime): bool
90    {
91        $currentTime = time();
92        foreach (self::$sessionStorage as $id => $session) {
93            if ($session['timestamp'] + $max_lifetime < $currentTime) {
94                unset(self::$sessionStorage[$id]);
95            }
96        }
97        return true;
98    }
99
100    /**
101     * (デバッグ用) 現在のセッションストレージの内容を取得します。
102     * このメソッドは、MyCustomSessionHandler の内部動作を確認するために使用します。
103     */
104    public static function getSessionStorageForDebug(): array
105    {
106        return self::$sessionStorage;
107    }
108}
109
110// -----------------------------------------------------------------------------
111// カスタムセッションハンドラの設定と使用例
112// -----------------------------------------------------------------------------
113
114// カスタムハンドラのインスタンスを作成
115$handler = new MyCustomSessionHandler();
116
117// `session_set_save_handler` を使用してカスタムハンドラを登録します。
118// PHP 8.4の引数リストに従い、必須の6つのcallableメソッドを指定します。
119session_set_save_handler(
120    [$handler, 'open'],    // セッション開始時に呼び出される
121    [$handler, 'close'],   // セッション終了時に呼び出される
122    [$handler, 'read'],    // セッションデータ読み込み時に呼び出される
123    [$handler, 'write'],   // セッションデータ書き込み時に呼び出される
124    [$handler, 'destroy'], // セッション破棄時に呼び出される
125    [$handler, 'gc']       // ガベージコレクション時に呼び出される
126    // (create_sid, validate_sid, update_timestamp は省略)
127);
128
129// PHPのセッション管理が、スクリプト終了時に正しくカスタムハンドラを呼び出すようにします。
130session_register_shutdown();
131
132// セッションを開始します。
133// これにより、`open()` や `read()` メソッドが呼び出され、`$_SESSION` が利用可能になります。
134session_start();
135
136echo "<h2>カスタムセッションハンドラの動作確認</h2>";
137
138// セッション変数の設定と取得の例
139if (!isset($_SESSION['visits'])) {
140    $_SESSION['visits'] = 1;
141    echo "<li>初めての訪問です!</li>";
142} else {
143    $_SESSION['visits']++;
144    echo "<li>あなたの訪問回数: " . $_SESSION['visits'] . "回目</li>";
145}
146
147$_SESSION['user_name'] = 'ゲストユーザー';
148echo "<li>セッションユーザー名: " . $_SESSION['user_name'] . "</li>";
149echo "<li>現在のセッションID: " . session_id() . "</li>";
150
151// 現在のセッションストレージの内容を表示 (デバッグ用)
152echo "<h3>セッションストレージの現在の状態 (デバッグ用):</h3>";
153echo "<pre>";
154print_r(MyCustomSessionHandler::getSessionStorageForDebug());
155echo "</pre>";
156
157// セッションを破棄するためのリンク
158echo "<h3>セッション操作</h3>";
159if (isset($_GET['destroy'])) {
160    session_destroy(); // セッションを破棄 (`destroy()` メソッドが呼び出されます)
161    echo "<li>セッションが破棄されました。ページをリロードすると新しいセッションが開始されます。</li>";
162    echo "<pre>セッション破棄後のストレージの状態:\n";
163    print_r(MyCustomSessionHandler::getSessionStorageForDebug());
164    echo "</pre>";
165} else {
166    $currentUrl = strtok($_SERVER['REQUEST_URI'], '?');
167    echo '<li><a href="?destroy=1">セッションを破棄する</a></li>';
168    echo '<li><a href="' . $currentUrl . '">ページをリロードする</a> (訪問回数が増えます)</li>';
169}
170
171// スクリプト終了時に `write()` および `close()` メソッドが自動的に呼び出されます。

session_set_save_handler関数は、PHPのセッションデータを保存・管理する方法をカスタマイズするための機能です。通常、PHPはセッションデータをサーバー上のファイルに保存しますが、この関数を使うと、データベースやキャッシュシステム(例:Redis)など、任意の場所にセッションを保存できるようになります。

このサンプルコードでは、MyCustomSessionHandlerというクラスを作成し、PHPのセッション管理に関する様々な処理をメモリ上で行う方法を示しています。session_set_save_handlerは、openclosereadwritedestroygcという6つのコールバック関数(またはメソッド)を引数として受け取ります。

  • open: セッションが開始される際に呼び出され、初期化処理を行います。
  • close: セッションが終了する際に呼び出され、後処理を行います。
  • read: セッションIDに対応するデータを読み込む際に呼び出されます。
  • write: セッションIDにデータを書き込む際に呼び出されます。
  • destroy: 指定されたセッションを破棄する際に呼び出されます。
  • gc (ガベージコレクション): 古くなったセッションデータを定期的に削除する際に呼び出されます。

これらの関数は、セッションのライフサイクル(開始、読み込み、書き込み、終了など)の特定の段階でPHPによって自動的に呼び出されます。関数はすべて処理の成功時にtrue、失敗時にfalseを返すbool型の戻り値を持ちます。サンプルコードの実行結果では、カスタムハンドラによってメモリ上に保存されたセッションデータが実際にどのように変化し、利用されるかを確認できます。これにより、PHPのセッション管理の仕組みをより深く理解し、柔軟なシステム構築に役立てることができます。

session_set_save_handlerは、PHPのセッションデータをファイル以外に保存するための機能です。引数には、セッションの開始から終了、読み書き、破棄、ガベージコレクションに対応する最低6つのメソッドを渡す必要があります。サンプルコードのメモリ保存は一時的であり、PHPプロセスが終了するとデータが失われるため、実運用ではデータベースやキャッシュシステムなど永続的なストレージの利用が必須です。また、session_register_shutdown()を呼び出すことで、スクリプト終了時にセッションデータが確実に保存されます。複数のリクエストによる同時アクセスを考慮し、セッションデータの排他制御(ロック)を適切に実装することがデータ整合性維持のために非常に重要です。セキュリティ面では、セッションIDの生成・検証やデータの暗号化も検討してください。

PHPセッションをファイルに保存するサンプル

1<?php
2
3/**
4 * CustomFileSessionHandlerクラス
5 * PHPのセッションをファイルシステムに保存するためのカスタムハンドラを提供します。
6 * session_set_save_handler関数で使用するメソッドを実装しています。
7 */
8class CustomFileSessionHandler
9{
10    private string $savePath;
11
12    /**
13     * コンストラクタ
14     * セッションファイルを保存するディレクトリを設定し、存在しない場合は作成します。
15     *
16     * @param string $savePath セッションファイルを保存するディレクトリのパス
17     */
18    public function __construct(string $savePath)
19    {
20        $this->savePath = $savePath;
21        if (!is_dir($this->savePath)) {
22            mkdir($this->savePath, 0777, true);
23        }
24    }
25
26    /**
27     * セッションを開く際に呼び出されます。
28     * このメソッドは、セッションストレージの初期化や接続確立などを行います。
29     * ファイルベースのハンドラでは通常、特に何もする必要はありません。
30     *
31     * @param string $path php.iniのsession.save_pathで設定されたパス
32     * @param string $name セッション名
33     * @return bool 成功した場合true、失敗した場合false
34     */
35    public function open(string $path, string $name): bool
36    {
37        // 実際には、この$pathは使用せず、クラスで設定された$this->savePathを使用します。
38        return true;
39    }
40
41    /**
42     * セッションを閉じる際に呼び出されます。
43     * このメソッドは、セッションストレージの終了処理や接続解除などを行います。
44     * ファイルベースのハンドラでは通常、特に何もする必要はありません。
45     *
46     * @return bool 成功した場合true、失敗した場合false
47     */
48    public function close(): bool
49    {
50        return true;
51    }
52
53    /**
54     * セッションデータを読み込む際に呼び出されます。
55     * 指定されたセッションIDに対応するデータをストレージから読み込みます。
56     *
57     * @param string $id セッションID
58     * @return string セッションデータ (文字列)、またはデータがない場合は空文字列
59     */
60    public function read(string $id): string
61    {
62        $file = $this->getSessionFileName($id);
63        if (file_exists($file)) {
64            // ファイルの最終更新時刻とセッションの最大ライフタイムを比較し、
65            // 期限切れの場合はファイルを削除して空文字列を返します。
66            if (filemtime($file) + ini_get('session.gc_maxlifetime') < time()) {
67                unlink($file);
68                return '';
69            }
70            return (string) file_get_contents($file);
71        }
72        return '';
73    }
74
75    /**
76     * セッションデータを書き込む際に呼び出されます。
77     * 指定されたセッションIDとデータ文字列をストレージに書き込みます。
78     *
79     * @param string $id セッションID
80     * @param string $data 書き込むセッションデータ
81     * @return bool 成功した場合true、失敗した場合false
82     */
83    public function write(string $id, string $data): bool
84    {
85        $file = $this->getSessionFileName($id);
86        return (bool) file_put_contents($file, $data);
87    }
88
89    /**
90     * セッションを破棄する際に呼び出されます。
91     * 指定されたセッションIDに対応するデータをストレージから削除します。
92     *
93     * @param string $id 破棄するセッションID
94     * @return bool 成功した場合true、失敗した場合false
95     */
96    public function destroy(string $id): bool
97    {
98        $file = $this->getSessionFileName($id);
99        if (file_exists($file)) {
100            unlink($file);
101        }
102        return true;
103    }
104
105    /**
106     * ガベージコレクション (GC) を実行する際に呼び出されます。
107     * 古いセッションデータ (最大ライフタイムを超えたもの) を削除します。
108     *
109     * @param int $max_lifetime セッションの最大ライフタイム (秒)
110     * @return bool 成功した場合true、失敗した場合false
111     */
112    public function gc(int $max_lifetime): bool
113    {
114        foreach (glob($this->savePath . '/sess_*') as $file) {
115            if (filemtime($file) + $max_lifetime < time()) {
116                unlink($file);
117            }
118        }
119        return true;
120    }
121
122    /**
123     * ヘルパーメソッド: セッションファイル名を生成します。
124     *
125     * @param string $id セッションID
126     * @return string セッションファイルのフルパス
127     */
128    private function getSessionFileName(string $id): string
129    {
130        return $this->savePath . '/sess_' . $id;
131    }
132}
133
134// --- メインスクリプト ---
135
136// セッションファイルを保存するためのテンポラリディレクトリを設定します。
137// 環境に合わせて適切なパスに変更してください。
138$sessionSavePath = sys_get_temp_dir() . '/php_custom_sessions_example';
139
140// カスタムセッションハンドラをインスタンス化します。
141$handler = new CustomFileSessionHandler($sessionSavePath);
142
143// session_set_save_handler関数を使用して、PHPにカスタムセッションハンドラを登録します。
144// 各引数には、CustomFileSessionHandlerクラスの対応するメソッドへのcallableを指定します。
145// 最後の引数 'true' は、PHPのシャットダウン時にsession_write_close()が自動的に呼び出されるようにします。
146session_set_save_handler(
147    [$handler, 'open'],      // セッションを開く関数
148    [$handler, 'close'],     // セッションを閉じる関数
149    [$handler, 'read'],      // セッションデータを読み込む関数
150    [$handler, 'write'],     // セッションデータを書き込む関数
151    [$handler, 'destroy'],   // セッションを破棄する関数
152    [$handler, 'gc'],        // ガベージコレクションを行う関数
153    null,                    // オプション: create_sid callable
154    null,                    // オプション: validate_sid callable
155    null                     // オプション: update_timestamp callable
156);
157
158// カスタムハンドラが登録された状態でセッションを開始します。
159session_start();
160
161// --- セッションの動作をデモンストレーション ---
162
163// セッション変数 'counter' が設定されているか確認します。
164if (!isset($_SESSION['counter'])) {
165    // 初回アクセスの場合
166    $_SESSION['counter'] = 1;
167    echo "ようこそ!これはあなたの最初の訪問です。\n";
168} else {
169    // 2回目以降のアクセスの場合
170    $_SESSION['counter']++;
171    echo "あなたはこれまでこのページを " . $_SESSION['counter'] . " 回訪問しました。\n";
172}
173
174echo "セッションID: " . session_id() . "\n";
175echo "セッションデータは以下のディレクトリに保存されます: " . $sessionSavePath . "\n";
176
177// セッション破棄の動作を確認したい場合は、以下の行のコメントを解除してください。
178// その後、ページを複数回リロードし、再度コメントを解除した状態でリロードすると、
179// カウンターがリセットされるのが確認できます。
180// session_destroy();
181
182?>

PHPのsession_set_save_handler関数は、標準のセッション保存メカニズム(通常はファイル)を、開発者が定義した独自の処理に置き換えるための機能です。この関数を利用することで、セッションデータをファイルシステムだけでなく、データベースやキャッシュサーバーなど、様々な場所に保存できるようカスタマイズできます。

このサンプルコードでは、CustomFileSessionHandlerというクラスを定義し、セッションデータをファイルシステムに保存するための具体的なロジックを実装しています。このクラスは、セッションの開始時に呼ばれるopen、終了時に呼ばれるclose、データの読み込みを行うread、書き込みを行うwrite、セッションを削除するdestroy、そして古いセッションを定期的に削除するガベージコレクション(GC)を行うgcという、一連の必須メソッドを含んでいます。

session_set_save_handler関数は、これらCustomFileSessionHandlerクラスのメソッドを引数として受け取り、PHPのセッション処理に紐付けます。引数には、セッションを開く$open、閉じる$close、データを読み込む$read、書き込む$write、破棄する$destroy、古いセッションを削除する$gcという、それぞれセッション操作の特定の役割を担うcallable(呼び出し可能な関数やメソッド)を指定します。関数が正常にハンドラを登録できた場合、戻り値としてtrueが返されます。

カスタムハンドラが登録された後、session_start()関数を呼び出すことでセッションが開始され、それ以降の$_SESSION変数へのアクセスは、登録されたカスタムクラスのメソッドを通じて行われます。サンプルコードでは、訪問回数をカウントするセッション変数を使い、カスタムファイルハンドラが正しく動作し、セッションデータが指定されたディレクトリにsess_から始まるファイルとして保存される様子を示しています。

session_set_save_handlerは、PHPのセッションデータをファイル以外の場所(データベースやキャッシュサーバーなど)に保存したい場合に利用する関数です。サンプルコードはファイルベースのカスタムハンドラの例ですが、他のストレージへの応用も可能です。openclosereadwritedestroygcの6つのメソッドを正しく実装する必要があります。特にreadメソッドでの有効期限チェックとgcメソッドでの古いセッションデータ削除は、セッションの正常な機能と保存領域の管理に不可欠です。これらの実装が不適切だと、セッションが正しく動作しなかったり、ストレージが肥大化する原因となります。カスタムハンドラ登録後は、必ずsession_start()を呼び出してセッションを開始してください。実運用では、セッション保存パスのセキュリティやアクセス権限、堅牢なエラーハンドリングに十分配慮してください。

関連コンテンツ