1.分批查数据,防止数据库内存溢出
2.生成多个csv文件
3.zip打包下载
//分批打包下载excel
//导出说明:因为EXCEL单表只能显示104W数据,同时使用PHPEXCEL容易因为数据量太大而导致占用内存过大,
//因此,数据的输出用csv文件的格式输出,但是csv文件用EXCEL软件读取同样会存在只能显示104W的情况,所以将数据分割保存在多个csv文件中,并且最后压缩成zip文件提供下载
function putCsv(array $head, $data, $mark = 'attack_ip_info', $fileName = "test.csv")
{
set_time_limit(0);
$sqlCount = $data->count();
// 输出Excel文件头,可把user.csv换成你要的文件名
header('Content-Type: application/vnd.ms-excel;charset=utf-8');
header('Content-Disposition: attachment;filename="' . $fileName . '"');
header('Cache-Control: max-age=0');
$sqlLimit = 100000;//每次只从数据库取100000条以防变量缓存太大
// 每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
$limit = 100000;
// buffer计数器
$cnt = 0;
$fileNameArr = array();
// 逐行取出数据,不浪费内存
$disk = Storage::disk('excel_dir');
$disk->makeDirectory(date('Y_m_d'));
for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) {
$fp = fopen($mark . '_' . $i . '.csv', 'w'); //生成临时文件
// chmod('attack_ip_info_' . $i . '.csv',777);//修改可执行权限
$fileNameArr[] = $mark . '_' . $i . '.csv';
// 将数据通过fputcsv写到文件句柄
fputcsv($fp, $head);
$dataArr = $data->offset($i * $sqlLimit)->limit($sqlLimit)->get()->toArray();
foreach ($dataArr as $a) {
//有需要处理的字段可以在这里写
$cnt++;
if ($limit == $cnt) {
//刷新一下输出buffer,防止由于数据过多造成问题
ob_flush();
flush();
$cnt = 0;
}
fputcsv($fp, $a);
}
fclose($fp); //每生成一个文件关闭
}
//进行多个文件压缩
$zip = new \ZipArchive();
$filename = $mark . ".zip";
$zip->open($filename, \ZipArchive::CREATE); //打开压缩包
foreach ($fileNameArr as $file) {
$zip->addFile($file, basename($file)); //向压缩包中添加文件
}
$zip->close(); //关闭压缩包
foreach ($fileNameArr as $file) {
// unlink($file); //删除csv临时文件
Storage::delete($file);
}
//输出压缩文件提供下载
header("Cache-Control: max-age=0");
header("Content-Description: File Transfer");
header('Content-disposition: attachment; filename=' . basename($filename)); // 文件名
header("Content-Type: application/zip"); // zip格式的
header("Content-Transfer-Encoding: binary"); //
header('Content-Length: ' . filesize($filename)); //
@readfile($filename);//输出文件;
Storage::delete($filename);
// unlink($filename); //删除压缩包临时文件
}