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; }
问题分析
- PDO连接未指定字符集:原代码中PDO连接字符串未添加
charset=utf8mb4参数,导致数据库返回的字符编码不匹配,外文字符出现乱码。 - HTTP头重复设置:多次设置
Content-Disposition和Content-Type,后设置的头会覆盖之前的,导致浏览器无法正确识别文件编码。 - 错误的编码转换:
mb_convert_encoding不能直接转换数组,强行将数组转为UTF-16LE会破坏字符结构,导致问号显示。 - 冗余的连接代码:同时存在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
相关产品推荐
相关产品推荐

