php上传文件校验必须结合pathinfo()或splfileinfo安全提取小写后缀并过滤非法字符,再通过文件头magic number二次验证,否则易遭木马上传。

PHP处理上传文件时,仅靠$_FILES['file']['name']中提取的后缀名极易被伪造,必须结合服务端路径解析与文件头校验才能确认真实类型,否则可能触发木马上传、WebShell执行等高危风险。
用pathinfo()安全提取扩展名
第一步:调用pathinfo()并明确指定PATHINFO_EXTENSION选项,避免返回空数组或错误字段。
第二步:对结果强制转为小写,防止因大小写绕过白名单检查——【不转小写会导致.php5和.PHP同时通过校验】。
第三步:检查返回值是否为空字符串或包含非法字符(如/、\、:、*),这些说明原始文件名被恶意构造过。
用SplFileInfo类获取后缀(面向对象方式)
方法一:实例化SplFileInfo对象后直接调用getExtension()方法,该方法内部已做路径规范化,能正确处理多点文件名(如archive.tar.gz)和隐藏文件(如.gitignore)。
方法二:若需兼容PHP 5.3.6以下版本,不可用此方法,应退回pathinfo()方案。
手动截取后缀的三种写法及风险对比
方法1:用strrpos()+substr()组合——【遇到无点文件名(如README)会报Warning并返回整个字符串】,必须前置判断strrpos返回值是否为false。
方法2:用explode('.')+end()——当文件名以点结尾(如photo.)时,end()返回空,但不会报错;适合快速原型,不推荐用于生产环境。
方法3:用strrchr()获取最后一个点及之后全部内容,再用substr()剥掉开头的点——这一步操作起来很简单,直接把字符串切开就行,但要注意它返回的是".jpg"而非"jpg",必须手动去掉第一个字符。
必须配合文件头(Magic Number)二次验证
第一步:打开上传文件的临时路径$_FILES['file']['tmp_name'],以二进制只读模式('rb')打开。
第二步:读取前2–4字节,用unpack('H*')转为十六进制字符串,比对JPEG(ffd8ff)、PNG(89504e47)、GIF(47494638)等标准签名。
第三步:若文件头与后缀名不一致(如.jpg文件头是PK…),立即拒绝上传——【仅靠后缀名过滤等于给攻击者敞开大门】。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











