应使用finfo扩展读取魔数判断二进制文件类型,优先调用finfo_open(fileinfo_mime_type)获取mime类型;若未启用fileinfo扩展,则回退为手动读取前8字节比对jpeg、png、gif等常见格式魔数。

PHP判断二进制文件类型,不能依赖扩展名,而应读取文件头部的“魔数”(Magic Number)进行识别。这是最可靠的方式,尤其适用于上传文件校验、安全过滤等场景。
读取文件前几个字节比对魔数
不同二进制格式在文件开头有固定字节序列,例如:
- JPEG:以 0xFF, 0xD8 开头
- PNG:以 0x89, 0x50, 0x4E, 0x47(即 "\x89PNG")开头
- GIF:以 GIF87a 或 GIF89a 开头(ASCII 字符)
- PDF:以 %PDF 开头
- ZIP(含 APK、DOCX 等):以 0x50, 0x4B, 0x03, 0x04(即 "PK\x03\x04")开头
可用 file_get_contents($file, false, null, 0, 8) 读取前 8 字节做判断,避免加载整个大文件。
使用 finfo 扩展(推荐方式)
PHP 内置的 finfo 类封装了 libmagic 库,支持数百种格式识别,准确度高且维护成本低:
- 确保启用了 fileinfo 扩展(php.ini 中取消
extension=fileinfo注释) - 代码示例:
$finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, '/path/to/file'); finfo_close($finfo); // 返回如 'image/jpeg'、'application/pdf'、'application/zip'
也可用 FILEINFO_MIME 获取完整 MIME + 编码信息,或 FILEINFO_NONE 获取描述性字符串(如 "JPEG image data")。
注意边界情况和安全建议
仅靠魔数判断仍需结合业务逻辑防范绕过:
- 某些格式(如 ZIP)魔数易伪造,建议配合解压尝试或内容校验
- 不要仅用 $_FILES['xxx']['type'] —— 浏览器提交的 type 可被轻易篡改
- 上传后立即用 finfo 验证,再决定是否移动到目标目录
- 若环境不支持 fileinfo,可手写魔数映射表,但需定期更新以覆盖新格式
简单封装一个检测函数
兼顾兼容性与实用性:
function detectBinaryType($filePath) {
if (extension_loaded('fileinfo')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, $filePath);
finfo_close($finfo);
return $type ?: 'unknown';
}
// 回退:手动读魔数(示例 JPEG/PNG/GIF)
$header = file_get_contents($filePath, false, null, 0, 8);
if (substr($header, 0, 2) === "\xFF\xD8") return 'image/jpeg';
if (substr($header, 0, 4) === "\x89PNG") return 'image/png';
if (substr($header, 0, 3) === 'GIF') return 'image/gif';
return 'unknown';
}php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











