cookie
作為小甜餅,充斥著網路世界。沒有了cookie
,那麼估計大多數的網站鑑權功能就全部失效了。可見cookie
的重要性。今天帶給大家的是php
跟cookie
的一些小事。 - 本文中的實驗對象,是純正的
php
,不夾雜任何任何框架的php
。所以,所有的寫法都是原生的,請你知道。 cookie
輸出之前,請確保沒有任何的頁面輸出。即使一個空白字元也不行。蘇南大叔想起了php
新手經典大坑:php
檔案保存為utf8
的時候,必須是nobom
的。
相關推薦:《php cookie(專題)》
方案一:setcookie
函數
PHP
bool setcookie ( string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] )
函數說明請見這裡:https://doc.php.sh/zh/function.setcookie.html 。
-
$name
不就必說了,cookie的項目名稱,一般為個類似「str」的字串,但也陣列的形式,例如「arr[one ]」。 -
$value
傳輸的過程中會被轉義,例如空格會變成加號等,其轉義函數,根據蘇南大叔推斷,應該是urlencode。 -
$expire
時間戳,秒數而非毫秒數,cookie的過期時間,是具體的時間點,而非時間段,PHP會對它做進一步的轉換為GMT格式。 。一般都是控制這個時間為一個過去的時間,來刪除掉cookie的。不填或填0的話,就是瀏覽器會話期間生效,瀏覽器關閉即失效。表示過期時間的時候,http協定裡面有2個,expire和max-age。目前php裡面還是設定expire過期時間的,但從http協定的角度來看,expire已經開始被max-age取代。 expire指的是失效的時間點,max-age是多少秒後才失效。 -
$path
cookie的有效目錄,一般是和$domain配置使用的,一般設定為/
即可。 -
$domain
這個參數需要重點注意,如果不填的話,則是預設目前網域。如果填寫的話,一般來說,也是需要自己用$_SERVER['SERVER_NAME']
取得的網域。並且主動填寫的話,最終的cookie作用域是填寫的所有子域。如果填入"newsn.net",那麼反應到瀏覽器端,最終的值是「.newsn.net"。注意,前面增加了個".",表示的範圍就擴大了。 -
$secure
另外一個很邪門的參數,表示是否只透過安全的 HTTPS 連線傳給客戶端
。如果設定為true的話,目前網站環境不是https的話,那麼這整個cookie就是完全失效的狀態。但是,我們透過抓包可以發現,這個cookie已經被php設置,只不過在瀏覽器端被失效了。而php中,是可以用isset($_SERVER["HTTPS"])
來判定,是否支持https的。 -
$httponly
這個參數的位置也非常尷尬,是所有可選參數的最後一個。想設定它,就必須先設定$domain
和$secure
這兩個似乎可以不必設定的值。而在目前的網路環境裡面,$httponly 又應該是強烈建議設定值。具體情況請參考蘇南大叔的後續httponly文章:https://newsn.net/tag/httponly/ 。
所以,很有可能你需要的php
語句是這樣的:
PHP
setcookie("cookie_name", "cookie_value", time() + 3600, "/", $_SERVER['SERVER_NAME'], isset($_SERVER["HTTPS"]), true);
方案二:setrawcookie
函數
PHP
bool setrawcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool$ httponly = false ]]]]]] )
setrawcookie
和setcookie
,基本一致,区别就在于对$value的处理。下面的两条语句是一致的效果:
PHP
setcookie($name,$value);setrawcookie($name,urlencode($value));
特别说明:
-
urlencode
和rawurlencode
是有区别的,两者的区别不在本篇文章中叙述。需要明确的就是,两者是有区别的。 - 当
setrawcookie
的$value
,不进行encode
操作的话,如果里面含有空格的话,整条语句都是失效的。并且不会报错!所以,setrawcookie
必须联合urlencode
才能保证其正确性。但是这个时候,就不如使用setcookie
了。
方案三:header
输出cookie
set cookie
函数,如果想要生效,也是通过header
设置浏览器端进而生效的。所以通过header
输出也是可行的。那么关于写出几条等价的header
操作,大家对比学习一下:
PHP
header("Set-Cookie:cookie_name1_cp=" . urlencode("浏览器关闭失效"));setcookie("cookie_name1", "浏览器关闭失效");
PHP
header("Set-Cookie:cookie_name=" . urlencode("设置有效域名/https/httponly") . "; expires=" . gmstrftime("%a, %d-%b-%Y %H:%M:%S GMT", time() + 3600*24) . "; Max-Age=3600; path=/; domain= ".$_SERVER['SERVER_NAME']."; httponly");setcookie("cookie_name3", "设置有效域名/https/httponly", time() + 3600*24, "/", $_SERVER['SERVER_NAME'], isset($_SERVER["HTTPS"]),true);
需要注意的是:
- 设置内容的时候,会对特殊字符进行转义。
setcookie
的转义是自动的,header
的转义是主动的。 - 使用
header
的时候,过期时间是个gmt
时间字符串,而setcookie
是个时间戳。 - 设置域名的时候,两者都直接写的域名,但是生效的时候,生效的是.域名,就是说生效范围包括二级域名。
-
header
比setcookie
好的地方在于:它可以跳过哪些过期时间/域名/path等参数,直接设置httponly
。
最后对比
下面来个php
的cookie
相关函数的终极对决:
PHP
<?php $val="我是中文 newsn.net";setcookie("cookie_normal",$val);setrawcookie("cookie_raw",urlencode($val));setrawcookie("cookie_raw2",rawurlencode($val));header("Set-Cookie:cookie_header=带 空 + 格 的中文",false);?><script src="js/jquery-3.2.1.min.js"></script><script src="js/jquery.cookie.js"></script><script> var cookie_normal=$.cookie('cookie_normal'); var cookie_raw=$.cookie('cookie_raw'); var cookie_raw2=$.cookie('cookie_raw2'); var cookie_header=$.cookie('cookie_header'); document.write(document.cookie+"<br/><br/>normal:"+cookie_normal+",<br/>raw:"+cookie_raw+",<br/>raw2:"+cookie_raw2+",<br/>header:"+cookie_header);</script>
这些cookie
值使用了不同的方法进行了设置。里面含有空格和加号。从结果中,我们得出如下结论:
-
setcookie
和setrawcookie
中的中文,用document.cookie
不能顺利读出,但是用jquery.cookie
可以顺利读出。 -
jquery
的cookie
插件,均正确读取了php
端的各种cookie
值。但是读取header
中的值时,对加号的处理似乎有些问题。 -
document.cookie
,只能正常读取header
设置的中文。即使中文中带有空格,也能正常读取。这也是最正常,表现最好的组合。
總結
表面上看,使用header
設定cookie
和使用setcookie
函數設定cookie
,是可以得到相同的效果的。蘇南大叔認為,用header
設定cookie
,比setcookie
更好。下一篇文章將繼續敘述相關事宜。敬請期待。
在實際操作中,還是有意料之外的事情的。