参考资料 : https://blog.csdn.net/tim_phper/article/details/77581071 https://www.imooc.com/wenda/detail/316785php
/** * 下载/导出到csv文件 * @param $title 标题栏标题 * @param $data : array($count = M(表名)->where($where)->count(), $data_model = M(表名)->where($where)->order($order)) * @param $sqlLimit 单文件容许写入最大行 * @param $mark 文件名标记信息名称 * @param $func 回调函数处理查询出来的数据 */ function downloadCsv(array $title, $data, $sqlLimit = 10000, $mark = 'test', $func = '') { set_time_limit(0); $sqlCount = $data[0]; $max_line_perfile = 100000; //单文件容许写入最大行 // 输出Excel文件头,可把user.csv换成你要的文件名 header('Content-Type: application/vnd.ms-excel;charset=utf-8'); header('Content-Disposition: attachment;filename="' . $mark . '.csv' . '"'); header('Cache-Control: max-age=0'); //临时文件的删除处理 $path = "./Upload/export/" . date('Ymd'); //判断目录存在否,存在将删除目录下全部文件 if (is_dir($path)) { rmdirr($path); } if (!is_dir($path)) { //建立目录 mkdir(iconv("UTF-8", "GBK", $path), 0777, true); } //每次只从数据库取最大数目以防变量缓存太大 // 每隔$limit行,刷新一下输出buffer,不要太大,也不要过小 $limit = $sqlLimit; // buffer计数器 $cnt = 0; $fileNameArr = array(); // 逐行取出数据,不浪费内存 for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) { $tmp_filename = $path . '/' . $mark . '_' . $i . '.csv'; $fp = fopen($tmp_filename, 'w'); //生成临时文件 // chmod('attack_ip_info_' . $i . '.csv',777);//修改可执行权限 $fileNameArr[] = $tmp_filename; // 将数据经过fputcsv写到文件句柄 foreach ($title as $key => &$value) { $value = iconv("UTF-8", "GBK", $value); } fputcsv($fp, $title); $dataArr = $data[1]->limit($i * $sqlLimit, $sqlLimit)->select(); foreach ($dataArr as $a) { if($func) { $func($a); } //判断是否为多维数组来决定是一次写几行 if(count($a) == count($a, 1)){ //一维数组 if($sqlLimit > $max_line_perfile){ //限制一个文件不超过最大行 exit('下载单文件数目过大,请从新设置'); } $cnt++; if ($limit == $cnt) { //刷新一下输出buffer,防止因为数据过多形成问题 ob_flush(); flush(); $cnt = 0; } fputcsv($fp, $a); } else { if(($sqlLimit * count($a)) > $max_line_perfile){ //限制一个文件不超过100000行 exit('下载单文件数目过大,请从新设置'); } foreach ($a as $a_v) { $cnt++; if ($limit == $cnt) { //刷新一下输出buffer,防止因为数据过多形成问题 ob_flush(); flush(); $cnt = 0; } fputcsv($fp, $a_v); } } } fclose($fp); //每生成一个文件关闭 } //进行多个文件压缩 $zip = new ZipArchive(); $filename = $path . '/' . $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临时文件 } //输出压缩文件提供下载 header("Cache-Control: max-age=0"); header("Content-Description: File Transfer"); header('Content-disposition: attachment; filename=' . date('YmdHis').'_'.basename($filename)); // 文件名 header("Content-Type: application/zip"); // zip格式的 header("Content-Transfer-Encoding: binary"); // header('Content-Length: ' . filesize($filename)); // @readfile($filename);//输出文件; unlink($filename); //删除压缩包临时文件 }
引用片断node
$title = array("ID\t","用户名\t","币种\t","变更资金\t","剩余资金\t","日志类型\t","行为\t","日志描述\t","IP\t","产生路径\t","时间\t"); $where = preg_replace('/a\./', 'c.', $where); $where = preg_replace('/b\./', 'd.', $where); $data_model = M('user_coinlog as c')->join('LEFT JOIN basanyi_user as d on c.userid = d.id')->where($where)->field('d.username,c.*')->order('c.id desc'); downloadCsv($title, array($count, $data_model), 50000, 'user_trade', function(&$data){ //数据处理显示 $data['add_time'] = addtime($data['add_time']); //排序并排除不须要的字段 $tmp_data = []; $tmp_data[0] = $data['id']; $tmp_data[1] = $data['username']; $tmp_data[2] = $data['coin_name']; $tmp_data[3] = $data['effect']; $tmp_data[4] = $data['total']; $tmp_data[5] = $data['log_type']; $tmp_data[6] = iconv("UTF-8", "GBK", $data['action']); $tmp_data[7] = iconv("UTF-8", "GBK", $data['content']); $tmp_data[8] = $data['ip']; $tmp_data[9] = $data['node']; $tmp_data[10] = $data['add_time']; $data = $tmp_data; });