【问题标题】:PHP readfile doesn't work, but only for 20+ meg filesPHP readfile 不起作用,但仅适用于 20+ meg 文件
【发布时间】:2012-02-27 00:05:31
【问题描述】:

小脚本,用于根据获取字符串向用户发送两个 .pdf 文件之一:

if ($fileToSend == "bigone") { 
   $filename = "largefile.pdf";
   $header = "application/pdf";
} else if ($fileToSend == "smallone") { 
   $filename = "smallfile.pdf";
   $header = "application/pdf";
}
if (file_exists('d/' . $filename)){
    header('Content-type: ' . $header);
    header('Content-disposition: attachment; filename=' . $filename);   
    readfile('d/' . $filename);
} else { 
    echo('No good');
}

文件 d/smallfile.pdf 和 d/largefile.pdf 都存在。 smallfile.pdf 大约为 5 兆。 largefile.pdf 大约 25 兆。

sendFile.php?fileToSend=smallone 有效。

sendFile.php?fileToSend=bigone 不起作用;在FF中,它说

找不到文件 Firefox 在 [url]/sendFile.php?fileToSend=bigone 处找不到文件

没有文件名错误。

我试过了

  • 添加flush();在读取文件之前;这会导致出现下载文件对话框,但随后会提供一个 0 字节的文件
  • 添加flush();在读取文件之前,并添加 header('Content-Length: ' . filesize('d/' . $filename)); - 这工作成功,但需要近 2 分钟来处理(即,一旦我点击 URL,近 2 分钟没有任何反应,然后出现对话框,其中包含要正确下载的实际文件)。

任何帮助将不胜感激。 乔恩

【问题讨论】:

  • 你试过增加 PHP 的内存限制吗?
  • 否;有趣的想法。这会导致这种行为吗?我会问我的管理员。
  • 如果允许,您也可以使用ini_set 自己执行此操作。 ini_set('memory_limit', '128M');

标签: php header readfile


【解决方案1】:

是的,您的问题很可能是在为您提供文件时 php 超时,对此的补救措施是为您提供块以免咀嚼内存和set_time_limit(0);,因此它不会在 60 秒后超时:

 <?php 
 if(isset($_GET['fileToSend'])){

    switch($_GET['fileToSend']){
        case "bigone":
            if(downloadFile("./d/largefile.pdf")===false){
                //failed, do somthing
            }
            break;

        case "smallone":
            if(downloadFile("./d/smallfile.pdf")===false){
                //failed, do something
            }
            break;

        default:
            echo 'No file selected';
            break;

    }

 }

 function downloadFile($file){
    if (file_exists($file)) {
        if(is_dir($file)){return false;}
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($file)).'"';
        header('Content-Transfer-Encoding: binary');
        header('Connection: Keep-Alive');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));

        ob_clean();
        $handle = fopen($file, "rb");
        $chunksize=(filesize($file)/1024);

        set_time_limit(0);
        while (!feof($handle)) {
            echo fgets($handle, $chunksize);
            flush();
        }
        fclose($handle);
        die;
    }else{
        return false;
    }
 }
?>

【讨论】:

  • 劳伦斯 - 我会试一试。对于它的价值,找不到文件会立即返回,所以我不确定这是一个超时问题,但我会尝试。
  • 很高兴能提供帮助,还可以通过更改块大小1024 来限制下载速度。
  • 这里使用ob_clean();要小心。如果你没有启动一个输出缓冲区,并且错误设置没有正确设置,它会生成一个错误渲染下载的文件没用。
【解决方案2】:

会不会是下载时间过长导致 PHP 脚本超时?

如果可能的话,一个更简洁的解决方案是重定向到正确的文件,并让网络服务器直接处理它。

<?php header('Location: http://www.example.com/d/' . $filename) ;?>

【讨论】:

  • 出于几个原因(包括因为它受用户名和唯一令牌保护,以及因为我不希望谷歌抓取它),我宁愿自己提供文件。
【解决方案3】:

流式传输文件时,请确保您已禁用输出缓冲。否则 PHP 会缓冲整个文件。在您的情况下,PHP 可能内存不足,因为它正在缓冲整个文件。在 readfile 之前添加 ob_clean,flush:

ob_clean();
flush();
readfile('d/' . $filename);

浏览器只要在接收数据就不会超时,所以如果需要下载可能需要10分钟。

【讨论】:

    猜你喜欢
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2016-04-20
    • 2014-12-09
    相关资源
    最近更新 更多