php查询数据怎么导出csv_查询结果转csv文件保存【操作】
技术百科
蓮花仙者
发布时间:2026-01-01
浏览: 次 PHP导出CSV需用fputcsv流式处理并加UTF-8 BOM:清空缓冲、设置header、写BOM、逐行fetch,避免内存溢出与Excel乱码。
PHP 查询 MySQL 后直接输出 CSV 文件(浏览器下载)
最常用场景:后台导出报表,用户点击即下载。关键不是“保存到服务器”,而是让浏览器弹出下载对话框。
核心要点:fputcsv() 是 PHP 原生安全写 CSV 的函数,别用字符串拼接;输出前必须清空缓冲区、设置正确 header;MySQL 查询结果需转为二维数组(每行是 array)。
- 务必在
header()之前没有输出(包括空格、BOM、echo、var_dump) - 使用
ob_end_clean()清除可能存在的前置输出 - 文件名中的中文要用
rawurlencode()处理,否则 IE/Edge 可能乱码 -
fputcsv()自动处理字段内含逗号、换行、双引号的情况,比手动str_replace可靠得多
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="user_export_' . rawurlencode(date('Y-m-d')) . '.csv"');
header('Cache-Control: no-cache');
$output = fopen('php://output', 'w');
fputcsv($output, ['ID', '用户名', '邮箱', '注册时间']); // 表头
$stmt = $pdo->query("SELECT id, username, email, created_at FROM users WHERE status = 1");
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
fputcsv($output, $row);
}
fclose($output);
导出大表时内存溢出怎么办(超 10 万行)
用 fetchAll() 把全部数据读进内存,PHP 很容易报 Fatal error: Allowed memory size exhausted。必须流式处理(streaming)。
- 禁用 PDO 的默认缓存行为:
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false) - 用
fetch()逐行取,而不是fetchAll() - 每写 1000 行调用一次
ob_flush()+flush(),防止 Web 服务器缓冲卡住 - 避免在循环里做耗时操作(如格式化日期、查关联表),提前在 SQL 中处理好
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->prepare("SELECT id, username, DATE_FORMAT(created_at, '%Y-%m-%d') as date_str FROM users");
$stmt->execute();
$output = fopen('php://output', 'w');
fputcsv($output, ['ID', '用户名', '日期']);
$i = 0;
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
fputcsv($output, $row);
$i++;
if ($i % 1000 === 0) {
ob_flush();
flush();
}
}
fclose($output);
CSV 导出中文乱码(Excel 打开全是方块)
根本原因:Excel for Windows 默认用 ANSI(GBK/GB2312)打开 CSV,而 PHP 输出的是 UTF-8。不加 BOM,Excel 就认不出来。
- 只对
UTF-8编码的 CSV 加 BOM,且必须加在文件最开头(fopen('php://output')后立即写) - BOM
是三个字节:\xEF\xBB\xBF,不能用mb_convert_encoding或其他方式生成 - 加了 BOM 后,
Content-Type仍写charset=utf-8,不要改成gbk - 如果用 Notepad++ 查看,选“编码 → 转为 UTF-8-BOM”可验证是否生效
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="data.csv"');
$output = fopen('php://output', 'w');
fwrite($output, "\xEF\xBB\xBF"); // 写入 UTF-8 BOM
fputcsv($output, ['姓名', '地址', '备注']);
fputcsv($output, ['张三', '北京市朝阳区', '测试用户']);
fclose($output);
想先保存到服务器再提供下载链接
适合需要审计日志、定时批量导出、或文件要复用的场景。重点是路径权限、文件命名防覆盖、以及下载链接的安全控制。
- 保存路径别放在 Web 可访问目录下(如
./uploads/),建议放/var/tmp/或项目外独立目录 - 文件名必须唯一:用
uniqid() . '_' . date('Ymd_His'),避免并发写入冲突 - 生成下载链接时,不要直接暴露物理路径,走一个中间 PHP 脚本(如
download.php?file=xxx.csv)做校验 - 下载脚本里必须检查
$_GET['file']是否为合法格式(正则匹配^[a-z0-9_]+\.csv$),并用basename()防止路径遍历
保存示例(不输出,只写磁盘):
$filename = '/var/tmp/export_' . uniqid() . '_' . date('Ymd_His') . '.csv';
$output = fopen($filename, 'w');
fputcsv($output, ['ID', 'Name']);
fputcsv($output, [1, '测试']);
fclose($output);
// 记录到数据库或日志:成功写入 $filename
实际用的时候,BOM 和流式处理这两点最容易被跳过,一出问题就花半天排查。尤其是导出功能上线后数据量变大,原来小表没问题的代码突然挂掉——大概率是没关缓冲查询或没分批 flush。
# ai
# 的是
# 放在
# 尤其是
# excel
# windows
# 朝阳区
# 很容易
# 浏览器
# 下载链接
# 清空
# win
# edge
# 循环
# Error
# 并发
# 编码
# 字节
# 中文乱码
# 字符串
# var
# bom
# php
# echo
# 遍历
# 流式
# for
# csv
# mysql
# sql
# 注册时间
# fopen
# pdo
# date
# Array
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php本地部署后数据库连接报错_1045acces
- php转exe用什么工具打包快_高效打包软件推荐【
- 如何使用Golang table-driven基准
- Win11开机Logo怎么换_Win11自定义启动
- Windows10电脑怎么设置自动连接WiFi_W
- php485返回数据不完整怎么办_php485数据
- C#如何在一个XML文件中查找并替换文本内容
- Win11怎么开启智能存储_Windows11存储
- 如何在Golang中指定模块版本_使用go.mod
- 如何诊断并终止卡死的 multiprocessin
- php怎么捕获异常_trycatch结构处理运行时
- Golang如何测试HTTP中间件_Golang
- Mac怎么安装软件_Mac安装dmg与pkg文件的
- VSC怎样在VSC中调试PHPAPI_接口调试技巧
- Windows怎样拦截WPS弹窗广告_Window
- Win10如何设置双wan路由器 Win10双wa
- Win11怎么设置开机问候语_自定义Win11锁屏
- c++怎么操作redis数据库_c++ hired
- 如何在 Go 中调用动态链接库(.so)中的函数
- Mac电脑如何恢复出厂设置_Mac抹掉数据并重装系
- c# 如何深拷贝和浅拷贝
- Win11怎么设置声音输出设备_Windows11
- Python文件操作优化_大文件与流处理解析【教程
- Mac如何设置动态壁纸?(让桌面动起来)
- 如何有效拦截拼接式恶意域名的垃圾信息
- Mac系统更新下载慢或失败怎么办_解决macOS升
- Win11怎么开启剪贴板历史记录_Windows1
- Win10怎样设置多显示器_Win10多显示器扩展
- 如何在 Go 开发中正确处理本地包导入与远程模块路
- 如何使用Golang捕获测试日志_Golang t
- Linux怎么禁止Root用户远程登录_Linux
- Python文本编码与解码_跨平台解析说明【指导】
- php删除数据怎么清空表_truncate与del
- 为什么Go建议使用error接口作为错误返回_Go
- Win11视频默认播放器怎么改_Win11关联第三
- Windows10如何更改任务栏高度_Win10解
- 如何在Golang中处理模块包路径变化_Golan
- Windows10系统怎么查看设备管理器_Win1
- 如何在 Go 中正确初始化结构体中的 map 字段
- php增删改查在php8里有什么变化_新特性对cu
- Win11怎么查看显卡显存_查询Win11显卡详细
- Laravel 查询 JSON 列:高效筛选包含数
- Win11怎么关闭自动修复_跳过Win11开机自动
- Windows10怎么查看硬件信息_Windows
- Go 语言标准库为何不提供泛型 Contains
- Windows如何查看和管理已安装的字体?(字体文
- 如何优化Golang内存分配与GC调度_Golan
- Windows10如何查看蓝屏日志_Win10使用
- php485在php5.6下能用吗_php485旧
- 如何将文本文件中的竖排字符串转换为横排字符串

是三个字节:
QQ客服