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 相关文章推荐
MYSQL环境变量设置方法
Jan 15 PHP
PHP JSON 数据解析代码
May 26 PHP
php使用mkdir创建多级目录入门例子
May 10 PHP
PHP开发框架Laravel数据库操作方法总结
Sep 03 PHP
PHP中new static() 和 new self() 的区别介绍
Jan 09 PHP
简单谈谈PHP vs Node.js
Jul 17 PHP
PHP简单获取及判断提交来源的方法
Apr 22 PHP
PHP文件操作实例总结
Sep 27 PHP
全面解析PHP面向对象的三大特征
Jun 10 PHP
php基于自定义函数记录log日志方法
Jul 21 PHP
php中的依赖注入实例详解
Aug 14 PHP
php引用和拷贝的区别知识点总结
Sep 23 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 面向对象实现代码
2009/11/11 PHP
destoon整合ucenter后注册页面不跳转的解决方法
2014/06/21 PHP
PHP获取指定时间段之间的 年,月,天,时,分,秒
2016/06/05 PHP
laravel 框架执行流程与原理简单分析
2020/02/01 PHP
Jquery显示和隐藏元素或设为只读(含Ligerui的控件禁用,实例说明介绍)
2013/07/09 Javascript
js实现动态改变字体大小代码
2014/01/02 Javascript
纯JavaScript实现获取onclick、onchange等事件的值
2014/12/29 Javascript
angular.foreach 循环方法使用指南
2015/01/06 Javascript
Markdown+Bootstrap图片自适应属性详解
2016/05/21 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
JavaScript中的工厂函数(推荐)
2017/03/08 Javascript
js原生Ajax的封装和原理详解
2017/03/11 Javascript
Angularjs 实现动态添加控件功能
2017/05/25 Javascript
使用 jQuery 实现表单验证功能
2017/07/05 jQuery
JS使用canvas中的measureText方法测量字体宽度示例
2019/02/02 Javascript
微信小程序模板消息推送的两种实现方式
2019/08/27 Javascript
vue相同路由跳转强制刷新该路由组件操作
2020/08/05 Javascript
Ant Design Pro 之 ProTable使用操作
2020/10/31 Javascript
flask中使用蓝图将路由分开写在不同文件实例解析
2018/01/19 Python
Python实现简单http服务器
2018/04/12 Python
Python爬取数据保存为Json格式的代码示例
2019/04/09 Python
windows下Python安装、使用教程和Notepad++的使用教程
2019/10/06 Python
Python sublime安装及配置过程详解
2020/06/29 Python
Python从MySQL数据库中面抽取试题,生成试卷
2021/01/14 Python
python使用scapy模块实现ping扫描的过程详解
2021/01/21 Python
用css3写出气球样式的示例代码
2017/09/11 HTML / CSS
css3编写浏览器背景渐变背景色的方法
2018/03/05 HTML / CSS
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
The Kooples美国官方网站:为情侣提供的法国当代时尚品牌
2019/01/03 全球购物
考试不及格检讨书
2014/01/09 职场文书
新学期开学标语
2014/06/30 职场文书
2014镇副书记群众路线专题民主生活会思想汇报
2014/09/23 职场文书
三行辞职书范文
2015/02/26 职场文书
MySQL索引失效的典型案例
2021/06/05 MySQL
Mongo服务重启异常问题的处理方法
2021/07/01 MongoDB
vue判断按钮是否可以点击
2022/04/09 Vue.js