PHP - 如何在 Content-Disposition 中设置完整的目录路径?

5
我正在向下载页面传递文件名。
例如:somefile.xls

下载页面会将完整的目录路径添加回文件名中。
例如:c:\temp\somefile.xls

问题在于,现在设置头部的 'Content-Disposition' 不起作用了。它想要下载的文件名是完整的目录-文件名路径。 例如:c_temp_somefile

'Content-Disposition' 能否处理完整路径?

如果可以的话,我该如何让我的脚本正确地下载文件?

代码如下:

$myad = $_GET['myad'];
$glob_string =  realpath('/foldera/folderb/folderc'). DIRECTORY_SEPARATOR .$myad;

header('Content-Type: application/excel');
$headerstring = 'Content-Disposition: attachment; filename='.$glob_string;
header($headerstring);
readfile($myad);

更新后的代码(来自答案):

$myad = $_GET['myad'];
$glob_string =  realpath('/mit/mit_tm/mrl_bol'). DIRECTORY_SEPARATOR .$myad;

header('Content-Type: application/excel');
$headerstring = 'Content-Disposition: attachment; filename='.$myad;
header($headerstring);
readfile($glob_string);    
4个回答

9
请勿通过header字符串传递完整路径,而应使用基本名称($myad)。 您应该为$_GET['myad']使用更好的验证,因为您的脚本将向用户传递任意路径(readfile()获取未经过滤的用户输入)。 这是一个安全漏洞! 使用realpath计算实际路径,确保文件在允许的文件夹内,然后在完整路径上使用basename()以获得纯文件名子字符串。通过Content-Disposition头传递此子字符串,但对于readfile()请使用实际路径。
更新:您的更新代码仍然存在安全漏洞。 如果$_GET['myad']包含../../../some/full/path,则您的脚本将乐意向客户端发送任何请求的可读文件。 您应该类似于以下片段使用某些内容:
$myad = $_GET['myad'];

$rootDir = realpath('/mit/mit_tm/mrl_bol');
$fullPath = realpath($rootDir . '/' . $myad);

// Note that, on UNIX systems, realpath() will return false if a path
// does not exist, but an absolute non-existing path on Windows.
if ($fullPath && is_readable($fullPath) && dirname($fullPath) === $rootDir) {
    // OK, the requested file exists and is in the allowed root directory.
    header('Content-Type: application/excel');
    // basename() returns just the file name.
    header('Content-Disposition: attachment; filename=' . basename($fullPath));
    readfile($fullPath);
}

为什么这个被踩了?它看起来确实是一个重大的安全漏洞。 - qid
费迪南德是正确的,这是一个巨大的安全漏洞:恶意用户可以下载几乎所有Web服务器可以访问的内容(例如数据库密码)。然而,即使有有效路径,关于Content-Disposition头,浏览器仍将忽略它。 - Patonza

9
你可以在 Content-Disposition 头中放置几乎任何你想要的东西,但出于安全原因,大多数浏览器会忽略或替换路径,并将其转换为运行在操作系统上的有效文件名。 Content-Disposition 只是对浏览器的提示,它并不是网络客户端必须遵守的设置。
所以,不,你不能强制下载到客户端计算机的特定目录。

2
是的。事实上,HTTP 1.1规范明确从Content-disposition头中排除目录路径信息:http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1 - Jordan Running
+1 - 谢谢。很有道理 - 我的代码是为内部网站编写的,所以安全漏洞并不太重要。 - John M
1
即使是为了内部网络,我也会遵循费迪南德的建议:避免漏洞要比以后修补它们好得多 :) - Patonza

3
永远不要这样做。如果浏览器接受完整路径,那么就是时候快速提交错误报告了:这将是一个重大的安全漏洞。

0

我不确定这是否有帮助,但我认为Excel文档的内容类型标头可能并不正确。我自己没有尝试过,但那些微软软件包都很复杂,比如Microsoft Word是
application/vnd.openxmlformats-officedocument.wordprocessingml.document


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接