大家都知道SESSION是不可以跨域的,也就是說: A.WEMVC.COM這個域的可執行檔不可以訪問到B.WEMVC.COM的SESSION,這個是SESSION的特性,同樣也是出於安全形度才這樣的.
在一般情況下,一個網站只有一個網域名稱,但是也有些網站架構是由多個子網域名稱組建的.所以就需要SESSION可以跨子域被訪問到,這樣才可以實現使用者的跨域登入.就是說客戶在A下登入的,同樣B也同時登入了,不需要使用者再次登入,同時也實現了參數的跨域傳遞.當然不可跨域的SESSION本身已經可以協助我們做很多事情了,那麼跨域後的SESSION呢.讀到這裡是否很激動人心,當然你也可能是正在為SESSION跨域而發愁而找到這篇文章的,同樣也祝賀你.我們長話斷說了,開始我們今天的課程:COOKIE與SESSION聯用實現SESSION跨域.
首先讓我們再重新溫習下PHP中的COOKIE和SESSION:
COOKIE:
定義:
cookie 常用於識別使用者。cookie 是伺服器留在使用者電腦中的小檔案。每當相同的電腦通過瀏覽器請求頁面時,它同時會發送 cookie。通過 PHP,您能夠建立並取回 cookie 的值。PS:其中文名叫”曲奇”.
在PHP中用setCookie函數來設定COOKIE,該函數一共有7個參數(在此我要向曾經我面試過的一位同仁道歉,當時我把答案說成了6個,SORRY~,同時我也提醒廣大作家儘快更新自己的文章,在PHP5.2.0版本中已經增加為7個參數.),這7個參數分別為 string $name [, string $value [, int $expire [, string $path [, string $domain [, bool $secure [, bool $httponly ]]]]]] .
name The name of the cookie. 規定 cookie 的名稱。
value The value of the cookie. This value is stored on the clients computer; do not store sensitive information. Assuming the name is ‘cookiename’, this value is retrieved through $_COOKIE['cookiename'] 規定 cookie 的值。
expire The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. In other words, you’ll most likely set this with the time() function plus the number of seconds before you want it to expire. Or you might use mktime(). time()+60*60*24*30 will set the cookie to expire in 30 days. If set to 0, or omitted, the cookie will expire at the end of the session (when the browser closes).規定 cookie 的有效期間。
Note: You may notice the
expire parameter takes on a Unix timestamp, as opposed to the date format
Wdy, DD-Mon-YYYY HH:MM:SS GMT, this is because PHP does this conversion internally.
expire is compared to the client’s time which can differ from server’s time.
path The path on the server in which the cookie will be available on. If set to ‘/’, the cookie will be available within the entire domain . If set to ‘/foo/’, the cookie will only be available within the /foo/ directory and all sub-directories such as /foo/bar/ of domain . The default value is the current directory that the cookie is being set in.規定 cookie 的伺服器路徑。
domain The domain that the cookie is available. To make the cookie available on all subdomains of example.com then you’d set it to ‘.example.com’. The . is not required but makes it compatible with more browsers. Setting it to www.example.com will make the cookie only available in the www subdomain. Refer to tail matching in the » spec for details.規定 cookie 的網域名稱。
secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client. When set to TRUE, the cookie will only be set if a secure connection exists. The default is FALSE. On the server-side, it’s on the programmer to send this kind of cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).規定是否通過安全的 HTTPS 串連來傳輸 cookie。
httponly When TRUE the cookie will be made accessible only through the HTTP protocol. This means that the cookie won’t be accessible by scripting languages, such as JavaScript. This setting can effectly help to reduce identity theft through XSS attacks (although it is not supported by all browsers). Added in PHP 5.2.0. TRUE or FALSE.規定是否必須通過HTTP協議來定義訪問COOKIE,防止XSS攻擊.
SESSION全面教程
SESSION在這裡就不過多的講解了,主要是:
- session_cache_expire — Return current cache expire
- session_cache_limiter — Get and/or set the current cache limiter
- session_commit — Alias of session_write_close
- session_decode — Decodes session data from a string
- session_destroy — Destroys all data registered to a session
- session_encode — Encodes the current session data as a string
- session_get_cookie_params — Get the session cookie parameters
- session_id — Get and/or set the current session id
- session_is_registered — Find out whether a global variable is registered in a session
- session_module_name — Get and/or set the current session module
- session_name — Get and/or set the current session name
- session_regenerate_id — Update the current session id with a newly generated one
- session_register — Register one or more global variables with the current session
- session_save_path — Get and/or set the current session save path
- session_set_cookie_params — Set the session cookie parameters
- session_set_save_handler — Sets user-level session storage functions
- session_start — Initialize session data
- session_unregister — Unregister a global variable from the current session
- session_unset — Free all session variables
- session_write_close — Write session data and end session
哈哈,不是我懶噢,這裡只講跨域.
OK,大概溫習了下COOKIE和SESSION,開始實現我們的跨域.
首先我描述下我的思路,COOKIE可以指定網域名稱,也就是說它可以跨域子域,例如:setcookie(’name’,'joshua’,time()+3600*24,’/',’wemvc.com’),那麼A.wemvc.com,B.wemvc.com都可以訪問到$_COOKIE['name'],值也均為’joshua’.同理,SESSION ID也可以設定成這個網域名稱,那麼A.wemvc.com和B.wemvc.com都可以得到同一個SESSION ID,那麼我們的目的也就達到了.因為知道了同一個SESSION ID就可以訪問到這個SESSION中的值了.SESSION有多種方式儲存,檔案\資料庫\記憶體等,我們採用資料庫儲存,因為如果A.wemvc.com,B.wemvc.com不在同一台伺服器上,那麼記憶體和檔案的儲存方式就很難實現跨域了,至於到底又沒有方法,本人還沒有試過.
首先在資料庫中建立一張SESSION表:
CREATE TABLE `sessions` (
`sid` varchar(32) NOT NULL default '',
`expiry` int(20) unsigned NOT NULL default '0',
`value` text NOT NULL,
PRIMARY KEY (`sid`),
KEY `expiry` (`expiry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
然後寫一個類,這個類用於讀取\插入\更新\刪除以及記憶體回收SESSION
class session{
private $db;
function __construct($db){
$this->db=$db;
}
public function open($save_path,$session_name){
return true;
}
public function close(){
$this->db=null;
return true;
}
public function read($sid){
$rs=$this->db->query("select * from sessions where sid='".$sid."'");
foreach ($rs as $row){
return $row['value'];
}
return null;
}
public function write($sid,$value){
if(is_null($oldvalue=$this->read($sid))){
//insert
return $this->db->query(”insert into sessions (sid,expiry,value)values(’”.$sid.”‘,’”.time().”‘,’”.$value.”‘)”);
}else{
//update
return $this->db->query(”update sessions set expiry=’”.time().”‘,value=’”.$value.”‘ where sid=’”.$sid.”‘”);
}
}
public function destroy($sid){
return $this->db->query(”delete from sessions where sid=’”.$sid.”‘”);
}
public function gc($max_life_time){
return $this->db->query(’delete from sessions where expiry+’.$max_life_time.’<’.time());
}
}
我來解釋下這個類:
private $db; 類的DATABASE屬性.
function __construct($db) 類的建構函式,在聲明類時,可以直接傳遞DB屬性到類中,當然如果還不明白可以先GOOGLE一下”PHP 類 construct 方法”;
public function open($save_path,$session_name) session開啟,沒有什麼花頭,直接返回TRUE;
public function close() session關閉,同理open,但注意要關閉DB串連;
public function read($sid) session讀取,傳值SID,在資料表中將這個SID的VALUE作為傳回值返回;
public function write($sid,$value) session的寫入與更新,這個你會有疑問,為什麼set expiry=’”.time().”‘,稍後答案在清空到期SESSION GC方法中便會揭曉;
public function destroy($sid) session的銷毀,很簡單,就是把資料表中等於這個SID的資料刪除掉;
public function gc($max_life_time) 清空到期session,把超過max_life_time的SESSION都銷毀掉,也就是SESSION的建立時間加上最大存留時間小於現在時間( expiry+’.$max_life_time.’<’.time())的SESSION資料刪除掉,這下你會明白為什麼在寫入和更新SESSION的方法中為什麼寫目前時間了吧,當然這個寫法不是絕對的,隨個人意願只要你的SQL寫正確了,也就可以了.
好我們接著來看更重要的部分:
上面的類中需要一個資料庫連結屬性,所以聲明對象的時候需要這樣:
$session=new session(your db connect adapter);
資料庫連結我可以提供大家一個PDO的方法,參照使用:
function connect_db($arrPDODB){
$db=new PDO($arrPDODB['db_driver'].’:host=’.$arrPDODB['db_host'].’;dbname=’.$arrPDODB['db_name'],$arrPDODB['db_user'],$arrPDODB['db_password']);
$db->query(”set names ‘utf8′”);
return $db;
}
SO,上面聲明對象部分你可以這樣寫:
$session=new session(connect_db($arrPDODB));
接下來:
//設定色session id的名字
ini_set('session.name', 'sid');
//不使用 GET/POST 變數方式
ini_set('session.use_trans_sid', 0);
//設定記憶體回收最大存留時間
ini_set('session.gc_maxlifetime', 3600);
//使用 COOKIE 儲存 SESSION ID 的方式
ini_set('session.use_cookies', 1);
ini_set('session.cookie_path', '/');
//多主機共用儲存 SESSION ID 的 COOKIE,注意此處網域名稱為頂層網域
ini_set('session.cookie_domain', ' wemvc.com');
//將 session.save_handler 設定為 user,而不是預設的 files
session_module_name('user');
session_set_save_handler(array($session,'open'),
array($session,'close'),
array($session,'read'),
array($session,'write'),
array($session,'destroy'),
array($session,'gc'));
以上都是SESSION的設定,不明白的多搜尋下手冊,我喜歡刨根究底這樣的學習方式,這樣你可以學透一個知識點,而不是知道一知半解,就認為自己懂了或者會了.
最後在你需要的地方將SESSION啟動:
session_start();
最後再提供一個如何防止Session偽造攻擊的博文,希望能夠仔細閱讀.
好了,大功告成,只要在每個執行檔案之前包含這個類,並啟動它,你的程式可以跨域了,呵呵.當然也可以跨頂層網域.你可以在我寫出下一篇博文之前自己先研究下啊.
另外,先說一句,其實AJAX也可以跨子域,當時給我下一篇博文作鋪墊了.哈哈,歡迎大家與我一同討論學習.
2008年9月26日更新:
新增了一個demo程式,程式很簡單,沒有寫入庫的東西,適合新手學習.
附:
demo_session_1
程式講解:很簡單的 a b 兩個檔案夾代表你兩個域,把你的虛擬機器設定為a.yourdomain.com、b.yourdomain.com就可以了。先把這個搞懂,再考慮session入庫的事情。session入庫主要是因為一個網站有多台伺服器的情況下,若session還是以預設的檔案型儲存的話,多伺服器是行不通的。
demo_session 2
程式講解:這份程式添加了入庫功能,資料表的建立,檔案上面有的。