$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);
if (!in_array($mime, ['image/jpeg','image/png'], true)) exit('类型不允许');

选择框限定了 image/*,用户把 shell.php 改名成 shell.jpg 后仍能选中,上传按钮亮起。后端只看了扩展名,文件就这样进了 uploads 目录。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,accept 只是给文件选择框的过滤建议,用户切到所有文件就能绕开,改扩展名更不受它约束。真正的类型判断要靠服务端读文件头,扩展名和浏览器给的 MIME 都可以伪造。

「accept 文件类型」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。

接口问题先分清是没发出去、发出去了没收到,还是收到了处理失败。

处理上按这个顺序:前端保留 accept 作为体验优化,同时检查 file.type 和扩展名白名单;服务端用 finfo 读真实 MIME,与扩展名做双重比对;上传目录关闭 PHP 解析,文件统一重命名。

改完只确认一件事:把 php 文件改成 .jpg 再传,接口返回类型不允许,上传目录里没有新增文件。

作者 9823189