RFC标准就是个屁啊。各种行为就没个统一的,根源就是早期协议对header本身的编码没有做规定,而现实中,浏览器有面临这种需求 于是就纷纷乱操了。。
就是个抱怨文 记录下免得自己忘记 主要的内容 这篇文章都讲了 所以 这边给个注解,
主要的意思 大家还是看原文 我来说下目前 RFC 5987 正式规定了 HTTP Header 中多语言编码的处理方式,规定是这样的:
parameter*=charset'lang'value
其中 value 应根据 RFC 3986 Section 2.1 使用百分号进行编码,并且规定浏览器至少应该支持 ASCII 和 UTF-8
2011年 RFC 6266 发布,正式将 Content-Disposition 纳入 HTTP 标准,并再次强调了 RFC 5987 中多语言编码的方法,还给出了一个范例用于解决向后兼容的问题
但是由于HTTP 1.1 草案中建议的使用 RFC 2047 来进行多语言编码的特性从未被主流浏览器支持过,我们把lang那个置空,之后对应到Content-Disposition就是这样的
filename*=utf-8''encoded_text
其中,encoded_text指的是将 UTF-8 编码的原始文件名按照 RFC 3986 进行百分号 urlencode 后得到的( PHP 中对应 rawurlencode()
函数,rawurlencode
会把空格编码成%20,而PHP的urlencode会把空格编码为+号 这个是不对的)。
所以 原文博主给出了一个RFC推荐的方式,测试下来目前也确实安好
1 2 3 |
Content-Disposition: attachment; filename="$encoded_fname"; filename*=utf-8''$encoded_fname |
但是,等等,这还没完 还是那个rawurlencode
的问题。使用这种方式WebKit和Gecko核心的浏览器都没有问题 但是IE又来作了 从IE7~IE11 %20 还是显示成 %20(就是空格被编码以后) 你让强迫症用户咋办啊。尝试不进行编码,Firefox就会把空格后面的字给丢了,Chrome依然可以正常显示。
虽然上面这张hack很优雅的能显示汉字了,但是为了强迫症用户考虑 还得根据IE这个奇葩来处理一下 我现在使用这样的代码
1 2 3 4 5 |
header('Content-type: application/octet-stream'); $fileName = rawurlencode($info['name']); //IE不能正确的处理空格 IE11也不行 还是避免不了hack IE6必须附加一个正确的英文扩展名 if (strpos($_SERVER["HTTP_USER_AGENT"],'Trident') !== false) $fileName = str_replace('%20','_',$fileName); header(sprintf("Content-Disposition: attachment; filename=%1\$s; filename*=%2\$s''%1\$s",$fileName,(defined("CHARSET"))?CHARSET:'UTF-8')); |
我把%20替换成了下划线 当然直接替换成空格也是可以的。还是免不得对IE这个奇葩做一些特殊处理 但是已经比网上流传的那些trick更加符合标准多了。我喜欢这种方式。
补充一句:DZ的那个做法也是不恰当的。