程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP session的詳細分析

PHP session的詳細分析

編輯:關於PHP編程

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人生
 
 
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved