定製php4的session功能

來源:互聯網
上載者:User
這篇文章描述了怎樣定製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儲存在資料庫中的。(比如你服務於很多使用者並且需要
Server Load Balancer時)
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也很容易,我們只需要從資料庫中刪除到期session().

作為結束這個小教程,希望你在擴充php4的session處理時有個好感覺。
這個範例只是簡單的示範了你怎樣做才能擴充它們使其適應你的需要,如果你找到什麼bug的話,請讓我知道:)

faq:
如果你擔心session檔案在/tmp目錄中和別的虛擬機器混淆,正好將它們存到別處。
這就是為什麼有session.save_path選項的原因。
如果你擔心效能的話你可以考慮將session存在共用記憶體中。你只需要在編譯php時加上MM支援(--with-mm)並指定sessio.save_handler 為 mm
在.htaccess中,php.ini中或httpd.conf中。

我覺得只有多台機器要儲存session時才會用到資料庫。
(最後這句實在不好譯,自已看吧)

session_dbm.php
=========================================================================
<?
/* ------------------------------------------------------------------------
* session_dbm.php
* ------------------------------------------------------------------------
* PHP4 DBM Session Handler
* Version 1.00
* by Ying Zhang (ying@zippydesign.com)
* Last Modified: May 21 2000
*
* ------------------------------------------------------------------------
* TERMS OF USAGE:
* ------------------------------------------------------------------------
* You are free to use this library in any way you want, no warranties are
* expressed or implied. This works for me, but I don't guarantee that it
* works for you, USE AT YOUR OWN RISK.
*
* While not required to do so, I would appreciate it if you would retain
* this header information. If you make any modifications or improvements,
* please send them via email to Ying Zhang <ying@zippydesign.com>.
*
* ------------------------------------------------------------------------
* DESCRIPTION:
* ------------------------------------------------------------------------
* This library tells the PHP4 session handler to write to a DBM file
* instead of creating individual files for each session.
*
* ------------------------------------------------------------------------
* INSTALLATION:
* ------------------------------------------------------------------------
* Make sure you have DBM support compiled into PHP4. Then copy this
* script to a directory that is accessible by the rest of your PHP
* scripts.
*
* ------------------------------------------------------------------------
* USAGE:
* ------------------------------------------------------------------------
* Include this file in your scripts before you call session_start(), you
* don't have to do anything special after that.
*/

$SESS_DBM = "";
$SESS_LIFE = get_cfg_var("session.gc_maxlifetime");

function sess_open($save_path, $session_name) {
global $SESS_DBM;

$SESS_DBM = dbmopen("$save_path/$session_name", "c");
return ($SESS_DBM);
}

function sess_close() {
global $SESS_DBM;

dbmclose($SESS_DBM);
return true;
}

function sess_read($key) {
global $SESS_DBM, $SESS_LIFE;

$var = "";
if ($tmp = dbmfetch($SESS_DBM, $key)) {
$expires_at = substr($tmp, 0, strpos($tmp, "&brvbar"));

if ($expires_at > time()) {
$var = substr($tmp, strpos($tmp, "&brvbar") + 1);
}
}

return $var;
}

function sess_write($key, $val) {
global $SESS_DBM, $SESS_LIFE;

dbmreplace($SESS_DBM, $key, time() + $SESS_LIFE . "&brvbar" . $val);
return true;
}

function sess_destroy($key) {
global $SESS_DBM;

dbmdelete($SESS_DBM, $key);
return true;
}

function sess_gc($maxlifetime) {
global $SESS_DBM;

$now = time();
$key = dbmfirstkey($SESS_DBM);
while ($key) {
if ($tmp = dbmfetch($SESS_DBM, $key)) {
$expires_at = substr($tmp, 0, strpos($tmp, "&brvbar"));
if ($now > $expires_at) {
sess_destroy($key);
}
}

$key = dbmnextkey($SESS_DBM, $key);
}
}

session_set_save_handler(
"sess_open",
"sess_close",
"sess_read",
"sess_write",
"sess_destroy",
"sess_gc");
?>
=====================================================================================
session_mysql.php
=======================================================================================
<?
/* ------------------------------------------------------------------------
* session_mysql.php
* ------------------------------------------------------------------------
* PHP4 MySQL Session Handler
* Version 1.00
* by Ying Zhang (ying@zippydesign.com)
* Last Modified: May 21 2000
*
* ------------------------------------------------------------------------
* TERMS OF USAGE:
* ------------------------------------------------------------------------
* You are free to use this library in any way you want, no warranties are
* expressed or implied. This works for me, but I don't guarantee that it
* works for you, USE AT YOUR OWN RISK.
*
* While not required to do so, I would appreciate it if you would retain
* this header information. If you make any modifications or improvements,
* please send them via email to Ying Zhang <ying@zippydesign.com>.
*
* ------------------------------------------------------------------------
* DESCRIPTION:
* ------------------------------------------------------------------------
* This library tells the PHP4 session handler to write to a MySQL database
* instead of creating individual files for each session.
*
* Create a new database in MySQL called "sessions" like so:
*
* CREATE TABLE sessions (
* sesskey char(32) not null,
* expiry int(11) unsigned not null,
* value text not null,
* PRIMARY KEY (sesskey)
* );
*
* ------------------------------------------------------------------------
* INSTALLATION:
* ------------------------------------------------------------------------
* Make sure you have MySQL support compiled into PHP4. Then copy this
* script to a directory that is accessible by the rest of your PHP
* scripts.
*
* ------------------------------------------------------------------------
* USAGE:
* ------------------------------------------------------------------------
* Include this file in your scripts before you call session_start(), you
* don't have to do anything special after that.
*/

$SESS_DBHOST = "localhost"; /* database server hostname */
$SESS_DBNAME = "sessions"; /* database name */
$SESS_DBUSER = "phpsession"; /* database user */
$SESS_DBPASS = "phpsession"; /* database password */

$SESS_DBH = "";
$SESS_LIFE = get_cfg_var("session.gc_maxlifetime");

function sess_open($save_path, $session_name) {
global $SESS_DBHOST, $SESS_DBNAME, $SESS_DBUSER, $SESS_DBPASS, $SESS_DBH;

if (! $SESS_DBH = mysql_pconnect($SESS_DBHOST, $SESS_DBUSER, $SESS_DBPASS)) {
echo "<li>Can't connect to $SESS_DBHOST as $SESS_DBUSER";
echo "<li>MySQL Error: ", mysql_error();
die;
}

if (! mysql_select_db($SESS_DBNAME, $SESS_DBH)) {
echo "<li>Unable to select database $SESS_DBNAME";
die;
}

return true;
}

function sess_close() {
return true;
}

function sess_read($key) {
global $SESS_DBH, $SESS_LIFE;

$qry = "SELECT value FROM sessions WHERE sesskey = '$key' AND expiry > " . time();
$qid = mysql_query($qry, $SESS_DBH);

if (list($value) = mysql_fetch_row($qid)) {
return $value;
}

return false;
}

function sess_write($key, $val) {
global $SESS_DBH, $SESS_LIFE;

$expiry = time() + $SESS_LIFE;
$value = addslashes($val);

$qry = "INSERT INTO sessions VALUES ('$key', $expiry, '$value')";
$qid = mysql_query($qry, $SESS_DBH);

if (! $qid) {
$qry = "UPDATE sessions SET expiry = $expiry, value = '$value' WHERE sesskey = '$key' AND expiry > " . time();
$qid = mysql_query($qry, $SESS_DBH);
}

return $qid;
}

function sess_destroy($key) {
global $SESS_DBH;

$qry = "DELETE FROM sessions WHERE sesskey = '$key'";
$qid = mysql_query($qry, $SESS_DBH);

return $qid;
}

function sess_gc($maxlifetime) {
global $SESS_DBH;

$qry = "DELETE FROM sessions WHERE expiry < " . time();
$qid = mysql_query($qry, $SESS_DBH);

return mysql_affected_rows($SESS_DBH);
}

session_set_save_handler(
"sess_open",
"sess_close",
"sess_read",
"sess_write",
"sess_destroy",
"sess_gc");
?>
=========================================================================
test.php
==========================================================================
<?
/* ------------------------------------------------------------------------
* test.php
* ------------------------------------------------------------------------
* PHP4 Customer Session Handler Test Script
* Version 1.00
* by Ying Zhang (ying@zippydesign.com)
* Last Modified: May 21 2000
*/

/* default to DBM handler */
if (! isset($handler)) {
$handler = "dbm";
}

/* default action is increment */
if (! isset($action)) {
$action = "increment";
}

/* load up the appropriate session handling script, depending on the handler */
if ($handler == "dbm") {
include("session_dbm.php");

} elseif ($handler == "mysql") {
include("session_mysql.php");

} else {
echo "<li>Unrecognized handler ($handler)";
die;
}

/* start the session and register a simple counter */
session_start();
session_register("count");

/* figure out what we should do, depending on the action */
switch ($action) {
case "increment" :
$count = isset($count) ? $count + 1 : 0;
break;

case "destroy" :
session_destroy();
break;

case "gc" :
$maxlife = get_cfg_var("session.gc_maxlifetime");
sess_gc($maxlife);
break;

default:
echo "<li>Unknown action ($action)";
break;
}
?>

<h1>Session Test Script</h1>
<ul>
<li>Handler: <b><?=$handler?></b>
<li>Action: <b><?=$action?></b>
<li>Count: <b><?=$count?></b>
</ul>

<hr size=1>
<form>
<table>
<tr>
<td>Handler:</td>
<td>
<select name="handler">
<option value="dbm">DBM</option>
<option value="mysql">MySQL</option>
</select>
</td>
</tr>
<tr>
<td>Action:</td>
<td>
<select name="action">
<option value="increment">Increment</option>
<option value="destroy">Session Destroy</option>
<option value="gc">Force Garbage Collection</option>
</select>
</td>
</tr>
<tr>
<td></td>
<td><br><input type="submit"></td>
</tr>
</table>
</form>
=========================================================================================

(原文作者:Ying Yang,翻譯:馬勇)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.