You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP+MySQL导出CSV文件时外文显示为问号的问题求助

PHP导出CSV外文字符显示问号的解决方案

问题描述

我已查阅该主题的其他相关帖子,但仍未能解决问题。以下PHP代码用于从数据库导出CSV文件,但其中的外文字符显示为问号(???)。我已为此尝试数小时,恳请各位提供帮助。

原代码

$conn = mysqli_connect($servername, $username, $password,$db);
$conn->set_charset('utf8');
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


    //header('Content-Type: application/octet-stream');
    header("Content-Transfer-Encoding: Binary"); 
    header("Content-disposition: attachment; filename=\"  2.csv\""); 
    header('Content-Encoding: UTF-8');
    // header('Content-type: text/csv; charset=utf8mb4');


$delimiter = ",";
$filename = "weddingList2-" . date('Y-m-d') . ".csv";

//create a file pointer
$f = fopen('php://memory', 'w');
fputs($f, chr(0xEF) . chr(0xBB) . chr(0xBF));


//set column headers
$fields = array('', 'name', 'phone', 'status', 'num. people');
fputcsv($f, $fields, $delimiter);


    $sql = "SELECT * FROM attending";

    // GET USERS FROM DATABASE + DIRECT OUTPUT
    foreach ($conn->query($sql) as $row) {
        $lineData = array($row['id'], $row['name'], $row['phone'], $row['status'], $row['people']);
        $convertInfo = mb_convert_encoding($lineData, 'UTF-16LE', 'UTF-8');
        fputcsv($f, $convertInfo, $delimiter);
    }

     //move back to beginning of file
fseek($f, 0);

//set headers to download file rather than displayed
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="' . $filename . '";');

//output all remaining data on a file pointer
fpassthru($f);
exit;
}

问题分析

  1. PDO连接未指定字符集:原代码中PDO连接字符串未添加charset=utf8mb4参数,导致数据库返回的字符编码不匹配,外文字符出现乱码。
  2. HTTP头重复设置:多次设置Content-Disposition和Content-Type,后设置的头会覆盖之前的,导致浏览器无法正确识别文件编码。
  3. 错误的编码转换:mb_convert_encoding不能直接转换数组,强行将数组转为UTF-16LE会破坏字符结构,导致问号显示。
  4. 冗余的连接代码:同时存在mysqli和PDO两种数据库连接方式,逻辑混乱且无意义。

修复后的代码

<?php
try {
    // PDO连接时指定UTF-8mb4字符集,兼容所有外文字符
    $conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8mb4", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $delimiter = ",";
    $filename = "weddingList2-" . date('Y-m-d') . ".csv";

    // 创建内存文件指针
    $f = fopen('php://memory', 'w');
    // 写入UTF-8 BOM,确保Excel能正确识别编码
    fputs($f, chr(0xEF) . chr(0xBB) . chr(0xBF));

    // 设置CSV表头
    $fields = array('', 'name', 'phone', 'status', 'num. people');
    fputcsv($f, $fields, $delimiter);

    // 查询数据
    $sql = "SELECT * FROM attending";
    foreach ($conn->query($sql) as $row) {
        $lineData = array($row['id'], $row['name'], $row['phone'], $row['status'], $row['people']);
        // 无需额外编码转换,直接写入UTF-8数据
        fputcsv($f, $lineData, $delimiter);
    }

    // 回到文件开头
    fseek($f, 0);

    // 设置正确的HTTP响应头,仅保留必要的
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('Content-Transfer-Encoding: binary');

    // 输出文件内容
    fpassthru($f);
    exit;
} catch(PDOException $e) {
    echo "数据库连接失败: " . $e->getMessage();
    exit;
}
?>

关键修改说明

  • PDO连接添加字符集:在连接字符串末尾加上;charset=utf8mb4,确保数据库返回UTF-8编码的字符。
  • 移除冗余代码:删除无用的mysqli连接代码,保持逻辑清晰。
  • 修正HTTP头:统一设置Content-Type为text/csv; charset=utf-8,确保浏览器和Excel能识别编码;移除重复的头设置。
  • 删除错误的编码转换:去掉mb_convert_encoding调用,直接写入原始UTF-8数据,配合UTF-8 BOM即可确保外文字符正常显示。
  • 添加异常捕获:补充PDO的异常捕获逻辑,方便排查连接或查询错误。

内容的提问来源于stack exchange,提问作者danw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:17:03