跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何在 PHP 中准确识别上传文件的类型(图像、视频、文档)

本文介绍一种基于 MIME 类型检测与文件扩展名双重验证的可靠方法,解决仅依赖后缀名或 getimagesize() 导致的视频类型误判问题,确保图像、视频、文档三类文件被精准分类。 本文介绍一种基于 mime 类型检测与文件扩展名双重验证的可靠方法,解决仅依赖后缀名或 `getimagesize()` 导致的视频类型误判问题,确保图像、视频、文档三类文件被精准分类。 在 PHP 文件上传处理中,仅通过文件扩展名(如 .mp4)或 getimagesize() 判断类型存在严重缺陷:前者易被伪造,后者对非图像文件(如视频)直接返回 false 或警告,无法用于视频识别。更健壮的方案是结合 文件扩展名预过滤 与 真实 MIME 类型检测 (推荐使用 mime_content_type() 或 finfo_open()),从而实现高准确率的类型分类。 以下是一个生产就绪的分类函数示例:
function classifyUploadedFile($tmpPath, $allowedTypes = ['image', 'video', 'document']) { if (!is_uploaded_file($tmpPath) || !file_exists($tmpPath)) { throw new InvalidArgumentException('Invalid uploaded file path.'); } // 获取小写扩展名 $ext = strtolower(pathinfo($tmpPath, PATHINFO_EXTENSION)); // 预定义类型映射(扩展名 + 对应 MIME 类型组) $typeRules = [ 'image' => [ 'extensions' => ['gif', 'jpg', 'jpeg', 'png', 'webp', 'bmp'], 'mime_patterns' => ['image/'] ], 'video' => [ 'extensions' => ['mp4', 'mov', 'avi', 'mkv', 'webm', 'flv'], 'mime_patterns' => ['video/'] ], 'document' => [ 'extensions' => ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'], 'mime_patterns' => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument', 'text/plain', 'text/csv'] ] ]; // 第一步:扩展名快速筛选(低成本) foreach ($typeRules as $type => $rules) { if (in_array($ext, $rules['extensions'])) { // 第二步:MIME 类型深度验证(高可靠性) $mime = @mime_content_type($tmpPath); // 注意:PHP 8.1+ 已弃用,建议改用 finfo if (!$mime) { // 回退方案:使用 finfo(更推荐、更稳定) $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $tmpPath); finfo_close($finfo); } // 匹配 MIME:支持前缀匹配(如 'video/')和精确匹配 $mimeMatched = false; foreach ($rules['mime_patterns'] as $pattern) { if (strpos($mime, $pattern) === 0 || $mime === $pattern) { $mimeMatched = true; break; } } if ($mimeMatched && in_array($type, $allowedTypes)) { return $type; // 成功识别 } } } return 'unknown'; } // 使用示例 if ($_FILES['file']['error'] === UPLOAD_ERR_OK) { $type = classifyUploadedFile($_FILES['file']['tmp_name']); switch ($type) { case 'image': echo "✅ 处理图像文件..."; // 例如:生成缩略图、调用 getimagesize() 安全校验 break; case 'video': echo "✅ 处理视频文件..."; // 例如:调用 FFmpeg 检查关键帧、提取封面 break; case 'document': echo "✅ 处理文档文件..."; // 例如:限制 PDF 大小、检查 Office 文档宏风险 break; default: throw new RuntimeException("不支持的文件类型: {$_FILES['file']['name']} (MIME: {$mime})"); } }
✅ 关键注意事项: PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 ❗ mime_content_type() 在 PHP 8.1+ 已标记为废弃,请优先使用 finfo_open(FILEINFO_MIME_TYPE) —— 它更准确、更安全,且不受 magic.mime 文件缺失影响; ❗ 始终先校验 is_uploaded_file() 和文件存在性,防止路径遍历或空文件攻击; ❗ 扩展名仅作初筛, 绝不可作为唯一判断依据 ;真实 MIME 是内容层面的指纹; ❗ 对于文档类(尤其 Office 文件),建议额外使用 ziparchive 或专用库(如 PhpSpreadsheet)做二次结构校验,防范伪装文件; ⚠️ getimagesize() 仅适用于图像,对视频返回 false 并触发警告, 不能用于视频识别 ——这是原文中逻辑错误的根本原因。 总结:构建可靠的文件类型识别机制,需坚持「扩展名快速过滤 + MIME 内容检测」双校验原则,并选用 finfo 替代过时函数。这不仅能准确区分图像、视频与文档,更能显著提升应用安全性与鲁棒性。 立即学习 “ PHP免费学习笔记(深入) ”;

相关文章