使用PHP fgetcsv()导入含特殊字符的CSV到MySQL乱码如何解决
特殊字符导入MySQL存储异常解决方案
核心问题排查&修复步骤
- 移除错误的编码转换逻辑
你代码中调用的utf8_encode()仅适用于将ISO-8859-1编码的内容转换为UTF-8,若你的CSV文件本身已经是UTF-8编码、或是其他编码(如Windows平台导出的CSV常为GBK/CP1252编码),调用该方法会直接导致字符二次转码乱码。
正确做法是先确认CSV的原始编码,再使用mb_convert_encoding()做统一转换,示例:
若CSV本身就是UTF-8编码,直接删除编码转换的相关代码即可。// 假设CSV原始编码为CP1252(西欧编码,支持德文字符),转为UTF-8 $data = array_map(function($item) { return mb_convert_encoding($item, 'UTF-8', 'CP1252'); }, $data); - 指定MySQL连接编码
仅表和字段设置utf8排序规则不生效,必须保证PDO连接时指定字符集为UTF-8,在初始化PDO实例时补充charset参数:
若使用低版本PHP,可在连接后执行SQL设置编码:$con = new PDO('mysql:host=你的数据库地址;dbname=你的库名;charset=utf8', '用户名', '密码');$con->exec("SET NAMES 'utf8'"); - 处理UTF-8 BOM头异常
如果CSV文件是带BOM的UTF-8格式,fgetcsv读取到的第一行第一个字段会携带BOM头字符导致乱码,可在读取文件前先跳过前3字节的BOM头:$handle = fopen ('../csv/file.csv', 'r' ); // 检查是否存在UTF-8 BOM if (fread($handle, 3) !== "\xef\xbb\xbf") { // 不存在则将指针移回文件开头 rewind($handle); } - 可选:升级为utf8mb4字符集
若后续需要存储Emoji等更复杂的Unicode字符,可将表和字段的排序规则改为utf8mb4_general_ci,同时连接编码也对应改为utf8mb4,兼容性更好。
修正后完整代码示例
// 初始化PDO时指定编码 $con = new PDO('mysql:host=localhost;dbname=test_db;charset=utf8', 'root', 'password'); $handle = fopen ('../csv/file.csv', 'r' ); // 处理BOM头 if (fread($handle, 3) !== "\xef\xbb\xbf") { rewind($handle); } while ($data = fgetcsv ($handle, 1024, ';')) { // 按需调整编码转换逻辑,CSV本身是UTF-8可删除下方转换代码 $data = array_map(function($item) { return mb_convert_encoding($item, 'UTF-8', 'CP1252'); }, $data); $stmt = $con->prepare("INSERT INTO tbl_name (Col_1 , Col_2, Col_3, Col_4) VALUES (:ncol_1, :ncol_2, :ncol_3, :ncol_4)"); $stmt->execute(array( 'ncol_1' => $data[0], 'ncol_2' => $data[1], 'ncol_3' => $data[2], 'ncol_4' => $data[3], )); } fclose($handle);
内容的提问来源于stack exchange,提问作者Ahmad Mardini
相关产品推荐
相关产品推荐

