实例脚本:
1 2 3 |
<?php setcookie("phpor", "hello;world"); print_r($_COOKIE); |
请求和响应:
输出:
结论:
- setcookie函数会对cookie的value做一次urlencode编码
- 客户端(浏览器)不会对cookie的value做任何转码
- PHP的server端在解析提交的cookie时,会对cookie的value做一次urldecode然后初始化到$_COOKIE数组中
延伸:
如果使用setrawcookie函数,对cookie的value不做urlencode,那么value中如果含有 “;”,则上行cookie的编码会是什么样的呢?(因为上行的多个cookie是靠”;”开分隔的)
测试代码:
1 2 3 |
<?php setrawcookie("phpor", "hello;world"); print_r($_COOKIE); |
结果:
1 |
Warning: Cookie values can not contain any of the folllowing ',; \t\r\n\013\014' (hello;world) in D:\Program\www\a.php on line 2 |
结论:
1. 设置cookie时,cookie的value是需要urlencode的; 毕竟http协议中cookie的设置如下:
1 |
Set-Cookie: phpor=hello%3Bworld; expires=Thu, 01-Jan-1970 00:01:40 GMT; path=/ |
cookie的属性之间使用”;” 来分隔的,如果cookie的value中含有 “;” ,自然也不会当做value的一部分的
2. PHP对于上行的cookie也是做urldecode的(尽管多个cookie之间的分隔符不是”&”)
3. 从协议层不难看出,cookie名字也是不能有特殊字符的,就像value中不能函数特殊字符一样
PHP中setcookie的部分实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//1. url_encode 指示是否做url编码,setrawcookie时,该标识为0 //2. url_encode 只针对value有效,cookie名字不做编码 PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, time_t expires, char *path, int path_len, char *domain, int domain_len, int secure, int url_encode, int httponly TSRMLS_DC) { char *cookie, *encoded_value = NULL; int len=sizeof("Set-Cookie: "); char *dt; sapi_header_line ctr = {0}; int result; if (name && strpbrk(name, "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */ zend_error( E_WARNING, "Cookie names cannot contain any of the following '=,; \\t\\r\\n\\013\\014'" ); return FAILURE; } if (!url_encode && value && strpbrk(value, ",; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */ zend_error( E_WARNING, "Cookie values cannot contain any of the following ',; \\t\\r\\n\\013\\014'" ); return FAILURE; } |
从上面实现,我们不难发现,cookie名字中不能含有哪些字符;而对于cookie值,如果允许编码,则允许任意字符了
注意:
PHP中setcookie对value的编码使用的是urlencode:
1. urlencode对有些字符是不编码的,有些时候会带来不必要的麻烦
2. urlencode会将空格编码为’+’,而有些解码函数如JS中的 unescape 、decodeURIComponent 并不会将 ‘+’ 解码为空格的,于是cookie中的’hello world’,使用JS从cookie中取出后就会成为’hello+world’
针对上面两个问题,建议:
1. 自己对cookie值做rawurlencode,使用setrawcookie来设置cookie
2. 自己对cookie值做rawurlencode,使用header函数来set-cookie