thinkphp视频上传需重写关键环节:命名防冲突、分片抗卡顿、路径防遍历、存储避单点;原始文件名含路径或重名会导致安全与覆盖问题,必须弃用getoriginalname()、自动生成唯一安全文件名,大文件须分片上传,存储应对接oss并校验md5。

ThinkPHP 视频上传不是“传完就行”的事——默认写法在并发、大文件、安全性上全会掉链子。必须拆开重写关键环节:命名防冲突、分片抗卡顿、路径防遍历、存储避单点。
为什么 move() 直接传原始名会出问题
原始文件名带路径(如 ../../etc/passwd.mp4)会被 move() 当作相对路径解析,直接写到系统敏感目录;更隐蔽的是,多个用户同时上传 cover.mp4,后上传的会覆盖前一个——数据库里还存着两条记录,但实际只剩一个文件。
-
$file->getOriginalName()必须丢弃,只取后缀:$file->getExtension() - TP6.x 的
validate()->move($path, $savename)不自动重命名,$savename得自己生成 - TP5.1 没有
move($path, $savename),得先用move_uploaded_file($tmp, $dest)手动搬 - 别用
date('YmdHis').$file->getOriginalName()—— 秒级时间戳在压测时 10 个请求全撞在同一秒,名字全一样
怎么生成真正唯一又安全的文件名
唯一性 ≠ 随机性,要兼顾可读性、长度限制和熵值。Windows 对总长超 255 字符的文件名直接报错,而 uniqid('', true) 返回的字符串含小数点,不能直接当文件名用。
- 推荐组合:
date('YmdHis') . '_' . substr(md5(microtime(true)), 0, 8) . '_' . substr(uniqid('', true), -6) . '_' . rand(1000, 9999) . '.' . $ext -
microtime(true)是浮点数,必须转字符串前做md5或sprintf('%.0f', ...)截断,否则生成1715502541.123456.mp4这种非法名 -
substr(uniqid('', true), -6)比完整uniqid()更稳——后者在某些 PHP 版本下可能重复,末 6 位加随机数已足够区分并发 - 后缀必须来自
$file->getExtension(),不能从原始名explode('.', $name)截,否则用户传shell.php.jpg就绕过扩展名校验
大视频(>100MB)必须分片,别碰 $_FILES 同步读
TP 默认走 PHP 原生 $_FILES,整个文件先落地临时目录再搬,1GB 视频进来,PHP 进程就卡死十几秒,Nginx 极易返回 502。分片不是可选项,是保命线。
- 前端用
WebUploader或Uppy切 5MB/片,每片带chunkIndex、totalChunks、file_id(建议用文件名+大小+修改时间的 MD5) - 后端路由分开:
/api/upload/chunk接收分片,/api/upload/merge合并,别和普通/upload混用 - 分片存储路径按
file_id哈希散列,例如runtime/chunks/ab/{$file_id}/chunk_001,避免单目录塞几万文件拖慢scandir - 合并时用
file_put_contents($final, file_get_contents($chunk), FILE_APPEND | LOCK_EX),别用fopen+fwrite手动循环——容易丢字节
别让视频文件堆在本地磁盘,OSS 直传才是正解
$file->move() 只支持本地路径,硬传 https://bucket.oss-cn-hangzhou.aliyuncs.com/xxx 会报 Invalid path。想上云,必须换存储驱动。
- TP6.0+ 用
think-filesystem-oss扩展,配置好endpoint、access_key_id、access_key_secret,再调Filesystem::disk('oss')->put($key, $stream) - TP5.1 得桥接
league/flysystem,手动 new Adapter + Filesystem,move()不适用 - 最优方案是前端直传 OSS:后端只生成 Policy + Signature,前端用
aliyun-oss-sdk直传,PHP 进程零 IO 压力 - OSS 存储路径别暴露真实 bucket,用 Nginx
proxy_pass或X-Accel-Redirect中转,防止用户猜到并遍历所有视频
最易被忽略的一点:分片合并后,必须校验最终文件的 MD5 是否等于前端传来的总 MD5,否则网络丢包会导致视频损坏却无感知。这个校验不在 ThinkPHP 范围内,得自己加。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











