似乎谷歌搜索xsendfile问题产生了许多相互矛盾/过时的点击。
为了充分披露,我正在考虑xsendfile 1.0 beta,记录在https://tn123.org/mod_xsendfile/beta/(此网站通常不会显示在搜索结果中,只是没有/ beta的网站)。我在Linux和Windows上使用apache 2.4和php 5.4.34。除了是最新版本之外,我还需要使用测试版,因为只有测试版网站有使用VC9为apache 2.4构建的Windows二进制文件。
我错误地阅读了文档,其中标题中文件名值的描述如下:
在 标题给出的值(文件名)被定义为url编码, 即将执行unescaping / url-decoding。请参阅XSendFileUnescape。 如果您碰巧使用已经url编码的文件名存储文件,那么 必须“加倍”编码名称...%20 - > %2520
XSendFIleUnescape的描述说:
关闭XSendFileUnescape将恢复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上的源已过时,否则该函数将对象为PHP的urlencode()
函数执行的简单%编码。作为一个疯狂的猜测我尝试调用ap_escape_url()
,但它没有在PHP中定义。因此,将 假设的 编码应用于X-SendFile
标题中的pathname参数?
再观察一次/问题
使用“apache internals”发送文件的XSendFile
的描述可能会让您认为它将使用Content-Type
从文件扩展名构造mod_mime
标头。但事实上它没有,并且示例显示header()
对Content-Type
的明确X-SendFile
调用。所以我的后续是从传递给mod_mime
的路径名构造头的“正确”方法,这样可以保证匹配X-SendFile
如果我们不使用的话会做什么fileinfo
?我能想到的最好的是使用PHP的 $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");
扩展的以下代码 - 但据我所知,没有特别的理由期望它实际上与apache在给出文件名的url时所做的相符。
{{1}}
答案 0 :(得分:2)
我不会接受这个作为问题的答案,因为我还没有找到"""预期使用的编码函数。但我确实找到了这个古老的Apache API文档:http://pedrowa.weba.sk/docs/ApiDoc/apidoc_ap_unescape_url.html。它将ap_unescape_url()的retuen值记录为:
成功时返回0,如果找到错误的转义序列则返回BAD_REQUEST, 如果找到%2F(/),则为NOT_FOUND。
但当然在PHP中,urlencode()和rawurlencode()编码' /'如%2F。
很明显,XSendFile标头中使用的任何完整路径名都必须 NOT 使用其中任何一个函数进行urlencoded !!
我猜测最好的"我可以使用的解决方案:
$encoded = str_replace('%2F', '/', rawurlencode($pathname));
我必须承认,我很惊讶XSendFile文档没有提到这一点。而且我更惊讶的是这个问题在这里没有得到任何答案。我应该将其发布在不同的Stack Exchange站点吗?