$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\"大众);不才载前见告浏览器这个文件有多大了。不过不影响整体的效果这里的核心问题是办理大文件的实时天生和下载。
更新: 说一下我数据库查询这里的思路,由于逐步写入EXCEL的数据实际上来自Mysql的分页查询,大家知道其语法是LIMIT offset, num 不过随着offset越来越大Mysql在每次分页查询时须要跳过的行数就越多,这会严重影响Mysql查询的效率(包括MongoDB这样的NoSQL也是不建议skip掉多条来取结果集),以是我采取LastId的办法来做分页查询。
类似下面的语句:
SELECT columns FROM `table_name`
WHERE `created_at` >= 'time range start'
AND `created_at` <= 'time range end'
AND `id` < LastId
ORDER BY `id` DESC
LIMIT num