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各种编码集详解和以及在什么情况下进行使用
Sep 11 PHP
php获取字段名示例分享
Mar 03 PHP
PHP源码分析之变量的存储过程分解
Jul 03 PHP
PHP导出Excel实例讲解
Jan 24 PHP
PHP图片加水印实现方法
May 06 PHP
PHP封装的MSSql操作类完整实例
May 26 PHP
PHP通过CURL实现定时任务的图片抓取功能示例
Oct 03 PHP
php基于单例模式封装mysql类完整实例
Oct 18 PHP
Laravel5.* 打印出执行的sql语句的方法
Jul 24 PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
Aug 15 PHP
php删除一个路径下的所有文件夹和文件的方法
Feb 07 PHP
thinkPHP利用ajax异步上传图片并显示、删除的示例
Sep 26 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开发中四种查询返回结果分析
2011/01/02 PHP
php中常量DIRECTORY_SEPARATOR用法深入分析
2014/11/14 PHP
PHP封装的Twitter访问类实例
2015/07/18 PHP
Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)
2010/07/11 Javascript
Js判断参数(String,Array,Object)是否为undefined或者值为空
2013/11/04 Javascript
JS图片切换的具体方法(带缩略图版)
2013/11/12 Javascript
javascript中声明函数的方法及调用函数的返回值
2014/07/22 Javascript
PHP配置文件php.ini中打开错误报告的设置方法
2015/01/09 PHP
javascript中使用new与不使用实例化对象的区别
2015/06/22 Javascript
jQuery延迟执行的实现方法
2016/12/21 Javascript
vue、react等单页面项目应该这样子部署到服务器
2018/01/03 Javascript
Express下采用bcryptjs进行密码加密的方法
2018/02/07 Javascript
在vue和element-ui的table中实现分页复选功能
2019/12/04 Javascript
[03:28]2014DOTA2国际邀请赛 EG战队官方纪录片
2014/07/21 DOTA
[45:40]Ti4 冒泡赛第二天NEWBEE vs NaVi 1
2014/07/15 DOTA
Python 'takes exactly 1 argument (2 given)' Python error
2016/12/13 Python
Python3实现的Mysql数据库操作封装类
2018/06/06 Python
Python爬虫之正则表达式的使用教程详解
2018/10/25 Python
python实现多层感知器MLP(基于双月数据集)
2019/01/18 Python
Python3简单实现串口通信的方法
2019/06/12 Python
在Python中使用turtle绘制多个同心圆示例
2019/11/23 Python
Python 生成一个从0到n个数字的列表4种方法小结
2019/11/28 Python
使用遗传算法求二元函数的最小值
2020/02/11 Python
python 决策树算法的实现
2020/10/09 Python
CSS3绘制不规则图形的一些方法示例
2015/11/07 HTML / CSS
html5服务器推送_动力节点Java学院整理
2017/07/12 HTML / CSS
整理HTML5的一些新特性与Canvas的常用属性
2016/01/29 HTML / CSS
研究生求职推荐信范文
2013/11/30 职场文书
计算机求职信
2013/12/01 职场文书
趣味比赛活动方案
2014/02/15 职场文书
采购求职信
2014/03/17 职场文书
春季防火方案
2014/05/10 职场文书
幼儿园奖惩制度范本
2015/08/05 职场文书
Sql-Server数据库单表查询 4.3实验课
2021/04/05 SQL Server
利用Sharding-Jdbc进行分库分表的操作代码
2022/01/22 Java/Android
windows11选中自动复制怎么开启? Win11自动复制所选内容的方法
2022/07/23 数码科技