如何手动过滤UTF-8文件BOM头前三个字节以在PHP中读取?
- 内容介绍
- 文章标签
- 相关推荐
本文共计635个文字,预计阅读时间需要3分钟。
直接使用`fgets()`、`file_get_contents()`或`include()`读取带BOM的UTF-8文件,常导致以下问题:
手动跳过BOM的三种可靠方式
核心思路:检测文件头是否为 UTF-8 BOM(\xEF\xBB\xBF),是则跳过前3字节再读取。不依赖扩展或编码转换函数,兼容 PHP 5.6+ 及所有环境。
- 用
fopen()+fread()手动判断并跳过:$fp = fopen('data.json', 'rb'); $bom = fread($fp, 3); if ($bom === "\xEF\xBB\xBF") { // BOM存在,继续读剩余内容 $content = stream_get_contents($fp); } else { // 无BOM,重置指针并读全部 fseek($fp, 0); $content = stream_get_contents($fp); } fclose($fp);
- 用
file_get_contents()配合substr()判断:$raw = file_get_contents('config.php'); if (substr($raw, 0, 3) === "\xEF\xBB\xBF") { $content = substr($raw, 3); } else { $content = $raw; }注意:该方式会一次性加载整个文件到内存,大文件慎用
- 封装成可复用函数:
function file_get_contents_no_bom($path) { $raw = file_get_contents($path); return $raw !== false && substr($raw, 0, 3) === "\xEF\xBB\xBF" ? substr($raw, 3) : $raw; }
为什么不用 mb_convert_encoding 或 iconv 过滤?
这些函数不是为“去BOM”设计的,容易引入新问题:
-
mb_convert_encoding($s, 'UTF-8', 'UTF-8')不会移除BOM,反而可能在某些 PHP 版本中重复添加 -
iconv('UTF-8', 'UTF-8//IGNORE', $s)会丢弃非法字节,但BOM本身是合法UTF-8,不会被过滤 - 若文件实际是 GBK/Big5 编码却误标BOM,强行用UTF-8处理会导致乱码——手动检测BOM能避免这种误判
- 部分旧版
mbstring在非默认设置下可能改变换行符或截断内容
真实项目中容易忽略的边界点
BOM不是只出现在文件开头——它可能藏在你没意识到的地方:
立即学习“PHP免费学习笔记(深入)”;
- 编辑器保存时自动添加:VS Code 默认不加,但 Sublime Text、Notepad++、某些IDEA模板可能默认启用“UTF-8 with BOM”
- Composer生成的
autoload_files.php或框架缓存文件,偶尔因模板文件带BOM而传染 - Windows记事本保存的 .php 文件几乎必然含BOM,而 Linux终端工具(如 vim)默认不加
- 用
file_put_contents()写入内容时,如果源字符串已含BOM(比如从另一个带BOM文件读来未清理),新文件也会带BOM
最稳妥的做法,是在读取任何外部文本输入(尤其是配置、模板、用户上传的JSON/XML)前,统一调用一次BOM检测逻辑——别等报错才想起这事。
本文共计635个文字,预计阅读时间需要3分钟。
直接使用`fgets()`、`file_get_contents()`或`include()`读取带BOM的UTF-8文件,常导致以下问题:
手动跳过BOM的三种可靠方式
核心思路:检测文件头是否为 UTF-8 BOM(\xEF\xBB\xBF),是则跳过前3字节再读取。不依赖扩展或编码转换函数,兼容 PHP 5.6+ 及所有环境。
- 用
fopen()+fread()手动判断并跳过:$fp = fopen('data.json', 'rb'); $bom = fread($fp, 3); if ($bom === "\xEF\xBB\xBF") { // BOM存在,继续读剩余内容 $content = stream_get_contents($fp); } else { // 无BOM,重置指针并读全部 fseek($fp, 0); $content = stream_get_contents($fp); } fclose($fp);
- 用
file_get_contents()配合substr()判断:$raw = file_get_contents('config.php'); if (substr($raw, 0, 3) === "\xEF\xBB\xBF") { $content = substr($raw, 3); } else { $content = $raw; }注意:该方式会一次性加载整个文件到内存,大文件慎用
- 封装成可复用函数:
function file_get_contents_no_bom($path) { $raw = file_get_contents($path); return $raw !== false && substr($raw, 0, 3) === "\xEF\xBB\xBF" ? substr($raw, 3) : $raw; }
为什么不用 mb_convert_encoding 或 iconv 过滤?
这些函数不是为“去BOM”设计的,容易引入新问题:
-
mb_convert_encoding($s, 'UTF-8', 'UTF-8')不会移除BOM,反而可能在某些 PHP 版本中重复添加 -
iconv('UTF-8', 'UTF-8//IGNORE', $s)会丢弃非法字节,但BOM本身是合法UTF-8,不会被过滤 - 若文件实际是 GBK/Big5 编码却误标BOM,强行用UTF-8处理会导致乱码——手动检测BOM能避免这种误判
- 部分旧版
mbstring在非默认设置下可能改变换行符或截断内容
真实项目中容易忽略的边界点
BOM不是只出现在文件开头——它可能藏在你没意识到的地方:
立即学习“PHP免费学习笔记(深入)”;
- 编辑器保存时自动添加:VS Code 默认不加,但 Sublime Text、Notepad++、某些IDEA模板可能默认启用“UTF-8 with BOM”
- Composer生成的
autoload_files.php或框架缓存文件,偶尔因模板文件带BOM而传染 - Windows记事本保存的 .php 文件几乎必然含BOM,而 Linux终端工具(如 vim)默认不加
- 用
file_put_contents()写入内容时,如果源字符串已含BOM(比如从另一个带BOM文件读来未清理),新文件也会带BOM
最稳妥的做法,是在读取任何外部文本输入(尤其是配置、模板、用户上传的JSON/XML)前,统一调用一次BOM检测逻辑——别等报错才想起这事。

