cookie作为小甜饼,充斥着网络世界。没有了cookie,那么估计大多数的网站鉴权功能就全部失效了。可见cookie的重要性。今天给大家带来的是phpcookie的一些小事情。
  • 本文中的实验对象,是纯正的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 ]]]]]] )

setrawcookiesetcookie,基本一致,区别就在于对$value的处理。下面的两条语句是一致的效果:

PHP
setcookie($name,$value);setrawcookie($name,urlencode($value));

特别说明:

  • urlencoderawurlencode是有区别的,两者的区别不在本篇文章中叙述。需要明确的就是,两者是有区别的。
  • 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는 쿠키를 설정합니다 [세 가지 옵션]

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);

PHP는 쿠키를 설정합니다 [세 가지 옵션]

需要注意的是:

  • 设置内容的时候,会对特殊字符进行转义。setcookie的转义是自动的,header的转义是主动的。
  • 使用header的时候,过期时间是个gmt时间字符串,而setcookie是个时间戳。
  • 设置域名的时候,两者都直接写的域名,但是生效的时候,生效的是.域名,就是说生效范围包括二级域名。
  • headersetcookie好的地方在于:它可以跳过哪些过期时间/域名/path等参数,直接设置httponly

最后对比

下面来个phpcookie相关函数的终极对决:

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(&#39;cookie_normal&#39;);  var cookie_raw=$.cookie(&#39;cookie_raw&#39;);  var cookie_raw2=$.cookie(&#39;cookie_raw2&#39;);  var cookie_header=$.cookie(&#39;cookie_header&#39;);
  document.write(document.cookie+"<br/><br/>normal:"+cookie_normal+",<br/>raw:"+cookie_raw+",<br/>raw2:"+cookie_raw2+",<br/>header:"+cookie_header);</script>

PHP는 쿠키를 설정합니다 [세 가지 옵션]

这些cookie值使用了不同的方法进行了设置。里面含有空格和加号。从结果中,我们得出如下结论:

  • setcookiesetrawcookie中的中文,用document.cookie不能顺利读出,但是用jquery.cookie可以顺利读出。
  • jquerycookie插件,均正确读取了php端的各种cookie值。但是读取header中的值时,对加号的处理似乎有些问题。
  • document.cookie,只能正常读取header设置的中文。即使中文中带有空格,也能正常读取。这也是最正常,表现最好的组合。

요약

표면적으로는 header设置cookie和使用setcookie函数设置cookie,是可以得到相同的效果的。苏南大叔认为,用header设置cookie,比setcookie사용하는 것이 더 좋습니다. 관련 내용은 다음 글에서 계속하겠습니다. 계속 지켜봐 주시기 바랍니다.

실제 운영에는 아직 예상하지 못한 일들이 있습니다.