PHP 文件下载总是损坏(50% 的时间)

Posted

技术标签:

【中文标题】PHP 文件下载总是损坏(50% 的时间)【英文标题】:PHP File Download Is Always Corrupt (50% of the time) 【发布时间】:2010-12-16 20:35:29 【问题描述】:

我有一个自动下载文件的脚本。 它可以完美地下载文件,但问题是 50% 或更多的时间,它会下载损坏的文件。

通常删除并再次下载会起作用,但并非总是如此。

我怎样才能让这个下载始终 100% 完美,不损坏? 文件大小因下载的文件而异。

<?php

// Automatically Start File Download 
if (isset($_GET['filename'])):
    $filename = $_GET['filename'];
    $domain = "http://www.domain.com";
    $filepath = "/addons/downloads/websites/";

     //BUILD THE FILE INFORMATION
     $file = $domain . $filepath . $filename;
     // echo $filepath . $filename;
     // echo $file;

     //CREATE/OUTPUT THE HEADER
    if (file_exists("/home/unrealde/public_html/ebook/domain.com/".$filepath . $filename)):
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
        ob_clean();
        flush();
        readfile($file);

    else: 
        $errorMsg = "<b>Download Error: File $filename Doesnt Exist!</b> <br />Please Contact <a href='mailto:support@domain.com'>support@domain.com</a>";
    endif;

    echo $errorMsg;

else: 
    // don't download any file
endif;
?>

【问题讨论】:

那么...如果它总是在 50% 的时间里损坏,难道它只有一半的时间损坏了吗? 某事怎么会“总是”并且有 50% 的时间? 只是为了引起争议 :-) 但说真的,我需要一些帮助 建议 1:理清你的缩进 - 它让阅读代码变得非常困难。建议 2:为您的 if()s 使用大括号 符号而不是冒号 : 符号;再次,它会更容易阅读。 (它们只是建议,但当代码易于阅读时更容易提供帮助:-)) “50% 的时间,它每次都有效。” 【参考方案1】:

我的预感是你的程序中的某些东西正在输出文件本身以外的一些数据。

您是否在二进制编辑器中查看了损坏的文件并将其与未损坏的版本进行了比较?您会发现,无论是在文件的开头还是结尾,都有一些意想不到的数据,这就是破坏文件的原因。

如果您以这种方式查看该文件,问题所在可能会变得非常明显。例如,您可能拥有该文件,然后是一条错误消息,在这种情况下,您的行 echo $errorMsg; 可能是罪魁祸首。

或者,您可能有一些空白空间。这也可能是相同的错误消息,或者可能是您的 PHP 标记上方或下方有空行,正在打印。

我的第一个建议是,因为当文件输出时程序实际上已经完成,所以在readfile(); 行之后立即放置一个显式的die; 函数。这将绝对防止在文件发送后输出任何进一步的虚假数据。

如果在readfile(); 之前发送了错误数据,这将无济于事,但它确实可以一口气排除一半可能的问题。

【讨论】:

嗨。谢谢你。我已添加它并将对其进行测试。如果不是这样,我该怎么做才能“猛扑”文件的前半部分来添加数据?谢谢! 你的 die; 建议对我有用,但前提是我也将 exit; 放在它后面(并删除了其他任何东西,如空格或 echo 之后的电话。)谢谢! @Basheer dieexit 在 PHP 中是同义词;两者都做同样的事情。如果did 不起作用,那么exit 也不会有任何不同。因此,我认为在您的情况下,删除所有空格和之后的 echos 会有所不同。 哇,我不敢相信我错过了。你是绝对正确的。感谢您指出这一点。【参考方案2】:

你不能只 tar/gzip/zip 内容并提供一个 tar/gzip/zip 文件供下载吗?

与 http 传输相比,较小的文件传输增加了成功的机会, 更重要的是,您可以提供校验和供用户验证

【讨论】:

在下载之前和之后验证文件的大小。如果它们不匹配,请废弃并再次下载(即校验和)。由于互联网的性质(可能会丢失数据包),不可能保证“永远完美,未损坏”,因此我们围绕它进行编程。 gzip 解决方案是个好主意,假设您可以访问正在下载的文件(或拥有这些文件的服务器,并且可以编写使用 Zip() 库的包装函数)。【参考方案3】:

尝试添加 error_reporting(0);在脚本的开头。只是为了好玩。如果您检查 php.net 中的 readfile,其他人报告说这会有所帮助。

【讨论】:

以上是关于PHP 文件下载总是损坏(50% 的时间)的主要内容,如果未能解决你的问题,请参考以下文章

DotNetCore.NPOI 总是创建损坏的文件

盖茨比 - 下载的文件总是损坏

IIS无法打开PHP文件

PHP强制下载.xlsx文件损坏

PHP强制下载.xlsx文件损坏

PHP:如何检查 gz 文件是不是损坏?