php會話控制(session與cookie)

cookie簡介

Cookie是存儲在客戶端瀏覽器中的數據,我們通過Cookie來跟蹤與存儲用戶數據。一般情況下,Cookie通過HTTP headers從服務端返回到客戶端。多數web程序都支持Cookie的操作,因爲Cookie是存在於HTTP的標頭之中,所以必須在其他信息輸出以前進行設置,類似於header函數的使用限制。

PHP通過setcookie函數進行Cookie的設置,任何從瀏覽器發回的Cookie,PHP都會自動的將他存儲在$_COOKIE的全局變量之中,因此我們可以通過$_COOKIE['key']的形式來讀取某個Cookie值。

PHP中的Cookie具有非常廣泛的使用,經常用來存儲用戶的登錄信息,購物車等,且在使用會話Session時通常使用Cookie來存儲會話id來識別用戶,Cookie具備有效期,當有效期結束之後,Cookie會自動的從客戶端刪除。同時爲了進行安全控制,Cookie還可以設置域跟路徑,我們會在稍後的章節中詳細的講解他們。

<?php
setcookie('test', time());
ob_start();//打開輸出控制緩衝
print_r($_COOKIE);
$content = ob_get_contents();//複製緩衝區內容到$content中
$content = str_replace(" ", '&nbsp;', $content);
ob_clean();//清空(擦掉)輸出緩衝區
header("content-type:text/html; charset=utf-8");
echo '當前的Cookie爲:<br/>';
echo nl2br($content);//nl2br 在字符串所有新行之前插入 HTML 換行標記

設置cookie

PHP設置Cookie最常用的方法就是使用setcookie函數,setcookie具有7個可選參數,我們常用到的爲前5個:

name( Cookie名)可以通過$_COOKIE['name'] 進行訪問
value(Cookie的值)
expire(過期時間)Unix時間戳格式,默認爲0,表示瀏覽器關閉即失效
path(有效路徑)如果路徑設置爲'/',則整個網站都有效
domain(有效域)默認整個域名都有效,如果設置了'www.icy.com',則只在www子域中有效

$value = 'test';
setcookie("TestCookie", $value);
setcookie("TestCookie", $value, time()+3600);  //有效期一小時
setcookie("TestCookie", $value, time()+3600, "/path/", "icy.com"); //設置路徑與域

PHP中還有一個設置Cookie的函數setrawcookie,setrawcookie跟setcookie基本一樣,唯一的不同就是value值不會自動的進行urlencode,因此在需要的時候要手動的進行urlencode。

setrawcookie('cookie_name', rawurlencode($value), time()+60*60*24*365); 

因爲Cookie是通過HTTP標頭進行設置的,所以也可以直接使用header方法進行設置。

header("Set-Cookie:cookie_name=value");

cookie的刪除與過期時間

們卻發現php中沒有刪除Cookie的函數,在PHP中刪除cookie也是採用setcookie函數來實現。

setcookie('test', '', time()-1); 

可以看到將cookie的過期時間設置到當前時間之前,則該cookie會自動失效,也就達到了刪除cookie的目的。之所以這麼設計是因爲cookie是通過HTTP的標頭來傳遞的,客戶端根據服務端返回的Set-Cookie段來進行cookie的設置,如果刪除cookie需要使用新的Del-Cookie來實現,則HTTP頭就會變得複雜,實際上僅通過Set-Cookie就可以簡單明瞭的實現Cookie的設置、更新與刪除。

瞭解原理以後,我們也可以直接通過header來刪除cookie。

header("Set-Cookie:test=1393832059; expires=".gmdate('D, d M Y H:i:s \G\M\T', time()-1));

這裏用到了gmdate,用來生成格林威治標準時間,以便排除時差的影響。

cookie的有效路徑

ookie中的路徑用來控制設置的cookie在哪個路徑下有效,默認爲’/’,在所有路徑下都有,當設定了其他路徑之後,則只在設定的路徑以及子路徑下有效,例如:

setcookie(‘test’, time(), 0, ‘/path’);

上面的設置會使test在/path以及子路徑/path/abc下都有效,但是在根目錄下就讀取不到test的cookie值。

一般情況下,大多是使用所有路徑的,只有在極少數有特殊需求的時候,會設置路徑,這種情況下只在指定的路徑中才會傳遞cookie值,可以節省數據的傳輸,增強安全性以及提高性能。

當我們設置了有效路徑的時候,不在當前路徑的時候則看不到當前cookie。

setcookie('test', '1',0, '/path');  
var_dump($_COOKIE['test']);  

session與cookie的異同

cookie將數據存儲在客戶端,建立起用戶與服務器之間的聯繫,通常可以解決很多問題,但是cookie仍然具有一些侷限:

cookie相對不是太安全,容易被盜用導致cookie欺騙
單個cookie的值最大隻能存儲4k
每次請求都要進行網絡傳輸,佔用帶寬

session是將用戶的會話數據存儲在服務端,沒有大小限制,通過一個session_id進行用戶識別,PHP默認情況下session id是通過cookie來保存的,因此從某種程度上來說,seesion依賴於cookie。但這不是絕對的,session id也可以通過參數來實現,只要能將session id傳遞到服務端進行識別的機制都可以使用session。

<?php
//開始使用session
session_start();
//設置一個session
$_SESSION['test'] = time();
//顯示當前的session_id
echo "session_id:".session_id();
echo "<br>";

//讀取session值
echo $_SESSION['test'];

//銷燬一個session
unset($_SESSION['test']);
echo "<br>";
var_dump($_SESSION);

輸出結果

session_id:4llodl1bjel9obqqajka7k4584
1460525275
array(0) {
}

使用session

在PHP中使用session非常簡單,先執行session_start方法開啓session,然後通過全局變量$_SESSION進行session的讀寫。

session_start();
$_SESSION['test'] = time();
var_dump($_SESSION);

session會自動的對要設置的值進行encode與decode,因此session可以支持任意數據類型,包括數據與對象等。

session_start();
$_SESSION['ary'] = array('name' => 'jobs');
$_SESSION['obj'] = new stdClass();
var_dump($_SESSION);

默認情況下,session是以文件形式存儲在服務器上的,因此當一個頁面開啓了session之後,會獨佔這個session文件,這樣會導致當前用戶的其他併發訪問無法執行而等待。可以採用緩存或者數據庫的形式存儲來解決這個問題,這個我們會在一些高級的課程中講到。

<?php
//在這裏設置name的session值爲jobs
session_start();
$_SESSION['name']='xuehairong';
$_SESSION['obj'] = new stdClass();
var_dump($_SESSION);
echo $_SESSION['name'];

輸出結果

array(2) {
  ["name"]=>
  string(10) "xuehairong"
  ["obj"]=>
  object(stdClass)#1 (0) {
  }
}
xuehairong

刪除與銷燬session

刪除某個session值可以使用PHP的unset函數,刪除後就會從全局變量$_SESSION中去除,無法訪問。

如果要刪除所有的session,可以使用session_destroy函數銷燬當前session,session_destroy會刪除所有數據,但是session_id仍然存在。

session_start();
$_SESSION['name'] = 'jobs';
unset($_SESSION['name']);
echo $_SESSION['name']; //提示name不存在

session_start();
$_SESSION['name'] = 'jobs';
$_SESSION['time'] = time();
session_destroy();

值得注意的是,session_destroy並不會立即的銷燬全局變量$_SESSION中的值,只有當下次再訪問的時候,$_SESSION才爲空,因此如果需要立即銷燬$_SESSION,可以使用unset函數。

session_start();
$_SESSION['name'] = 'jobs';
$_SESSION['time'] = time();
unset($_SESSION);
session_destroy(); 
var_dump($_SESSION); //此時已爲空

如果需要同時銷燬cookie中的session_id,通常在用戶退出的時候可能會用到,則還需要顯式的調用setcookie方法刪除session_id的cookie值。

使用session來存儲用戶的登錄信息

ession可以用來存儲多種類型的數據,因此具有很多的用途,常用來存儲用戶的登錄信息,購物車數據,或者一些臨時使用的暫存數據等。

用戶在登錄成功以後,通常可以將用戶的信息存儲在session中,一般的會單獨的將一些重要的字段單獨存儲,然後所有的用戶信息獨立存儲。

$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['userinfo'] = $userinfo;

一般來說,登錄信息既可以存儲在sessioin中,也可以存儲在cookie中,他們之間的差別在於session可以方便的存取多種數據類型,而cookie只支持字符串類型,同時對於一些安全性比較高的數據,cookie需要進行格式化與加密存儲,而session存儲在服務端則安全性較高。

<?php
session_start();
//假設用戶登錄成功獲得了以下用戶數據
$userinfo = array(
    'uid'  => 10000,
    'name' => 'spark',
    'email' => '[email protected]',
    'sex'  => 'woman',
    'age'  => '18'
);
header("content-type:text/html; charset=utf-8");

/* 將用戶信息保存到session中 */
$_SESSION['uid'] = $userinfo['uid'];
$_SESSION['name'] = $userinfo['name'];
$_SESSION['userinfo'] = $userinfo;

//* 將用戶數據保存到cookie中的一個簡單方法 */
$secureKey = 'icy'; //加密密鑰
$str = serialize($userinfo); //將用戶信息序列化
//用戶信息加密前
$str = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($secureKey), $str, MCRYPT_MODE_ECB));
//用戶信息加密後
//將加密後的用戶數據存儲到cookie中
setcookie('userinfo', $str);

//當需要使用時進行解密
$str = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($secureKey), base64_decode($str), MCRYPT_MODE_ECB);
$uinfo = unserialize($str);
echo "解密後的用戶信息:<br>";
print_r($uinfo);

輸出結果:

解密後的用戶信息:
Array
(
    [uid] => 10000
    [name] => spark
    [email] => [email protected]
    [sex] => man
    [age] => 18
)

讀取文件內容

PHP具有豐富的文件操作函數,最簡單的讀取文件的函數爲file_get_contents,可以將整個文件全部讀取到一個字符串中。

$content = file_get_contents('./test.txt');

file_get_contents也可以通過參數控制讀取內容的開始點以及長度。

$content = file_get_contents('./test.txt', null, null, 100, 500);

PHP也提供類似於C語言操作文件的方法,使用fopen,fgets,fread等方法,fgets可以從文件指針中讀取一行,freads可以讀取指定長度的字符串。

$fp = fopen('./text.txt', 'rb');
while(!feof($fp)) {
    echo fgets($fp); //讀取一行
}
fclose($fp);




$fp = fopen('./text.txt', 'rb');
$contents = '';
while(!feof($fp)) {
    $contents .= fread($fp, 4096); //一次讀取4096個字符
}
fclose($fp);

使用fopen打開的文件,最好使用fclose關閉文件指針,以避免文件句柄被佔用。

$filename = '/data/webroot/usercode/resource/test.txt';
//編寫代碼讀取$filename的文件內容
$contents=file_get_contents($filename);
echo $contents;

輸出內容

this is a test file.

判斷文件是否存在

一般情況下在對文件進行操作的時候需要先判斷文件是否存在,PHP中常用來判斷文件存在的函數有兩個is_file與file_exists.

$filename = './test.txt';
if (file_exists($filename)) {
    echo file_get_contents($filename);
}

如果只是判斷文件存在,使用file_exists就行,file_exists不僅可以判斷文件是否存在,同時也可以判斷目錄是否存在,從函數名可以看出,is_file是確切的判斷給定的路徑是否是一個文件。

$filename = './test.txt';
if (is_file($filename)) {
    echo file_get_contents($filename);
}

更加精確的可以使用is_readable與is_writeable在文件是否存在的基礎上,判斷文件是否可讀與可寫。

$filename = './test.txt';
if (is_writeable($filename)) {
    file_put_contents($filename, 'test');
}
if (is_readable($filename)) {
    echo file_get_contents($filename);
}

寫入內容到文件

與讀取文件對應,PHP寫文件也具有兩種方式,最簡單的方式是採用file_put_contents。

$filename = './test.txt';
$data = 'test';
file_put_contents($filename, $data);

上例中,$data參數可以是一個一維數組,當$data是數組的時候,會自動的將數組連接起來,相當於$data=implode('', $data);

同樣的,PHP也支持類似C語言風格的操作方式,採用fwrite進行文件寫入。

$fp = fopen('./test.txt', 'w');
fwrite($fp, 'hello');
fwrite($fp, 'world');
fclose($fp);

取得文件的修改時間

文件有很多元屬性,包括:文件的所有者、創建時間、修改時間、最後的訪問時間等。

fileowner:獲得文件的所有者
filectime:獲取文件的創建時間
filemtime:獲取文件的修改時間
fileatime:獲取文件的訪問時間

其中最常用的是文件的修改時間,通過文件的修改時間,可以判斷文件的時效性,經常用在靜態文件或者緩存數據的更新。

$mtime = filemtime($filename);
echo '修改時間:'.date('Y-m-d H:i:s', filemtime($filename));
<?php
$filename = '/data/webroot/usercode/code/resource/test.txt';
echo '所有者:'.fileowner($filename).'<br>';
echo '創建時間:'.filectime($filename).'<br>';
echo '修改時間:'.filemtime($filename).'<br>';
echo '最後訪問時間:'.fileatime($filename).'<br>';

//給$mtime賦值爲文件的修改時間
$mtime = filemtime($filename);; 
//通過計算時間差 來判斷文件內容是否有效
if (time() - $mtime > 3600) {
    echo '<br>緩存已過期';
} else {
    echo file_get_contents($filename);
}

輸出結果

所有者:501
創建時間:1446715450
修改時間:1446715450
最後訪問時間:1460473202

緩存已過期

取得文件的大小

通過filesize函數可以取得文件的大小,文件大小是以字節數表示的。

$filename = '/data/webroot/usercode/code/resource/test.txt';
$size = filesize($filename);

如果要轉換文件大小的單位,可以自己定義函數來實現。

function getsize($size, $format = 'kb') {
    $p = 0;
    if ($format == 'kb') {
        $p = 1;
    } elseif ($format == 'mb') {
        $p = 2;
    } elseif ($format == 'gb') {
        $p = 3;
    }
    $size /= pow(1024, $p);
    return number_format($size, 3);
}

$filename = '/data/webroot/usercode/code/resource/test.txt';
$size = filesize($filename);

$size = getsize($size, 'kb'); //進行單位轉換
echo $size.'kb';

值得注意的是,沒法通過簡單的函數來取得目錄的大小,目錄的大小是該目錄下所有子目錄以及文件大小的總和,因此需要通過遞歸的方法來循環計算目錄的大小。

刪除文件

跟Unix系統命令類似,PHP使用unlink函數進行文件刪除。

unlink($filename);

刪除文件夾使用rmdir函數,文件夾必須爲空,如果不爲空或者沒有權限則會提示失敗。

rmdir($dir);

如果文件夾中存在文件,可以先循環刪除目錄中的所有文件,然後再刪除該目錄,循環刪除可以使用glob函數遍歷所有文件。

foreach (glob("*") as $filename) {
   unlink($filename);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章