PHP导出CSV需用fputcsv流式处理并加UTF-8 BOM:清空缓冲、设置header、写BOM、逐行fetch,避免内存溢出与Excel乱码。
最常用场景:后台导出报表,用户点击即下载。关键不是“保存到服务器”,而是让浏览器弹出下载对话框。
核心要点: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);
用 fetchAll() 把全部数据读进内存,PHP 很容易报 Fatal error: Allowed memory size exhausted。必须流式处理(streaming)。
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false)
fetch() 逐行取,而不是 fetchAll()
ob_flush() + flush(),防止 Web 服务器缓冲卡住$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);
根本原因:Excel for Windows 默认用 ANSI(GBK/GB2312)打开 CSV,而 PHP 输出的是 UTF-8。不加 BOM,Excel 就认不出来。
UTF-8 编码的 CSV 加 BOM,且必须加在文件最开头(fopen('php://output') 后立即写)\xEF\xBB\xBF,不能用 mb_convert_encoding 或其他方式生成Content-Type 仍写 charset=utf-8,不要改成 gbk
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);
适合需要审计日志、定时批量导出、或文件要复用的场景。重点是路径权限、文件命名防覆盖、以及下载链接的安全控制。
./uploads/),建议放 /var/tmp/ 或项目外独立目录uniqid() . '_' . date('Ymd_His'),避免并发写入冲突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。
# mysql
# php
# excel
# windows
# 编码
# 浏览器
# edge
# 字节
# 中文乱码
# csv
# ai
# win
# sql
# echo
# Array
# for
# date
# fopen
# Error
# pdo
# 字符串
# 循环
# var
# 并发
# bom
# 下载链接
# 流式
# 清空
# 的是
# 注册时间
# 朝阳区
# 放在
# 尤其是
# 遍历
# 很容易
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
Win11怎么设置任务栏大小_Windows11注册表修改TaskbarSi值
如何在Golang中实现CI/CD流水线自动化测试_Golang持续集成测试执行方法
如何使用Golang template生成文本模板_动态生成HTML或文本
Win10电脑怎么设置休眠快捷键_Windows10电源按钮功能定义
如何在Golang中编写端到端测试_Golang E2E测试流程示例
Windows怎样关闭开始菜单推荐广告_Windows关闭开始菜单推荐设置【步骤】
如何在网页无标准表格标签时高效提取结构化数据
Win10怎样设置闹钟贪睡时间 Win10闹钟贪睡时长设置【步骤】
php中self::能调用子类重写的方法吗_静态绑定与重写关系【介绍】
Win11视频默认播放器怎么改_Win11关联第三方播放器【步骤】
Win11怎么解压RAR文件 Win11自带解压功能使用方法
Win11怎么更改系统语言_Win11中文语言包下载与安装【指南】
如何在Golang中捕获HTTP服务器错误_GolangHTTP Handler中error处理
Python与MongoDB NoSQL开发实战_文档模型与索引优化
c++ reinterpret_cast怎么用 c++最危险的类型转换【详解】
如何使用Golang实现微服务状态监控_Golang服务运行状态采集方法
如何在Golang中配置代码格式化工具_使用gofmt和goimports
Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言
Win10怎样卸载TeamViewer_Win10卸载TeamViewer步骤【教程】
Win11如何设置ipv6 Win11开启IPv6网络协议教程【步骤】
Python网页解析流程_html结构说明【指导】
如何在Golang中编写异步函数测试_Golang异步操作测试策略
Win10怎么设置开机密码_Windows10账户登录密码设置与取消
如何在Golang中处理数据库事务错误_回滚和日志记录
php打包exe后无法写入文件_权限问题解决方法【教程】
Win11怎么关闭搜索历史_Win11清除设备上的搜索历史记录
Python文本编码与解码_跨平台解析说明【指导】
如何使用 Python 合并文件夹内多个 Excel 文件并避免权限错误
Win11怎么设置按流量计费_Win11限制后台流量消耗【网络】
如何在Golang中验证模块完整性_Golanggo.sum校验与安全实践
Mac如何创建和管理多个桌面空间_Mac高效多任务处理【技巧】
为什么Go需要go mod文件_Go go mod文件作用说明
C#如何使用Channel C#通道实现异步通信
Win11时间格式怎么改成12小时制 Win11时间格式切换教程【步骤】
Win11声音忽大忽小怎么办 Win11音频增强功能关闭教程【修复】
Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件
Win11系统占用空间大怎么办 Win11深度瘦身清理指南【优化】
php本地部署支持nodejs吗_php与nodejs混合开发环境搭建教程【教程】
Python字符串处理进阶_切片方法解析【指导】
c++ nullptr与NULL区别_c++11空指针规范
Win10如何卸载微软拼音输入法 Win10只保留一个输入法【教程】
Win11怎么设置组合键快捷方式_Windows11自定义快捷键操作
MySQL 中使用 IF 和 CASE 实现查询字段条件化显示
如何在Golang中使用encoding/gob序列化对象_存储和传输数据
如何在 Go 中正确测试带 Cookie 的 HTTP 请求
PythonGIL机制理解_多线程限制解析【教程】
Linux如何安装JDK11_Linux环境变量配置与Java开发环境搭建【教程】
Win11怎么打开旧版计算器_Win11恢复传统计算器应用【详解】
Win11键盘快捷键大全_Windows 11常用高效快捷键汇总【技巧】
ACF 教程:正确更新嵌套在多层 Group 字段内的子字段
2026-01-01
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。