【PHP8.x】SessionHandlerInterface::gc()メソッドの使い方
gcメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
gcメソッドは、セッションの有効期限が切れたデータをストレージから削除するガベージコレクション処理を実行するメソッドです。このメソッドは、PHPの標準セッションメカニズムとは異なる方法でセッションを管理したい場合に利用するSessionHandlerInterfaceの一部として定義されます。
システムエンジニアがWebアプリケーションを開発する際、ユーザーのログイン状態やカートの中身といった情報をサーバー側に一時的に保存する「セッション」という仕組みを利用します。しかし、これらのセッションデータはいつまでも保存しておくわけにはいきません。ユーザーがログアウトしたり、一定時間アクセスがなかったりすると、セッションは「期限切れ」となり、不要なデータとして残ってしまいます。
gcメソッドは、そのような期限切れになったセッションデータを自動的に削除し、サーバーのリソースを解放するために呼び出されます。このメソッドは、$max_lifetimeという整数値の引数を受け取ります。この$max_lifetimeは、セッションが有効であると見なされる最大秒数を表しており、メソッドの実装ではこの値よりも古いセッションデータを削除するロジックを記述します。
PHPの内部で設定された確率と周期に基づき、セッションが開始される際にこのgcメソッドが呼び出されることがあります。開発者はSessionHandlerInterfaceを実装する際に、ファイルシステム、データベース、またはキャッシュサーバーなど、自身のアプリケーションが利用するセッションストレージから、どのようにして期限切れセッションを効率的に見つけて削除するかをこのメソッド内に実装します。これにより、セッションストレージの肥大化を防ぎ、アプリケーションのパフォーマンスとセキュリティを維持することができます。戻り値は、削除に成功した場合はtrue、失敗した場合はfalse、または削除されたセッションの数を返すことが期待されます。
構文(syntax)
1<?php 2 3interface SessionHandlerInterface 4{ 5 public function gc(int $max_lifetime): int; 6}
引数(parameters)
int $max_lifetime
- int $max_lifetime: セッションデータを削除する最大生存期間を秒単位で指定する整数
戻り値(return)
int
gc メソッドは、ガベージコレクション(不要になったセッションデータの削除)が正常に実行されたかどうかを示す整数値を返します。成功した場合は true の意味合いを持つ値、失敗した場合は false の意味合いを持つ値が返されます。
サンプルコード
PHPセッションGCのタイミングを解説する
1<?php 2 3/** 4 * MyCustomSessionHandler class 5 * Implements SessionHandlerInterface to provide custom session storage logic. 6 * This example uses file-based storage in a temporary directory. 7 */ 8class MyCustomSessionHandler implements SessionHandlerInterface 9{ 10 private string $savePath; 11 12 /** 13 * Initializes the session handler. 14 * Called when a session is opened (e.g., by session_start()). 15 * @param string $path The path where session data should be stored. 16 * @param string $name The session name. 17 * @return bool True on success, false on failure. 18 */ 19 public function open(string $path, string $name): bool 20 { 21 $this->savePath = $path; 22 if (!is_dir($this->savePath)) { 23 mkdir($this->savePath, 0777, true); // Create directory if it doesn't exist 24 } 25 return true; 26 } 27 28 /** 29 * Closes the session handler. 30 * Called when a session is closed (e.g., by session_write_close() or script termination). 31 * @return bool True on success, false on failure. 32 */ 33 public function close(): bool 34 { 35 // For file-based sessions, usually nothing specific to do here. 36 return true; 37 } 38 39 /** 40 * Reads session data. 41 * Called by PHP to retrieve session data for a given session ID. 42 * @param string $id The session ID. 43 * @return string The session data (serialized), or an empty string if not found. 44 */ 45 public function read(string $id): string 46 { 47 $file = $this->savePath . '/sess_' . $id . '.txt'; 48 if (file_exists($file)) { 49 // Update the last modification time to mark the session as recently accessed. 50 // This prevents it from being immediately garbage collected. 51 touch($file); 52 return (string)file_get_contents($file); 53 } 54 return ''; 55 } 56 57 /** 58 * Writes session data. 59 * Called by PHP to save session data for a given session ID. 60 * @param string $id The session ID. 61 * @param string $data The serialized session data. 62 * @return bool True on success, false on failure. 63 */ 64 public function write(string $id, string $data): bool 65 { 66 $file = $this->savePath . '/sess_' . $id . '.txt'; 67 return file_put_contents($file, $data) !== false; 68 } 69 70 /** 71 * Destroys a session. 72 * Called by PHP when a session is explicitly destroyed (e.g., by session_destroy()). 73 * @param string $id The session ID to destroy. 74 * @return bool True on success, false on failure. 75 */ 76 public function destroy(string $id): bool 77 { 78 $file = $this->savePath . '/sess_' . $id . '.txt'; 79 if (file_exists($file)) { 80 return unlink($file); // Delete the session file 81 } 82 return true; 83 } 84 85 /** 86 * Garbage collection handler. 87 * This method is called probabilistically by PHP during session_start(). 88 * Its purpose is to delete old, expired session data. 89 * @param int $max_lifetime The maximum time in seconds that a session can be inactive before it's considered expired. 90 * @return int The number of sessions deleted. 91 */ 92 public function gc(int $max_lifetime): int 93 { 94 $deletedCount = 0; 95 echo " [GC] Running garbage collection with max_lifetime: {$max_lifetime} seconds.\n"; 96 97 // Iterate over all session files in the designated save path 98 foreach (glob($this->savePath . '/sess_*.txt') as $file) { 99 if (file_exists($file)) { 100 // Get the last modification time of the session file 101 $lastModified = filemtime($file); 102 if ($lastModified === false) { 103 continue; // Skip if unable to get file modification time 104 } 105 106 // Calculate the age of the session file 107 $fileAge = time() - $lastModified; 108 109 // If the session file's age is greater than the configured max_lifetime, delete it. 110 if ($fileAge > $max_lifetime) { 111 unlink($file); // Delete the expired session file 112 $deletedCount++; 113 echo " [GC] Deleted old session file: " . basename($file) . " (Age: {$fileAge}s)\n"; 114 } 115 } 116 } 117 return $deletedCount; // Return the total count of deleted sessions 118 } 119} 120 121// --- Demonstration of MyCustomSessionHandler and gc() timing --- 122 123// 1. Setup a temporary directory for session files 124$sessionSavePath = sys_get_temp_dir() . '/php_beginner_sessions_' . uniqid(); 125if (!is_dir($sessionSavePath)) { 126 mkdir($sessionSavePath, 0777, true); 127} 128echo "Temporary session save path: " . $sessionSavePath . "\n\n"; 129 130// 2. Create some dummy session files to illustrate garbage collection: 131// - Two "old" sessions that should be collected by gc(). 132// - One "recent" session that should remain. 133$oldSessionId1 = 'old_session_one'; 134$oldSessionFile1 = $sessionSavePath . '/sess_' . $oldSessionId1 . '.txt'; 135file_put_contents($oldSessionFile1, 'This is old session data 1.'); 136// Set its modification time far in the past (e.g., 2 hours ago) 137touch($oldSessionFile1, time() - 7200); 138 139$oldSessionId2 = 'old_session_two'; 140$oldSessionFile2 = $sessionSavePath . '/sess_' . $oldSessionId2 . '.txt'; 141file_put_contents($oldSessionFile2, 'This is old session data 2.'); 142// Set its modification time moderately in the past (e.g., 1 hour ago) 143touch($oldSessionFile2, time() - 3600); 144 145$recentSessionId = 'recent_session_abc'; 146$recentSessionFile = $sessionSavePath . '/sess_' . $recentSessionId . '.txt'; 147file_put_contents($recentSessionFile, 'This is recent session data.'); 148// Set its modification time very recently (e.g., 5 seconds ago) 149touch($recentSessionFile, time() - 5); 150 151echo "--- Initial state of session files in " . basename($sessionSavePath) . " ---\n"; 152foreach (glob($sessionSavePath . '/sess_*.txt') as $file) { 153 echo " - " . basename($file) . " (Modified: " . date('Y-m-d H:i:s', filemtime($file)) . ")\n"; 154} 155echo "\n"; 156 157// 3. Instantiate and register our custom session handler 158$handler = new MyCustomSessionHandler(); 159session_set_save_handler($handler, true); // `true` registers it as the default handler 160 161// 4. Configure session settings for GC demonstration: 162// - `session.gc_maxlifetime`: How old (in seconds) a session can be before GC considers it. 163// - `session.gc_probability` & `session.gc_divisor`: Controls the probability of gc() being called. 164// Setting these to 1/1 ensures gc() will run every time session_start() is called for this example. 165// (In production, these are typically higher like 1/1000 or configured in php.ini). 166ini_set('session.gc_maxlifetime', 30); // Sessions older than 30 seconds will be collected 167ini_set('session.gc_probability', 1); 168ini_set('session.gc_divisor', 1); 169 170// Set the session save path to our temporary directory for the custom handler 171session_save_path($sessionSavePath); 172 173echo "--- Starting session and observing gc() timing ---\n"; 174echo "Current 'session.gc_maxlifetime' is set to " . ini_get('session.gc_maxlifetime') . " seconds.\n"; 175echo "Garbage Collection probability is " . ini_get('session.gc_probability') . "/" . ini_get('session.gc_divisor') . " (ensures gc() runs).\n"; 176echo "The custom `MyCustomSessionHandler::gc()` method will be called by PHP internally " 177 . "during the `session_start()` process if the probability check passes.\n"; 178 179// 5. Start a session. This is the point where PHP might trigger gc(). 180session_start(); 181 182// Store some data in the current session (this creates a new session file or updates an existing one) 183$_SESSION['user_id'] = 456; 184$_SESSION['username'] = 'beginner_se'; 185$_SESSION['message'] = 'Welcome to your custom session!'; 186 187echo "\nCurrent session started. Session ID: " . session_id() . "\n"; 188echo "Session data stored for the current active session.\n"; 189 190// 6. Close the session. This ensures any pending write operations are completed. 191session_write_close(); 192 193echo "\n--- State of session files AFTER session_start() and potential GC ---\n"; 194echo "Notice that old session files (older than " . ini_get('session.gc_maxlifetime') . "s) " 195 . "should have been cleaned up.\n"; 196foreach (glob($sessionSavePath . '/sess_*.txt') as $file) { 197 echo " - " . basename($file) . " (Modified: " . date('Y-m-d H:i:s', filemtime($file)) . ")\n"; 198} 199 200// 7. Clean up the temporary session directory 201if (is_dir($sessionSavePath)) { 202 foreach (glob($sessionSavePath . '/*') as $file) { 203 unlink($file); 204 } 205 rmdir($sessionSavePath); 206 echo "\nTemporary session directory '" . basename($sessionSavePath) . "' cleaned up.\n"; 207} 208 209?>
PHPのSessionHandlerInterface::gcメソッドは、カスタムセッションハンドラにおいて、期限切れのセッションデータを整理・削除する役割を持ちます。このメソッドはint $max_lifetimeという引数を受け取ります。これは、セッションが非アクティブと見なされるまでの最大秒数を指定し、この期間を超えてアクセスされていないセッションデータが削除の対象となります。メソッドは削除したセッションの総数をintで返します。
gcメソッドは、PHPのセッションが開始される際、具体的にはsession_start()関数が実行されるタイミングで、PHPの設定(session.gc_probabilityとsession.gc_divisor)に基づいて確率的に呼び出されます。これにより、セッションが開始されるたびに、古いデータが自動的にクリーンアップされる機会が与えられます。
サンプルコードのMyCustomSessionHandlerクラスは、SessionHandlerInterfaceを実装し、ファイルシステムを利用してセッションを管理する例です。その中のgcメソッドは、引数で渡された$max_lifetimeよりも最終更新日時が古いセッションファイルを検索し、削除する具体的な処理を実装しています。コードのデモンストレーション部分では、意図的に作成した古いセッションファイル群と、session.gc_maxlifetimeを短く設定した上でsession_start()を実行することで、gcメソッドが実際に機能し、期限切れのファイルを自動的にクリーンアップする様子を示しています。これにより、セッションの有効期限管理の仕組みと、gcメソッドが果たす重要な役割を理解できます。
gcメソッドは、開発者が直接呼び出すのではなく、session_start()実行時にPHPが内部で確率的に呼び出すものです。主な役割は、session.gc_maxlifetime設定値で指定された秒数よりも古いセッションデータを削除することです。サンプルコードのreadメソッドでセッションファイルの最終更新日時を更新しているように、セッションがアクティブである間は有効期限が延長されるよう適切に実装しないと、使用中のセッションが誤って削除される可能性がありますので注意が必要です。また、本番環境ではsession.gc_probabilityとsession.gc_divisorの設定によりgcの実行頻度を調整し、サーバー負荷を考慮することが重要です。サンプルではデモンストレーションのため強制実行していますが、一般的な運用では確率を低く設定します。ファイル以外でセッションを保存する場合も、このgcメソッド内で該当ストレージから古いデータを削除するロジックを実装してください。
PHPカスタムセッションハンドラでGCを実装する
1<?php 2 3/** 4 * カスタムセッションハンドラの実装例。 5 * SessionHandlerInterface を通じて、PHPのセッション管理をファイルシステムで行います。 6 * このクラスは、SessionHandlerInterface が要求するすべてのメソッドを実装しており、 7 * 特に gc() (ガーベージコレクション) メソッドの動作に焦点を当てています。 8 * 9 * システムエンジニアを目指す初心者向けに、セッションデータの寿命管理の概念を理解できるようにします。 10 */ 11class MySessionHandler implements SessionHandlerInterface 12{ 13 private string $savePath; 14 15 /** 16 * セッションを開きます。 17 * セッションデータが保存されるディレクトリパスを設定し、必要であれば作成します。 18 */ 19 public function open(string $path, string $alias): bool 20 { 21 $this->savePath = $path; 22 if (!is_dir($this->savePath)) { 23 mkdir($this->savePath, 0777, true); 24 } 25 return true; 26 } 27 28 /** 29 * セッションを閉じます。 30 */ 31 public function close(): bool 32 { 33 return true; 34 } 35 36 /** 37 * 指定されたセッションIDのデータを読み込みます。 38 * ファイルが存在しない場合は空文字列を返します。 39 */ 40 public function read(string $id): string|false 41 { 42 $file = $this->savePath . '/sess_' . $id; 43 if (file_exists($file)) { 44 return file_get_contents($file); 45 } 46 return ''; 47 } 48 49 /** 50 * 指定されたセッションIDにデータを書き込みます。 51 */ 52 public function write(string $id, string $data): bool 53 { 54 $file = $this->savePath . '/sess_' . $id; 55 return file_put_contents($file, $data) !== false; 56 } 57 58 /** 59 * 指定されたセッションIDのセッションデータを削除します。 60 */ 61 public function destroy(string $id): bool 62 { 63 $file = $this->savePath . '/sess_' . $id; 64 if (file_exists($file)) { 65 return unlink($file); 66 } 67 return true; 68 } 69 70 /** 71 * セッションのガーベージコレクション (GC) を実行します。 72 * $max_lifetime で指定された期間よりも古いセッションファイルを削除します。 73 * このメソッドはPHPの内部で、session_start() などのセッション初期化時に確率的に呼び出されます。 74 * 75 * @param int $max_lifetime セッションの最大有効期間 (秒)。この期間より古いデータが削除対象。 76 * @return int 実際に削除されたセッションファイルの数。 77 */ 78 public function gc(int $max_lifetime): int 79 { 80 $deletedCount = 0; 81 $now = time(); 82 83 // セッションファイルが保存されているディレクトリ内のファイルを全て取得 84 $files = glob($this->savePath . '/sess_*'); 85 if ($files === false) { 86 return 0; 87 } 88 89 foreach ($files as $file) { 90 // ファイルが存在し、かつ最終変更時刻が現在時刻から $max_lifetime 秒以上経過している場合 91 if (file_exists($file) && filemtime($file) + $max_lifetime < $now) { 92 unlink($file); // 古いセッションファイルを削除 93 $deletedCount++; 94 } 95 } 96 97 return $deletedCount; 98 } 99} 100 101// --- サンプルコード実行部分 --- 102 103// セッションデータ用の一時ディレクトリパスを生成 (他のプロセスと干渉しないようユニークに) 104$sessionSavePath = sys_get_temp_dir() . '/php_custom_sessions_' . uniqid(); 105if (!is_dir($sessionSavePath)) { 106 mkdir($sessionSavePath, 0777, true); 107 echo "セッション保存ディレクトリを作成しました: " . $sessionSavePath . "\n"; 108} 109 110// カスタムセッションハンドラのインスタンスを作成し、PHPのセッション管理に登録 111$handler = new MySessionHandler(); 112session_set_save_handler($handler, true); // true はスクリプト終了時に自動で close() を呼び出す設定 113 114// PHPのセッション保存パスをカスタムハンドラが使用するパスに設定 115session_save_path($sessionSavePath); 116 117// セッションを開始。これにより MySessionHandler::open() や MySessionHandler::read() が呼ばれます。 118session_start(); 119 120// セッションデータを設定・表示 121if (!isset($_SESSION['visits'])) { 122 $_SESSION['visits'] = 1; 123 echo "初めての訪問です。現在のセッションID: " . session_id() . "\n"; 124} else { 125 $_SESSION['visits']++; 126 echo "訪問回数: " . $_SESSION['visits'] . "回。現在のセッションID: " . session_id() . "\n"; 127} 128 129// セッションデータを保存し、セッションを終了します。 130// これにより MySessionHandler::write() と MySessionHandler::close() が呼び出されます。 131session_write_close(); 132 133// === gc() メソッドの動作デモンストレーション === 134// 通常、gc()はPHPがセッション開始時に確率的に自動呼び出ししますが、 135// ここでは動作確認のため、手動で呼び出し、削除される様子を示します。 136 137$currentSessionFile = $sessionSavePath . '/sess_' . session_id(); 138 139if (file_exists($currentSessionFile)) { 140 echo "\nセッションファイルが存在します: " . $currentSessionFile . "\n"; 141 // GCで削除されるように、このファイルの最終更新時刻を意図的に古くします (例: 100秒前) 142 touch($currentSessionFile, time() - 100); 143 echo "セッションファイルの最終更新時刻を意図的に古くしました。\n"; 144} else { 145 echo "\nセッションファイルが見つかりませんでした。\n"; 146} 147 148// $max_lifetime を短く設定し (例: 5秒)、gc() を呼び出します。 149// これにより、5秒より古い (ここでは意図的に古くした) セッションファイルが削除対象となります。 150$testMaxLifetime = 5; 151echo "gc() メソッドを呼び出し中 (最大生存期間: " . $testMaxLifetime . "秒より古いものを削除)...\n"; 152$deletedSessions = $handler->gc($testMaxLifetime); 153echo "削除されたセッションファイルの数: " . $deletedSessions . "\n"; 154 155// gc() 実行後、現在のセッションファイルが削除されたかを確認 156if (!file_exists($currentSessionFile)) { 157 echo "現在のセッションファイル (" . $currentSessionFile . ") は削除されました。\n"; 158} else { 159 echo "現在のセッションファイル (" . $currentSessionFile . ") は削除されませんでした。\n"; 160} 161 162// クリーンアップ: 作成した一時ディレクトリとその中のファイルを削除 163// (本番環境ではセッションデータディレクトリは通常削除しません) 164if (is_dir($sessionSavePath)) { 165 foreach (glob($sessionSavePath . '/*') as $file) { 166 unlink($file); 167 } 168 rmdir($sessionSavePath); 169 echo "セッション保存ディレクトリをクリーンアップしました。\n"; 170} 171 172?>
SessionHandlerInterface::gcは、PHPのセッション管理において、期限切れになった古いセッションデータを自動的に削除する「ガーベージコレクション」を実行するメソッドです。ウェブアプリケーションでは、ユーザーの活動が停止したり、有効期限が過ぎたりしたセッションのデータがサーバー上に残ってしまうことがあります。このメソッドは、そうした不要なデータを定期的にクリーンアップし、サーバーのリソースを効率的に保つ重要な役割を担います。
引数$max_lifetimeには、セッションデータの最大有効期間を秒単位で指定します。この期間よりも長く更新されていないセッションデータが、このメソッドによって削除の対象となります。例えば、$max_lifetimeが3600(1時間)であれば、1時間以上活動のない古いセッションファイルは削除されます。
戻り値はint型で、実際に削除されたセッションデータの数を返します。これにより、一度のガーベージコレクション処理でどれだけの古いセッションがクリーンアップされたかを確認できます。
PHPは通常、session_start()などでセッションが開始される際に、このgcメソッドを内部的に確率で呼び出し、セッションの寿命を管理しています。サンプルコードでは、カスタムセッションハンドラであるMySessionHandlerクラスがSessionHandlerInterfaceを実装し、gcメソッド内で、指定された$max_lifetimeに基づき、セッションファイル保存ディレクトリ内の古いファイルを検索して削除する具体的な処理を記述しています。この実装例を通じて、PHPがどのようにセッションの自動清掃を行うか、その仕組みを理解することができます。
PHPのSessionHandlerInterface::gc()メソッドは、セッション開始時にPHPによって自動的かつ確率的に呼び出されるため、通常は開発者が手動で実行する必要はありません。このメソッドは、引数$max_lifetimeで指定された最大有効期間を過ぎた古いセッションデータを削除する役割を持ちます。カスタムセッションハンドラを利用する際は、セッションファイルを保存するディレクトリに適切な読み書き権限を設定することが非常に重要です。権限不足はセッション管理の障害となりますのでご注意ください。また、「php gc_collect_cycles」はPHPのメモリ管理における循環参照のガベージコレクションであり、本メソッドのようにファイルやデータベース上のセッションデータを削除する役割とは目的が異なりますので混同しないようにしてください。このサンプルはファイルベースですが、データベースなど他のストレージを利用する場合も同様にgc()の実装が必要です。