PHP fputcsv()函数
fputcsv()函数用于将数组格式化为CSV(逗号分隔值)行并写入文件指针。这是PHP中处理CSV文件导出的主要函数。
语法
int|false fputcsv ( resource $handle , array $fields [, string $delimiter = "," [, string $enclosure = '"' [, string $escape_char = "\\" ]]] )
参数说明
| 参数 |
描述 |
handle |
文件指针资源,通常由fopen()函数创建 |
fields |
要写入的数组,数组中的每个元素对应CSV的一列 |
delimiter |
可选,字段分隔符,默认为逗号(,) |
enclosure |
可选,字段包围符,默认为双引号(") |
escape_char |
可选,转义字符,默认为反斜杠(\) |
CSV参数详解
| 参数 |
默认值 |
描述 |
常见用途 |
delimiter |
"," |
字段之间的分隔符 |
逗号(,)、分号(;)、制表符(\t) |
enclosure |
'"' |
包围字段的字符,用于处理包含分隔符的字段 |
双引号(")、单引号(') |
escape_char |
"\\" |
转义包围符的字符 |
反斜杠(\)、双引号(") |
返回值
- 成功时返回写入的字符串长度(字节数)
- 失败时返回
false
示例代码
示例1:基本CSV文件创建
<?php
// 创建CSV文件
$filename = 'data.csv';
$handle = fopen($filename, 'w');
if ($handle === false) {
die('无法打开文件');
}
// 写入CSV标题行
$header = ['ID', '姓名', '年龄', '邮箱'];
fputcsv($handle, $header);
// 写入数据行
$data = [
[1, '张三', 25, 'zhangsan@example.com'],
[2, '李四', 30, 'lisi@example.com'],
[3, '王五', 28, 'wangwu@example.com'],
[4, '赵六', 35, 'zhaoliu@example.com']
];
foreach ($data as $row) {
fputcsv($handle, $row);
}
// 关闭文件
fclose($handle);
echo "CSV文件创建成功: " . $filename . "<br>";
echo "文件大小: " . filesize($filename) . " 字节<br>";
// 显示文件内容
echo "<pre>" . htmlspecialchars(file_get_contents($filename)) . "</pre>";
?>
示例2:导出数据库数据为CSV
<?php
// 模拟从数据库获取数据
function getUsersFromDatabase() {
return [
['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com', 'created_at' => '2023-01-15'],
['id' => 2, 'name' => '李四', 'email' => 'lisi@example.com', 'created_at' => '2023-02-20'],
['id' => 3, 'name' => '王五', 'email' => 'wangwu@example.com', 'created_at' => '2023-03-10'],
['id' => 4, 'name' => '赵六', 'email' => 'zhaoliu@example.com', 'created_at' => '2023-04-05']
];
}
// 导出CSV文件(直接输出到浏览器下载)
function exportUsersToCSV($users, $filename = 'users.csv') {
// 设置HTTP头部,强制下载
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// 打开输出流
$output = fopen('php://output', 'w');
// 添加BOM头,确保Excel正确显示中文
fwrite($output, chr(0xEF) . chr(0xBB) . chr(0xBF));
// 写入标题行
fputcsv($output, ['ID', '姓名', '邮箱', '注册日期']);
// 写入数据行
foreach ($users as $user) {
fputcsv($output, [
$user['id'],
$user['name'],
$user['email'],
$user['created_at']
]);
}
// 关闭输出流
fclose($output);
exit; // 终止脚本执行
}
// 使用示例
$users = getUsersFromDatabase();
// 检查是否有导出请求
if (isset($_GET['export']) && $_GET['export'] === 'csv') {
exportUsersToCSV($users, '用户列表.csv');
}
echo "<a href='?export=csv' class='btn btn-success'><i class='fas fa-download me-2'></i>导出为CSV</a>";
?>
示例3:自定义分隔符和包围符
<?php
// 不同地区的CSV格式差异
$formats = [
[
'name' => '标准CSV(逗号分隔)',
'delimiter' => ',',
'enclosure' => '"',
'filename' => 'standard.csv'
],
[
'name' => '欧洲CSV(分号分隔)',
'delimiter' => ';',
'enclosure' => '"',
'filename' => 'european.csv'
],
[
'name' => 'TSV(制表符分隔)',
'delimiter' => "\t",
'enclosure' => '"',
'filename' => 'tab_separated.tsv'
],
[
'name' => '自定义(管道分隔)',
'delimiter' => '|',
'enclosure' => "'",
'filename' => 'pipe_separated.txt'
]
];
// 测试数据(包含特殊字符的数据)
$testData = [
['ID', '商品名称', '价格', '描述'],
[1, '苹果 iPhone 14', '6999.00', '高端智能手机,支持5G'],
[2, '华为 Mate 50', '5999.00', '搭载鸿蒙系统,支持卫星通信'],
[3, '小米电视, 65英寸', '3999.00', '4K超高清,支持HDR'],
[4, '戴尔笔记本"灵越"系列', '5999.00', '高性能办公笔记本']
];
foreach ($formats as $format) {
$handle = fopen($format['filename'], 'w');
if ($handle) {
foreach ($testData as $row) {
fputcsv($handle, $row, $format['delimiter'], $format['enclosure']);
}
fclose($handle);
echo "<h5>" . $format['name'] . "</h5>";
echo "<small>文件: " . $format['filename'] . " | 分隔符: " . htmlspecialchars($format['delimiter']) . " | 包围符: " . htmlspecialchars($format['enclosure']) . "</small>";
echo "<pre style='background:#f8f9fa;padding:10px;border-radius:4px;'>" . htmlspecialchars(file_get_contents($format['filename'])) . "</pre>";
}
}
?>
示例4:CSV数据导出类
<?php
class CSVExporter {
private $filename;
private $headers = [];
private $data = [];
private $delimiter = ',';
private $enclosure = '"';
private $includeBOM = false;
public function __construct($filename = 'export.csv') {
$this->filename = $filename;
}
/**
* 设置CSV头部
*/
public function setHeaders(array $headers) {
$this->headers = $headers;
return $this;
}
/**
* 添加数据行
*/
public function addRow(array $row) {
$this->data[] = $row;
return $this;
}
/**
* 添加多行数据
*/
public function addRows(array $rows) {
foreach ($rows as $row) {
$this->addRow($row);
}
return $this;
}
/**
* 设置分隔符
*/
public function setDelimiter($delimiter) {
$this->delimiter = $delimiter;
return $this;
}
/**
* 设置包围符
*/
public function setEnclosure($enclosure) {
$this->enclosure = $enclosure;
return $this;
}
/**
* 设置是否包含BOM(用于Excel中文显示)
*/
public function setIncludeBOM($include) {
$this->includeBOM = $include;
return $this;
}
/**
* 导出到文件
*/
public function exportToFile($filepath = null) {
if ($filepath === null) {
$filepath = $this->filename;
}
$handle = fopen($filepath, 'w');
if (!$handle) {
throw new Exception("无法创建文件: {$filepath}");
}
$this->writeCSV($handle);
fclose($handle);
return $filepath;
}
/**
* 导出到浏览器(下载)
*/
public function exportToBrowser($filename = null) {
if ($filename === null) {
$filename = $this->filename;
}
// 设置HTTP头部
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// 输出到浏览器
$output = fopen('php://output', 'w');
$this->writeCSV($output);
fclose($output);
exit;
}
/**
* 获取CSV字符串
*/
public function getCSVString() {
ob_start();
$handle = fopen('php://temp', 'r+');
$this->writeCSV($handle);
rewind($handle);
$csv = stream_get_contents($handle);
fclose($handle);
ob_end_clean();
return $csv;
}
/**
* 写入CSV数据
*/
private function writeCSV($handle) {
// 写入BOM(如果需要)
if ($this->includeBOM) {
fwrite($handle, chr(0xEF) . chr(0xBB) . chr(0xBF));
}
// 写入头部
if (!empty($this->headers)) {
fputcsv($handle, $this->headers, $this->delimiter, $this->enclosure);
}
// 写入数据
foreach ($this->data as $row) {
fputcsv($handle, $row, $this->delimiter, $this->enclosure);
}
}
/**
* 清空数据
*/
public function clear() {
$this->headers = [];
$this->data = [];
return $this;
}
}
// 使用示例
try {
// 创建导出器实例
$exporter = new CSVExporter('用户数据.csv');
// 设置数据
$exporter
->setHeaders(['ID', '用户名', '邮箱', '注册时间', '状态'])
->addRow([1, '张三', 'zhangsan@example.com', '2023-01-01', '激活'])
->addRow([2, '李四', 'lisi@example.com', '2023-01-15', '激活'])
->addRow([3, '王五', 'wangwu@example.com', '2023-02-01', '禁用'])
->addRow([4, '赵六', 'zhaoliu@example.com', '2023-02-15', '激活']);
// 示例1:保存到文件
$filepath = $exporter->exportToFile();
echo "CSV文件已保存: {$filepath}<br><br>";
// 示例2:显示CSV内容
echo "<h5>CSV文件内容:</h5>";
echo "<pre style='background:#f8f9fa;padding:10px;border-radius:4px;'>" . htmlspecialchars($exporter->getCSVString()) . "</pre>";
// 示例3:重新配置并导出为TSV
$exporter
->clear()
->setDelimiter("\t")
->setHeaders(['产品ID', '产品名称', '价格', '库存'])
->addRows([
[101, '无线鼠标', 129.00, 50],
[102, '机械键盘', 399.00, 30],
[103, '游戏耳机', 299.00, 25]
]);
echo "<br><h5>TSV格式内容:</h5>";
echo "<pre style='background:#f8f9fa;padding:10px;border-radius:4px;'>" . htmlspecialchars($exporter->getCSVString()) . "</pre>";
// 示例4:导出到浏览器(下载)
if (isset($_GET['download'])) {
$exporter
->clear()
->setIncludeBOM(true)
->setHeaders(['序号', '姓名', '部门', '工资'])
->addRows([
[1, '张三', '技术部', 15000],
[2, '李四', '销售部', 12000],
[3, '王五', '市场部', 13000]
])
->exportToBrowser('员工工资.csv');
}
echo "<br><a href='?download=1' class='btn btn-primary'><i class='fas fa-file-export me-2'></i>下载CSV文件</a>";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
注意事项
重要提示:
- 字符编码:确保数据源和输出的编码一致(通常为UTF-8)。对于Excel打开中文CSV,可能需要添加BOM头
- 特殊字符处理:如果字段包含分隔符、换行符或包围符,fputcsv()会自动使用包围符包裹字段
- 性能优化:导出大量数据时,建议使用流式输出(php://output)而不是先保存到文件再输出
- 内存管理:处理大数据集时,分批写入数据,避免内存溢出
- 文件权限:确保PHP进程有权限写入目标文件目录
- Excel兼容性:Excel对CSV的解析有特殊要求,可能需要设置特定的分隔符或添加BOM
- 跨平台兼容性:Windows和Unix系统对换行符的处理不同,PHP会自动处理这个问题
- 安全性:不要将用户提供的分隔符或包围符直接传递给fputcsv(),可能造成CSV注入攻击
CSV格式规范(RFC 4180)
| 规则 |
说明 |
示例 |
| 字段分隔 |
使用逗号分隔字段 |
value1,value2,value3 |
| 行分隔 |
使用CRLF(\r\n)分隔行 |
row1\r\nrow2\r\nrow3 |
| 包围符 |
包含分隔符的字段必须用双引号包围 |
"value,with,commas","normal" |
| 转义 |
字段内的双引号用两个双引号表示 |
"value with ""quotes""" |
| 头行 |
第一行可以作为标题行(可选) |
Name,Age,Email |
相关函数
fgetcsv() - 从文件指针中读入一行并解析CSV字段
fopen() - 打开文件或URL
fclose() - 关闭一个已打开的文件指针
str_getcsv() - 解析CSV字符串到一个数组
SplFileObject - 面向对象的文件处理类,支持CSV操作
header() - 发送原始HTTP头部
典型应用场景
- 数据导出:将数据库查询结果导出为CSV文件供用户下载
- 报表生成:生成各种业务报表,如销售报表、用户统计报表
- 数据交换:在不同系统间交换结构化数据
- 数据备份:将配置数据、用户数据等备份为CSV格式
- 批量导入准备:为其他系统准备批量导入的数据文件
- 日志记录:将操作日志、访问日志记录为CSV格式
- API响应:提供CSV格式的API数据下载