php查询数据怎么导出csv_查询结果转csv文件保存【操作】


PHP导出CSV需用fputcsv流式处理并加UTF-8 BOM:清空缓冲、设置header、写BOM、逐行fetch,避免内存溢出与Excel乱码。

PHP 查询 MySQL 后直接输出 CSV 文件(浏览器下载)

最常用场景:后台导出报表,用户点击即下载。关键不是“保存到服务器”,而是让浏览器弹出下载对话框。

核心要点:fputcsv() 是 PHP 原生安全写 CSV 的函数,别用字符串拼接;输出前必须清空缓冲区、设置正确 header;MySQL 查询结果需转为二维数组(每行是 array)。

  • 务必在 header() 之前没有输出(包括空格、BOM、echovar_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。


# 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

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.