91亚洲精华国内精华精华液_国产高清在线精品一区不卡_精品特级一级毛片免费观看_欧美日韩中文制服有码_亚洲精品无码你懂的网站369

http協(xié)議是WEB服務(wù)器與客戶 端(瀏覽器)相互通信的協(xié)議,它是一種無(wú)狀態(tài)協(xié)議。所謂無(wú)狀態(tài),指的是不會(huì)維護(hù)http請(qǐng)求數(shù)據(jù),http請(qǐng)求是獨(dú)立的,非持久的。而越來(lái)越復(fù)雜的WEB 應(yīng)用,需要保存一些用戶狀態(tài)信息。這時(shí)候,Session這種方案應(yīng)需而生。PHP從4.1開始支持Session管理。

session是很抽象的一個(gè)概念。我們不妨先從與它幾個(gè)息息相關(guān)的有跡可尋的小切入點(diǎn)入手,然后逐漸地認(rèn)識(shí)了解它。

session存儲(chǔ)

首先,我們?yōu)槭裁葱枰猄ession,就是因?yàn)槲覀冃枰鎯?chǔ)各個(gè)用戶的狀態(tài)數(shù)據(jù)。那么試問(wèn),如果由你來(lái)設(shè)計(jì)解決這個(gè)需求的方案,那么也許你會(huì)設(shè)置這樣一個(gè)數(shù)據(jù)表用與存儲(chǔ)各個(gè)用戶的狀態(tài)信息:
uid : 用戶唯一標(biāo)識(shí)符,區(qū)分其它用戶

created : 記錄產(chǎn)生時(shí)間

data : 存放與用戶相關(guān)的數(shù)據(jù)

max_age : 記錄的有效時(shí)間

同樣地,PHP設(shè)計(jì)管理session方案也大致如此,它分別包含了以下信息:

1. session id
      用戶session唯一標(biāo)識(shí)符,隨機(jī)生成的一串字符串,具有唯一性,隨機(jī)性。主要用于區(qū)分其它用戶的session數(shù)據(jù)。用戶第一次訪問(wèn)web頁(yè)面的時(shí)候,php的session初始化函數(shù)調(diào)用會(huì)分配給當(dāng)前來(lái)訪用戶一個(gè)唯一的ID,也稱之為session_id。

2. session data
      我們把需要通過(guò)session保存的用戶狀態(tài)信息,稱為用戶session數(shù)據(jù),也稱為session數(shù)據(jù)。

3. session file
      PHP 默認(rèn)將session數(shù)據(jù)存放在一個(gè)文件里。我們把存放session數(shù)據(jù)的文件稱為session文件。它由特殊的php.ini設(shè)置 session.save_path指定session文件的存放路徑,CentOS5.3操作系統(tǒng),PHP5.1默認(rèn)存放在/var/lib/php /session目錄中。用戶session文件的名稱,就是以sess_為前綴,以session_id為結(jié)尾命名,比如session id為vp8lfqnskjvsiilcp1c4l484d3,那么session文件名就是 sess_vp8lfqnskjvsiilcp1c4l484d3

4. session lifetime
我們把初始化session開始,直到注銷session這段期間,稱為session生命周期,這樣有助于我們理解session管理函數(shù)。

由 此,我們可見(jiàn): 當(dāng)每個(gè)用戶訪問(wèn)web, PHP的session初始化函數(shù)都會(huì)給當(dāng)前來(lái)訪用戶分配一個(gè)唯一的session ID。并且在session生命周期結(jié)束的時(shí)候,將用戶在此周期產(chǎn)生的session數(shù)據(jù)持久到session文件中。用戶再次訪問(wèn)的時(shí) 候,session初始化函數(shù),又會(huì)從session文件中讀取session數(shù)據(jù),開始新的session生命周期。

與session存儲(chǔ)相關(guān)php.ini設(shè)置

1. session.save_handler = file
用于讀取/回寫session數(shù)據(jù)的方式,默認(rèn)是files。它會(huì)讓PHP的session管理函數(shù)使用指定的文本文件存儲(chǔ)session數(shù)據(jù)

2. session.save_path =“/var/lib/php/session”
指 定保存session文件的目錄,可以指定到別的目錄,但是指定目錄必須要有httpd守護(hù)進(jìn)程屬主(比如apache或www等)寫權(quán)限,否則無(wú)法回存 session數(shù)據(jù)。當(dāng)指定目錄不存在時(shí),php session環(huán)境初始化函數(shù)是不會(huì)幫你創(chuàng)建指定目錄的,所以需要你手工建立指定目錄。
它還可以寫成這樣session.save_path =“N;/path” 其中N是整數(shù)。這樣使得不是所有的session文件都保存在同一個(gè)目錄中,而是分散在不同目錄。這對(duì)于服務(wù)器處理大量session文件是很有幫助的。(注:目錄需要自己手工創(chuàng)建)

3. session.auto_start = 0
如果啟用該選項(xiàng),用戶的每次請(qǐng)求都會(huì)初始化session。我們推薦不啟用該設(shè)置,最好通過(guò)session_start()顯示地初始化session。

Session同步數(shù)據(jù)

一 旦調(diào)用了session_start()初始化session,就意味著開始了一個(gè)session生命周期。也就是宣布了,可以使用相關(guān)函數(shù)操 作$_SESSION來(lái)管理session數(shù)據(jù)。這個(gè)session生命周期產(chǎn)生的數(shù)據(jù)并沒(méi)有實(shí)時(shí)地寫入session文件,而是通過(guò)$_SESSION 變量寄存在內(nèi)存中。那么,寄存在內(nèi)存的數(shù)據(jù)什么時(shí)候會(huì)寫入到session文件?這也是我們這一小節(jié)的主要測(cè)試內(nèi)容。

在進(jìn)行測(cè)試之前,先讓我們介紹幾個(gè)影響session數(shù)據(jù)的PHP函數(shù)、或事件

1. session_start()
      函數(shù)session_start會(huì)初始化session,也標(biāo)識(shí)著session生命周期的開始。要使用session,必須初始化一個(gè)session環(huán)境。有點(diǎn)類似于OOP概念中調(diào)用構(gòu)造函數(shù)構(gòu)創(chuàng)建對(duì)象實(shí)例一樣。
session 初始化操作,聲明一個(gè)全局?jǐn)?shù)組$_SESSION,映射寄存在內(nèi)存的session數(shù)據(jù)。如果session文件已經(jīng)存在,并且保存有session數(shù) 據(jù),session_start()則會(huì)讀取session數(shù)據(jù),填入$_SESSION中,開始一個(gè)新的session生命周期。

2. $_SESSION
      它是一個(gè)全局變量,類型是Array,映射了session生命周期的session數(shù)據(jù),寄存在內(nèi)存中。在session初始化的時(shí)候,從session文件中讀取數(shù)據(jù),填入該變量中。在session生命周期結(jié)束時(shí),將$_SESSION數(shù)據(jù)寫回session文件。

3. session_register()
      在 session生命周期內(nèi),使用全局變量名稱將注全局變量注冊(cè)到當(dāng)前session中。所謂注冊(cè),就是將變量填入$_SESSION中,值為NULL。它 不會(huì)對(duì)session文件進(jìn)行任何IO操作,只是影響$_SESSION變量。注意,它的正確寫法是 session_register(‘varname’),而不是session_register($varname)

4. session_unregister()
      與session_register操作正好相反,即在session生命周期,從當(dāng)前session注銷指定變量。同樣只影響$_SESSION,并不進(jìn)行任何IO操作。

5. session_unset()
      在 session生命周期,從當(dāng)前session中注銷全部session數(shù)據(jù),讓$_SESSION成為一個(gè)空數(shù)組。它與 unset($_SESSION)的區(qū)別在于:unset直接刪除$_SESSION變量,釋放內(nèi)存資源;另一個(gè)區(qū)別在 于,session_unset()僅在session生命周期能夠操作$_SESSION數(shù)組,而unset()則在整個(gè)頁(yè)面(page)生命周期都能 操作$_SESSION數(shù)組。session_unset()同樣不進(jìn)行任何IO操作,只影響$_SESSION數(shù)組。

6. session_destroy()
如果說(shuō)session_start()初始化一個(gè)session的話,而它則注銷一個(gè)session。意味著session生命周期結(jié)束了。在 session生命周期結(jié)整后,session_register, session_unset, session_register都將不能操作$_SESSION數(shù)組,而$_SESSION數(shù)組依然可以被unset()等函數(shù)操作。這 時(shí),session意味著是未定義的,而$_SESSION依然是一個(gè)全局變量,他們脫離了關(guān)映射關(guān)系。
通過(guò)session_destroy()注銷session,除了結(jié)束session生命周期外,它還會(huì)刪除sesion文件,但不會(huì)影響當(dāng)前$_SESSION變量。即它會(huì)產(chǎn)生一個(gè)IO操作。

7. session_regenerate_id()
      調(diào) 用它,會(huì)給當(dāng)前用戶重新分配一個(gè)新的session id。并且在結(jié)束當(dāng)前頁(yè)面生命周期的時(shí)候,將當(dāng)前session數(shù)據(jù)寫入session文件。前提是,調(diào)用此函數(shù)之前,當(dāng)前session生命周期沒(méi)有被 終止(參考第9點(diǎn))。它會(huì)產(chǎn)生一個(gè)IO操作,創(chuàng)建一個(gè)新的session文件,創(chuàng)建新的session文件的是在session結(jié)束之前,而不是調(diào)用此函 數(shù)就立即創(chuàng)建新的session文件。

8. session_commit()
      session_commit() 函數(shù)是session_write_close()函數(shù)的別名。它會(huì)結(jié)束當(dāng)前session的生命周期,并且將session數(shù)據(jù)立即強(qiáng)制寫入 session文件。不推薦通過(guò)session_commit()來(lái)手工寫入session數(shù)據(jù),因?yàn)镻HP會(huì)在頁(yè)面生命周期結(jié)束的時(shí)候,自動(dòng)結(jié)束當(dāng)前沒(méi) 有終止的session生命周期。它會(huì)產(chǎn)生一個(gè)IO寫操作

9. end session
      結(jié) 束session,默認(rèn)是在頁(yè)面生命周期結(jié)束的之前,PHP會(huì)自動(dòng)結(jié)束當(dāng)前沒(méi)有終止的session。但是還可以通過(guò)session_commit()與 session_destroy()二個(gè)函數(shù)提前結(jié)束session。不管是哪種方式,結(jié)束session都會(huì)產(chǎn)生IO操作,分別不一樣。默認(rèn)情況,產(chǎn)生 一個(gè)IO寫操作,將當(dāng)前session數(shù)據(jù)寫回session文件。session_commit()則是調(diào)用該函數(shù)那刻,產(chǎn)生一個(gè)IO寫操作,將 session數(shù)據(jù)寫回session文件。而session_destroy()不一樣在于,它不會(huì)將數(shù)據(jù)寫回session文件,而是直接刪除當(dāng)前 session文件。有趣的是,不管是session_commit(),還是session_destroy()都不會(huì)清空$_SESSION數(shù)組,更 不會(huì)刪除$_SESSION數(shù)組,只是所有session_*函數(shù)不能再操作session數(shù)據(jù),因?yàn)楫?dāng)前的session生命周期終止了,即不能操作一 個(gè)未定義對(duì)象。

為了驗(yàn)證以上陳述,我們可以做以下測(cè)試
      任務(wù)1: 觀察session初始化與默認(rèn)結(jié)束session的時(shí)候,產(chǎn)生的IO操作

[root@localhost ~]# strace -p `cat /var/run/httpd.pid`
      藍(lán)色加粗,通過(guò)系統(tǒng)內(nèi)核函數(shù)open調(diào)用打開session文件,這是由session_start()產(chǎn)生的調(diào)用,
      注意這里并沒(méi)有產(chǎn)生讀文件操作。紅色部分,將一個(gè)空字符串寫入session文件。
      由此可見(jiàn)session初始化在頁(yè)面生命周期開始之時(shí),手工調(diào)用session_start可以初始化session文件,
      而在頁(yè)面生命周期結(jié)束之時(shí),會(huì)自動(dòng)地注銷session,結(jié)束當(dāng)前session生命周期,
      同時(shí)在此周期產(chǎn)生的session數(shù)據(jù)寫回session文件,我們把這種方式結(jié)束的session,稱為session默認(rèn)結(jié)束。 

任務(wù)2 觀察session_register()查看它是否會(huì)產(chǎn)生磁盤操作,還是只操作$_SESSION。

 

通 過(guò)上面的觀察,藍(lán)色部分還是由session初始化(session_start)產(chǎn)生,注意這里依然沒(méi)讀文件操作,這是因?yàn)閟ession文件為空。紅 色部分,依然是默認(rèn)結(jié)束session產(chǎn)生的文件寫操作(pwrite)。由此,我們可以知道session_register()不會(huì)對(duì)session 文件操作,即不會(huì)把$_SESSION中的數(shù)據(jù)寫回session文件,它沒(méi)有產(chǎn)生任何IO操作。而只在session生命周期是影響當(dāng) 前$_SESSION變量,即$_SESSION[‘pg_uuid’] = NULL。所以,推薦使用$_SESSION[‘pg_uuid’] = $pg_uuid;

任務(wù)3 觀察session_destroy()與session_unset()的區(qū)別

   

 

//@這里是頁(yè)面析構(gòu)的時(shí)候– 本應(yīng)該將$_SESSION數(shù)據(jù)同步到session文件, 真的嗎???
//@事實(shí),沒(méi)有發(fā)生任何IO操作,即沒(méi)有將$_SESSION數(shù)據(jù)回寫,怎么回事???
//@因?yàn)楸籹ession_destroy()消毀了session…
 
程序輸出:
   

 

[root@localhost ~]# strace -p `cat /var/run/httpd.pid`
 

藍(lán) 色部分是我們熟悉的session初始化的時(shí)候產(chǎn)生的open系統(tǒng)內(nèi)核調(diào)用。綠色部分,是一個(gè)IO讀操作,因?yàn)樯弦淮卧L問(wèn)頁(yè)面的時(shí)候,產(chǎn)生了 session數(shù)據(jù),所以這一次會(huì)將上次的session填入$_SESSION中。紅色部分,可以看出,這里調(diào)用unlink刪除session文件, 而且后面(頁(yè)面生命周期結(jié)束時(shí)),一直沒(méi)有看到前兩例看到的任何與session文件有關(guān)的IO寫操作,即沒(méi)有將$_SESSION中的數(shù)據(jù)寫回 session文件。我們也沒(méi)有在session.save_path找到相應(yīng)的session文件

[root@localhost html]# ls /var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5  ls: /var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5: No such file or directory

注意: 雖然刪除了session文件,但用戶再次訪問(wèn)web的時(shí)候,并不會(huì)給用戶重新分配一個(gè)新的session id,而是依然用該session id,并且會(huì)重新創(chuàng)建文件名相同的session文件,即sess_SESSION-ID

任務(wù)4測(cè)試并觀察session_regenerate_id行為,以及$_SESSION的變化

觀 察測(cè)試結(jié)果,藍(lán)色部分照舊是session初始化的時(shí)候產(chǎn)生的系統(tǒng)內(nèi)核open調(diào)用,接著綠色部分是一個(gè)IO讀操作,即讀取session文件中的數(shù)據(jù), 由第一個(gè)var_dump($_SESSION)輸出。隨后,往session加入新的一條已定義了的session記錄,并且通過(guò) session_commit()將記錄寫回去。紅色部分就是由session_commit產(chǎn)生的一次IO寫操作。之 后,session_unset()并沒(méi)有生效,同時(shí),我們也沒(méi)有在頁(yè)面生命周期結(jié)束的時(shí)候看到任何與session文件有關(guān)的IO寫操作。這也正說(shuō)明 了,session_commit()調(diào)用的當(dāng)下,就會(huì)將session數(shù)據(jù)寫回session文件,并且會(huì)像session_destroy一樣注銷 session,但與session_destroy不同的時(shí),session_commit不會(huì)刪除session文件,而且會(huì)將當(dāng)前的session 數(shù)據(jù)寫回session文件。我們可以查看,調(diào)用session_commit之后,session文件還是依然存在的

[root@localhost html]# ls -lt /var/lib/php/session 
 -rw------- 1 apache apache 31 Apr 11 03:18 sess_qoa6knu9fg77un8le99o1vk1c7  
 -rw------- 1 apache apache 11 Apr 11 00:08 sess_4j38nv7l1fq1bj6n80l6g9cum5  …


總結(jié):

1, 用戶注銷web應(yīng)用系統(tǒng),最好的調(diào)用方式依次是 session_unset();  session_destroy();  unset($_SESSION); 
2, 盡量將鍵與值填入$_SESSION,而不推薦使用session_register()。同樣,盡量使用unset($_SESSION[‘var’]),而不使用session_unregister()。

3, 對(duì)于可能產(chǎn)生大量session的WEB應(yīng)用,推薦使用的session.save_path的格式是session.save_path=”N:/path”。注意:這些目錄需要手工創(chuàng)建,并且有httpd守護(hù)進(jìn)程屬主寫權(quán)限。這樣做可以獲得更好的性能

4, 如果調(diào)用了session_regenerate_id()給用戶分配了新的session id。該函數(shù)并不會(huì)主動(dòng)刪除舊的session文件,需要定時(shí)清理舊的session文件,這樣更優(yōu)化。

5, 盡量不要使用session_commit()提交sessioin數(shù)據(jù),因?yàn)樗瑫r(shí)會(huì)結(jié)束當(dāng)前session,PHP默認(rèn)會(huì)在頁(yè)面生命周期的時(shí)候提交session數(shù)據(jù)到session文件

Session ID傳遞

session 終究是因?yàn)楣芾碛脩魻顟B(tài)信息才存在的。我們?cè)接戇^(guò)session id的意義:每個(gè)來(lái)訪問(wèn)用戶都會(huì)被分配一個(gè)唯一的session id,用于區(qū)分其它用戶的session數(shù)據(jù)。換句話說(shuō),session id是用戶表明身份的一種標(biāo)識(shí),就像入場(chǎng)券一樣。用戶一旦從被分配了session id之后的每次訪問(wèn)(http請(qǐng)求)都會(huì)攜帶這個(gè)session id給服務(wù)端,用于加載該用戶的session數(shù)據(jù)。那么,通過(guò)什么方式傳給服務(wù)端?這是我們這節(jié)探討的內(nèi)容。

用 戶端與服務(wù)端的web通信協(xié)議是http。而PHP通過(guò)http取得用戶數(shù)據(jù)慣用的三種方法分別是:POST方法、GET方法還有Cookie。而PHP 默認(rèn)傳遞方法正是Cookie,也是最佳方法。只有在客戶端不支持Cookie的時(shí)候(瀏覽器禁用了Cookie功能)才會(huì)通過(guò)GET方法來(lái)傳遞 session_id,即通過(guò)在URL的query_string部分傳遞session id。

確 定了傳遞方法,我們還有必要清楚一下session id的傳遞過(guò)程。用戶通過(guò)瀏覽器訪問(wèn)網(wǎng)頁(yè),將URL輸入地址欄回車,瀏覽器發(fā)出請(qǐng)求,在調(diào)用sockect send之前瀏覽器引擎會(huì)搜索有效的Cookies記錄封裝在http請(qǐng)求頭的Cookie字段,一同發(fā)送出去。服務(wù)端器接收到請(qǐng)求后,交給PHP處理。 這時(shí),session初始化函數(shù)如果在$_COOKIE中沒(méi)有找到以session_name()作為鍵值存儲(chǔ)的生素(值為session id),則會(huì)以為用戶是第一次訪問(wèn)web。作為第一次訪問(wèn)的用戶,session初始化函數(shù)總會(huì)隨機(jī)生成一個(gè)session_id并且通過(guò) setcookie()函數(shù)調(diào)用將新生成的session_id以”sesseson_name = session_id”的格式填入http響應(yīng)頭Set-Cookie字段,發(fā)送給客戶端(這樣接下來(lái)的請(qǐng)求,http請(qǐng)求頭Cookie字段都會(huì)攜帶該 Cookie記錄給web服務(wù)器)。如果初始化函數(shù)發(fā)現(xiàn)用戶端Cookies中已定義了存在$_COOKIE[‘sess_name’],則會(huì)加載 與$_COOKIE[‘sess_name’]相對(duì)應(yīng)的session文件($_COOKIE[‘sess_name’]就是session ID)。如果用戶Cookie記錄過(guò)期,則會(huì)被瀏覽器刪除。之后的下一次請(qǐng)求,服務(wù)器會(huì)以為用戶又是第一次訪問(wèn),如此循環(huán)。

讓我們通過(guò)測(cè)與來(lái)驗(yàn)證以上的陳述

第 一次訪問(wèn)/a.php的時(shí)候,請(qǐng)求包里面沒(méi)有設(shè)置任何Cookie,所以這里的Cookie字段為空。當(dāng)然服務(wù)器php也就得不到 的$_COOKIE[‘PHPSESSID’](即session id為空)。如此,服務(wù)器會(huì)以為用戶是第一次訪問(wèn)web。所以session初始化的時(shí)候,會(huì)給用戶分配一個(gè)唯一的session_id并且以 Cookie的方法傳回給了用戶端。

我們?cè)賮?lái)觀察第二次請(qǐng)求與響應(yīng),會(huì)有哪些變化:

首 先,我們觀察http請(qǐng)求,加紅色部分是第一次http請(qǐng)求頭沒(méi)有出現(xiàn)的內(nèi)容。我們可以看到,該Cookie正是第一次訪問(wèn),服務(wù)端通過(guò)Set- Cookie要求瀏覽器設(shè)置的Cookie。它們是一樣的,即session_id為bk7655dqrm5m884c9nitfi7j00。然后,我們 再觀察這次的http響應(yīng),明顯沒(méi)有再要求用戶端設(shè)置鍵為session_name()的Cookie了。

我們?cè)賮?lái)測(cè)試偽造一個(gè)session_id發(fā)送給服務(wù),觀察服務(wù)端響應(yīng)。我們寫一個(gè)測(cè)試腳本,如下:

抓到的http請(qǐng)求、響應(yīng)數(shù)據(jù)包如下:

      上面的session_id是用戶端偽造的一個(gè)值,它并不實(shí)際存在。收到這樣的請(qǐng)求,服務(wù)端并沒(méi)有檢查,而是以這個(gè)session_id創(chuàng)建了相應(yīng)的 session文件。并且,從httpd響應(yīng)頭部信息來(lái)看,并沒(méi)給用戶端分配session id(沒(méi)有Set-Cookie)。由此,我們可以推斷:只要http請(qǐng)求頭部包含了以session_name()作為鍵值的Cookie,那么服務(wù)端 就不認(rèn)為用戶是第一次訪問(wèn)web,亦不會(huì)給客戶端分配session_id。否則,分配新的session_id,并通過(guò)Set-Cookie要求瀏覽器 創(chuàng)建該Cookie.
我們?cè)賮?lái)觀察一下,通過(guò)session_regenerate_id()函數(shù)給用戶分配一個(gè)新的session_id的情況

##
上 面可以觀察得到,http請(qǐng)求頭Cookie部分帶了session id,并且這個(gè)session_id還是用戶第一次訪問(wèn)web時(shí)被分配得到的。這一次,http響應(yīng)頭跟第二次示例http響應(yīng)有些不一樣,而是像第一次 訪問(wèn)那樣通過(guò)Set-Cookie去要求用戶端瀏覽器更新用戶的session id。這意味著:session_genrate_id()給用戶端重新生成的session id也是通過(guò)Cookie的方法傳遞。

1,User01和User02第一次去訪問(wèn)/p1.php,分別被分配了一個(gè)session id。

2,User01和User02第二次訪問(wèn)web,都會(huì)使用由/p1.php分配的session_id

3,User01 因?yàn)樵L問(wèn)了/p2.php,腳本/p2.php中的session_regenerate_id()給用戶User01重新分配了一個(gè)新 session_id,從用戶User01第4次訪問(wèn)的session_id就可以看得出來(lái),與前面幾幾次的session_id不同了。

4,User02因?yàn)闆](méi)有訪問(wèn)/p2.php,也就沒(méi)有被服務(wù)端重新分配session id,一下沿用著上一次分配的session_id與session id傳遞的有關(guān)的php.ini設(shè)置

1,session.use_cookie = 1
是否采用Cookie方法傳遞session id值。默認(rèn)是1,表示啟用。

2,session.name = PHPSESSID
不 管是Cookie傳遞sessioin_id,還是GET方法傳遞session_id,都需要使用鍵值。他們的格式分別是Cookie:  sess_name=session_id;和/path.php?sess_name=session_id,其中sess_name就是由這里指定的

3,session.use_only_cookies = 0
表 示只使用Cookie 的方法傳遞session id。我們說(shuō)過(guò),傳遞cookie的方法,除了cookie,還有GET方法,GET方法是不安全的方法。在用戶端禁用了cookie的時(shí)候,會(huì)采用 GET方法傳遞session_id,可以通過(guò)這個(gè)設(shè)置盡用GET方法傳遞session_id。

4,session.cookie_lifetime = 0, session.cookie_path = / 以及session.cookie_domain =
如 果使用Cookie方法傳遞session_id的話,這里分別指定了cookie有效域、目錄和時(shí)間。分別對(duì)應(yīng)setcookie()函數(shù)的形 參$expire、$path和$domain。其中cookie_lifetime=0表示直到關(guān)閉瀏覽器才刪除Cookie。還可以使用 session_set_cookie_params()函數(shù)修改這些值。

5,session_name([string $name])
獲 取或更新session_name。如果傳了name,則表示不使用默認(rèn)的名稱PHPSESSID(由session.name)指定,否則獲取當(dāng)前 session_name。注意:如果設(shè)置session_name,則必須在session_start()之前調(diào)用才生效。

6,session_id([string $id])
與session_name()類似,但它是讀取或者設(shè)置session_id的方法。同樣,設(shè)置session_id的話,必須在session_start()之前調(diào)用才有效。

7,session_set_cookie_params()和session_get_cookie_params()
通 過(guò)session_set_cookie_params()可以重新設(shè)定session.cookie_lifetime, session.cookie_path以及session.cookie_domain這三個(gè)php.ini設(shè)置。而 session_get_cookie_params()則是獲取這些設(shè)定的值。

Session回收

通過(guò)上文幾節(jié)介紹,我們知道session數(shù)據(jù)存放在服務(wù)端指定的session.save_path目錄中,同時(shí)會(huì)在用戶端存放一條Cookie用以記錄分配給用戶的session id。所以,session數(shù)據(jù)失效分服務(wù)端和客戶端,要?jiǎng)h除(回收)的對(duì)象也很清楚:
1,服務(wù)端:刪除過(guò)期的session文件,啟動(dòng)PHP GC回收。
2,用戶端:使存儲(chǔ)了過(guò)期session_id的用戶端Cookie記錄過(guò)期。通過(guò)將Cookie的Expire設(shè)置為負(fù)值,要求客戶端刪除Cookie。
服務(wù)端:刪除過(guò)期的session文件
PHP GC進(jìn)程被啟動(dòng)以后,則會(huì)掃描session.save_path,找出過(guò)期的session,并刪除該session文件。所謂,過(guò)期的 session,是指操作系統(tǒng)當(dāng)前時(shí)間與session文件最后訪問(wèn)時(shí)間之差大于session.gc_maxlifetime的話,該session認(rèn) 為是過(guò)期了。注意:有時(shí)候,你會(huì)發(fā)現(xiàn),即便是文件過(guò)期了,有可能也沒(méi)有被及時(shí)地刪除掉。這是因?yàn)?,每次session初始化的時(shí)候,并不會(huì)都啟動(dòng)PHP GC進(jìn)程的,啟動(dòng)GC進(jìn)程會(huì)大大降低php的運(yùn)行效率。所有一個(gè)啟動(dòng)概率,這個(gè)概率由php.ini設(shè)定session.gc_probability / session.gc_divisor二個(gè)設(shè)置決定,默認(rèn)概率是1%(1/1000)。這意味著,每1000次用戶請(qǐng)求中,會(huì)啟動(dòng)1次PHP GC回收session文件。比如,我們下面看到的,過(guò)期的session文件依然存在:

# date;find /var/lib/php/session -type f -atime -1440 -print |xargs ls -lt  
-rw------- 1 apache apache  0 Apr 12 20:01 /var/lib/php/session/sess_5tlaq5a8im3ob1bikn62motpv7  
-rw------- 1 apache apache  0 Apr 12 19:39 /var/lib/php/session/sess_f7q6jfdug4ekfsjhop6jftgna7  
-rw------- 1 apache apache  0 Apr 12 17:03 /var/lib/php/session/sess_dk7655dqrm5m884c9nitfi7j00

我們可以通過(guò)編輯設(shè)置,來(lái)驗(yàn)證啟動(dòng)php session的GC機(jī)制

從 上面藍(lán)色部分可以看出,通過(guò)用stat64檢查session文件的狀態(tài),如果發(fā)現(xiàn)過(guò)期了,則會(huì)通過(guò)調(diào)用系統(tǒng)內(nèi)核函數(shù)ulink()刪除過(guò)期的 session文件。可見(jiàn),session初始化的時(shí)候會(huì)啟動(dòng)GC, GC會(huì)掃描session.save_path中的所有session文件,查看他們狀態(tài)并且將過(guò)期的文件刪除。正因?yàn)槿绱?,所以默認(rèn)設(shè)置啟動(dòng)的概率是 1/1000。

客戶端:刪除過(guò)期session id的cookie記錄
如 果用戶發(fā)現(xiàn)session已經(jīng)過(guò)期,但是服務(wù)端的GC還沒(méi)有啟動(dòng),服務(wù)端可以手通過(guò)手工代碼setcookie的方式要求用戶端瀏覽器刪除鍵值為 session_name()的Cookie記錄。這樣,下回訪問(wèn)的時(shí)候,瀏覽器以為用戶是第一次訪問(wèn),并且重新給訪問(wèn)用戶分配一個(gè)新的 session_id。較好的做法類似這樣:

   
上面觀察可以知道,通過(guò)訪問(wèn)/session_destroy.php,它要求客戶端將session_id的Cookie記錄刪除。而接下來(lái)訪問(wèn) /p1.php的時(shí)候,http請(qǐng)求頭沒(méi)有通過(guò)Cookie將用戶的session id帶給服務(wù)器(因?yàn)閯偙灰髣h除)。而第二次請(qǐng)求/p1.php的http響應(yīng)里頭可以看到,服務(wù)端又給用戶重新分配了一個(gè)新的session id,而且不會(huì)繼續(xù)使用過(guò)去的session數(shù)據(jù)。

與session回收相關(guān)的php.ini設(shè)置:

1, session.gc_probability和session.gc_divisor
由 這二個(gè)函數(shù)決定了啟用GC的概率,默認(rèn)是1/1000。也就是說(shuō),每一千次用戶請(qǐng)求中有一次會(huì)啟動(dòng)GC回收session。啟動(dòng)GC進(jìn)程不宜過(guò)于頻繁。上 面的例子,我們可以看到,它會(huì)每次檢查session.save_path目錄下每個(gè)文件的狀態(tài)。這樣會(huì)降低php的執(zhí)行效率。

2, session.gc_maxlifetime = 1440
設(shè)置session存活時(shí)間,單位是秒。每次GC啟動(dòng)后, 會(huì)通過(guò)stat得到session文件最后訪問(wèn)的unix時(shí)間,通過(guò)現(xiàn)在時(shí)間減去文件最后訪問(wèn)時(shí)間之間大于session.gc_maxlifetime,則會(huì)刪除該文件。

總結(jié)

1, PHP使用Cookie的方法傳遞session id。盡量不要使用GET方法傳遞session id,因?yàn)檫@樣很不安全。

2, 可以通過(guò)setcookie()的方法,將客戶端的session id的Cookie記錄刪除。

3, PHP GC進(jìn)程由session初始化啟動(dòng)。但不是每一次用戶請(qǐng)求都會(huì)被啟動(dòng),它的啟動(dòng)概率默認(rèn)是1/1000。過(guò)于頻繁訪問(wèn)的網(wǎng)站,并發(fā)量大的網(wǎng)站,可減小PHP GC的啟動(dòng)頻率。PHP GC回收session會(huì)降低php的執(zhí)行效率。

4, 通過(guò)下面代碼,優(yōu)化session回收

 

session_start();
if (isset($_SESSION['SESS_TIMEOUT'])) {
  if ($_SERVER['REQUEST_TIME'] > $_SESSION['SESS_TIMEOUT']) {
    setcookie(session_name(), session_id(), -1, ‘/’);
    session_unset();
    session_destroy();
  }
} else {
  $_SESSION['SESS_TIMEOUT'] = $_SERVER['REQUEST_TIME'] + 3600;
}

穩(wěn)定

產(chǎn)品高可用性高并發(fā)

貼心

項(xiàng)目群及時(shí)溝通

專業(yè)

產(chǎn)品經(jīng)理1v1支持

快速

MVP模式小步快跑

承諾

我們選擇聲譽(yù)

堅(jiān)持

10年專注高端品質(zhì)開發(fā)
  • 返回頂部