【问题标题】:PHP readfile() causing corrupt file downloadsPHP readfile() 导致文件下载损坏
【发布时间】:2012-11-09 16:16:48
【问题描述】:

我正在使用 php 脚本在必要的 javascript 计时器后从我的网站提供下载,此 php 脚本包含在其中,导致下载。但是无论我尝试什么,下载的文件都是损坏的。谁能帮我指出我哪里出错了。

这是我的代码

     <?php
include "db.php";    
 $id = htmlspecialchars($_GET['id']);
 $error = false;
    $conn = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
    if(!($conn)) echo "Failed To Connect To The Database!";
    else{   
        if(mysql_select_db(DB_NAME,$conn)){
            $qry = "SELECT Link FROM downloads WHERE ID=$id";
            try{
                $result = mysql_query($qry);
                if(mysql_num_rows($result)==1){
                    while($rows = mysql_fetch_array($result)){
                        $f=$rows['Link'];
                    }
                    //pathinfo returns an array of information
                    $path = pathinfo($f);
                    //basename say the filename+extension
                    $n = $path['basename'];
                    //NOW comes the action, this statement would say that WHATEVER output given by the script is given in form of an octet-stream, or else to make it easy an application or downloadable
                    header('Content-type: application/octet-stream');
                    header('Content-Length: ' . filesize($f));
                    //This would be the one to rename the file
                    header('Content-Disposition: attachment; filename='.$n.'');
                    //Finally it reads the file and prepare the output
                    readfile($f);
                    exit();
                }else $error = true;
            }catch(Exception $e){
                $error = true;
            }
            if($error) 
            {
                header("Status: 404 Not Found");
                }
        }
  }
?> 

【问题讨论】:

  • 请不要使用mysql_* 函数,因为它们在deprecation process 中。请改用MySQLiPDObe a better PHP Developer
  • &lt;?php 开始前有 5 个空格吗?你有错误报告吗?
  • 去掉起始php标签前的所有空格,用ob_start开始脚本,在readfile前做ob_clean
  • 我正在学习 PDO...感谢您的建议。顺便说一句,这个脚本在 000webhost 上运行,这不太可能很快改变 PHP 版本以获得免费的虚拟主机服务......

标签: php file-io download


【解决方案1】:

这有助于我打开更多输出缓冲区。

//NOW comes the action, this statement would say that WHATEVER output given by the script is given in form of an octet-stream, or else to make it easy an application or downloadable
header('Content-type: application/octet-stream');
header('Content-Length: ' . filesize($f));
//This would be the one to rename the file
header('Content-Disposition: attachment; filename='.$n.'');
//clean all levels of output buffering
while (ob_get_level()) {
    ob_end_clean();
}
readfile($f);
exit();

【讨论】:

  • 那个 'while' 解决了我的问题:下载后丢失了几个字节。我不知道它们是如何相关的,但这解决了我的问题。
【解决方案2】:

首先,正如一些人在 cmets 上指出的那样,删除第一行开始 PHP 标记 (&lt;?php) 之前的所有空格,这样就可以解决问题(除非其他文件包含或需要此文件文件)。

当您在屏幕上打印任何内容时,即使是一个空格,您的服务器也会将标题连同要打印的内容一起发送(在这种情况下,是您的空格)。为防止这种情况发生,您可以:

a) 在写完标题之前不要打印任何东西;

b) 在脚本中首先运行 ob_start(),编写内容,编辑标题,然后在您希望将内容发送到用户浏览器时使用 ob_flush() 和 ob_clean()。

在 b) 中,即使您成功写入标头而没有出错,空格也会损坏您的二进制文件。你应该只写你的二进制内容,而不是二进制内容的几个空格。

ob_ 前缀代表输出缓冲区。当调用ob_start() 时,您告诉您的应用程序您输出的所有内容(echoprintf 等)都应该保存在内存中,直到您明确告诉它“开始”(ob_flush())给客户端。这样,您将输出与标题一起保存,当您完成编写它们时,它们将与内容一起发送。

【讨论】:

  • 是因为php标签前的空格...撞了我这么多头但是自己找不到...非常感谢...及时帮助...跨度>
  • 另外,如果您遇到此问题,请确保您在 flush()ing 输出缓冲区,就像在 documentation 中一样。
  • 我这几天一直在寻找这样的答案...非常感谢,您为我节省了很多时间!
【解决方案3】:
           ob_start();//add this to the beginning of your code 

      if (file_exists($filepath) && is_readable($filepath) ) {
header('Content-Description: File Transfer');
 header("Content-Type: application/octet-stream");
 header("Content-Disposition: attachment; filename=$files");
 header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
   header('Pragma: public');
 header("content-length=".filesize($filepath));
 header("Content-Transfer-Encoding: binary");

   /*add while (ob_get_level()) {
       ob_end_clean();
         }  before readfile()*/
  while (ob_get_level()) {
ob_end_clean();
   }
    flush();
   readfile($filepath);

【讨论】:

  • 嘿,感谢您的回答 - 即使这是一个非常古老的问题。如果您可以在代码 sn-p 周围添加更多信息以帮助找到此答案的任何人理解您的建议和原因,那就太好了。
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2015-07-16
  • 2021-02-15
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多