finfo_open(FILEINFO_MIME_TYPE)是唯一推荐的初始化方式,必须指定该标志以获取纯净MIME类型(如text/plain),避免FILEINFO_MIME返回带charset的冗余字符串;生产环境应显式传入系统magic路径以防识别不准。

finfo_open(FILEINFO_MIME_TYPE) 是唯一推荐的初始化方式
PHP8 中必须用 FILEINFO_MIME_TYPE 标志,不能用 FILEINFO_MIME(它返回带 charset 的完整字符串,比如 text/plain; charset=utf-8),解析麻烦且易出错。用 FILEINFO_MIME_TYPE 只返回干净的类型名,如 text/plain 或 image/jpeg。
生产环境建议显式指定系统 magic 文件路径,避免 fallback 到 PHP 内置精简库:
-
finfo_open(FILEINFO_MIME_TYPE, '/usr/share/misc/magic')(Linux 常见路径) -
finfo_open(FILEINFO_MIME_TYPE, 'C:/php/magic')(Windows,需确认实际位置) - 不指定路径时,
finfo_open()可能降级使用内置规则,对 UTF-16 无 BOM、JSON、SVG 等识别不准
finfo_file() 必须作用于临时文件路径,不是原始文件名
上传场景中,finfo_file() 的第二个参数必须是 $_FILES['xxx']['tmp_name'],不是 $_FILES['xxx']['name'] 或用户传来的任意路径。后者会读取错误位置甚至触发目录遍历风险。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 传入
$_FILES['file']['name']→ 返回 false 或空字符串(因为那是客户端起的名字,不是服务器上真实文件) - 未检查
$_FILES['file']['error'] === UPLOAD_ERR_OK就调用 → 对失败上传调用finfo_file()会读取无效路径 - 在
move_uploaded_file()之后再检测 → 临时文件已消失,finfo_file()失败
空文件和特殊编码文本需单独处理
finfo_file() 对空文件一律返回 application/octet-stream,这不是 bug,是规范行为。必须前置判断 filesize($_FILES['file']['tmp_name']) === 0。
对于文本类判断(如要求上传纯文本),MIME 类型只是“声称”,还需验证内容是否真能被当作文本处理:
- 用
mb_detect_encoding($content, ['UTF-8', 'GB2312', 'BIG5', 'ISO-8859-1'], true),第三个参数true表示严格模式(遇到非法字节直接返回 false) - 再用
mb_check_encoding($content, $encoding)二次确认,不能只信mb_detect_encoding()返回值 - 大文件别全量读取:限制只读前 64KB(
fread($fp, 65536)),否则内存爆掉 - Windows 记事本保存的无 BOM UTF-16 文件常被误判为
application/octet-stream,此时可尝试用mb_convert_encoding($content, 'UTF-8', 'UTF-16LE')转码后重检
白名单校验不能用 strpos 模糊匹配
安全过滤必须用精确匹配或预定义白名单数组,禁止用 strpos($mime, 'image/') 这类写法 —— 它会让 image/svg+xml、image/x-icon 甚至 image/vnd.microsoft.icon 全部通过,而 SVG 和 ICO 都可能含可执行脚本。
正确做法是枚举可信值:
- 图片:只放行
image/jpeg、image/png、image/gif - PDF:
application/pdf(注意不是application/x-pdf) - 文本:
text/plain、text/csv,且必须配合编码验证 - 拒绝所有
application/*和text/html、text/xml(除非业务明确需要)
真正难处理的不是函数怎么调,而是边界情况:空文件、BOM 缺失、多编码混杂、魔数合法但内容恶意。这些没法靠一行 finfo_file() 解决,得组合判断,而且顺序不能错 —— 先过 MIME,再验编码,最后才考虑内容抽样。


















