1.PHP session 工作原理
Session文件儲存於服務器端,,默認情況下SESSION 文件保存的目錄由session.save_path 指定,文件名以sess_ 為前綴,後跟SESSION ID,如:sess_c72665af28a8b14c0fe11afe3b59b51b。可以根據客戶端提供的session id來得到用戶的文件,取得變量的值,session id可以使用客戶端的Cookie或者Http1.1協議的Query_String(就是訪問的URL的“?”後面的部分)來傳送給服務器,然後服務器讀取Session的目錄。也就是說,session id是取得存儲在服務上的session變量的身份證。
當代碼session_start();運行的時候,就在服務器上產生了一個session文件,隨之也產生了與之唯一對應的一個session id,定義session變量以一定形式存儲在剛才產生的session文件中。通過session id,可以取出定義的變量。跨頁後,為了使用session,你必須又執行session_start();將又會產生一個session文件,與之對應產生相應的session id,用這個session id是取不出前面提到的第一個session文件中的變量的,因為這個session id不是打開它的“鑰匙”。如果在session_start();之前加代碼session_id($session id);將不產生新的session文件,直接讀取與這個id對應的session文件。
2. Session常見函數及用法
2.1 Session_start(): 開始一個會話或者返回已經存在的會話。
這個函數沒有參數,且返回值均為true。如果你使用基於cookie的session,那麼在使用Session_start()之前浏覽器不能有任何輸出.可以在php.ini裡啟動session.auto_start=1,這樣就無需每次使用session之前都要調用session_start()。但啟用該選項也有一些限制,如果確實啟用了session.auto_start,則不能將對象放入會話中,因為類定義必須在啟動會話之前加載以在會話中重建對象。
2.2 注冊SESSION變量 :
PHP5使用$_SESSION[‘xxx’]=xxx注冊SESSION全局變量。注意session_register(),
session_unregister ,session_is_registered在php5下不再使用,除非在php.ini裡把
register_globle設為on,不過出於安全考慮,強烈建議關閉register_globle。
HTTP_SESSION_VARS也不提倡使用了,官方建議用$_SESSION代替之。
Page1.php
<?php
session_start(); //使用SESSION前必須調用該函數。
$_SESSION[‘name’]=”我是黑旋風李逵!”; //注冊一個SESSION變量
$_SESSION[‘passwd’]=”mynameislikui”;
$_SESSION[‘time’]=time();
//如果客戶端支持cookie,可通過該鏈接傳遞session到下一頁。
echo '<br/><a href="page2.php">通過COOKIE傳遞SESSION</a>';
//客戶端不支持cookie時,使用該辦法傳遞session.
echo '<br /><a href="page2.php?' . SID . '">通過URL傳遞SESSION</a>';
Page2.php
<?php
session_start();
echo $_SESSION['name'];
echo $_SESSION['passwd'];
echo date('Y m d H:i:s', $_SESSION['time']);
echo '<br /><a href="page1.php">返回上一頁</a>';
?>
2.3 session_id ([ string $id ] ):Get and/or set the current session id
php5中既可以使用session_id(),也可以通過附加在url上的SID取得當前會話的session_id和session_name。
如果session_id()有具體指定值的話(即指定了參數$id),將取代當前的session_id值。使用該函數前必須啟動會話:session_start();
例子:手動設置Session 的生存期:
<?php
session_start();
// 保存一天
$lifeTime = 24 * 3600;
setcookie(session_name(), session_id(), time() + $lifeTime, "/");
?>
其實Session 還提供了一個函數session_set_cookie_params(); 來設置Session 的生存期的,該函數必須在session_start() 函數調用之前調用:
<?php
// 保存一天
$lifeTime = 24 * 3600;
session_set_cookie_params($lifeTime);
session_start();
$_SESSION["admin"] = true;
?>
如果客戶端使用IE 6.0 ,session_set_cookie_params(); 函數設置Cookie 會有些問題,所以我們還是手動調用setcookie 函數來創建cookie。
2.4 檢查session是否存在?
在以往的php版本中通常使用session_is_register()檢查session是否存在,如果您使用$_SESSION[‘XXX’]=XXX來注冊會話變量,則session_is_register()函數不再起作用。你可以使用
isset($_SESSION[‘xxx’])來替代。
2.5更改session_id session_regenerate_id([bool $delete_old_session]) 更改成功則返回true,失敗則返回false。
使用該函數可以為當前session更改session_id,但默認不改變當前session的其他信息,除非$delete_old_session為true。例如:
<?php
session_start();
$old_sessionid = session_id();
session_regenerate_id();
$new_sessionid = session_id();
echo "原始SessionID: $old_sessionid<br />";
echo "新的SessionID: $new_sessionid<br />";
echo"<pre>";
print_r($_SESSION);
echo"</pre>";
?>
2.6 session_name() 返回當前session的name或改變當前session的name。如果要改變當前session的name,必須在session_start()之前調用該函數。注意:session_name不能只由數字組成,它至少包含一個字母。否則會在每時每刻都生成一個新的session id.
session改名示例:
<?php
$previous_name = session_name("WebsiteID");
echo "新的session名為:$previous_name<br />";
?>
2.7 如何刪除session
(1) unset ($_SESSION['xxx']) 刪除單個session,unset($_SESSION['xxx']) 用來unregister一個已注冊的session變量。其作用和session_unregister()相同。session_unregister()在PHP5中不再使用,可將之打入冷宮。
unset($_SESSION) 此函數千萬不可使用,它會將全局變量$_SESSION銷毀,而且還沒有可行的辦法將其恢復。用戶也不再可以注冊$_SESSION變量。
(2) $_SESSION=array() 刪除多個session
(3) session_destroy()結束當前的會話,並清空會話中的所有資源。該函數不會unset和當前session相關的全局變量(globalvariables),也不會刪除客戶端的session cookie.PHP默認的session是基於cookie的,如果要刪除cookie的話,必須借助setcookie()函數。
下面是PHP官方關於刪除session的案例:
<?php
// 初始化session.
session_start();
/*** 刪除所有的session變量..也可用unset($_SESSION[xxx])逐個刪除。****/
$_SESSION = array();
/***刪除sessin id.由於session默認是基於cookie的,所以使用setcookie刪除包含session id的cookie.***/
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-42000, '/');
}
// 最後徹底銷毀session.
session_destroy();
?>
由此我們可以得出刪除Session的步驟:
①session_start()
②$_SESSION=array()/unset($_SESSION['xxx'])
③session_destroy()
3. Session跨頁傳遞問題:
3.1有兩種方法傳遞一個會話ID:cookie URL 參數
會話模塊支持這兩種方法。cookie 更優化,但由於不總是可用,也提供替代的方法。第二種方法直接將會話ID 嵌入到URL 中間去。
PHP 可以透明地轉換頁面之間的鏈接。如果使用低於PHP 4.2的版本,則需要手工在編譯PHP 時激活,在Unix 下,用--enable-trans-sid 配置選項。如果此配置選項和運行時選項session.use_trans_sid 都被激活(修改php.ini),相對URI 將被自動修改為包含會話ID。
Note: 非相對的URL 被假定為指向外部站點,因此沒有附加SID,因為這可能是個安全隱患將SID 洩露給不同的服務器。
另外,也可以用常量SID。如果客戶端沒有發送會話cookie ,則SID 的格式為session_name=session_id,否則就為一個空字符串。因此可以無條件將其嵌入到URL 中去。
3. 2 解決session跨頁傳遞問題的三條途徑
①客戶端禁用了cookie。
②浏覽器出現問題,暫時無法存取cookie
③php.ini中的session.use_trans_sid = 0或者編譯時沒有打開--enable-trans-sid選項
當客戶端的Cookie被禁用或出現問題時,PHP會自動把session id附著在URL中,這樣再通過session id就能跨頁使用session變量了。但這種附著也是有一定條件的:“php.ini中的session.use_trans_sid = 1或者編譯時打開打開了--enable-trans-sid選項”;
明白了以上的道理,我們就可以得出解決session跨頁傳遞問題的三條途徑:
1、設置php.ini中的session.use_trans_sid = 1或者編譯時打開打開了--enable-trans-sid選項,讓PHP自動跨頁傳遞session id。
(有人說:但在測試的時候,修改php.ini哪種方式在頁面中用header('location: xx.php') 和javascript window.location=xx.php 情況下沒有達到想要的效果。目前發現在<a href='xx.php'>xx</a>中正常。)
2、手動通過URL傳值、隱藏表單傳遞session id。
3、用文件、數據庫等形式保存session_id,在跨頁過程中手動調用。
下面舉例說明:
第一種情況:
page1.php
<?php
session_start();
$_SESSION['var1']="中華人民共和國";
$url="<a href="."\"s2.php\">下一頁</a>";
echo $url;
?>
page2.php
<?php
session_start();
echo "傳遞的session變量var1的值為:".$_SESSION['var1'];
?>
運行以上代碼,在客戶端cookie正常的情況下,應該可以在得到結果“中華人民共和國”。
現在你手動關閉客戶端的cookie,再運行,可能得不到結果了吧。如果得不到結果,再“設置php.ini中的session.use_trans_sid = 1或者編譯時打開打開了--enable-trans-sid選項”,又得到結果“中華人民共和國”
第二種途徑:
s1.php
<?php
session_start();
$_SESSION['var1']="中華人民共和國";
$sn = session_id();
//PHP5定義了一個常量SID來表示session_id(),$url還可以寫成$url='<a href="page2.php?' . SID . '">下一頁</a>';
$url="<a href="."\"s2.php?s=".$sn."\">下一頁</a>";
echo $url;
?>
s2.php
<?php
session_id($_GET['s']);
session_start();
echo "傳遞的session變量var1的值為:www.2cto.com".$_SESSION['var1'];
?>
第三種途徑:
login.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Login</title>
<meta http-equiv="Content-Type" content="text/html; charset=??????">
</head>
<body>
請登錄:
<form name="login" method="post" action="mylogin1.php">
用戶名:<input type="text" name="name"><br>
口 令:<input type="password" name="pass"><br>
<input type="submit" value="登錄">
</form>
</body>
</html>
mylogin1.php
<?php
$name=$_POST['name'];
$pass=$_POST['pass'];
if(!$name || !$pass) {
echo "用戶名或密碼為空,請<a href=\"login.html\">重新登錄</a>";
die();
}
if (!($name=="laogong" && $pass=="123")) {
echo "用戶名或密碼不正確,請<a href=\"login.html\">重新登錄</a>";
die();
}
//注冊用戶
ob_start(); // Turn on output buffering
session_start();
$_SESSION['user']= $name;
$psid=session_id();
$fp=fopen("e:\\tmp\\phpsid.txt","w+");
fwrite($fp,$psid);
fclose($fp);
//身份驗證成功,進行相關操作
echo "已登錄<br>";
echo "<a href=\"mylogin2.php\">下一頁</a>";
?>
mylogin2.php
<?php
$fp=fopen("e:\\tmp\\phpsid.txt","r");
$sid=fread($fp,1024);
fclose($fp);
session_id($sid);
session_start();
if(isset($_SESSION['user']) && $_SESSION['user']="laogong" ) {
echo "已登錄!";
}
else {
//成功登錄進行相關操作
echo "未登錄,無權訪問";
echo "請<a href=\"login.html\">登錄</a>後浏覽";
die();
}
?>
4.關於多服務器共享同一session的解決辦法
稍大一些的網站,通常都會有好幾個服務器,每個服務器運行著不同功能的模塊,使用不同的二級域名,而一個整體性強的網站,用戶系統是統一的,即一套用戶名、密碼在整個網站的各個模塊中都是可以登錄使用的。各個服務器共享用戶數據是比較容易實現的,只需要在後端放個數據庫服務器,各個服務器通過統一接口對用戶數據進行訪問即可。但還存在一個問題,就是用戶在這個服務器登錄之後,進入另一個服務器的別的模塊時,仍然需要重新登錄,這就是一次登錄,全部通行的問題,映射到技術上,其實就是各個服務器之間如何實現共享SESSION 數據的問題。
想要共享SESSION 數據,那就必須實現兩個目標:一個是各個服務器對同一個客戶端產生的SESSION ID 必須相同,並且可通過同一個COOKIE 進行傳遞,也就是說各個服務器必須可以讀取同一個名為PHPSESSID 的COOKIE;另一個是SESSION 數據的存儲方式/位置必須保證各個服務器都能夠訪問到。簡單地說就是多服務器共享客戶端的SESSION ID,同時還必須共享服務器端的SESSION 數據。
第一個目標的實現其實很簡單,只需要對COOKIE 的域(domain)進行特殊地設置即可,默認情況下,COOKIE 的域是當前服務器的域名/IP 地址,而域不同的話,各個服務器所設置的COOKIE 是不能相互訪問的,如www.2cto.com 的服務器是不能讀寫www.bbb.com 服務器設置的COOKIE 的。這裡我們所說的同一網站的服務器有其特殊性,那就是他們同屬於同一個一級域,如:aaa.infor96.com 和www.infor96.com 都屬於域.infor96.com,那麼我們就可以設置COOKIE 的域為.infor96.com,這樣aaa.infor96.com、www.infor96.com 等等都可以訪問此COOKIE。PHP 代碼中的設置方法如下:
CODE:
ini_set('session.cookie_domain', '.infor96.com');
第二個目標的實現可以使用文件共享方式,如NFS 方式,但設置、操作上有些復雜。我們可以參考先前所說的統一用戶系統的方式,即使用數據庫來保存SESSION 數據,這樣各個服務器就可以方便地訪問同一個數據源,獲取相同的SESSION 數據了。
關於如何將session放入數據庫可以見《php 程序設計》,和以下網頁
http://www.eb163.com/article.php?id=75&PHPSESSID=d226cc07cec0580ec7dad47119ee4667摘自 河大李信的Crazy Coding人生