thinkphp多图上传必须使用name="xxx[]",否则后端仅接收最后一张;tp6推荐putfile()替代手动move(),ajax需设置processdata:false和contenttype:false,且须严格校验扩展名、mime及文件头,并禁用上传目录的脚本执行权限。

ThinkPHP 多图上传必须用 name="xxx[]",否则后端收不到数组
浏览器对 <input type="file" multiple> 的处理很直接:选多张,就发多个同名字段——但前提是 name 带方括号,否则 ThinkPHP 的 $this->upload() 或 request()->file() 只会取到最后一张。
常见错误现象是“明明选了 5 张,后台只存了 1 张”。
-
<input name="images[]" type="file" multiple>✅ 后端收到$_FILES['images']是标准数组结构(['name']、['tmp_name']等均为数组) -
<input name="images" type="file" multiple>❌ 浏览器仍发多份,但 PHP 覆盖式解析,只留最后一个 - TP3.2 中用
$upload->upload();TP6 中用request()->file('images'),两者都依赖这个数组结构
TP6 用 Filesystem::disk('public')->putFile() 更安全,别手写 move()
手动调 $file->move() 容易漏校验、硬编码路径、生成重复文件名,还绕过框架的磁盘抽象。TP6 的 putFile() 自动做三件事:重命名防冲突、按日期分目录、返回带哈希的唯一 save_name。
- 它默认禁用危险扩展名(如
.php),即使前端绕过accept,后端也会拦截 MIME 不匹配的文件 -
putFile('uploads', $file)的uploads是子目录,不是绝对路径,不依赖./Public/这类硬编码 - 如果用
$file->validate(['size' => 5 * 1024 * 1024, 'ext' => 'jpg,png,gif'])配合putFile(),验证和存储就是原子操作
AJAX 提交必须设 processData: false 和 contentType: false
FormData 发送二进制文件时,浏览器会自动生成正确的 Content-Type: multipart/form-data; boundary=...。如果没关掉 jQuery 默认行为,它会强行转成 application/x-www-form-urlencoded,导致后端收不到文件——连 $_FILES 都为空。
- 错误配置:
processData: true(默认值)→ 把 FormData 序列化成字符串,文件变空 - 错误配置:
contentType: 'multipart/form-data'→ 缺少boundary,服务端无法解析分段 - 正确写法:
processData: false, contentType: false,把构造和编码全交给浏览器
TP3.2 的 Upload 类要关掉 autoCheckExtension 才能真正防木马?不,别关
有人为了“兼容某些奇怪后缀”把 $upload->autoCheckExtension = false,这是高危操作。ThinkPHP 的扩展名校验只是第一道门,真正防木马靠的是 MIME 检查 + 临时文件头检测 + 禁止执行权限。关掉它等于裸奔。
- TP3.2 的
Upload类在checkExt()之后还会调checkType()读文件头,比如 PNG 必须以\x89PNG开头 - 服务器上
./upload/目录必须禁止 CGI/PHP 解析(Nginx 加location ~ \.(php|html|js)$ { deny all; }) - 更稳妥的做法是:上传目录放在 Web 根目录外,或用符号链接指向不可执行路径
文件名哈希、MIME 校验、Web 服务器执行限制——这三层缺一不可。光靠框架配置拦不住所有攻击,尤其当上传目录本身可被直接访问时。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











