PHP zip 下载错误

Posted

技术标签:

【中文标题】PHP zip 下载错误【英文标题】:PHP zip download bug 【发布时间】:2012-09-25 23:27:01 【问题描述】:

我有一个脚本,可让用户根据要求下载 zip 文件。它在计算机浏览器上 100% 有效,但不适用于 android/移动浏览器,仅 Opera(移动)除外。

这是我的脚本。

    $leads = new Packer($zip_name);
$index = 1;
$count = 0;
foreach($cLeads->lastUnitInfo['leads'] as $lead)

    // build a request string
    $export = 'export_lead_'.$index;
    $req    = $_POST[$export];

    // add it to the zip file
    if(isset($req) && $req == '1')
    
        // debug only
        //echo 'adding lead: '.$lead['file_name'].'<br />';
        $leads->addLead('leads/'.$lead['file_name'],$lead['item_name']);
        $count++;
        //echo 'count: '.$count.'<br/>';
    
    $index++;


// debug
//exit('count: '.$count);  // displays same results on all browsers.

// we got anything packed ?
if($count <= 0)    //// <-------- BLOCK OF BUG ON MOBILE PHONE

    if(file_exists($zip_name))
        unlink($zip_name);  // delete the zip file created.
    exit('<h1>Nothing to export</h1>'); 
   ///// <---------------------- END BLOCK

// download the leads here.
$leads->purge();
exit;

这是我的purge() 函数

public function purge($zip_name = 'leads.zip')
  
    header('Content-type: application/zip');
    header('Content-Disposition: attachment; filename="'.$zip_name.'"');
    ob_clean();
    flush();
    readfile($this->zip_name);

    // errors will be disabled here
    unlink($this->zip_name);
  

在我的 Android 手机上,zip 文件已下载,但包含 &lt;h1&gt;Nothing to export&lt;/h1&gt;,这会将其呈现为无效的 zip 文件。

所以我的问题是,如果$count 完全为零,那么该块如何仅在移动浏览器(Opera 除外)上执行然后继续下载应该有exited 的 zip?

我用 Fiddler 调试过,请求都一样,但是输出不一样,为什么?

这是 php 中的错误吗?因为如果您查看我的代码,函数 purge() 应该会输出错误消息,指出标头已发送,但它只是继续下载 zip 文件。

浏览器:

海豚(+Beta) 火狐 默认安卓浏览器 船用浏览器

测试的 PHP 版本:

5.3.13(生产,共享服务器) 5.1.4

这让我快疯了。


@Alix 这是我见过的最奇怪的错误。我在这里没有认真看到任何逻辑错误。对于启动下载的脚本,实际上必须将文件添加到 zip 中。现在在我的手机上,它说没有添加任何文件,但temp 文件夹中有一个 zip 文件。此外,如果没有添加文件($count = 0),那么脚本应该终止(因此是exit() 函数),只显示一条消息&lt;h1&gt;Nothing to export&lt;/h1&gt;。但它会继续下载 zip 文件(此时它不存在,但在 temp 文件夹中存在)。 zip 文件最终损坏,因为它包含 &lt;h1&gt;Nothing to export&lt;/h1&gt;

阿利克斯写道: *>如果您在提供文件之前注释掉退出调用会发生什么?

它说readfile 错误,然后以乱码的 UNICODE 字符清除 zip 文件。我可以说它是 zip 文件,因为它以 PK 开头并包含要导出的图像的名称。

阿利克斯写道:

如果这不起作用,您可能想将 exit('&lt;h1&gt;Nothing to export&lt;/h1&gt;'); 更改为 exit(var_dump($_REQUEST));,这样您就可以通过检查 Zip 文件来检查表单提交中可能存在的错误。

有趣。它只打印 cookie 和 $_GET 参数。如果我将代码放在脚本开头的建议中以及将文件添加到 zip 的块中,它会打印所有 $_POST 变量。

这里显然存在 PHP 部分的错误。它应该在调用 exit 时终止,但它不会。请注意,这只发生在除 Opera 之外的移动浏览器上。我现在要哭血了。

【问题讨论】:

你发送的是no-cache的缓存头吗?众所周知,某些浏览器会导致文件不会被缓存的问题,因此在下载后将其从用户临时目录中删除。 我补充说希望能解决这个问题。但很可惜,它似乎不起作用。 我似乎也有同样的问题。下载在台式机上运行良好,但安卓或 ios 浏览器似乎与现在的数据下载超时。 您的项目设置如何?喜欢我的吗? 其实我的错误略有不同。下载似乎是在浏览器中开始的,但从来没有下载过,最终它会超时,你会得到一个下载失败的错误。我使用 java 和 Objective-c http 请求从相同类型的 php 代码中提取文件,但浏览器似乎根本不起作用。我最后没有删除 zipfile,我不相信我使用了任何 ob 命令。我想知道下载是否比正常的互联网连接慢,因为命令执行时间太长,但我没有在日志中看到。 【参考方案1】:

您确定其他浏览器将$_POST[$export] 设置为正确的值吗?

另外,你应该先ob_[end_]clean() 然后输出标题,而不是反过来:

public function purge($zip_name = 'leads.zip')
  
    ob_end_clean();
    flush();
    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename="'.$zip_name.'"');
    readfile($this->zip_name);

    // errors will be disabled here
    unlink($this->zip_name);
  

此外,您可能想要设置这些标题:

header('Content-Length: ' . intval(filesize($zip_name)));
header('Content-Transfer-Encoding: binary');

如果这不起作用,您可能想将 exit('&lt;h1&gt;Nothing to export&lt;/h1&gt;'); 更改为 exit(var_dump($_REQUEST));,这样您就可以通过检查 Zip 文件来检查表单提交中可能存在的错误。

【讨论】:

$_POST[$export] 已设置。我使用此代码在所有上述浏览器中检查它。 exit('count: '.$count) 导致 count: 2。但让我感到困惑的是,它进入了表达式计算为false 的块,然后调用exit() 但没有终止,而是继续下载 zip 文件。 @chx101:我盯着代码看了一会儿,我不明白为什么它在某些浏览器上可能会失败。我非常怀疑这是一个 PHP 错误(算术逻辑非常明显)。也许还有一些其他代码(或订单)你没有透露?另外,如果您在提供文件之前注释掉 exit 调用会发生什么?

以上是关于PHP zip 下载错误的主要内容,如果未能解决你的问题,请参考以下文章

PHP on the fly ZIP 下载为空白

ZipArchive php 获取损坏或空的 zip

在 php 中创建和下载 zip 存档

.zip 文件下载为 .php

如何启动使用jQuery自动下载zip文件的PHP脚本

php打包文件为ZIP包后下载到本地