1. 程式人生 > >PHP強化之14 - cookie與session

PHP強化之14 - cookie與session

一、會話

在講理Cookie與Session之前,寫這裡先引入一個叫做會話的概念。

在計算機術語中,會話是指一個終端使用者與互動系統進行通訊的過程,比如從輸入賬戶密碼進入作業系統到退出作業系統就是一個會話過程。會話較多用於網路上,TCP的三次握手就建立了一個會話,TCP關閉連線就是關閉會話。

會話跟蹤是Web程式中常用的技術,用來跟蹤使用者的整個會話。常用的會話跟蹤技術是Cookie與Session。Cookie通過在客戶端記錄資訊確定使用者身份,Session通過在伺服器端記錄資訊確定使用者身份。

Web應用程式是使用HTTP協議傳輸資料的。HTTP協議是無狀態的協議。一旦資料交換完畢,客戶端與伺服器端的連線就會關閉,再次交換資料需要建立新的連線。這就意味著伺服器無法從連線上跟蹤會話。而使用會話跟蹤技術,則可以彌補HTTP協議無狀態的不足。

二、COOKIE

1、簡介

Cookie技術是客戶端的解決方案,Cookie就是由伺服器發給客戶端的特殊資訊,而這些資訊以文字檔案的方式存放在客戶端,然後客戶端每次向伺服器傳送請求的時候都會帶上這些特殊的資訊。

讓我們說得更具體一些:當用戶使用瀏覽器訪問一個支援Cookie的網站的時候,使用者會提供包括使用者名稱在內的個人資訊並且提交至伺服器;接著,伺服器在向客戶端回傳相應的超文字的同時也會發回這些個人資訊,當然這些資訊並不是存放在HTTP響應體(Response Body)中的,而是存放於HTTP響應頭(Response Header);當客戶端瀏覽器接收到來自伺服器的響應之後,瀏覽器會將這些資訊存放在一個統一的位置,對於Windows作業系統而言,我們可以從: [系統盤]:\Documents and Settings\[使用者名稱]\Cookies

目錄中找到儲存的Cookie;自此,客戶端再向伺服器傳送請求的時候,都會把相應的Cookie再次發回至伺服器。而這次,Cookie資訊則存放在HTTP請求頭(Request Header)了。有了Cookie這樣的技術實現,伺服器在接收到來自客戶端瀏覽器的請求之後,就能夠通過分析存放於請求頭的Cookie得到客戶端特有的資訊,從而動態生成與該客戶端相對應的內容。

2、cookie的原理

當伺服器返回給客戶端一個http響應資訊時,其中如果包含Set-Cookie這個頭部時,意思就是指示客戶端建立一個cookie,並且在後續的http請求中自動傳送這個cookie到伺服器端,直到這個cookie過期。如果cookie的生存時間是整個會話期間的話,那麼瀏覽器會將cookie儲存在記憶體中,瀏覽器關閉時就會自動清除這個cookie。另外一種情況就是儲存在客戶端的硬碟中,瀏覽器關閉的話,該cookie也不會被清除,下次開啟瀏覽器訪問對應網站時,這個cookie就會自動再次傳送到伺服器端。一個cookie的設定以及傳送過程分為以下四步:

  • 客戶端傳送一個http請求到伺服器端
  • 伺服器端傳送一個http響應到客戶端,其中包含Set-Cookie頭部
  • 客戶端傳送一個http請求到伺服器端,其中包含Cookie頭部
  • 伺服器端傳送一個http響應到客戶端

3、cookie的基本操作

1)建立cookie
bool setcookie ( string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] )
setcookie() 定義了 Cookie,會和剩下的 HTTP 頭一起傳送給客戶端。 和其他 HTTP 頭一樣,必須在指令碼產生任意輸出之前傳送 Cookie(由於協議的限制)。 請在產生任何輸出之前(包括 和 或者空格)呼叫本函式。

一旦設定 Cookie 後,下次開啟頁面時可以使用 $_COOKIE 讀取。

如果在呼叫本函式以前就產生了輸出,setcookie() 會呼叫失敗並返回 FALSE。 如果 setcookie() 成功執行,返回 TRUE。當然,它的意思並非使用者是否已接受 Cookie。

2)獲取cookie
$_COOKIE['name']

問題:客戶端的cookie資訊是怎麼傳遞給伺服器的?
通過http協議的Cookie:name=test;這個機制是http協議規定的。

3)更新cookie
更新某個cookie的key<==>val,實際是就是重新設定;依然是使用setcookie();

4)刪除cookie
指定刪除某個cookie,只需要把這個key的time設定成time()-秒數即可。
如:setcookie('name','',time()-1);
如果需要刪除所有的cookie則可以用遍歷的方法:

foreach($_COOKIE as $key=>$val){
  setcookie($key,'',time()-1);
}

如果你把這個網站的所有cookie都刪除掉,則瀏覽器會自動把這個cookie檔案也刪除掉的。

4、注意

1)Cookie功能需要瀏覽器的支援。
如果瀏覽器不支援Cookie(如大部分手機中的瀏覽器)或者把Cookie禁用了,Cookie功能就會失效。

2)Cookie具有不可跨域名性。
Cookie在客戶端是由瀏覽器來管理的,Cookie是不可跨域名的。如域名www.google.com頒發的Cookie不會被提交到域名www.baidu.com去。這是由Cookie的隱私安全機制決定的。

三、SESSION

1、簡介

Session 是存放在伺服器端的,類似於Session結構來存放使用者資料,當瀏覽器 第一次傳送請求時,伺服器自動生成了一個Session和一個Session ID用來唯一標識這個Session,並將其通過響應傳送到瀏覽器。當瀏覽器第二次傳送請求,會將前一次伺服器響應中的Session ID放在請求中一併傳送到伺服器上,伺服器從請求中提取出Session ID,並和儲存的所有Session ID進行對比,找到這個使用者對應的Session。

2、seesion的工作原理


3、seesion的基本用法

1)儲存sesion

session_start();  //初始化session
$_SESSION['name'] = 'nosee123';

檢視伺服器的session檔案,儲存結果如:name|s:8:"nosee123";
上面的s表示儲存型別為字串,8為表示所儲存資料的位元組大小,最後nosee123是session的值。
seesion檔案中可以儲存的型別有如:string、float、integer、bool、array、object。

2)獲取sesion資料

session_start();  //初始化session
$name = $_SESSION['name'];

注意:如果我們需要取出物件,則需要實現申明一下類的定義資訊。(如:可以使用require_once來解決)

3)刪除seesion資料
刪除某個key:

unset($_SESSION['key']);

刪除所有session:

session_destroy();   //相當於刪除整個對應的session檔案

4、配置說明

在配置檔案php.ini中我們可以作一些session的配置。

1)session.auto_start
指定會話模組是否在請求開始時自動啟動一個會話。預設為 0(不啟動,也不推薦啟用)。
此時使用$_SESSION前要先呼叫session_start()初始化session。

2)session.name
session.name = PHPSESSID 預設值為PHPSESSID;用於設定session的名字,該值可以通過session_name()獲取。

3)session.save_path
session的儲存路徑,預設為:session.save_path = "/var/lib/php/sessions"

4)垃圾回收
session.gc_maxlifetime = 1440這個時間是指在1440秒(24分鐘)內,沒有使用session檔案,該session就會被當做垃圾回收。
session.gc_probability = 1session.gc_divisor = 1000,ession.gc_divisor 與 session.gc_probability 合起來定義了在每個會話初始化時啟動 gc(garbage collection 垃圾回收)程序的概率。此概率用 gc_probability/gc_divisor 計算得來。例如 1/1000 意味著在每個請求中有 0.1% 的概率啟動 gc 程序。如果網站的規模越大,我們建議把這個概率設定越小。

5)session.use_cookie
session.use_cookies = 1設定是否使用cookie,預設使用。

6)session.cookie_lifetime
session.cookie_lifetime = 0cookie儲存時間,預設0,關閉瀏覽器就失效

7)session.use_trans_sid
session.use_trans_sid 指定是否啟用透明 SID 支援。預設為 0(禁用)。

8)session.save_handler
session.save_handler 定義了來儲存和獲取與會話關聯的資料的處理器的名字。預設為 files。
session資料還可以存放的位置如:資料庫(mysql),記憶體(redis、memcache),網路檔案(nfs)

5、禁用cookie的情況
當用戶禁用cookie後,伺服器每次session_start()都會建立一個全新的session檔案。

解決辦法:
方法一,在每個超連結上新增一個PHPSESSIONID=$sessionId

//在每個超連結上新增一個PHPSESSIONID=$sessionId;同時每個頁面加入:
if(isset($_GET['PHPSESSIONID'])){
  session_id($_GET['PHPSESSIONID']);    //設定session_id();
}
session_start();    //若有設定session_id()則sesssion_start()不會建立一個新的session檔案。
//$sessionId = session_id();

方法二,使用常量SID
SID是一個包含著會話名以及會話 ID 的常量,格式為 “name=ID”,它的值相當於字串"session_name().'='.session_id()";或者如果會話 ID 已經在適當的會話 cookie 中設定時則為空字串。

可以在超連結(herf)、action、header(Location:xxx)裡直接拼接SID常量,如

<a href="index.php?<?php echo SID; ?>">下個頁面</a>

方法三,使用session.use_trans_sid指定是否啟用透明SID支援
直接配置php.ini檔案的session.use_trans_sid = 0,把0改為1即可。(配置成功後則在herf、action、header中會自動加SID,但是javascript的跳轉中不會自動新增)
但是該方法對安全有影響,不推薦開啟。

6、注意

1)在使用$_SESSION前要保證session被初始化,具體方法如下:
方法一:先呼叫session_start();
方法二:配置php.ini的session.auto_start=1(不推薦,會影響效率)

2)一個會話對應一個session:
當關閉瀏覽器再開啟操作session後,會建立一個新的session檔案。

3)誤解:“只要關閉瀏覽器,session就消失了”
產生這種錯覺的原因:當關閉瀏覽器後這個 session id就消失了,再次連線伺服器時也就無法找到原來的session。
恰恰是由於關閉瀏覽器不會導致session被刪除,迫使伺服器為seesion設定了一個失效時間,當距離客戶端上一次使用session的時間超過這個失效時間時,伺服器就可以認為客戶端已經停止了活動,所以session的gc機制都會有存在的意義。

四、COOKIE與SESSION

1)存放位置
cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。

2)安全性
cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙,考慮到安全應當使用session。

3)網路傳輸量
cookie通過網路在客戶端與伺服器傳輸,而session儲存在伺服器不需要傳輸。
cookie每次請求都會被自動新增到Request Header中,無形中增加了流量。cookie資訊越大,對伺服器請求的時間越長。

4)生命週期(以20分鐘為例)
cookie的生命週期是累計的,從建立開始計時,20分鐘後cookie生命週期結束,cookie失效。
session生命週期是間隔的,從建立計時,如在20分鐘內沒有訪問過session,那麼session資訊無效;如果在第19分鐘訪問過session,那麼它的生命週期將重新開始計算。

5)伺服器效能:
session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能。考慮到減輕伺服器效能方面,應當使用COOKIE。

6)儲存大小:
單個cookie在客戶端的限制一般是4K,就是說一個站點在客戶端存放的COOKIE不能超過4K。

7)儲存內容
cookie儲存的是字串,session中可以儲存多種資料型別。

參考

官方手冊:
cookie: http://php.net/manual/zh/features.cookies.php
seesion: http://php.net/manual/zh/book.session.php

部落格:
https://my.oschina.net/xianggao/blog/395675?fromerr=GC9KVenE