必须提取真实扩展名并验证合法性,用pathinfo()获取扩展名后白名单校验或mime双重检测,再生成uniqid前缀的安全文件名,过滤非法字符,最后移至无执行权限的绝对路径。

当用户上传文件名含英文点号加中文后缀(如my.photo.jpeg)时,PHP默认的$_FILES['file']['name']会保留原始名称,但直接使用可能导致路径解析错误、存储混乱或安全漏洞,必须先提取真实扩展名并验证合法性。
提取真实扩展名
用pathinfo()获取扩展名,而非简单strrchr()或end(explode()),避免被恶意构造的多点文件名欺骗(如my.photo.jpeg.php)。
执行:$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
这一步必须做,因为$_FILES['file']['name']可能包含多个点,仅取最后一个点之后的内容不等于真实扩展名;【pathinfo()是唯一能正确识别标准文件名结构的内置函数】。
验证扩展名合法性
方法一:白名单硬校验
定义允许列表:$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
检查:if (!in_array($ext, $allowed)) { die('不支持的文件类型'); }
方法二:MIME类型双重校验(更安全)
读取文件头:$finfo = finfo_open(FILEINFO_MIME_TYPE); → $mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
匹配常见图片MIME:if (0 !== strpos($mime, 'image/')) { die('非图片文件'); }
【仅靠扩展名校验可被绕过,必须配合MIME或文件头检测】
生成安全文件名
第一步:生成唯一前缀
用uniqid('', true)生成带微秒精度的字符串,避免并发重名。
第二步:拼接新名
组合:$safe_name = uniqid('', true) . '.' . $ext;
第三步:过滤残留非法字符
即使原始名含斜杠、NULL、控制字符,也要清理:$safe_name = preg_replace('/[^a-zA-Z0-9._-]/', '', $safe_name);
这一步不能省略——上传名可能被前端篡改,【未过滤的文件名可能导致目录穿越或写入危险路径】。
保存文件
指定绝对路径存储目录,例如/var/www/uploads/,确保该目录无执行权限。
执行移动:move_uploaded_file($_FILES['file']['tmp_name'], '/var/www/uploads/' . $safe_name);
操作完成。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











