PHP中大文件下载的bug及ob_*系列函数介绍

代码1、2的功能为实现大文件下载

代码1(有问题)(猜错在哪里)

        $fp = @fopen($filePath, 'rb');
        if ($fp) {
            $file_size = filesize($filePath);

            header('content-type:application/octet-stream');
            header('Content-Disposition: attachment; filename=' . $fileName);

            header('HTTP/1.1 200 OK');
            header('Accept-Ranges:bytes');
            header('content-length:' . $file_size);

            while (!feof($fp)) {
                echo fread($fp, 4096);
                ob_flush();
            }
            
            fclose($fp);
        }

代码2(无问题)

        $fp = @fopen($filePath, 'rb');
        if ($fp) {
            $file_size = filesize($filePath);

            header('content-type:application/octet-stream');
            header('Content-Disposition: attachment; filename=' . $fileName);

            header('HTTP/1.1 200 OK');
            header('Accept-Ranges:bytes');
            header('content-length:' . $file_size);

            ob_end_clean();
            ob_start();

            while (!feof($fp)) {
                echo fread($fp, 4096);
                ob_flush();
                flush();
            }

            ob_end_flush();

            fclose($fp);
        }

使用代码1下载文件,在 php+apache的环境下测试下载文件无问题,但是在php+nginx的环境下,会出现下载文件内容变多的情况,而且多出的内容为文件首部的一段空白内容

代码2就不会出现此问题,由于代码2中使用了 ob_end_clean(),作用为:删除内部缓冲区的内容,关闭缓冲区,因此不会存在缓冲区中的冗余内容没有被清理而被携带到文件中,造成下载文件不完整

ob的基本原则:
如果ob缓存打开,则echo的数据首先放在ob缓存
如果是header信息,直接放在程序缓存
当页面执行到最后,会把ob缓存的数据放到程序缓存,然后依次返回给浏览器

(分为ob缓存和php程序缓存,后者可以理解为比前者处于更外层)

常见 ob_* 系列函数:

函数说明
ob_start打开一个输出缓冲区,所有的输出信息不再直接发送到浏览器,而是保存在输出缓冲区里面
ob_clean删除内部缓冲区的内容,不关闭缓冲区(不输出)
ob_end_clean删除内部缓冲区的内容,关闭缓冲区(不输出)
ob_get_length返回内部缓冲区的长度,如果缓冲区未被激活,该函数返回FALSE
ob_get_level返回输出缓冲机制的嵌套级别
ob_get_status获取输出缓冲区的状态
ob_get_contents返回缓冲区的内容,不输出
ob_get_clean返回内部缓冲区的内容,关闭缓冲区。相当于执行 ob_get_contents() and ob_end_clean()
ob_get_flush返回内部缓冲区的内容,并关闭缓冲区,再释放缓冲区的内容。相当于ob_end_flush()并返回缓冲区内容
flush将ob_flush释放出来的内容,以及不在PHP缓冲区中的内容,全部输出至浏览器;刷新内部缓冲区的内容,并输出
ob_flush发送内部缓冲区的内容到浏览器,删除缓冲区的内容,不关闭缓冲区
ob_end_flush发送内部缓冲区的内容到浏览器,删除缓冲区的内容,关闭缓冲区

原创文章,作者:witersen,如若转载,请注明出处:https://www.witersen.com

(0)
witersen的头像witersen
上一篇 2022年7月2日 下午9:51
下一篇 2022年7月13日 上午12:21

相关推荐

  • Centos8安装PHP

    安装好虚拟机后,可以进行PHP的安装。 一:安装Apache 1.安装Apache:执行命令yum install httpd 2.配置ServerName:执行命令vi /etc…

    2020年12月26日
    1.5K0

发表回复

登录后才能评论