【问题标题】:What encoding does xsendfile expect?xsendfile 期望什么编码?
【发布时间】:2014-11-05 23:31:25
【问题描述】:

似乎在谷歌上搜索 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 编码, 即将执行取消转义/url解码。请参阅 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 字符工作。如果你用谷歌搜索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标头中的路径名参数的问题??

另一个观察/问题 XSendFile 使用“apache internals”发送文件的描述可能会让你认为它会从使用mod_mime 的文件扩展名构造一个Content-Type 标头。但实际上并非如此,示例显示了对Content-Type 的显式header() 调用。所以我的后续是从传递给X-SendFile的路径名构造该标头的“正确”方法是什么,这样可以保证匹配mod_mime如果我们不使用X-SendFile会做什么?我能想到的最好的方法是使用 PHP 的 fileinfo 扩展名的以下代码 - 但据我所知,没有特别的理由期望它实际上会匹配 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");

【问题讨论】:

    标签: php apache encoding x-sendfile


    【解决方案1】:

    我不会接受这个作为问题的答案,因为我还没有找到预期使用的“the”编码函数。但我确实找到了这个古老的 Apache API 文档:http://pedrowa.weba.sk/docs/ApiDoc/apidoc_ap_unescape_url.html。它将 ap_unescape_url() 的返回值记录为:

    成功时返回 0,如果发现错误的转义序列则返回 BAD_REQUEST, 如果找到 %2F (/),则为 NOT_FOUND。

    当然,在 PHP 中,urlencode() 和 rawurlencode() 都将 '/' 编码为 %2F。

    很明显,在 XSendFile 标头中使用的任何完整路径名都必须使用这些函数中的任何一个进行 urlencoded!

    我对我使用的“最佳”解决方案的猜测:

    $encoded = str_replace('%2F', '/', rawurlencode($pathname));
    

    我必须承认我很惊讶 XSendFile 文档没有提到这一点。我更惊讶的是这个问题在这里没有得到任何答案。我应该将其发布到其他 Stack Exchange 站点吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 2015-02-28
      • 2016-08-31
      相关资源
      最近更新 更多