当前位置:首页 > 文章列表 > 文章 > php教程 > PHP 怎么识别上传文件的 MIME 类型

PHP 怎么识别上传文件的 MIME 类型

来源:17golang原创 2026-09-06 10:16:01 0浏览 收藏

PHP 识别上传文件的 MIME 类型,应该读取服务器保存的临时文件,而不是直接相信浏览器传来的 $_FILES['upload']['type'] 或原始扩展名。最小写法是 new finfo(FILEINFO_MIME_TYPE),再调用 file($_FILES['upload']['tmp_name'])。得到 image/jpegimage/png 这类纯 MIME 值后,与服务端允许列表比较,最后才决定是否保存。

要点速览
  • 先检查 $_FILES['upload']['error'],成功后再读取 tmp_name
  • finfo(FILEINFO_MIME_TYPE) 判断文件内容,不把客户端的 type 当成安全结论。
  • MIME 允许列表、大小限制、随机文件名和 move_uploaded_file() 要组成一条完整链路。

先读上传临时文件,不要相信客户端 MIME

上传表单提交后,PHP 会把文件放到服务器临时目录,并在 $_FILES 中给出 nametypesizetmp_nameerror。其中 type 是浏览器提供的 MIME 提示,PHP 手册明确提醒它没有在服务端校验;真正用于判断的输入应是服务器临时文件。

PHP 上传文件中客户端元数据、服务器临时文件、finfo 和 MIME 结果的信任边界关系图
图1:上传文件的客户端元数据只能作为提示,MIME 判断应从服务器临时文件读取。

因此,顺序不要写成“看扩展名就保存”。先看错误码,再确认临时文件确实由 PHP 上传产生,最后交给 Fileinfo。这样即使用户把一个脚本改名成 photo.jpg,文件名也不会直接改变判断依据。

用 finfo 获取纯 MIME,并和允许列表比较

FILEINFO_MIME_TYPE 返回不带字符集的 MIME 类型,适合做白名单比较;FILEINFO_MIME 可能附带字符集,例如 text/plain; charset=us-ascii,更适合展示或记录。上传接口通常需要前者。

字段或函数用途安全判断
$_FILES['upload']['name']客户端原始文件名不直接拼接到保存路径
$_FILES['upload']['type']浏览器上报的 MIME 提示不能单独作为校验结果
tmp_name服务器临时文件路径交给 finfo 读取内容
finfo(FILEINFO_MIME_TYPE)识别文件内容类型和服务端允许列表严格比较
PHP FILEINFO_MIME_TYPE 将临时文件连接到 MIME 允许列表并分出接受保存和拒绝记录的关系图
图2:MIME 结果先进入允许列表,扩展名只用于最终命名,不能替代内容判断。

示例中,$allowed 是接口自己的业务边界,而不是“所有被 finfo 识别出来的类型都允许”。例如头像接口只接受三种图片 MIME;PDF 上传接口应维护另一份列表,不能把同一套规则到处复用。

把类型判断放进完整上传链路

下面的例子把文件上传到当前目录的 uploads 子目录。它先处理 PHP 上传错误,再检查大小、来源、MIME 和保存结果。生产环境还应把上传目录放到不能直接执行脚本的位置,并把拒绝原因写入应用日志。

 $maxBytes || !is_uploaded_file($file['tmp_name'])) {
    throw new RuntimeException('文件大小或上传来源不符合要求');
}

$finfo = new finfo(FILEINFO_MIME_TYPE); // 从服务器临时文件读取内容类型。
$mime = $finfo->file($file['tmp_name']);
$extensions = [
    'image/jpeg' => 'jpg',
    'image/png' => 'png',
    'image/gif' => 'gif',
];
if ($mime === false || !isset($extensions[$mime])) {
    throw new RuntimeException('不允许的文件类型');
}

$uploadDir = __DIR__ . '/uploads';
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0750, true)) {
    throw new RuntimeException('上传目录创建失败');
}
$target = $uploadDir . '/' . bin2hex(random_bytes(16)) . '.' . $extensions[$mime];
if (!move_uploaded_file($file['tmp_name'], $target)) {
    throw new RuntimeException('文件保存失败');
}
echo '上传成功';
?>

这里的扩展名来自 MIME 白名单映射,不来自用户输入。随机文件名避免了原始名称中的路径片段和特殊字符;move_uploaded_file() 只负责把已经通过判断的临时文件移动到目标位置,不能替代前面的类型和大小检查。

处理 finfo 误判、空文件和扩展名陷阱

MIME 识别不是“图片安全检测”的同义词。损坏文件、极短文件或格式内部带有异常内容时,识别结果可能是 false、通用二进制类型,或者与业务预期不一致。对图片服务,必要时还要在解码阶段确认尺寸、重新编码,并限制资源消耗。

另外,UPLOAD_ERR_OK 只说明 PHP 这次上传流程成功,不代表文件类型合规;finfo 返回图片 MIME 也不意味着可以信任原始文件名。日志中建议记录请求标识、识别出的 MIME、文件大小和拒绝原因,避免记录完整临时路径或用户提交的敏感名称。

常见问题

为什么不直接用 $_FILES['upload']['type']?

它由客户端提供,只能作为展示提示。服务端应读取 tmp_name,使用 finfo 自己判断。

FILEINFO_MIME 和 FILEINFO_MIME_TYPE 有什么区别?

前者可能返回 MIME 加字符集,后者只返回 MIME 类型。做精确白名单比较时通常选择 FILEINFO_MIME_TYPE

finfo 判断通过后还要检查扩展名吗?

可以检查,但扩展名应由服务端根据允许的 MIME 映射生成,而不是拿用户提交的扩展名决定是否放行。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go 泛型约束里的 int 和波浪号 int 有什么区别Go 泛型约束里的 int 和波浪号 int 有什么区别
上一篇
Go 泛型约束里的 int 和波浪号 int 有什么区别
Go 项目怎么打包依赖以支持离线构建
下一篇
Go 项目怎么打包依赖以支持离线构建
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    162次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    88次使用
  • LangGPT提示词框架:结构化Prompt设计方法与开源工具指南
    LangGPT
    LangGPT是一种受编程语言启发的结构化提示词设计工具,提供双层框架、模块化模板及变量功能,帮助用户高效编写高质量Prompt。该项目已在GitHub免费开源,适用于内容创作、编程辅助等多场景。
    12次使用
  • ClickPrompt:AI提示词生成与优化工具,支持Stable Diffusion、ChatGPT及代码辅助
    ClickPrompt
    ClickPrompt是一款专为AI提示词编写者设计的开源在线工具,支持Stable Diffusion绘图、ChatGPT对话及GitHub Copilot代码辅助。提供Prompt自动生成、一键运行、社区分享及可视化优化功能,帮助用户高效获取精准AI输出。
    49次使用
  • PromptHero官网:AI提示词搜索、优化与学习平台,支持Midjourney/Stable Diffusion
    PromptHero
    PromptHero是专业的AI提示词搜索引擎与优化平台,支持Stable Diffusion、Midjourney等主流模型。提供海量提示词库、分类搜索、在线课程及社区互动,助力用户高效生成高质量AI图像与文本。
    32次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码