【问题标题】:Symfony2 - File download and 'The filename fallback must only contain ASCII characters.' errorSymfony2 - 文件下载和“文件名回退只能包含 ASCII 字符。”错误
【发布时间】:2025-12-14 11:50:02
【问题描述】:

在这里使用 Symfony 2.5,用户将 MS Office 文件上传到我们的应用程序中,并在以后根据需要下载。现在,当文件附件包含非 ascii 字符(这在我们来自捷克*时很常见)时,Symfony 会引发错误“文件名后备必须只包含 ASCII 字符。”

我发现了很多关于这个问题的报告和讨论,例如

https://github.com/symfony/symfony/issues/9093

...但没有真正的解决方案。我知道我可以在制作 Content-Disposition 标头时将文件名转换为 ascci,但它会更改呈现给用户的文件名,这对用户来说不是很好而且很容易产生误导。有没有办法避免这种情况并能够提供以前的文件名?能够下载文件名中包含非 ascii 字符的文件在互联网上很常见,为什么会有这种限制?

通过关注How to encode the filename parameter of Content-Disposition header in HTTP?,我什至尝试使用 urlencode() 对文件名进行编码,但现在它说 % is not allowed char :-(

更新 1: 这是我正在使用的代码 sn-p。我正在使用流式传输对浏览器的响应,并且我认为标题是手动定义的。

$response = new StreamedResponse();
$response->headers->set('Content-Type', $upload->getMimeType());
$contentDisposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $upload->getFilename());
$response->headers->set('Content-Disposition', $contentDisposition);

【问题讨论】:

  • 在 github 页面上,这个家伙说,“这是因为 HTTP 指定 Content-Disposition 标头的方式” - 虽然这对于 RFC 2616 是正确的,但这是现在被 RFC 6266 取代,它指定了一个额外的 filename* 参数(注意末尾的 *)以使用 ISO-8859-1 以外的编码。这当然不会帮助您解决最初的问题(但如果您愿意,可能有助于与 github 上的 symfony 人员争论)。
  • 在他们愿意改变之前,我建议您自己寻找一种方法来发送该标头(通过 symfony 提供的任何方式),以便 BinaryFileResponse 的标头(或您正在使用的任何创建下载)创建被您指定的覆盖。
  • 谢谢,我用代码 sn-p 对我的问题进行了 ipdated。在这种情况下如何自己发送标头?
  • 究竟是什么方法引发了异常/错误?如果是makeDisposition……那就干脆别用那个方法,自己创造价值……
  • 我今天有点傻 :-( ,确定它是由 'makeDisposition' 方法引起的,我忽略了它并自己创建了标题,它现在可以工作了......谢谢

标签: php symfony


【解决方案1】:

Symfony 4 在HeaderUtils::makeDisposition 中有$filenameFallback

例子

$filenameFallback = preg_replace(
    '#^.*\.#', 
    md5($filename) . '.', $filename
);

$disposition = $response->headers->makeDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT, 
    $filename, 
    $filenameFallback
);

$response->headers->set('Content-Disposition', $disposition);

【讨论】:

  • 这应该是经过验证的答案。不带非 ASCII 字符的 $filenameFallback 是为了符合底层协议,而 $filename 实际上是用户下载文件的实际名称。所以它解决了问题。