【问题标题】:Having issues with php downloadphp下载有问题
【发布时间】:2018-09-04 23:53:17
【问题描述】:

所以我之前遇到过这个问题,但这是一个 PHP 版本问题。现在不是这样了。

从未更改过代码,并且运行良好。仅更改了托管,但我认为这应该没有问题。

我唯一得到的是垃圾代码。

下载链接如下:https://example.com/forum/download.php?file=TEST.zip

<?php

$file = 'TEST.zip';
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header("Content-Type: application/octet-stream");
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    while (ob_get_level()) {
        ob_end_clean();
    }
    readfile($file);
    exit;
}

?>

【问题讨论】:

  • garbage code. 是什么意思。而且我不认为这个问题应该看起来像它,只是说块注释是&lt; in SO,块代码是 4 个前导空格。
  • 我是新来的,如果你能帮助我,那会有所帮助。
  • 嗯,我要做的第一件事就是在循环之后移动readfileexit,你真的不希望它们在循环中。如果ob_get_level() &gt; 1 可能会导致文件损坏
  • 实际上它在循环之外,这就是格式很重要的原因。但接下来我要做的就是删除这个垃圾?&gt;

标签: php force-download


【解决方案1】:

在有限的代码中我能想到的最好的就是删除这个东西?&gt;我讨厌这个标签,我从不亲自使用它。

如果 PHP 之后没有类似 HTML 的内容,则不需要它,如果这样,它实际上会损坏您的文件下载

?>
//empty line here

由于 PHP 的工作方式,它会将 TAG 之外的任何内容作为内容输出,因此它们之前或之后的任何内容都可能在您的文件中结束,具体取决于调用的位置等。

我猜exit 会解决这个问题,但我不喜欢那个标签。因为如果你在你的应用程序中包含一堆 PHP 文件,只需要一个在标签之外有空格的文件就会把事情搞砸,祝你好运。

这一点

while (ob_get_level()) {
    ob_end_clean();
}

如果设置了输出缓冲区,则清除它,如果这是您文件的全部内容,则可能未设置。我个人会这样做:

<?php  
 //start output buffering
 ob_start();

//be careful with casing
// - Windows is case insensitive
// - Linux is case sensitive
//for example if the file is named text.zip
//it will work on Windows, but be mission on Linux

$file = 'TEST.zip';

//without the file no download can happen
// -- so kill it before header are sent
// -- that way if file is missing we can easily debug it.
if (file_exists($file)) die("Missing required file {$file}");

header('Content-Description: File Transfer');
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));

$debug = '';
while (ob_get_level()) {
    //end all output buffering before file download
    //save this stuff, there could be useful debug information in here.
    $debug .= ob_get_clean();
}

if(!empty($debug)){
    //put "stuff" in a file 
    // -- FILE_APPEND = append to end of log
    // -- lock writing on the file for this opperation
    // --- its possible 2 clients could download the same time.
    file_put_contents(__DIR__.'/download_error.txt', $debug, FILE_APPEND|FILE_EX);
}

//finally output the file
readfile($file);
//this is good
exit;

这样您可以记录输出而不会弄乱下载。基本上你把那些东西扔掉了,它可能是有用的信息。

除此之外,其他一切看起来都不错,我的意思是没有太多可能出错的地方。如果我知道garbage code. 是什么,也许我可以提供更多帮助。可能原文件不行,谁知道呢……

我不能肯定地说这会解决你的问题,我所说的大部分只是我个人对日志记录和执行顺序的偏好。但它可能无法解决它。

安全

作为最后一点,我应该提到你应该非常小心这个?file=TEST.zip 恶意用户可以这样做。

 ?file=../../../../etc/passwd  //which is a bad example (unless PHP is admin)

基本上,他们可以使用您的输入来遍历目录结构。更好的方法是这样做

 $file = false;
 switch($_GET['file']){
      case 'TEST.zip': //you can even use a hash 
          $file = 'TEST.zip';
      break;

      //you can even use a hash instead of the name
      //this prevents errors caused by things like quotes in the filename.
      //something as simple as switch(md5($_GET['file'])), is finr
      case 'uiOzAWe8aser':
          //then the user has no access to your filesystem
         $file = 'TEST.zip';
      break;
      default: die('File not found '.$_GET['file'];
 }

当然这在很多情况下可能并不实用,但你可以在数据库等中验证它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多