Zlib正在破坏CodeIgniter Zip下载器和PHPExcel

Zlib正在破坏CodeIgniter Zip下载器和PHPExcel,php,apache,codeigniter,phpexcel,zlib,Php,Apache,Codeigniter,Phpexcel,Zlib,我面临的问题是,如果在web服务器上启用了Zlib压缩,则使用系统的download\u helper.php文件中的CodeIgniter的force\u download功能下载任何zip文件会破坏存档文件并阻止用户打开它 以下是压缩XLSX文件后压缩文件的force_download功能: function force_download($filename = '', $data = '') { if ($filename == '' OR $data =

我面临的问题是,如果在web服务器上启用了Zlib压缩,则使用系统的
download\u helper.php
文件中的CodeIgniter的
force\u download
功能下载任何zip文件会破坏存档文件并阻止用户打开它

以下是压缩
XLSX
文件后压缩文件的
force_download
功能:

    function force_download($filename = '', $data = '')
    {
        if ($filename == '' OR $data == '')
        {
            return FALSE;
        }

        // Try to determine if the filename includes a file extension.
        // We need it in order to set the MIME type
        if (FALSE === strpos($filename, '.'))
        {
            return FALSE;
        }

        // Grab the file extension
        $x = explode('.', $filename);
        $extension = end($x);

        // Load the mime types
        if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
        {
            include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
        }
        elseif (is_file(APPPATH.'config/mimes.php'))
        {
            include(APPPATH.'config/mimes.php');
        }

        // Set a default mime if we can't find it
        if ( ! isset($mimes[$extension]))
        {
            $mime = 'application/octet-stream';
        }
        else
        {
            $mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
        }

        // Generate the server headers
        if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
        {
            header('Content-Type: "'.$mime.'"');
            header('Content-Disposition: attachment; filename="'.$filename.'"');
            header('Expires: 0');
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header("Content-Transfer-Encoding: binary");
            header('Pragma: public');
            header("Content-Length: ".strlen($data));
        }
        else
        {
            header('Content-Type: "'.$mime.'"');
            header('Content-Disposition: attachment; filename="'.$filename.'"');
            header("Content-Transfer-Encoding: binary");
            header('Expires: 0');
            header('Pragma: no-cache');
            header("Content-Length: ".strlen($data));
        }

        exit($data);
    }
启用Zlib还可以通过在Excel文件中生成乱码来破坏PHPExcel,如图所示

用于单个
XLSX
文件的PHPExcel下载功能。下面是整个Excel生成器、zip和下载程序功能的要点


是否有适当的解决方法来启用Zlib而不破坏这些功能?

您还没有清楚地指出脚本的所有细节,但是您开始描述“zip文件”并引用“归档文件”。然而,您发布的一小部分代码会为excel文件发送一个内容类型标题。如果向浏览器发送zip文件,但告诉浏览器其mime类型为application/vnd.ms excel,则这可能是您的问题

您是否考虑过只使用force_下载功能?无论文件是excel还是zip,此控制器都适用于我:

public function download() {
    $filepath = "/path/to/file.zip";
     // or you can send an Excel file
    $filepath = "/path/to/file.xls";

    $filename = basename($filepath);

    $data = file_get_contents($filepath);

    $this->load->helper('download');
    force_download($filename, $data);
}
这个。根据您的Codeigniter版本,您可能需要指定第三个参数TRUE

通过将mime类型设置为application/vnd.ms excel,但发送ZIP文件,我复制了您描述的“乱码”问题。相反,我已经通过使用force_下载功能成功下载了ZIP和XLS文件

编辑 看过一些代码后,我建议您重新编写逻辑,因为在foreach循环中检查
count($result)
有点尴尬。您可以在进入foreach循环之前检查这一点

更重要的是,在分配数组元素之前,无法将
$download\u data
初始化为数组。根据您的环境和错误报告设置,这可能会触发E_通知或E_警告,从而在您开始输出zip文件内容之前导致额外输出。如果您的代码在开始输出zip存档的实际二进制数据之前输出了不需要的字符,这将损坏文件。另一种可能性是,对未定义变量的引用将导致向stdout发出E_NOTICE错误,这可能导致任何后续头命令失败,因为一旦开始输出文本,就无法发送头命令

另一种可能是mime类型不正确。您的Codeigniter版本很旧,但我认为这不太可能是个问题。如果可以,请尝试检查发送到浏览器的响应标题,查看它们是应用程序/x-gzip还是应用程序/zip或其他内容

最后,您应该检查中的压缩输出设置。请注意此处的评论:

/*
|--------------------------------------------------------------------------
|输出压缩
|--------------------------------------------------------------------------
|
|启用Gzip输出压缩以更快地加载页面。启用时,
|输出类将测试服务器是否支持Gzip。
|然而,即使它支持压缩,也不是所有浏览器都支持压缩
|因此,只有当您合理地确信您的访问者能够处理它时才启用。
|
|仅在php.ini中关闭zlib.output_压缩时使用。
|请不要将其与httpd级输出压缩一起使用。
|
|非常重要:如果您在启用压缩时得到一个空白页,请将其删除
|表示您过早地将某些内容输出到浏览器。它可以
|甚至可以在脚本的末尾添加一行空格。对于
|压缩要工作,在调用输出缓冲区之前不能发送任何内容
|通过输出类。不要在启用压缩的情况下“回显”任何值。
|
*/

如果我没弄错的话,force_download函数负责为您发送标题。此外,您可能不应该使用
pragma:public
,因为这意味着任何缓存都可以随意缓存文档。您可能正在查看缓存(且已损坏)的文档,而不是该文件的最新版本。@S.Imp将
pragma:public
更改为
pragma:no cache
,打开归档文件时仍会出错。请参阅下面的答案,并澄清我是否误解了。这是什么版本的Codeigniter?接受第三个参数。如果您的Codeigniter版本很旧,那么它也可能缺少您正在下载的任何文件的正确mime类型。不幸的是,您发布的代码完全没有告诉我们您实际发送给用户的是什么类型的文件。@Daniel harris解决此问题是否顺利?该函数已按问题中所述使用。@DanielHarris在您的问题中没有调用force_download函数。此外,您发布的“PHPExcel下载函数的标题”代码会发送excel文件的mime类型。如果输出的是zip文件,但发送的是XLS文件的标题,则会出现您描述的乱码问题。事实上,如果你使用的是强制下载函数,考虑提供一个第三参数的真到力代码编辑器来从文件名的扩展中读取MIME类型。这个问题意味着由相同的问题(ZLIB)引起的两个不同的问题(PHPExcel和CODEIGITER ZIP下载器)。我提到在第一段中使用了
force_download
功能。要点
public function download() {
    $filepath = "/path/to/file.zip";
     // or you can send an Excel file
    $filepath = "/path/to/file.xls";

    $filename = basename($filepath);

    $data = file_get_contents($filepath);

    $this->load->helper('download');
    force_download($filename, $data);
}