我开发了一个C++ CGI应用程序,可以传递包含特殊字符的文件名,例如"weird # € = { } ; filename.txt"。
似乎没有可能以适用于每个浏览器的方式设置HTTP Content-Dispostion,例如:
- Internet Explorer
- Firefox
- Chrome
- Opera
- Safari
现在这就是我所做到的: Internet Explorer (添加双引号并替换#和;)
Content-Disposition: attachment; filename="weird %23 € = { } %3B filename.txt"
Firefox(双引号似乎可以使用,没有更多要做的了):
Content-Disposition: attachment; filename="weird # € = { } ; filename.txt"
另一个可行的选择:
Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
Chrome
当只使用双引号时,会出现以下问题:
- = 在文件名中会消失
- € 会被替换为 -
但是这样可以解决问题:
Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
Opera
使用双引号或语法: filename*=UTF-8''...会产生以下问题:
- 文件名中多个连接在一起的空格被减少为一个
- { 和 } 消失: "ab{}cd.txt" -> "abcd.txt"
- 文件名在 ; 后被截断: "abc ; def.txt" -> "abc"
编辑2: 这是由于文件名长度限制。这种语法在Opera中可以使用:
Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
苹果浏览器
€ will be replaced by an invisble character (using double quotes)
no solution that prevents that little problem
另一个线程中的建议(如上所述)使用
Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt
对我没有用。转义字符不会被翻译回来,或者浏览器想要将文件保存为我的cgi应用程序的名称。这是因为我的编码错误。我没有按照RFC 5987进行编码。但Safari也没有使用这种编码。到目前为止,对于€字符还没有解决方案。
顺便说一句:UTF-8转换器 http://www.rishida.net/tools/conversion/
我使用每个浏览器的最新版本进行了测试:
- Firefox 7
- Internet Explorer 9
- Chrome 15
- Opera 11.5
- Safari 5.1
PS:我尝试了键盘上的所有特殊字符。在本主题中,我只使用了那些造成麻烦的字符。
编辑:
我还尝试过一个包含键盘上所有特殊字符(文件名中可能出现的)的文件名,但与上面的测试字符串不同,这并没有起作用:
完整的测试字符串:
0 ! § $ % & ( ) = ` ´ { } [ ] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg
编码测试字符串:
0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg
使用这种方法:
Content-Disposition: attachment; filename*=UTF-8''0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg
我得到了以下结果:
- Firefox可用
- Chrome可用
- IE:$ % & ( ) = ` ´ { } [ ] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg(删除了前6个字符)。编辑2:这是因为浏览器的文件名长度限制。它开始从字符串的开头截断文件名。我没有深入研究,但看起来普通文件名可以长达200个字符,具有许多转义序列的文件名甚至更多,但少于250个。但没关系。
- Opera:0!§ $ % & ( ) = ` ´ [] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg(与之前一样缺少一些字符)。编辑2:我缩短了我的测试字符串,因为我怀疑Opera存在文件名长度“问题”,就像IE一样,在那里也能正常工作。
- Safari不支持该语法。这是意料之中的。
编辑2:
到目前为止,filename*=UTF-8''filname escape sequence"语法适用于除Safari之外的所有浏览器。而唯一被Safari替换的字符是€。我想我可以接受这一点。谢谢!
编辑3:文件名长度
我注意到了一些文件名长度问题。
- Internet Explorer:文件名可以长达147个字符。如果字符串不包含转义序列,则文件名长度为147个字符。如果包含,则文件名可能会有所变化。生成的文件名比147个字符短。但是它们不同。我使用了2个转义序列,文件名缩短了5个字符,我使用了许多转义序列,文件名仅缩短了2个字符。我找不到规律。
- 其他浏览器似乎没有这个问题。如果文件系统能够处理,它们将保存文件。例如,我尝试使用250个字符,浏览器说我必须缩短文件名(Chrome),或者他们自己缩短到220(Opera)或210(Firefox)个字符。Opera切断了文件末尾。Safari尝试保存那个长文件名,最终没有保存,并在下载列表中写入“-1”作为文件名。