PHP从MySQL导出CSV异常:本地保存正常但下载空文件
解决PHP导出CSV时服务器保存正常但下载为空文件的问题
我碰到过不少开发者遇到这个情况——服务器上的CSV文件明明有内容,但浏览器下载下来却是空的。大概率是输出缓冲区残留内容或者HTTP响应头设置不全导致的,咱们一步步来修复:
先排查核心问题点
首先确认服务器上生成的$filename文件确实有内容(手动打开看看),如果服务器上的文件是空的,那得先查数据查询和写入的逻辑;如果服务器文件有内容,那问题就出在下载响应的处理上。
修正后的完整脚本示例
我把你的代码补全并加上关键修复:
<?php // 开启输出缓冲,提前捕获所有意外输出 ob_start(); // 加载数据库配置文件(注意这个文件里不能有多余的空格/echo) include '../secure/db_connect.php'; // 从数据库获取记录 $sql_list = "SELECT * FROM `hakom` ORDER BY id DESC"; $sql_list_result = $mysqli->query($sql_list); if($sql_list_result->num_rows > 0){ $delimiter = ","; $filename = "members_" . date('Y-m-d') . ".csv"; // 生成CSV并保存到服务器 $f = fopen($filename, 'w'); if(!$f){ die("无法创建CSV文件,请检查目录权限"); } // 写入表头(可以根据你的表字段自定义) $header = array_keys($sql_list_result->fetch_assoc()); fputcsv($f, $header, $delimiter); // 重置结果指针,因为刚才fetch_assoc移动了指针 $sql_list_result->data_seek(0); // 写入数据行 while($row = $sql_list_result->fetch_assoc()){ fputcsv($f, $row, $delimiter); } fclose($f); // --- 关键下载处理部分 --- // 清空所有之前的输出缓冲区(避免include文件的空格/BOM头干扰) ob_clean(); // 强制浏览器识别为CSV下载文件 header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename="' . basename($filename) . '"'); // 告诉浏览器文件大小,避免截断 header('Content-Length: ' . filesize($filename)); // 禁止缓存,确保每次下载都是最新的 header('Cache-Control: no-cache, no-store, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); // 高效输出文件内容 readfile($filename); // 立即终止脚本,防止后续代码输出多余内容 exit; } else { echo "没有可导出的记录"; } ?>
关键修复说明
- 输出缓冲区处理:
ob_start()提前开启缓冲,ob_clean()清空所有意外输出(比如db_connect.php文件开头/结尾的空格、BOM头),这些内容会破坏HTTP头,导致浏览器无法正确解析CSV。 - 完整的HTTP头:
Content-Type指定文件类型和编码,避免乱码Content-Disposition强制浏览器触发下载对话框Content-Length让浏览器知道文件大小,防止下载截断- 缓存控制头确保用户下载的是最新文件
readfile()函数:比手动fopen+fread更可靠,能高效输出文件内容,不会出现读取不全的情况- 脚本终止:
exit()确保脚本在输出文件后立即停止,避免后续代码输出多余内容
额外检查项
- 确认
db_connect.php文件没有多余输出:比如文件开头的空格、echo调试语句,这些都会导致HTTP头失效 - 检查服务器目录权限:确保脚本有写入
$filename所在目录的权限,以及读取该文件的权限 - 如果下载的文件有乱码,可以在
fputcsv前加上fprintf($f, chr(0xEF).chr(0xBB).chr(0xBF));,写入UTF-8 BOM头
内容的提问来源于stack exchange,提问作者rtstorm
相关产品推荐
相关产品推荐

