似乎谷歌搜索 xsendfile 问题会产生许多相互矛盾/过时的命中。
为了全面披露,我正在讨论 xsendfile 1.0 beta,记录在https://tn123.org/mod_xsendfile/beta/(该站点通常不会出现在搜索结果中,只是没有 /beta 的站点做)。我在 Linux 和 Windows 上都将它与 apache 2.4 和 php 5.4.34 一起使用。除了是最新版本之外,我还需要使用 beta 版本,因为只有 beta 站点具有使用 VC9 为 apache 2.4 构建的 Windows 二进制文件。
我犯了阅读文档的错误,其中标题中文件名值的描述说:
头部给定的值(文件名)被假定为 url-encoded,即 unescaping/url-decoding 将被执行。请参阅 XSendFileUnescape。如果您碰巧使用已经 url 编码的文件名存储文件,则必须“双重”对名称进行编码... %20 -> %2520
XSendFIleUnescape 的描述说:
将 XSendFileUnescape 设置为 off 将恢复 1.0 之前使用原始标头值的行为,而不是先尝试 unescape/url-decode。
关于相对路径的文档清楚地表明X-SendFile
标题上的文件名应该是完整的路径名。所以我小心地通过php的urlencode
函数运行我的路径名。
对我来说,最终结果总是在 Linux 和 Windows 上出现服务器内部错误(500 状态代码)。当我在server config
上下文中使用我的 XSendFilePath 指令时,文档说这是允许的,我的错误日志中没有更具体的信息。但是当我(最终)将该指令移到Directory
上下文时,我逐渐在我的错误日志中得到了这个:
(404)Unknown error: [client 127.0.0.1:20742] xsendfile: bad file name encoding
最终,出于绝望,我说“搞砸了文档”,并删除urlencode
了路径名上的 。突然间它开始完美运行(Windows 和 Linux)!!!
我没有任何包含非 ASCII 字符的路径名,所以我准备好了。但我确实想知道应该应用哪种编码来允许非 ASCII 字符工作。如果您 google xsendfile: bad file name encoding
,您将在https://github.com/nmaier/mod_xsendfile/blob/master/mod_xsendfile.c找到以下源代码,其中该消息字符串是通过采用以下真正分支生成的:
rv = ap_unescape_url(file);
if (rv != OK) {
但我找不到好的描述或源代码ap_unescape_url()
。除非 github 上的源代码已过时,否则该函数反对 PHPurlencode()
函数执行的简单 % 编码。作为一个疯狂的猜测,我尝试调用ap_escape_url()
,但它没有在 PHP 中定义。所以这就留下了应该对X-SendFile
标头中的路径名参数应用什么编码的问题?
另一个观察/问题使用“apache internals”发送文件
的描述XSendFile
可能会让你认为它会Content-Type
使用mod_mime
. 但实际上并非如此,并且示例显示了header()
对Content-Type
. 所以我的后续工作是从传递给的路径名构造该标头的“正确”方法是什么X-SendFile
,这样可以保证匹配mod_mime
如果我们不使用会做什么X-SendFile
?我能想到的最好的方法是使用 PHPfileinfo
扩展的以下代码 - 但据我所知,没有特别的理由期望它实际上会匹配 apache 在给定文件名的 url 时所做的事情。
$finfo = new finfo(FILEINFO_MIME);
$mime_info = $finfo->file($pathname);
if (! strlen($mime_info)) {
$mime_info = 'application/octet-stream; charset=binary';
}
$basename = basename($pathname);
$encoded = "$pathname";
header("Content-Type: $mime_info");
header("Content-Disposition: attachment; filename=\"$basename\"");
header("X-SendFile: $encoded");