這篇文章描述了怎樣定制php4的session處理。我們提供一個怎樣寫一個全功能的基於mysql數據庫或dbm文件的session處理程序例子。
一、序言
新的php4有一套自己的session處理函數。缺省情況下,每個session存貯在系統臨時目錄的一個個獨立文件中(例如在unix系統中為/tmp)。
這適合或不適合,依你的需求而言。例如:如果你的支持php的web服務器分布在不同的機器上,你不能很容易地共享它們之間的session(當然,你也可以將sessions保存在NFS共享中)。另一個潛在的問題是你機器上的數千或數百萬個session文件使你的文件系統變得散亂 。
對我們來說幸運的是,php4的開發者非常有遠見(感謝他們),他們為你我這樣的用戶提供了擴展session處理的接口。
這個文檔解釋一點session的處理並且提供兩個能夠工作的怎樣擴展session處理的例子。我們的第一個例子將使session處理程序保存 session數據到DBM文件中。我們的第二個例子將保存session數據到MYSQL數據庫中。
在你開始之前,請下載ying20000602.zip 並且將它解開放到web文檔目錄中。(我已經將它帶在本文的結尾處了)
任何一個我們寫的session處理程序會提供6個基本的函數,它們將被php4的session處理程序調用,所以你不用擔心怎樣調用它們。
好在這些定制處理session的函數對你來說是完全透明的。所以你可以改動它們而不會影響你自己的PHP腳本。
這幾個函數是:
sess_open($sess_path, $session_name);
這個函數被session處理程序調用來作初始化工作。需要傳給它的兩個參數是$sess_path,它對應你的php.ini文件中的session.save_path選項;$session_name,它對應php.ini中的session.name選項。它們具體怎樣工作,請看下面的例子。
sess_close();
這個函數在頁面結束執行並且session處理程序需要關閉時被調用。(注意,不要和sess_destory混淆了,它是用來結束session的)
sess_read($key);
這個函數在session處理程序讀取指定session鍵值($key)時。
這個函數檢索並返回標識為$key的session數據.(注意:你不用擔心怎樣序列化和反序列化數據,如果你不知道這是什麼意思,不要擔心它)
譯者注:序列化是將變量或對象在程序結束或需要時保存在文件中,在下次程序運行或需要時再調入內存的技術,有別於只保存數據的方法。
sess_write($key, $val);
這個函數據在session處理程序需要將數據保存時調用,這種情況經常在你的程序結束時發生。
它負責將數據保存在下次能用sess_read($key)函數檢索的地方。
sess_destroy($key);
這個函數在需要消毀session時。它負責刪除session並且清除環境。
sess_gc($maxlifetime);
這個函數負責清理碎片。在這種情況下,它負責刪除過時的session數據。session處理程序會偶爾調用它們。
現在我們已經清楚了我們提供的函數。它們不是非要這樣命名,但必須接受這些參數。(不管你需不需要它們)
DBM session 處理程序
我們的第一個范例是寫一個保存session數據到DBM文件中的定制session處理程序。(這是ying20000602.zip中的session_dbm.php文件)
有很多充足的理由讓你要這樣做,例如,如果你在isp那兒有一台共享的服務器(譯注:相當於我們說的虛擬主機吧)並且你不想讓你的session數據
和別人的混在一起。
重要注釋:
在你試驗這些程序時你的php4必須有DBM支持。如果不是這樣的(譯注:如果沒有DBM支持)會很難看,真的很難看!
我們要做的這些工作將會得到一個所有session數據的DBM文件。(萬一你不知道,DBM文件象一個僅保存"鍵/值"對的非常簡單的數據庫.
由下面的6個函數據實現:
sess_open($sess_path, $session_name);
我們將調用dbmopen()打開一個處於讀寫模式的DBM文件。我們的DBM文件將被命名為/tmp/PHPSESSID,除非你修改了php.ini中的session路
徑和名字設置。
sess_close();
在這個函數中,我們將簡單地調用dbmclose()函數關閉DBM文件。
sess_read($key);
這兒我們僅僅調用dbmfetch()載入和參數$key相關連的session數據。
在載入一個session時,我們需要保證讀入的不是一個過期數據,所以我們必須給session配上一個時間標記。
為什麼?因為在它們失效,不管什麼原因而沒有被刪掉時,我們不會意外地讀入過期數據。這會是一個很大的禁忌。
我們知道DBM文件只保存 鍵/值 對,因此不得不在寫session數據時將時間標記同" 值"一起寫入,在讀session數據時去掉。
任何已經過期的session將被忽略。看看這個源程序,它會讓你更清楚。
sess_write($key, $val);
寫入一個session,我們會使用dbmreplace()函數。注意,從上所述我們要保存過期時間標記在session中,所以我們要將時間標記綁到值上。
sess_destroy($key);
消毀一個session很容易,我們只需要調用dbmdelete()函數將它從session文件中刪除。
sess_gc($maxlifetime);
過期數據收集在這兒有點令人討厭但卻是必需的,為了達到目的我們在循環掃描所有保存在DBM文件中的session並且刪掉過期的。這會很慢因
為我們循環通過所有保存在這個文件中的所有session數據。
現在我們已經有了一個DBM session處理程序,太酷了!
現在,我們讓這些session保存到mysql數據庫中。
Mysql session處理程序
(This
我們的下一個范例是寫一個將session數據存到mysql數據庫的定制session處理程序。(這個在session_mysql.php文件中,見文章尾部)
在你有許多支持PHP的服務器並且你需要共享它們之間的session時你會想將session保存在數據庫中的。(比如你服務於很多用戶並且需要
負載平衡時)
You have a bunch of machines doing web/PHP stuff, a machine serving
你有一批機器作支持php的服務器,需要一台機器作你的普通數據庫服務器,另外一台運行mysql數據庫處理session。僅這樣對大多數人來
說就具有很大的殺傷力的。:)(譯注:可能意思是太酷了吧)
重要提示:
在你試驗之前你的php必須支持mysql。(譯注:這好象已經不成問題了,php現在已經內建mysql支持了)如果不是這樣的話,事情會很難看,真的
很難看。
首先我們在mysql中創建一個session數據庫,並且創建一個session表。先運行你的mysql客戶端並且運行下面的命令:
mysql> CREATE DATABASE sessions;
mysql> GRANT select, insert, update, delete ON sessions.* TO phpsession@localhost
-> IDENTIFIED BY 'phpsession';
mysql> CREATE TABLE sessions (
-> sesskey char(32) not null,
-> expiry int(11) unsigned not null,
-> value text not null,
-> PRIMARY KEY (sesskey)
-> );
下一步,修改session_mysql.php文件的$SESS_DB* 變量使其匹配你機器上的數據庫設置。在你繼續之前確信一切看起來良好。
我們的6個函數會依靠mysql數據庫工作:
sess_open($sess_path, $session_name);
我們需要調用mysql_Pconnect(),然後用mysql_selsect_db()選擇session數據庫 。$sess_path 和$session_name 參數
是無關的但我們不得不保留它們。(譯注:原文如此,可能是為了兼容吧)
sess_close();
我們要打開一個mysql永久連接因此我們在這個函數中不做任何事。(一個空函數)
sess_read($key);
這個竅門就是一個簡單的select語句,我們想要讀取所給的$key的session數據,需要指定過期時間信息。
sess_write($key, $val);
寫session數據用了一個小把戲。我們首先試圖用insert語句保存session數據到數據庫中。如果失敗(主鍵約束)則意味著這個key已經寫入,然後我們
不得不用一update語句代替。
sess_destroy($key);
刪除一個session很容易,我們只需要從數據庫中刪除這個鍵值。
sess_gc($maxlifetime);
處理過期session也很容易,我們只需要從數