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
を使った方が良いです。関連事項は次回に続きます。乞うご期待。
実際の運用では、まだまだ予想外のことが起こります。