PHP实现实时生成并下载超大数据量的EXCEL文件详解


Posted in PHP onOctober 23, 2017

前言

最近在工作中接到一个需求,通过选择的时间段导出对应的用户访问日志到excel中, 由于用户量较大,经常会有导出50万加数据的情况。而常用的PHPexcel包需要把所有数据拿到后才能生成excel, 在面对生成超大数据量的excel文件时这显然是会造成内存溢出的,所以考虑使用让PHP边写入输出流边让浏览器下载的形式来完成需求。

我们通过如下的方式写入PHP输出流

$fp = fopen('php://output', 'a');
fputs($fp, 'strings');
....
....
fclose($fp)

php://output是一个可写的输出流,允许程序像操作文件一样将输出写入到输出流中,PHP会把输出流中的内容发送给web服务器并返回给发起请求的浏览器

另外由于excel数据是从数据库里逐步读出然后写入输出流的所以需要将PHP的执行时间设长一点(默认30秒)set_time_limit(0)不对PHP执行时间做限制。

注:以下代码只是阐明生成大数据量EXCEL的思路和步骤,并且在去掉项目业务代码后程序有语法错误不能拿来直接运行,请根据自己的需求填充对应的业务代码!

/**
  * 文章访问日志
  * 下载的日志文件通常很大, 所以先设置csv相关的Header头, 然后打开
  * PHP output流, 渐进式的往output流中写入数据, 写到一定量后将系统缓冲冲刷到响应中
  * 避免缓冲溢出
  */
 public function articleAccessLog($timeStart, $timeEnd)
 {
  set_time_limit(0);
  $columns = [
   '文章ID', '文章标题', ......
  ];
  $csvFileName = '用户日志' . $timeStart .'_'. $timeEnd . '.xlsx';
  //设置好告诉浏览器要下载excel文件的headers
  header('Content-Description: File Transfer');
  header('Content-Type: application/vnd.ms-excel');
  header('Content-Disposition: attachment; filename="'. $fileName .'"');
  header('Expires: 0');
  header('Cache-Control: must-revalidate');
  header('Pragma: public');
  $fp = fopen('php://output', 'a');//打开output流
  mb_convert_variables('GBK', 'UTF-8', $columns);
  fputcsv($fp, $columns);//将数据格式化为CSV格式并写入到output流中
  $accessNum = '1000000'//从数据库获取总量,假设是一百万
  $perSize = 1000;//每次查询的条数
  $pages = ceil($accessNum / $perSize);
  $lastId = 0;
  for($i = 1; $i <= $pages; $i++) {
   $accessLog = $logService->getArticleAccessLog($timeStart, $timeEnd, $lastId, $perSize);
   foreach($accessLog as $access) {
    $rowData = [
     ......//每一行的数据
    ];
    mb_convert_variables('GBK', 'UTF-8', $rowData);
    fputcsv($fp, $rowData);
    $lastId = $access->id;
   }
   unset($accessLog);//释放变量的内存
   //刷新输出缓冲到浏览器
   ob_flush();
   flush();//必须同时使用 ob_flush() 和flush() 函数来刷新输出缓冲。
  }
  fclose($fp);
  exit();
 }

好了, 其实很简单,就是用逐步写入输出流并发送到浏览器让浏览器去逐步下载整个文件,由于是逐步写入的无法获取文件的总体size所以就没办法通过设置header("Content-Length: $size");在下载前告诉浏览器这个文件有多大了。不过不影响整体的效果这里的核心问题是解决大文件的实时生成和下载。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP设计聊天室步步通
Oct 09 PHP
PHP之变量、常量学习笔记
Mar 27 PHP
PHP define函数的使用说明
Aug 27 PHP
CodeIgniter框架提示Disallowed Key Characters的解决办法
Apr 21 PHP
php多次include后导致全局变量global失效的解决方法
Feb 28 PHP
PHP实现获取客户端IP并获取IP信息
Mar 17 PHP
php获取文件类型和文件信息的方法
Jul 10 PHP
PHP实现冒泡排序的简单实例
May 26 PHP
php 输入输出流详解及示例代码
Aug 25 PHP
PHP基于ORM方式操作MySQL数据库实例
Jun 21 PHP
php设计模式之装饰模式应用案例详解
Jun 17 PHP
PhpStorm2020 + phpstudyV8 +XDebug的教程详解
Sep 17 PHP
Laravel学习教程之model validation的使用示例
Oct 23 #PHP
laravel实现批量更新多条记录的方法示例
Oct 22 #PHP
利用PHP获取汉字首字母并且分组排序详解
Oct 22 #PHP
Laravel 5.4因特殊字段太长导致migrations报错的解决
Oct 22 #PHP
PHP高效获取远程图片尺寸和大小的实现方法
Oct 20 #PHP
PHP静态延迟绑定和普通静态效率的对比
Oct 20 #PHP
php+ajax实现仿百度查询下拉内容功能示例
Oct 20 #PHP
You might like
php数组函数序列之in_array() - 查找数组中是否存在指定值
2011/11/07 PHP
解析如何屏蔽php中的phpinfo()函数
2013/06/06 PHP
laravel安装和配置教程
2014/10/29 PHP
php-fpm.conf配置文件中文说明详解及重要参数说明
2018/10/10 PHP
javascript onmouseout 解决办法
2010/07/17 Javascript
Javascript中的window.event.keyCode使用介绍
2011/04/26 Javascript
jQuery去掉字符串起始和结尾的空格(多种方法实现)
2013/04/01 Javascript
jquery更换文章内容与改变字体大小代码
2013/09/30 Javascript
jQuery在iframe中无法弹出对话框的解决方法
2014/01/12 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
简单了解Backbone.js的Model模型以及View视图的源码
2016/02/14 Javascript
在JavaScript中使用JSON数据
2016/02/15 Javascript
JavaScript操作HTML DOM节点的基础教程
2016/03/11 Javascript
BOM系列第二篇之定时器requestAnimationFrame
2016/08/17 Javascript
原生JS发送异步数据请求
2017/06/08 Javascript
Vue-Cli中自定义过滤器的实现代码
2017/08/12 Javascript
jquery+css实现Tab栏切换的代码实例
2019/05/14 jQuery
JS实现可切换图片的幻灯切换效果示例
2019/05/24 Javascript
Vue实现渲染数据后控制滚动条位置(推荐)
2019/12/09 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
利用JS判断元素是否为数组的方法示例
2021/01/08 Javascript
[55:23]VGJ.T vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python3爬虫学习入门教程
2018/12/11 Python
python 标准差计算的实现(std)
2019/07/29 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
Python执行时间的几种计算方法
2020/07/31 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
Django后端按照日期查询的方法教程
2021/02/28 Python
css3针对移动端卡顿问题的解决(动画性能优化)
2020/02/14 HTML / CSS
MSC邮轮官方网站:加勒比海、地中海和世界各地的假期
2018/08/27 全球购物
会计毕业生自我鉴定
2013/11/04 职场文书
2014年国培研修感言
2014/03/09 职场文书
2014婚礼司仪主持词
2014/03/14 职场文书
个人收入证明范本
2015/06/12 职场文书
redis sentinel监控高可用集群实现的配置步骤
2022/04/01 Redis
CSS link与@import的区别和用法解析
2023/05/07 HTML / CSS