【问题标题】:PHP readfile() adding extra bytes to downloaded filePHP readfile()向下载的文件添加额外的字节
【发布时间】:2011-11-07 19:37:11
【问题描述】:

我正在尝试解决从 php 脚本下载“zip”文件时遇到的问题。似乎当我使用以下代码下载文件时,下载的文件在文件开头附加了一个额外的 0A09,导致 winzip 抛出损坏错误。

<?php
$pagePermissions = 7;
require_once ('util/check.php');
require_once ('util/file_manager.php');

$file_manager = new FileManager();

if ($_SERVER['REQUEST_METHOD'] == "GET") {
if (isset($_GET['q']) && $_GET['q'] == 'logout') {
    //require_once ('util/users.php');
    //$userdata = new Userdata();
    $userdata -> kill_session();
    header("Location: download.php");
    exit ;
}

if (isset($_GET['q']) && $_GET['q'] == 'fetch') {
    if (isset($_GET['name'])) {
        @apache_setenv('no-gzip', 1); 
        header("Content-length: " . filesize('upload/' . $_GET['name'])); 
        header('Content-type: application/zip');
        //header("Content-Disposition: attachment; filename=\"{$_GET['name']}\" ");
        header("Content-Disposition: attachment; filename={$_GET['name']}");
        header('Content-Transfer-Encoding: binary');

        readfile('upload/' . $_GET['name']);
        exit();
    }
}

}
?>

任何帮助将不胜感激,文件可以通过直接链接很好地下载,文件开头附加的 2 个字节仅通过此代码发生。 提前致谢

【问题讨论】:

  • 我希望你没有在生产环境中使用它,它允许访问者在你的服务器中获取 PHP 可以访问的 any 文件。
  • 与您的错误无关,但是...过滤您的输入!否则我可以在 URL 上提供 ?name=../../../etc/passwd。
  • readfile() 将在末尾追加从文件读取的字节数。

标签: php


【解决方案1】:

删除最后一个?&gt; 并检查您的开始标记是否位于第一行,即脚本的第一个字符处。 PHP 文件必须以结束标记结束。您下载的文件包含(或更多)\r\n 的原因是因为 PHP 将直接回显(输出)&lt;?php ?&gt; 之外的任何内容。通常,如果您的脚本不回显 HTML,您将省略结束 PHP 标记,因为它不是强制性的,而且 IMO 产生的麻烦比其他任何事情都多。

** 编辑 **

如果您阅读了readfile 的 PHP 手册,您有一个有用的示例,几乎就是您问题中的代码,少了两行代码:

@apache_setenv('no-gzip', 1); 
header("Content-length: " . filesize('upload/' . $_GET['name'])); 
header('Content-type: application/zip');
//header("Content-Disposition: attachment; filename=\"{$_GET['name']}\" ");
header("Content-Disposition: attachment; filename={$_GET['name']}");
header('Content-Transfer-Encoding: binary');

// add these two lines
ob_clean();   // discard any data in the output buffer (if possible)
flush();      // flush headers (if possible)

readfile('upload/' . $_GET['name']);
exit();

如果在那之后你仍然有问题,那么问题可能不在于你的 PHP 代码。

【讨论】:

  • 还要确保 &lt;?php 确实位于脚本第一行的开头,之前没有任何内容。哦,请确保这些内容也适用于您包含的任何其他 PHP 文件。
  • 这听起来像是一个空白问题,但由于 readfile 在关闭之前?>读取文件后的空白真的是问题吗?对于发送二进制文件,如果您可以访问所需的 apache 模块,我更喜欢使用 X-Sendfile。使用 x-sendfile 还增加了一些安全性,例如缺少 GET 清理 Apache Web 根目录之外的调用文件。
  • 是的。函数readfile 输出文件然后返回。那么如果脚本末尾的结束标签后面有多余的字符,那么在关闭 HTTP 连接之前都会回显所有内容。
  • 但是,在这个问题中,问题似乎来自于 PHP 开头的标签,因为额外的 \r\n 位于开头。
  • 太棒了,ob_clean();为我做的。
【解决方案2】:

抱歉回复晚了.....

在你投票之前我不知道我是对的.....

将您的代码编辑为:

ob_start(""); 
//instead of ob_start(); with out a null callback 

ob_end_clean();  //at the end , Note : "important" add instead of ob_end_flush()

即;

ob_start("");
//header           
ob_end_clean();

【讨论】:

    【解决方案3】:

    我今天遇到了与 readfile() 相关的类似问题。原来我的 php.ini 文件启用了输出压缩,这弄乱了试图检索文件的 flash 模块。 (我猜它无法处理它。)

    我所要做的就是关闭 php.ini 文件中的压缩:

    zlib.output_compression = off
    

    或者,在您的脚本中:

    <?php ini_set('zlib.output_compression', 'Off'); ?> 
    

    只是想分享一下,以防其他人无法从 readfile() 输出接收文件。

    【讨论】:

      【解决方案4】:

      我在 Joomla (2.5) 中遇到了类似的问题,使用 readfile 将 Excel (.xls) 文件传回给用户。

      我还注意到文本和 xml 文件在开始时也插入了一些代码,但几乎忽略了它,因为 xml 和文本阅读器仍然倾向于打开文件。

      我决定尝试 Yanick 的建议(而不是使用服务器压缩选项),只需在 readfile 之前刷新缓冲区:

      ob_clean();   // discard any data in the output buffer (if possible)
      flush();      // flush headers (if possible)
      

      嘿,很快,它奏效了。我建议将此作为替代答案:为了突出根本原因,表明它可以解决 Joomla 问题,并且因为我混合了二进制和文本返回。

      只是补充一下(如果这很明显,请道歉!)- mime 类型设置工作正常:

      $document = JFactory::getDocument();
      $document->setMimeEncoding($mimetype);
      

      当 mime 类型为 application/octet-stream 时,我什至不需要设置“Content-Transfer-Encoding: binary”。

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,所以我使用了这个标题并得到了解决方案。

            $filename = ABSPATH.'/wp-content/summary/user_content/'.trim($file);
            header('Pragma: public');
            header('Expires: 0');
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header('Content-Description: File Transfer');
            header('Content-Type: text/text');
            header('Content-Disposition: attachment; filename="'.$file.'"');
            header('Content-Transfer-Encoding: binary');
            header('Cache-Control: max-age=0');
            readfile($filename);
            exit;
        

        【讨论】:

          【解决方案6】:

          我在图像文件的开头遇到了类似的空白问题。

          我怀疑我的问题是由打开前的空白引起的

          对我有用的是:

          @ob_start('');  //@ supresses a warning  
          //header entries
          ob_end_clean();
          ob_clean();
          readfile($file);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-08-05
            • 2016-11-12
            • 2021-06-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多