下载.zip文件时运行了一个损坏的php文件

17

我想强制下载一个受保护的zip文件(我不希望人们在未登录的情况下访问它)。

我已经创建了用于登录等操作的函数,但我遇到了一个问题,即下载的文件出现损坏。

这是我拥有的代码:

$file='../downloads/'.$filename;
header("Content-type: application/zip;\n");
header("Content-Transfer-Encoding: Binary");
header("Content-length: ".filesize($file).";\n");
header("Content-disposition: attachment; filename=\"".basename($file)."\"");
readfile("$file");
exit();

这里是错误信息:无法打开文件:它似乎不是有效的存档文件。

除此之外,文件可以正常下载,所以肯定是我的头部信息设置有问题。

有什么想法吗?

7个回答

37

这个问题可能有几个原因。也许您的文件找不到,或者无法读取,因此文件的内容只是 PHP 错误消息。或者 HTTP 标头已经发送。又或者您有一些额外的输出内容,这会导致文件内容损坏。

尝试在脚本中添加一些错误处理,例如:

$file='../downloads/'.$filename;
if (headers_sent()) {
    echo 'HTTP header already sent';
} else {
    if (!is_file($file)) {
        header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
        echo 'File not found';
    } else if (!is_readable($file)) {
        header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
        echo 'File not readable';
    } else {
        header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
        header("Content-Type: application/zip");
        header("Content-Transfer-Encoding: Binary");
        header("Content-Length: ".filesize($file));
        header("Content-Disposition: attachment; filename=\"".basename($file)."\"");
        readfile($file);
        exit;
    }
}

太棒了!这就回答了问题。 就是这样...我认为发送的头部信息是导致它不工作的原因。 - Troy
@Gumbo 我的文件确实存在,但是为什么会返回“找不到文件”的错误呢?有什么想法吗? - Momoro
从@Pekka读取消息。我的文件里有一条消息。所以,我获取了手动的PHP和一个用户marro在cz之前放置---ob_clean(); flush(); ---在readfile()之前。它有效! - LUISAO

11

我打赌会出现PHP错误,并且错误消息会弄乱ZIP文件。请求的文件可能不存在。

用记事本或类似文本编辑器打开ZIP文件,找出问题所在。


我同意,我打赌readfile()中有一个错误,比如无效的权限,或者可以找到... - prodigitalson
用记事本打开以查看错误信息真是救了我一命。谢谢! :) - Rajib Sarker
这个答案让我想到,也许任何输出(不仅仅是错误)都可能会破坏Zip文件。结果发现我的echo语句正在搞砸它。删除所有的echo,问题解决了。 - Willt42
谢谢@Pekka。我的文件里面有一条消息。所以,我查看了PHP手册,并且用户cz的marro提供了一个解决方案——在readfile()之前加上---ob_clean(); flush();---。它奏效了! - LUISAO

2
晚回答,但可能对于无法使“强制下载”起作用的用户有用。在您的php脚本顶部添加以下内容。
<?php
apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);

2

我曾经在处理大zip文件时遇到过类似的问题。

以下设置对我有用:

  • Upload_max_filesize - 1500 M
  • Max_input_time - 1000
  • Memory_limit - 640M
  • Max_execution_time - 1800
  • Post_max_size - 2000 M

在你的php文件中也同样需要这些设置。

    $filename = "MyFile.zip";           
    $filepath='../downloads/'.$filename;    //your folder file path    
    header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
    header("Content-Type: application/zip");
    header("Content-Transfer-Encoding: Binary");    
    header("Content-Length: ".filesize($filepath)); 
    header("Content-Disposition:attachment;filename=\"".basename($filepath)."\"");


    while (ob_get_level()) 
    {
     ob_end_clean();
     }
    readfile($filepath);   
    exit;
    ob_start ();

这段代码之所以能够运行,完全是因为 "while" 部分。不过,"while ob_get_level ob_end_clean" 这句话的意思是什么呢? - Evanh Shumakov
ob_get_level — 返回输出缓冲机制的嵌套级别ob_end_clean — 清除(擦除)输出缓冲区并关闭输出缓冲 - borgomeister

1

以下是解决方案: 创建一个名为 .htaccess 的文件 在其中写入以下行: SetEnv no-gzip dont-vary

将该文件上传到您的网站。如果您已经有了该文件,请进行上述更改。


0

尝试使用此方法查找是否存在任何错误

error_reporting(0);

在编写头文件之前不要打印任何内容; 在你的脚本中运行ob_start(),在代码编辑后修改头文件,然后使用ob_flush()和ob_clean()


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接