2024 PHP Conference Japan

SessionHandlerInterface 類別

(PHP 5 >= 5.4.0, PHP 7, PHP 8)

簡介

SessionHandlerInterface 是一個定義了建立自訂工作階段處理程式最小原型的介面。為了使用其 OOP 呼叫將自訂工作階段處理程式傳遞給 session_set_save_handler(),類別可以實作此介面。

請注意,此類別的回呼方法設計為由 PHP 內部呼叫,不應從使用者空間程式碼呼叫。

介面概要

介面 SessionHandlerInterface {
/* 方法 */
公開 close(): 布林值
公開 destroy(字串 $id): 布林值
公開 gc(整數 $max_lifetime): 整數|false
公開 open(字串 $path, 字串 $name): 布林值
公開 read(字串 $id): 字串|false
公開 write(字串 $id, 字串 $data): 布林值
}

範例

範例 #1 使用 SessionHandlerInterface 的範例

以下範例提供基於檔案的 session 儲存,類似於 PHP session 的預設儲存處理器 files。此範例可以輕鬆擴展以涵蓋使用您最喜歡的 PHP 支援的資料庫引擎的資料庫儲存。

請注意,我們使用 OOP 原型與 session_set_save_handler() 並使用函式的參數旗標註冊關閉函式。當註冊物件作為 session 儲存處理器時,通常建議這樣做。

注意事項

為求簡潔,此範例省略了輸入驗證。然而,$id 參數實際上是使用者提供的數值,需要適當的驗證/清理以避免漏洞,例如路徑遍歷問題。*因此,請勿在生產環境中直接使用此範例。*

<?php
class MySessionHandler implements SessionHandlerInterface
{
private
$savePath;

public function
open($savePath, $sessionName): bool
{
$this->savePath = $savePath;
if (!
is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}

return
true;
}

public function
close(): bool
{
return
true;
}

#[
\ReturnTypeWillChange]
public function
read($id)
{
return (string) @
file_get_contents("$this->savePath/sess_$id");
}

public function
write($id, $data): bool
{
return
file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}

public function
destroy($id): bool
{
$file = "$this->savePath/sess_$id";
if (
file_exists($file)) {
unlink($file);
}

return
true;
}

#[
\ReturnTypeWillChange]
public function
gc($maxlifetime)
{
foreach (
glob("$this->savePath/sess_*") as $file) {
if (
filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}

return
true;
}
}

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();

// proceed to set and retrieve values by key from $_SESSION

目錄

新增註解

使用者貢獻的註解 8 則註解

ohcc at 163 dot com
6 年前
從 PHP 7.0 開始,您可以實作 SessionUpdateTimestampHandlerInterface 來
定義您自己的 session id 驗證方法,例如 validate_sid,以及時間戳記更新方法,例如在非物件導向原型 session_set_save_handler() 中的 update_timestamp。

SessionUpdateTimestampHandlerInterface 是 PHP 7.0 中引入的新介面,目前尚未有文件記載。它有兩個抽象方法:SessionUpdateTimestampHandlerInterface :: validateId($sessionId) 和 SessionUpdateTimestampHandlerInterface :: updateTimestamp($sessionId, $sessionData)。

<?php
/*
@author 吳顯成
此程式碼結構僅適用於 PHP 7.0+,因為 SessionUpdateTimestampHandlerInterface 是在 PHP 7.0 中引入的。
使用此類別,您可以驗證 PHP 工作階段 ID 並更新 PHP 工作階段資料的時間戳記
使用 PHP 7.0+ 中 session_set_save_handler() 的 OOP 原型。
*/
class PHPSessionXHandler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
public function
close(){
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
public function
destroy($sessionId){
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
public function
gc($maximumLifetime){
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
public function
open($sessionSavePath, $sessionName){
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
public function
read($sessionId){
// 傳回值應為工作階段資料或空字串
// ...
}
public function
write($sessionId, $sessionData){
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
public function
create_sid(){
// 從 PHP 5.5.1 開始可用
// 在需要新的工作階段 ID 時於內部呼叫
// 不需要參數,傳回值應為建立的新工作階段 ID
// ...
}
public function
validateId($sessionId){
// 實作 SessionUpdateTimestampHandlerInterface::validateId()
// 從 PHP 7.0 開始可用
// 如果工作階段 ID 有效,則傳回值應為 true,否則為 false
// 如果傳回 false,PHP 將在內部產生新的工作階段 ID
// ...
}
public function
updateTimestamp($sessionId, $sessionData){
// 實作 SessionUpdateTimestampHandlerInterface::validateId()
// 從 PHP 7.0 開始可用
// 傳回值應為 true 表示成功,false 表示失敗
// ...
}
}
?>
ohcc at 163 dot com
6 年前
即使在 PHP 7.2 中,session_set_save_handler() 的非 OOP 原型也支援 validate_sid 和 update_timestamp,而 OOP 原型則不支援。 然而,自 PHP 5.5.1 起,OOP 原型支援 create_sid。

validate_sid($sessionId)
此回呼函式用於驗證 $sessionId。 對於有效的工作階段 ID $sessionId,其傳回值應為 true;對於無效的工作階段 ID $sessionId,其傳回值應為 false。 如果傳回 false,則會產生新的工作階段 ID 以取代無效的工作階段 ID $sessionId。

update_timestamp($sessionId)
此回呼函式用於更新時間戳記,其傳回值應為 true 表示成功,false 表示失敗。
ohcc at 163 dot com
7 年前
從 PHP 5.5.1 開始,支援另一個方法 create_sid()。 當呼叫 session_regenerate_id() 時,將會呼叫它。

SessionHandlerInterface {
/* 方法 */
abstract public bool close ( void )
抽象 public bool create_sid ( void )
抽象 public bool destroy ( string $session_id )
抽象 public bool gc ( int $maxlifetime )
抽象 public bool open ( string $save_path , string $session_name )
抽象 public string read ( string $session_id )
抽象 public bool write ( string $session_id , string $session_data )
}
avenidagez at foro5 dot com
9 年前
請注意,session_start() 會先呼叫 open(),然後呼叫 read(),而這個類別會在 open() 時回傳 true,並在 read() 時回傳 session 值或空字串。
這樣就沒有錯誤捕捉機制了。也就是說,session_start() 在失敗時應該回傳 false,但在這個類別的 open() 方法實作中卻不是這樣。無論 open() 回傳 true、false 或其他任何值,session_start() 函式都會忽略它,並繼續執行 read() 方法。
這是 bug 嗎?如果 open() 回傳 false,session_start() 應該停止下一步 (read()) 並回傳 false。

if(session_start()) ...程式碼
else exit( );

因此,請忘記 session_start() 的回傳值,您需要實作一個錯誤捕捉例程,並在 open() 方法失敗時呼叫 exit()。
warxcell at gmail dot com
12 年前
您應該在類別名稱前面加上 <b>\</b>,以告知 PHP 它是來自根命名空間。
tony at marston-home dot demon dot co dot uk
6 年前
您的自訂 session 處理器不應該呼叫任何 session 函式,例如 session_name() 或 session_id(),因為相關的值會作為參數傳遞給各種處理器方法。嘗試從其他來源取得值可能無法如預期般運作。
ohcc at 163 dot com
4 年前
如果您想在自己的 session 處理類別中使用類型宣告,請不要「實作」SessionHandlerInterface、SessionIdInterface 或 SessinUpdateTimestampInterface,否則會出現致命錯誤,指出類別方法的宣告必須與介面方法相容。

不良範例
<?php
class SessionWuXianchengHandler implements SessionHandlerInterface {
public function
open(string $sessionPath, string $sessionName) : bool {
}
......
}
?>

良好範例
<?php
class SessionWuXianchengHandler {
public function
open(string $sessionPath, string $sessionName) : bool {
}
......
}
?>
StanE
9 年前
我認為 MySessionHandler 類別的 gc() 方法範例中有一個小「錯誤」。它使用了 filemtime() 函式,其回傳值會被 PHP 快取。請在 gc() 方法的 foreach 區塊內加入以下一行:

clearstatcache(true, $file);
To Top