技術交流

Store Sessions in Database with ADODB

Dennis Dennis

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

Session 是 Web Application 中常用的一種保持 Client 與 Server 會話狀態的技術。因為 HTTP 無法保存狀態,所以實現 Session State 的目的,也就是要想辦法把狀態保存起來。按照 Session 保存的位置, Session State 模式被分為三種。

  • 將 Session 儲存在客戶端 - Client Session State
  • 將 Session 儲存在服務器 ( File System) - Server Session State
  • 將 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?

  • 在多台 Application 之間共享 Session
  • Improve Performance

設定 Session Save Handler

如果我們需要把 Session 存放到 Database 中,必須要設定 php.ini 其中選項 Session.save_handler,有兩種方式修改:

  • 直接修改 php.ini 中的Session.save_handler = user (default 'files')
  • 用程式設定的方式 ini_set('Session.save_handler','user');

設定完 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 並初始化相關參數


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

如果有興趣了解 Session 如何存放到 database 的 table 中, 請打開 ADODB library 下的 adodb-Session2.php 研究其原理。