/** * 導出csv文件 * @param $filename * @param $data * @param array $columns * @param int $chunk 限制每個文件條數 */ function exportCsv($filename, $data, $columns = [], $chunk = 10000) { header('Content-Type: application/csv; charset=UTF-8'); header('Content-Disposition: attachment; filename="' . $filename . '.csv"'); header('Cache-Control: max-age=0'); $storageDir = rtrim(sys_get_temp_dir(), '/'); $prefix = str_random(10); $fileList = []; // 文件集合 $fileList[] = $file = "$storageDir/${prefix}_${filename}_1.csv"; $fp = fopen($file, 'w'); fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF)); $head = array_pluck($columns, 'title'); fputcsv($fp, $head); // 計數器 $i = 0; // 每隔$limit行刷新一下輸出buffer,不要太大,也不要太小 $limit = 10000; // 行上限 $maxLimit = 100000000; foreach ($data as $item) { if ($i >= $maxLimit) { break; } if ($i > 0 && $i % $chunk == 0) { fclose($fp); // 關閉上一個文件 $j = $i / $chunk + 1; $fileList[] = $file = "$storageDir/${prefix}_${filename}_$j.csv"; $fp = fopen($file, 'w'); fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF)); fputcsv($fp, $head); } $i++; if ($i % $limit == 0) { ob_flush(); flush(); } $row = []; foreach ($columns AS $column) { $value = isset($column['key']) ? (is_object($item) ? $item->{$column['key']} : $item[$column['key']]) : null; $render = array_get($column, 'render'); if ($render && $render instanceof \Closure) { $row[] = $render($value, $item); } else { if (is_numeric($value) && strlen($value) > 10) { $value .= "\t"; } $row[] = $value; } } fputcsv($fp, $row); unset($row); } fclose($fp); if (count($fileList) > 1) { $zip = new ZipArchive(); $oldFilename = $filename; $filename = "$storageDir/${prefix}_${filename}.zip"; $zip->open($filename, ZipArchive::CREATE); // 打開壓縮包 foreach ($fileList as $file) { $zip->addFile($file, str_replace("${prefix}_", '', basename($file))); // 向壓縮包中添加文件 } $zip->close(); // 關閉壓縮包 foreach ($fileList as $file) { @unlink($file); // 刪除csv臨時文件 } // 輸出壓縮文件提供下載 header("Cache-Control: max-age=0"); header("Content-Description: File Transfer"); header('Content-disposition: attachment; filename=' . $oldFilename . '.zip'); header("Content-Type: application/zip"); // zip格式的 header("Content-Transfer-Encoding: binary"); header('Content-Length: ' . filesize($filename)); } else { $filename = head($fileList); } @readfile($filename); @unlink($filename); // 刪除臨時文件 exit; }