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头部

典型应用场景

  1. 数据导出:将数据库查询结果导出为CSV文件供用户下载
  2. 报表生成:生成各种业务报表,如销售报表、用户统计报表
  3. 数据交换:在不同系统间交换结构化数据
  4. 数据备份:将配置数据、用户数据等备份为CSV格式
  5. 批量导入准备:为其他系统准备批量导入的数据文件
  6. 日志记录:将操作日志、访问日志记录为CSV格式
  7. API响应:提供CSV格式的API数据下载