php读取csv乱码本质是编码不匹配,fgetcsv()不识别bom也不转码;应先用file_get_contents()读取原始字节,再用mb_convert_encoding()转码为utf-8,或通过stream_filter_append()添加convert.iconv.gbk/utf-8过滤器实现流式转码。

PHP读取CSV文件时乱码,本质是编码不匹配
PHP本身没有内置的“CSV编码参数”,fgetcsv() 和 str_getcsv() 都只按字节流解析,不识别BOM、不转换编码。乱码不是函数出错,而是你用UTF-8方式读了GBK编码的文件,或反过来。
用mb_convert_encoding()手动转码最可靠
读取后立刻转码,比试图“让fgetcsv支持UTF-8”更可控。尤其适合Windows生成的GBK/GB2312 CSV(带BOM或无BOM都适用):
- 先用
file_get_contents()读原始字节,避免fgetcsv()提前截断或误判换行 - 用
mb_detect_encoding()粗略判断源编码(仅作参考,不绝对准确) - 明确知道来源时,直接用
mb_convert_encoding($content, 'UTF-8', 'GBK') - 若文件带UTF-8 BOM,可用
ltrim($content, "\xEF\xBB\xBF")去掉开头三个字节再处理
fopen()加b模式 + stream_filter_append()可透明转码
想保留 fgetcsv() 流式读取优势?可以用过滤器在读取过程中自动转码:
$handle = fopen('data.csv', 'r');
stream_filter_append($handle, 'convert.iconv.GBK/UTF-8');
while (($row = fgetcsv($handle)) !== false) {
// $row 中的字符串已是UTF-8
}
fclose($handle);
注意:convert.iconv.* 过滤器依赖系统libiconv,部分Linux容器或旧PHP版本可能未启用;Windows上更不稳定。优先测试 iconv_get_encodings() 是否包含 gbk。
立即学习“PHP免费学习笔记(深入)”;
写CSV时用mb_convert_encoding() + BOM防Excel乱码
PHP输出CSV给Excel打开乱码,90%是因为没加UTF-8 BOM。单纯用 utf8_encode() 不够(它只处理ISO-8859-1),必须手动拼接BOM:
- 数据统一转为UTF-8:
$row = array_map(fn($v) => mb_convert_encoding($v, 'UTF-8', 'auto'), $row) - 写入前加BOM:
fwrite($fp, "\xEF\xBB\xBF") - 避免用
echo直接输出CSV给浏览器——HTTP头未声明Content-Type: text/csv; charset=utf-8时,IE/Edge会当ANSI处理
BOM不是万能的,但对Windows Excel是事实标准;Mac Numbers和LibreOffice通常也能识别。别指望靠meta标签或header()绕过BOM——CSV不是HTML。











