PHP表单如何限制文件上传类型_限制上传类型PHP表单验证法【格式】

1次阅读

$_files’file’不可靠,需用finfo_open()读取文件头识别真实mime类型并白名单校验,同时严格检查小写扩展名,accept属性仅前端提示,不能替代服务端验证。

PHP表单如何限制文件上传类型_限制上传类型PHP表单验证法【格式】

php 表单中用 $_FILES['file']['type'] 判断 MIME 类型不可靠

浏览器提交的 $_FILES['file']['type'] 是前端伪造的,仅由文件扩展名推断而来,完全可被绕过。比如把 evil.php 改名为 image.jpg,它就会显示为 image/jpeg,但实际仍是 PHP 文件。真实场景中,仅靠这个字段做判断等于没验证。

正确做法是结合服务端文件内容检测

  • finfo_open() 读取二进制头(magic bytes)识别真实 MIME 类型
  • 配合白名单校验,只允许如 image/pngapplication/pdf 等明确类型
  • 同时检查扩展名是否匹配(防止 .htaccess 或 .user.ini 类型绕过)

finfo_file() 获取真实 MIME 类型并校验

这是目前最通用、兼容性好的方式。注意必须用 FILEINFO_MIME_TYPE 模式,避免返回带字符集的完整字符串(如 text/plain; charset=utf-8)。

$finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']); finfo_close($finfo);  $allowedTypes = ['image/jpeg', 'image/png', 'application/pdf']; if (!in_array($mimeType, $allowedTypes, true)) {     die('不支持的文件类型'); }

常见坑:

立即学习PHP免费学习笔记(深入)”;

  • 未开启 fileinfo 扩展(PHP 默认可能关闭),需确认 phpinfo() 中存在 fileinfo support => enabled
  • 上传大文件时 $_FILES['file']['tmp_name'] 可能为空,要先检查 $_FILES['file']['Error'] === UPLOAD_ERR_OK
  • 某些 PDF 文件可能被识别为 application/x-empty,需额外 fallback 处理

扩展名二次校验不能只看 pathinfo($filename, PATHINFO_EXTENSION)

用户上传 shell.php.jpg 时,pathinfo() 会返回 jpg,看似安全,但 apache 等服务器可能按从右到左顺序解析,仍执行 PHP。所以必须提取「最后一个点之后」的扩展名,并统一转小写比对。

$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)); $allowedExts = ['jpg', 'jpeg', 'png', 'pdf']; if (!in_array($ext, $allowedExts, true)) {     die('扩展名不合法'); }

更稳妥的做法是:生成新文件名,强制使用根据 MIME 类型推导出的扩展名(如 image/jpeg → .jpg),彻底丢弃原始文件名。

HTML 表单里的 accept 属性只是提示,不是限制

<input type="file" accept=".jpg,.png,.pdf"> 仅影响浏览器文件选择对话框的过滤选项,无法阻止用户手动输入或拖入非法文件,也不能替代服务端验证。

真正起作用的只有服务端逻辑。如果发现“明明写了 accept 还能传 php”,这不是 bug,是预期行为。

复杂点在于:不同浏览器对 accept 的实现不一致(比如 safari 对 MIME 类型支持较弱),而攻击者根本不会走这个 ui —— 他们直接发 POST 请求或用 curl 上传。所以只要服务端验证没做牢,前端所有限制都形同虚设。

text=ZqhQzanResources