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 相关文章推荐
其他功能
Oct 09 PHP
LotusPhp笔记之:Logger组件的使用方法
May 06 PHP
PHP中substr_count()函数获取子字符串出现次数的方法
Jan 07 PHP
Yii操作数据库实现动态获取表名的方法
Mar 29 PHP
php支付宝在线支付接口开发教程
Sep 19 PHP
Laravel5.1自定义500错误页面示例
Oct 09 PHP
php写一个函数,实现扫描并打印出自定目录下(含子目录)所有jpg文件名
May 26 PHP
PHP静态方法和静态属性及常量属性的区别与介绍
Mar 22 PHP
php5.6.x到php7.0.x特性小结
Aug 17 PHP
php自动加载代码实例详解
Feb 26 PHP
PHP时间类完整代码实例
Feb 26 PHP
PHP7 foreach() 函数修改
Mar 09 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遍历目录方法小结
2015/03/10 PHP
php 实现进制相互转换
2016/04/07 PHP
简单解决微信文章图片防盗链问题
2016/12/17 PHP
php实现连接access数据库并转txt写入的方法
2017/02/08 PHP
php smtp实现发送邮件功能
2017/06/22 PHP
浅谈Laravel核心解读之Console内核
2018/12/02 PHP
如何在PHP中使用数组
2020/06/09 PHP
JavaScript设计模式之策略模式实例
2014/10/10 Javascript
jquery+css3实现网页背景花瓣随机飘落特效
2015/08/17 Javascript
js 函数式编程学习笔记
2017/03/25 Javascript
JavaScript实现弹出广告功能
2017/03/30 Javascript
解析Vue2 dist 目录下各个文件的区别
2017/11/22 Javascript
详解如何用babel转换es6的class语法
2018/04/03 Javascript
Vue中使用vue-i18插件实现多语言切换功能
2018/04/25 Javascript
nodejs读取本地中文json文件出现乱码解决方法
2018/10/10 NodeJs
vue2.0基于vue-cli+element-ui制作树形treeTable
2019/04/30 Javascript
Vue 2.0 侦听器 watch属性代码详解
2019/06/19 Javascript
JQuery绑定事件四种实现方法解析
2020/12/02 jQuery
[56:47]Ti4 循环赛第三日 iG vs Liquid
2014/07/12 DOTA
python批量提交沙箱问题实例
2014/10/08 Python
python字典的常用操作方法小结
2016/05/16 Python
Python中用字符串调用函数或方法示例代码
2017/08/04 Python
解决python selenium3启动不了firefox的问题
2018/10/13 Python
Python实现的排列组合、破解密码算法示例
2019/04/12 Python
PyQT实现菜单中的复制,全选和清空的功能的方法
2019/06/17 Python
django创建最简单HTML页面跳转方法
2019/08/16 Python
解决pyinstaller打包运行程序时出现缺少plotly库问题
2020/06/02 Python
Python实现将元组中的元素作为参数传入函数的操作
2020/06/05 Python
哪种Python框架适合你?简单介绍几种主流Python框架
2020/08/04 Python
美国医疗用品、医疗设备和家庭保健用品商店:Medical Supply Depot
2018/07/08 全球购物
写好求职信第一句话的技巧
2013/10/26 职场文书
企划专员岗位职责
2013/12/09 职场文书
劳资专员岗位职责
2013/12/27 职场文书
联谊活动总结范文
2015/05/09 职场文书
房屋转让协议书(标准范本)
2016/03/21 职场文书
Django模型层实现多表关系创建和多表操作
2021/07/21 Python