ARES資通電子報

技術交流

Store Sessions in Database with ADODB

文 -Dennis

上次文章我們討論了有關 L10N 的其中一種常見的實現方式,有興趣的朋友可以去研究一下 PoEdit 這個軟體,網上的教程也比較多,就不再贅述。本文我們一起討論如何利用 ADODB 已有的 Library 來實現 Sessions 自動儲存到資料庫中。

Session 是 Web Application 中常用的一種保持 Client 與 Server 會話狀態的技術。因為 HTTP 無法保存狀態,所以實現 Session State 的目的,也就是要想辦法把狀態保存起來。
按照 Session 保存的位置, Session State 模式被分為三種。
1) 將 Session 儲存在客戶端 - Client Session State
2) 將 Session 儲存在服務器 ( File System) - Server Session State
3) 將 Session 儲存在資料庫 - Database Session State

Client Session State
基本思想是客戶端每次提交 HTTP 請求時報告自己當前的狀態,也就是把狀態資料儲存在客戶端。客戶端有很多種實現方式,不論哪種方式,最大的優點就是它天生的包含了對於每個用戶的標示—每個用戶的狀態資訊不可能被誤認為其他用戶。但是,由於狀態資訊儲存在客戶端,因此狀態資訊在每次提交 HTTP 請求時都會被傳輸到服務端,假如這個狀態資訊記憶體過大,那麼將會帶來很恐怖的網絡流量。另外,由於狀態資訊每次由客戶端自己提交,因此這個狀態資訊的安全性就成了很大的問題,我們必須使用各種加密技術防止它被篡改。

Server Session State
基本思想是服務器處理請求後,在記憶體裡保留下用戶的狀態資訊,下次請求時再讀取出來。和 Client Session State 相反,這樣安全性和流量的問題就得到了解決。但是如何標示每個用戶就成了問題,因為一個 WebServer 往往要同時處理成千上萬的用戶。Session 保存在 Server 的 File System 中,在 Windows 上 PHP 默認的 Session服務端文件存放在 C:\WINDOWS\Temp下,*NIX下默認存放在 /tmp下,如果說同時訪問很大或者 Session 建立太多,在這兩個目錄下就會存在大量類似 sess_xxxxxx 的 Session 文件,同一個目錄下文件數過多會導致性能下降,並且可能導致受到攻擊最終出現文件系統錯誤。

另外將狀態資訊存儲在服務器上也會有其他的問題,比如性能問題,成千上萬的用戶狀態資訊很可能快速吃光服務器的記憶體,如果是以文件形式存放在硬碟上,那麼造成的 I/O流量又不可忽略。分布式服務也是大問題,如果存在多台服務器構成的集群,我們必須考慮用戶狀態資訊如何在多台服務器之間共享。還有一個關於狀態資訊失效的問題,對於一個大型的 B2C 應用而言,很多用戶已經離開,但我們根本無法知道什麼時候改會讓他的狀態資訊失效。如果不及時清除已經失效的狀態資訊,顯然服務器的記憶體或者硬碟將會受到考驗。

Database Session State
Server Session State 的另外一種形式,也就是把狀態資訊存放在資料庫中,這樣其實仍然屬於 Server Session State ,不過是習慣把一些煩人操作交給了資料庫。

為何要把 Session 存放在 Database ?
1) 在多台 Application 之間共享 Session
2) Improve Performance

設定 Session Save Handler
如果我們需要把 Session 存放到 Database 中,必須要設定 php.ini 其中選項 Session.save_handler,有兩種方式修改:
1) 直接修改 php.ini 中的Session.save_handler = user (default 'files')
2) 用程式設定的方式
  <?php
   ini_set('Session.save_handler','user');
  ?>
Create Table for Store Sessions
設定完 Session Handler 的方式後,我們要建一個 table 存放 Session,如下 ( 以Oracle 為例 ),因為我們要用 ADODB 相關 Library,所以 table 必須附合其要求。
create table SESSIONS_xxx
(
SESSKEY  
VARCHAR2(48) not null primary key,
EXPIRY 
DATE not null,
EXPIREREF 
VARCHAR2(200),
CREATED  
DATE not null,
MODIFIED
 DATE not null,
SESSDATA
 CLOB
);


引入 ADODB 處理 Session 的 class
程式中,在 Session_start() 之前引入相關 class 並初始化相關參數,程式代碼如下:
<?php
  include_once 'YOUR_ADODB_HOME/Session/adodb-Session2.php';
  ini_set('Session.save_handler','user');
  $driver = $adapter;
  $host = $host;
  $user = $username;
  $password = $password;
  $database = $dbname;
  $options['table'] =
'Sessions_xxx';
  
ADOdb_Session::config($driver, $host, $user, $password, $database,$options);
  ?>

使用 Session

使用 Session 部分跟原來把 Session 放在 File System 時方法是一樣的,Session_start() 之後就可以像之前一樣使用 Session。您可能覺得說,這麼簡單?是的,因為我們引用了 ADODB 中已經寫好的 library,那些與 DB 交互,存取 Session 值的事情已經幫我們做好了。

如果有興趣了解 Session 如何存放到 database 的 table 中, 請打開 ADODB library 下的 adodb-Session2.php 研究其原理。限於篇幅,本次討論的內容就到這裡。

參考資料:
[1] PHP.NET http://www.php.net
[2] ADODB Manual http://phplens.com/lens/adodb/docs-adodb.htm
[3] Sessions http://en.wikipedia.org/wiki/Session_%28computer_science%29

>>回電子報首頁