PHP會話(Session)使用入門(來自深空老大)

對比起 Cookie,Session 是存儲在服務器端的會話,相對安全,而且不像 Cookie 那樣有存儲長度限制,本文簡單介紹 Session 的使用。
因爲 Session 是以文本文件形式存儲在服務器端的,因此不怕客戶端修改 Session 內容。實際上在服務器端的 Session 文件,PHP 自動修改 Session 文件的權限,只保留了系統讀和寫權限,並且不能經過 ftp 修改,因此安全得多。
對於 Cookie 來講,假設咱們要驗證用戶是否登錄,就必須在 Cookie 中保存用戶名和密碼(多是 md5 加密後字符串),並在每次請求頁面的時候進行驗證。若是用戶名和密碼存儲在數據庫,每次都要執行一次數據庫查詢,給數據庫形成多餘的負擔。由於咱們並不能只作一次驗證。爲何呢?由於客戶端 Cookie 中的信息是有可能被修改的。假如你存儲 $admin 變量來表示用戶是否登錄,$admin 爲 true 的時候表示登錄,爲 false 的時候表示未登陸,在第一次經過驗證後將 $admin 等於 true 存儲在 Cookie,下次就不用驗證了,這樣對麼?錯了,假若有人僞造一個值爲 true 的 $admin 變量那不是就當即取的了管理權限麼?很是的不安全。
而 Session 就不一樣了,Session 是存儲在服務器端的,遠程用戶沒辦法修改 Session 文件的內容,所以咱們能夠單純存儲一個 $admin 變量來判斷是否登錄,首次驗證經過後設置 $admin 值爲 true,之後判斷該值是否爲 true,假如不是,轉入登錄界面,這樣就能夠減小不少數據庫操做了。並且能夠減小每次爲了驗證 Cookie 而傳遞密碼的不安全性了(Session 驗證只須要傳遞一次,假如你沒有使用 SSL 安全協議的話)。即便密碼進行了 md5 加密,也是很容易被截獲的。
固然使用 Session 還有不少優勢,好比控制容易,能夠按照用戶自定義存儲等(存儲於數據庫)。我這裏就很少說了。
Session 在 php.ini 是否須要設置呢?通常不須要的,由於並非每一個人都有修改 php.ini 的權限,默認 Session 的存放路徑是服務器的系統臨時文件夾,咱們能夠自定義存放在本身的文件夾裏,這個稍後我會介紹。
開始介紹如何建立 Session。很是簡單,真的。
啓動 Session 會話,並建立一個 $admin 變量:
1
2
3
4
5
6
<?php
//  啓動 Session
session_start();
//  聲明一個名爲 admin 的變量,並賦空值。
$_SESSION [ "admin" ] = null;
?>

若是你使用了 Seesion,或者該 PHP 文件要調用 Session 變量,那麼就必須在調用 Session 以前啓動它,使用 session_start() 函數。其它都不須要你設置了,PHP 自動完成 Session 文件的建立。
執行完這個程序後,咱們能夠到系統臨時文件夾找到這個 Session 文件,通常文件名形如:sess_4c83638b3b0dbf65583181c2f89168ec,後面是 32 位編碼後的隨機字符串。用編輯器打開它,看一下它的內容:php

1
admin|N;

通常該內容是這樣的結構:數據庫

1
變量名|類型:長度:值;

並用分號隔開每一個變量。有些是能夠省略的,好比長度和類型。
咱們來看一下驗證程序,假設數據庫存儲的是用戶名和 md5 加密後的密碼:
login.php數組

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
//  表單提交後...
$posts = $_POST ;
//  清除一些空白符號
foreach ( $posts as $key => $value ) {
     $posts [ $key ] = trim( $value );
}
$password = md5( $posts [ "password" ]);
$username = $posts [ "username" ]; 
  
$query = "SELECT `username` FROM `user` WHERE `password` = '$password' AND `username` = '$username'" ;
//  取得查詢結果
$userInfo = $DB ->getRow( $query ); 
  
if (! empty ( $userInfo )) {
     //  當驗證經過後,啓動 Session
     session_start();
     //  註冊登錄成功的 admin 變量,並賦值 true
     $_SESSION [ "admin" ] = true;
} else {
     die ( "用戶名密碼錯誤" );
}
?>

咱們在須要用戶驗證的頁面啓動 Session,判斷是否登錄:瀏覽器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
//  防止全局變量形成安全隱患
$admin = false;
//  啓動會話,這步必不可少
session_start();
//  判斷是否登錄
if (isset( $_SESSION [ "admin" ]) && $_SESSION [ "admin" ] === true) {
     echo "您已經成功登錄" ;
} else {
     //  驗證失敗,將 $_SESSION["admin"] 置爲 false
     $_SESSION [ "admin" ] = false;
     die ( "您無權訪問" );
}
?>

是否是很簡單呢?將 $_SESSION 當作是存儲在服務器端的數組便可,咱們註冊的每個變量都是數組的鍵,跟使用數組沒有什麼分別。
若是要登出系統怎麼辦?銷燬 Session 便可。安全

1
2
3
4
5
6
7
<?php
session_start();
//  這種方法是將原來註冊的某個變量銷燬
unset( $_SESSION [ 'admin' ]);
//  這種方法是銷燬整個 Session 文件
session_destroy();
?>

Session 可否像 Cookie 那樣設置生存週期呢?有了 Session 是否就徹底拋棄 Cookie 呢?我想說,結合 Cookie 來使用 Session 纔是最方便的。
Session 是如何來判斷客戶端用戶的呢?它是經過 Session ID 來判斷的,什麼是 Session ID,就是那個 Session 文件的文件名,Session ID 是隨機生成的,所以能保證惟一性和隨機性,確保 Session 的安全。通常若是沒有設置 Session 的生存週期,則 Session ID 存儲在內存中,關閉瀏覽器後該 ID 自動註銷,從新請求該頁面後,從新註冊一個 Session ID。
若是客戶端沒有禁用 Cookie,則 Cookie 在啓動 Session 會話的時候扮演的是存儲 Session ID 和 Session 生存期的角色。
咱們來手動設置 Session 的生存期:服務器

1
2
3
4
5
6
<?php
session_start();
//  保存一天
$lifeTime = 24 * 3600;
setcookie(session_name(), session_id(), time() + $lifeTime , "/" );
?>

其實 Session 還提供了一個函數 session_set_cookie_params(); 來設置 Session 的生存期的,該函數必須在 session_start() 函數調用以前調用:cookie

1
2
3
4
5
6
7
<?php
//  保存一天
$lifeTime = 24 * 3600;
session_set_cookie_params( $lifeTime );
session_start();
$_SESSION [ "admin" ] = true;
?>

若是客戶端使用 IE 6.0 , session_set_cookie_params(); 函數設置 Cookie 會有些問題,因此咱們仍是手動調用 setcookie 函數來建立 cookie。
假設客戶端禁用 Cookie 怎麼辦?沒辦法,全部生存週期都是瀏覽器進程了,只要關閉瀏覽器,再次請求頁面又得從新註冊 Session。那麼怎麼傳遞 Session ID 呢?經過 URL 或者經過隱藏表單來傳遞,PHP 會自動將 Session ID 發送到 URL 上,URL 形如:http://www.openphp.cn/index.php?PHPSESSID=bba5b2a240a77e5b44cfa01d49cf9669,其中 URL 中的參數 PHPSESSID 就是 Session ID了,咱們可使用 $_GET 來獲取該值,從而實現 Session ID 頁面間傳遞。session

<?php
//  保存一天
$lifeTime = 24 * 3600;
//  取得當前 Session 名,默認爲 PHPSESSID
$sessionName = session_name();
//  取得 Session ID
$sessionID = $_GET[$sessionName];
//  使用 session_id() 設置得到的 Session ID
session_id($sessionID); 

session_set_cookie_params($lifeTime);
session_start();
$_SESSION['admin'] = true;
?>

對於虛擬主機來講,若是全部用戶的 Session 都保存在系統臨時文件夾裏,將給維護形成困難,並且下降了安全性,咱們能夠手動設置 Session 文件的保存路徑,session_save_path() 就提供了這樣一個功能。咱們能夠將 Session 存放目錄指向一個不能經過 Web 方式訪問的文件夾,固然,該文件夾必須具有可讀寫屬性。編輯器

1
2
3
4
5
6
7
8
9
10
<?php
//  設置一個存放目錄
$savePath = './session_save_dir/' ;
//  保存一天
$lifeTime = 24 * 3600;
session_save_path( $savePath );
session_set_cookie_params( $lifeTime );
session_start();
$_SESSION [ 'admin' ] = true;
?>

同 session_set_cookie_params(); 函數同樣,session_save_path() 函數也必須在 session_start() 函數調用以前調用。
咱們還能夠將數組,對象存儲在 Session 中。操做數組和操做通常變量沒有什麼區別,而保存對象的話,PHP 會自動對對象進行序列化(也叫串行化),而後保存於 Session 中。下面例子說明了這一點:
person.php函數

1
2
3
4
5
6
7
8
9
10
11
<?php
class person {
     var $age ;
     function output() {
         echo $this ->age;
     }
     function setAge( $age ) {
         $this ->age = $age ;
     }
}
?>

setage.php

1
2
3
4
5
6
7
8
<?php
session_start();
require_once 'person.php' ;
$person = new person();
$person ->setAge(21);
$_SESSION [ 'person' ] = $person ;
echo '<a href=' output.php '>check here to output age</a>' ;
?>

output.php

1
2
3
4
5
6
7
8
9
10
11
<?php
// 設置回調函數,確保從新構建對象。
ini_set ( 'unserialize_callback_func' , 'mycallback' );
function mycallback( $classname ) {
     include_once $classname . '.php' ;
}
session_start();
$person = $_SESSION [ 'person' ];
//  輸出 21
$person ->output();
?>

當咱們執行 setage.php 文件的時候,調用了 setage() 方法,設置了年齡爲 21,並將該狀態序列化後保存在 Session 中(PHP 將自動完成這一轉換),當轉到 output.php 後,要輸出這個值,就必須反序列化剛纔保存的對象,又由於在解序列化的時候須要實例化一個未定義類,因此咱們定義了之後回調函數,自動包含 person.php 這個類文件,所以對象被重構,並取得當前 age 的值爲 21,而後調用 output() 方法輸出該值。 另外,咱們還可使用 session_set_save_handler 函數來自定義 Session 的調用方式。

相關文章
相關標籤/搜索