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 小心urldecode引发的SQL注入漏洞
Oct 27 PHP
php摘要生成函数(无乱码)
Feb 04 PHP
下拉列表多级联动dropDownList示例代码
Jun 27 PHP
PHP中nowdoc和heredoc使用需要注意的一点
Mar 21 PHP
CMS中PHP判断系统是否已经安装的方法示例
Jul 26 PHP
php+mysql数据库查询实例
Jan 21 PHP
Yii2中事务的使用实例代码详解
Sep 07 PHP
Laravel 中使用 Vue.js 实现基于 Ajax 的表单提交错误验证操作
Jun 30 PHP
PHP基于堆栈实现的高级计算器功能示例
Sep 15 PHP
PHP的PDO预定义常量讲解
Jan 24 PHP
PHP抽象类和接口用法实例详解
Jul 20 PHP
php如何实现数据库的备份和恢复
Nov 30 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获取服务器操作系统相关信息的方法
2016/10/08 PHP
PHP的mysqli_stat()函数讲解
2019/01/23 PHP
PHP SESSION机制的理解与实例
2019/03/22 PHP
php 多进程编程父进程的阻塞与非阻塞实例分析
2020/02/22 PHP
JavaScript 自动分号插入(JavaScript synat:auto semicolon insertion)
2009/11/04 Javascript
passwordStrength 基于jquery的密码强度检测代码使用介绍
2011/10/08 Javascript
为什么要在引入的css或者js文件后面加参数的详细讲解
2013/05/03 Javascript
js操作输入框提示信息且响应鼠标事件
2014/03/25 Javascript
nodejs 提示‘xxx’ 不是内部或外部命令解决方法
2014/11/20 NodeJs
JavaScript时间转换处理函数
2015/04/14 Javascript
jquery实现跳到底部,回到顶部效果的简单实例(类似锚)
2016/07/10 Javascript
jQuery自适应轮播图插件Swiper用法示例
2016/08/24 Javascript
用js控件div的滚动条,让它在内容更新时自动滚到底部的实现方法
2016/10/27 Javascript
javascript 数据存储的常用函数总结
2017/06/01 Javascript
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
2017/06/04 Javascript
详解如何使用PM2将Node.js的集群变得更加容易
2017/11/15 Javascript
vue使用element-ui的el-input监听不了回车事件的解决方法
2018/01/12 Javascript
深入理解JS的事件绑定、事件流模型
2018/05/13 Javascript
JavaScript使用享元模式实现文件上传优化操作示例
2018/08/07 Javascript
如何使用less实现随机下雪动画详解
2019/01/02 Javascript
详解Python的hasattr() getattr() setattr() 函数使用方法
2018/07/09 Python
50行Python代码实现视频中物体颜色识别和跟踪(必须以红色为例)
2019/11/20 Python
python实现ip地址的包含关系判断
2020/02/07 Python
解决使用Pandas 读取超过65536行的Excel文件问题
2020/11/10 Python
CSS3 @keyframes简单动画实现
2018/02/24 HTML / CSS
橄榄树药房:OLIVEDA
2019/09/01 全球购物
医科学校毕业生自荐信
2013/11/09 职场文书
数控专业大学生的自我鉴定
2013/11/13 职场文书
工程专业毕业生自荐信范文
2013/12/25 职场文书
2015年纪检监察工作总结
2015/04/08 职场文书
初中毕业感言300字
2015/07/31 职场文书
汽车销售员工作总结
2015/08/12 职场文书
2016毕业实习单位评语大全
2015/12/01 职场文书
SqlServer 垂直分表(减少程序改动)
2021/04/16 SQL Server
使用vue判断当前环境是安卓还是IOS
2022/04/12 Vue.js
Oracle中日期的使用方法实例
2022/07/07 Oracle