Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】SessionHandlerInterface::read()メソッドの使い方

readメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

readメソッドはSessionHandlerInterfaceインターフェースの一部として、セッションIDに基づいてセッションデータを読み込むメソッドです。PHPのセッション機能は、ウェブサイト上でユーザーのログイン状態などをページ間で維持するために利用されます。開発者が標準のファイル保存以外の方法(例えば、データベースやRedis)でセッションデータを管理したい場合に、このSessionHandlerInterfaceを実装し、その中でセッションデータの読み込み処理を定義します。

このメソッドは、PHPエンジンからセッションID(文字列)を引数として受け取り、そのIDに対応するセッションデータをストレージから取得し、文字列として返す役割を持ちます。もし該当するデータが見つからない場合は、必ず空の文字列を返さなければなりません。readメソッドは、セッション開始時やセッションデータへのアクセス時にPHPのセッションハンドラによって自動的に呼び出され、セッションデータの取得を担います。

構文(syntax)

1<?php
2
3interface SessionHandlerInterface
4{
5    public function read(string $id): string|false;
6}

引数(parameters)

string $id

  • string $id: セッションIDを指定する文字列

戻り値(return)

string|false

セッションIDに対応するセッションデータを文字列で返します。セッションデータが存在しない、または読み込みに失敗した場合は false を返します。

サンプルコード

PHPセッションハンドラreadreadfileを理解する

1<?php
2
3/**
4 * PHP 8 Example: Custom Session Handler implementing SessionHandlerInterface
5 * Demonstrates the `read` method and its relation to file reading,
6 * specifically contrasting `file_get_contents` with the `readfile` keyword.
7 *
8 * This class provides a basic file-based session handler.
9 */
10class FileSessionHandler implements SessionHandlerInterface
11{
12    private string $savePath;
13
14    /**
15     * Constructor for the FileSessionHandler.
16     * Ensures the session save path exists.
17     *
18     * @param string $savePath The directory where session files will be stored.
19     */
20    public function __construct(string $savePath)
21    {
22        $this->savePath = $savePath;
23        if (!is_dir($this->savePath)) {
24            mkdir($this->savePath, 0777, true);
25        }
26    }
27
28    /**
29     * Opens the session storage.
30     * For file-based handlers, this often doesn't require specific actions.
31     *
32     * @param string $path The path argument passed to session_set_save_handler.
33     * @param string $name The session name.
34     * @return bool True on success, false on failure.
35     */
36    public function open(string $path, string $name): bool
37    {
38        return true;
39    }
40
41    /**
42     * Closes the session storage.
43     * For file-based handlers, this often doesn't require specific actions.
44     *
45     * @return bool True on success, false on failure.
46     */
47    public function close(): bool
48    {
49        return true;
50    }
51
52    /**
53     * Reads the session data for a given session ID.
54     * This method is called by PHP when a session is started to retrieve existing data.
55     *
56     * @param string $id The session ID to read.
57     * @return string|false The session data as a string, or false if an error occurred.
58     *                      An empty string should be returned if no data exists for the ID.
59     */
60    public function read(string $id): string|false
61    {
62        $sessionFile = $this->getSessionFilename($id);
63        if (file_exists($sessionFile)) {
64            // file_get_contents is used to read the file content and return it as a string.
65            // This is crucial for SessionHandlerInterface::read, as the data needs to be
66            // returned to PHP for processing into $_SESSION.
67            // In contrast, `readfile()` (related to the keyword) would directly
68            // output the file content, which is not suitable here.
69            return file_get_contents($sessionFile);
70        }
71        return ''; // Return an empty string if session data does not exist for the ID.
72    }
73
74    /**
75     * Writes the session data for a given session ID.
76     *
77     * @param string $id The session ID.
78     * @param string $data The serialized session data to write.
79     * @return bool True on success, false on failure.
80     */
81    public function write(string $id, string $data): bool
82    {
83        $sessionFile = $this->getSessionFilename($id);
84        return file_put_contents($sessionFile, $data) !== false;
85    }
86
87    /**
88     * Destroys a session for a given session ID.
89     *
90     * @param string $id The session ID to destroy.
91     * @return bool True on success, false on failure.
92     */
93    public function destroy(string $id): bool
94    {
95        $sessionFile = $this->getSessionFilename($id);
96        if (file_exists($sessionFile)) {
97            return unlink($sessionFile);
98        }
99        return true;
100    }
101
102    /**
103     * Cleans up expired sessions (Garbage Collection).
104     *
105     * @param int $max_lifetime The maximum time in seconds a session can be inactive.
106     * @return int|false The number of deleted sessions, or false on failure.
107     */
108    public function gc(int $max_lifetime): int|false
109    {
110        $count = 0;
111        foreach (glob($this->savePath . '/sess_*') as $file) {
112            if (file_exists($file) && filemtime($file) + $max_lifetime < time()) {
113                unlink($file);
114                $count++;
115            }
116        }
117        return $count;
118    }
119
120    /**
121     * Helper method to construct the full file path for a session.
122     *
123     * @param string $id The session ID.
124     * @return string The full path to the session file.
125     */
126    private function getSessionFilename(string $id): string
127    {
128        return $this->savePath . '/sess_' . $id;
129    }
130
131    /**
132     * Demonstrates the `readfile()` function to explicitly show how it outputs
133     * file content directly. This function is not used by `SessionHandlerInterface::read`
134     * but helps illustrate the concept of "reading files" as hinted by the keyword.
135     *
136     * @param string $id The session ID of the file to read and output.
137     * @return bool True if the file was found and output, false otherwise.
138     */
139    public function debugSessionFileContents(string $id): bool
140    {
141        $sessionFile = $this->getSessionFilename($id);
142        if (file_exists($sessionFile)) {
143            echo "--- Content of session file '{$sessionFile}' using readfile(): ---\n";
144            // `readfile()` directly outputs the file content to the standard output.
145            // This is different from `file_get_contents()` which returns the content as a string.
146            readfile($sessionFile);
147            echo "\n-------------------------------------------------------------------\n";
148            return true;
149        }
150        echo "Error: Session file for ID '{$id}' not found at '{$sessionFile}'.\n";
151        return false;
152    }
153
154    /**
155     * Provides a self-contained example demonstrating the usage of this session handler.
156     * This method makes the script runnable independently.
157     */
158    public static function runExample(): void
159    {
160        $sessionSavePath = __DIR__ . '/sessions';
161
162        // Ensure the session save path exists
163        if (!is_dir($sessionSavePath)) {
164            mkdir($sessionSavePath, 0777, true);
165        }
166
167        // 1. Instantiate the custom session handler
168        $handler = new self($sessionSavePath);
169
170        // 2. Register the custom session handler with PHP
171        session_set_save_handler($handler, true);
172
173        // 3. Start the session (this will implicitly call $handler->read() if data exists)
174        session_start();
175
176        // 4. Store/update some data in the session
177        $_SESSION['user_name'] = 'Alice';
178        $_SESSION['login_time'] = time();
179        $_SESSION['counter'] = ($_SESSION['counter'] ?? 0) + 1;
180
181        $currentSessionId = session_id();
182        echo "Session initialized/updated. Current Session ID: " . $currentSessionId . "\n";
183        echo "Stored data: User=" . ($_SESSION['user_name'] ?? 'N/A') . ", Counter=" . ($_SESSION['counter'] ?? 'N/A') . "\n\n";
184
185        // 5. Close the session to ensure data is written to the file
186        // (This makes the session file available for manual inspection)
187        session_write_close();
188
189        echo "--- Demonstrating SessionHandlerInterface::read method's typical role ---\n";
190        // PHP internally calls 'read' when session_start() is invoked.
191        // We'll simulate a direct call for illustrative purposes to show its return value.
192        $rawSessionData = $handler->read($currentSessionId);
193        echo "Raw session data retrieved by handler->read('{$currentSessionId}'): " .
194             ($rawSessionData === false ? 'false (error)' : ($rawSessionData === '' ? 'empty (new session)' : $rawSessionData)) . "\n\n";
195
196        // 6. Demonstrate the 'readfile' keyword's concept by outputting the raw session file
197        echo "--- Connecting to the 'php readfile' keyword concept ---\n";
198        $handler->debugSessionFileContents($currentSessionId);
199
200        // Clean up the created session file and directory for a fresh run next time
201        if (file_exists($handler->getSessionFilename($currentSessionId))) {
202            unlink($handler->getSessionFilename($currentSessionId));
203        }
204        // Remove the directory only if it's empty
205        if (is_dir($sessionSavePath) && !(new FilesystemIterator($sessionSavePath))->valid()) {
206            rmdir($sessionSavePath);
207        }
208        echo "\nCleanup: Session file and directory (if empty) removed.\n";
209    }
210}
211
212// Execute the example to demonstrate the custom session handler and `readfile` context.
213FileSessionHandler::runExample();

PHPのSessionHandlerInterface::readメソッドは、PHPのセッション機能をカスタマイズする際に使用される重要なメソッドです。このメソッドは、セッションが開始されると、指定されたセッションID ($id) に対応するセッションデータを読み込むためにPHPによって自動的に呼び出されます。引数$idは、どのセッションの情報を取得するかを特定するための文字列です。戻り値は、読み込んだセッションデータが文字列として返されるか、エラーが発生した場合はfalse、該当するデータが存在しない場合は空の文字列を返します。

サンプルコードでは、ファイルをセッション保存場所として利用するFileSessionHandlerクラスがreadメソッドを実装しています。ここでは、与えられたセッションIDに基づいてファイルパスを生成し、file_get_contents()関数を用いてファイルからセッションデータを読み込み、その内容を文字列として返しています。

キーワードのphp readfileが示すreadfile()関数は、ファイルの内容を直接出力する目的で使用されます。一方、SessionHandlerInterface::readはセッションデータを「プログラム内部に返す」必要があるため、file_get_contents()のように文字列として内容を取得する関数が適切です。この違いは、ファイルの内容をどのように利用したいかによって、適切な関数を選択することの重要性を示しています。

このサンプルコードは、PHPのセッション処理をカスタマイズするためのSessionHandlerInterface::readメソッドの実装例です。このreadメソッドは、指定されたセッションIDに対応するデータを読み込み、その内容を文字列としてPHPの内部に返す役割を担っています。

特に注意すべきは、ファイルからデータを読み込む際にfile_get_contentsを使用している点です。これはファイルの内容を文字列として取得し、戻り値として適切に返すためです。一方、キーワードにあるreadfile関数は、ファイルの内容をブラウザなどに直接出力してしまうため、SessionHandlerInterface::readの目的には合致しません。readメソッドでデータが見つからない場合は、エラーを示すfalseではなく、空の文字列''を返すのが一般的です。カスタムセッションハンドラは、PHP標準のファイルベース以外の方法でセッションを管理したい場合に利用し、セッションファイルの保存パスのセキュリティ管理には十分な注意が必要です。

PHP 8.1 readonlyでセッションを安全に読み込む

1<?php
2
3/**
4 * カスタムセッションハンドラクラス
5 * SessionHandlerInterface を実装し、セッションデータの保存と読み込みをカスタマイズします。
6 * この例では、ファイルシステムをセッションストレージとして使用します。
7 */
8class MyFileSessionHandler implements SessionHandlerInterface
9{
10    /**
11     * セッションファイルを保存するディレクトリパス。
12     * PHP 8.1以降の `readonly` キーワードにより、このプロパティはコンストラクタで
13     * 初期化された後、変更できなくなります。これにより、セッションの保存場所が
14     * スクリプト実行中に意図せず変更されることを防ぎ、堅牢性が向上します。
15     */
16    private readonly string $savePath;
17
18    /**
19     * MyFileSessionHandler の新しいインスタンスを生成します。
20     *
21     * @param string $savePath セッションファイルを保存するディレクトリのパス。
22     * @throws InvalidArgumentException 指定されたパスがディレクトリでない、または書き込み可能でない場合。
23     */
24    public function __construct(string $savePath)
25    {
26        if (!is_dir($savePath) || !is_writable($savePath)) {
27            throw new InvalidArgumentException(
28                "Session save path '{$savePath}' is not a valid or writable directory."
29            );
30        }
31        $this->savePath = $savePath;
32    }
33
34    /**
35     * セッションを開きます。
36     *
37     * @param string $path セッションの保存パス (通常は php.ini の session.save_path の値)。
38     * @param string $name セッション名。
39     * @return bool 成功した場合に true、それ以外の場合に false。
40     */
41    public function open(string $path, string $name): bool
42    {
43        // カスタムハンドラでは、openメソッド内で特別な初期化が不要な場合が多い。
44        // コンストラクタで既にパスを検証済みです。
45        return true;
46    }
47
48    /**
49     * セッションを閉じます。
50     *
51     * @return bool 成功した場合に true、それ以外の場合に false。
52     */
53    public function close(): bool
54    {
55        // 閉じるときに特別なクリーンアップが不要な場合が多いです。
56        return true;
57    }
58
59    /**
60     * 指定されたセッションIDに関連付けられたデータを読み込みます。
61     *
62     * SessionHandlerInterface::read(string $id): string|false
63     *
64     * このメソッドはセッションIDに基づいてセッションデータを取得します。
65     * `readonly` プロパティである `$this->savePath` を利用してファイルパスを構築し、
66     * 指定されたファイルからデータを読み込みます。
67     *
68     * @param string $id 読み込むセッションのID。
69     * @return string|false 読み込んだセッションデータ、またはデータが存在しない、読み込みに失敗した場合は false。
70     *                      (PHPのデフォルトセッションハンドラはデータが存在しない場合に空文字列を返しますが、
71     *                      SessionHandlerInterface の戻り値型定義に合わせて false も有効です。)
72     */
73    public function read(string $id): string|false
74    {
75        // readonly プロパティ $this->savePath を利用してセッションファイルのパスを構築
76        $filePath = $this->savePath . '/sess_' . $id;
77
78        if (file_exists($filePath)) {
79            // ファイルが存在すれば内容を読み込む
80            // file_get_contents は成功時に string、失敗時に false を返すため、戻り値型に合致します。
81            return file_get_contents($filePath);
82        }
83
84        // ファイルが存在しない(セッションデータがない、または読み込みに失敗)場合は false を返す
85        return false;
86    }
87
88    /**
89     * セッションIDと関連付けられたデータを書き込みます。
90     *
91     * @param string $id 書き込むセッションのID。
92     * @param string $data 書き込むセッションデータ。
93     * @return bool 成功した場合に true、それ以外の場合に false。
94     */
95    public function write(string $id, string $data): bool
96    {
97        $filePath = $this->savePath . '/sess_' . $id;
98        // `readonly` プロパティ `$this->savePath` を利用してファイルにデータを書き込む
99        return file_put_contents($filePath, $data, LOCK_EX) !== false;
100    }
101
102    /**
103     * 指定されたセッションを破棄します。
104     *
105     * @param string $id 破棄するセッションのID。
106     * @return bool 成功した場合に true、それ以外の場合に false。
107     */
108    public function destroy(string $id): bool
109    {
110        $filePath = $this->savePath . '/sess_' . $id;
111        if (file_exists($filePath)) {
112            return unlink($filePath);
113        }
114        return true; // 存在しない場合は既に破棄されていると見なします
115    }
116
117    /**
118     * ガベージコレクション (GC) を実行します。
119     * 古いセッションファイルを削除します。
120     *
121     * @param int $max_lifetime セッションの有効期限 (秒)。
122     * @return bool 成功した場合に true、それ以外の場合に false。
123     */
124    public function gc(int $max_lifetime): bool
125    {
126        foreach (glob($this->savePath . '/sess_*') as $file) {
127            if (filemtime($file) + $max_lifetime < time() && file_exists($file)) {
128                unlink($file);
129            }
130        }
131        return true;
132    }
133}
134
135// --- サンプルコードの実行部分 ---
136
137// セッションファイルを保存するためのディレクトリを作成します。
138// 実行ユーザーが書き込み可能なパスを指定してください。
139$sessionSavePath = __DIR__ . '/sessions';
140if (!is_dir($sessionSavePath)) {
141    mkdir($sessionSavePath, 0777, true);
142    echo "セッション保存ディレクトリ '{$sessionSavePath}' を作成しました。\n";
143}
144
145try {
146    // カスタムセッションハンドラのインスタンスを作成します。
147    // `readonly` プロパティ `$savePath` はコンストラクタで一度だけ初期化されます。
148    $handler = new MyFileSessionHandler($sessionSavePath);
149
150    // PHPにカスタムセッションハンドラを登録します。
151    // これにより、PHPのセッション関数 (session_start, $_SESSIONなど) が
152    // MyFileSessionHandler のメソッドを使用するようになります。
153    session_set_save_handler($handler, true);
154
155    // セッションを開始します。
156    // この時点で MyFileSessionHandler::open() と MyFileSessionHandler::read() が呼ばれる可能性があります。
157    session_start();
158
159    // セッションデータの設定と表示
160    if (!isset($_SESSION['count'])) {
161        $_SESSION['count'] = 0;
162        echo "初回アクセスです。セッションを開始しました。\n";
163    } else {
164        $_SESSION['count']++;
165        echo "アクセス回数: " . $_SESSION['count'] . "\n";
166    }
167
168    // 現在のセッションIDを表示 (MyFileSessionHandler::read メソッドで読み込まれるIDに対応)
169    echo "現在のセッションID: " . session_id() . "\n";
170    echo "セッションデータが '{$sessionSavePath}/sess_" . session_id() . "' に保存されます。\n";
171
172    // セッションデータの書き込みは通常スクリプト終了時、または session_write_close() で行われます。
173    // この時点で MyFileSessionHandler::write() が呼ばれる可能性があります。
174    session_write_close(); 
175
176    echo "\n";
177    echo "このスクリプトを複数回実行してみてください。\n";
178    echo "セッションデータが保持され、アクセス回数が増加する様子が確認できます。\n";
179    echo "また、'{$sessionSavePath}' ディレクトリにセッションファイルが生成されていることを確認してください。\n";
180
181    // `readonly` プロパティの変更を試みる (Fatal error が発生することを示すコメント)
182    // 次の行のコメントを外すと、PHP 8.1以降では実行時エラー(Fatal error)が発生します。
183    // $handler->savePath = '/new/path'; // Fatal error: Uncaught Error: Cannot modify readonly property MyFileSessionHandler::$savePath
184} catch (InvalidArgumentException $e) {
185    echo "エラー: " . $e->getMessage() . "\n";
186    exit(1);
187} catch (Error $e) {
188    echo "致命的なエラー: " . $e->getMessage() . "\n";
189    echo "readonly プロパティの不正な変更を試みた可能性があります。\n";
190    exit(1);
191}

PHP 8のSessionHandlerInterface::readメソッドは、カスタムセッションハンドラを実装する際に、特定のセッションIDに関連付けられたデータを読み込む役割を担います。このメソッドは、PHPのsession_start()関数が呼ばれた際などに、既存のセッションデータを復元するために内部的に呼び出されます。

引数$idには、読み込みたいセッションを一意に識別する文字列(セッションID)が渡されます。このIDを使って、どのセッションのデータを取得すべきかを判断します。

戻り値は、読み込んだセッションデータが存在すればその内容を文字列として返し、データが存在しないか読み込みに失敗した場合はfalseを返します。

サンプルコードでは、MyFileSessionHandlerクラスがファイルシステムをセッションストレージとして利用しており、readメソッドは$idと、クラスのreadonlyプロパティである$savePath(セッションファイルを保存する固定されたディレクトリパス)を組み合わせてファイルパスを生成し、そのファイルからデータを読み込みます。このreadonlyプロパティは、コンストラクタで初期化された後、その値を変更できないようにすることで、セッションの保存場所が誤って変更されるのを防ぎ、システムの堅牢性を高めます。readメソッドは、この堅牢なパスを利用して、安全にセッションデータを取得しています。

readonlyプロパティはPHP 8.1以降で導入され、コンストラクタで一度設定すると変更できなくなります。これにより、セッション保存パスのような重要な設定が実行中に意図せず変更されるのを防ぎ、プログラムの堅牢性が向上します。変更を試みると致命的なエラーが発生しますのでご注意ください。SessionHandlerInterface::readメソッドは、指定されたセッションIDのデータを読み込みます。データが存在しない場合や読み込みに失敗した場合はfalseを返すため、標準のセッションハンドラが空文字列を返す挙動とは異なります。実装や利用時には、戻り値の型string|falseの扱いを誤らないよう注意が必要です。このカスタムハンドラをPHPのセッション処理に適用するには、session_set_save_handler()関数で登録することが必須です。セッションファイルの保存ディレクトリには、PHPの実行ユーザーに適切な書き込み権限が必要です。

関連コンテンツ