1

我试图制作一个脚本来从我的本地主机下载图像。只是为了一个学校项目。

我通过 url ("$_GET['file']") 获取文件名。然后我运行这个脚本。每次文件损坏,无法查看。我想下载图像,但是当我尝试使用 word 文档时,它也被损坏了。这是我的代码:

<?php
//get file
$file = $_GET['file'];
//set path of file
$path = $_SERVER['DOCUMENT_ROOT']."/blackbox/mediafiles/"; 
$fullPath = $path.$file;
if ($fd = fopen ($fullPath, "r")) {
    $path_parts = pathinfo($fullPath);
        header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\""); // fore a download
        header("Content-type: application/octet-stream");
        header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
}
    header("Cache-control: private"); // open files directly
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
fclose ($fd);
exit;
?>

有人知道出了什么问题吗?

提前致谢!!

4

4 回答 4

3

尝试以二进制模式显式打开文件:

if ($fd = fopen ($fullPath, "rb")) {

正如关于fopen的文档所述:

Windows 提供了一个文本模式翻译标志 ('t'),它在处理文件时会将 \n 透明地转换为 \r\n。相反,您也可以使用“b”强制二进制模式,这不会转换您的数据。要使用这些标志,请将“b”或“t”指定为模式参数的最后一个字符。

默认翻译模式取决于您使用的 SAPI 和 PHP 版本,因此出于可移植性原因,鼓励您始终指定适当的标志。如果您正在处理纯文本文件并且使用 \n 来分隔脚本中的行尾,则应该使用“t”模式,但希望您的文件可以被记事本等应用程序读取。在所有其他情况下,您应该使用“b”。

如果在处理二进制文件时没有指定 'b' 标志,您的数据可能会遇到奇怪的问题,包括损坏的图像文件和 \r\n 字符的奇怪问题。

于 2012-06-28T12:11:47.060 回答
1

<?php要么是某些东西从 PHP 中抛出错误,要么是文件 ( )中的开始标记之前有前导空格。

做两件事:

  • 确保<of<?php是文件中的第一个字符。确保您的脚本中没有字节顺序标记。
  • 将这些行添加到脚本的顶部:error_reporting(0); ini_set('display_errors', 0);

请注意,如果禁用错误解决了您的问题,则意味着存在需要修复的错误,这不是问题的最终解决方案!

使用readfile()也比打开文件指针并循环它更短、更安全、更高效。

于 2012-06-28T12:13:04.047 回答
1

您可以使用readfile代替手动读取文件和输出。

另外请注意,$_GET['file'] 可以包含 '../' 并打开任何文件,这是一个安全风险。使用basename函数(如果所有文件都在同一个目录中)或限制对 mediafiles 目录之外的文件的访问

<?php
//get file
$file = $_GET['file'];
//set path of file
$path = $_SERVER['DOCUMENT_ROOT']."/blackbox/mediafiles/"; 
$fullPath = $path. basename($file);
if (is_readable($fullPath) {
    $path_parts = pathinfo($fullPath);
    header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\""); // fore a download
    header("Content-type: application/octet-stream");
    header("Content-length: " . filesize($fullPath));
    header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
    header("Cache-control: private"); // open files directly
    readfile($fullPath);
}
exit;
?>
于 2012-06-28T12:12:09.180 回答
1

起初它不是你的答案。但是你真的应该看看 PHP 中的安全性。在您的脚本上,您可以通过 GET 参数和 DOCUMENT_ROOT 访问所有文件。

不要相信用户。

您应该首先过滤变量或将它们与已知的文件列表映射,然后再将它们传递给用户。

PHPSec

于 2012-06-28T12:16:49.833 回答