应统一使用 $request->header('referer') 安全读取,因 ThinkPHP 仅识别小写键名;Referer 可被伪造,须结合白名单域名解析与服务端权限校验,静态资源防盗链优先由 Web 服务器处理。

ThinkPHP 怎么安全读取 Referer Header
直接用 $request->header('Referer') 可能拿不到,或者拿到空值——因为 HTTP Header 名是大小写不敏感的,但 ThinkPHP 默认只认小写键名,而实际客户端发来的可能是 Referer(带大写 R),也可能是 referer,甚至某些代理会转成 HTTP_REFERER 环境变量。
正确做法是统一用小写 key 查询,框架内部做了标准化映射:
-
$request->header('referer')是唯一可靠写法,Referer或REFERER都会命中 - 不要写
$request->header('Referer'),大小写敏感时可能返回 null - 如果在中间件或控制器外获取,可用
think\facade\Request::header('referer') - 注意:CLI 环境下
referer恒为空,别在命令行里测这个
Referer 为空的常见原因和排查点
不是代码写错了,而是请求本身就没带 —— 这比读取失败更常导致防盗链失效。
- 用户从书签、地址栏直输、HTTPS 页面跳转到 HTTP 页面(浏览器主动清空 Referer)
- Chrome 等现代浏览器对
Referrer-Policy: no-referrer响应头的遵守越来越严格 - 前端用了
<a href="..." referrerpolicy="no-referrer">或fetch()/XMLHttpRequest显式禁用 - 某些 CDN 或反向代理(如 Nginx)默认不透传
Referer,需检查配置中是否有proxy_set_header Referer $http_referer;
用 Referer 做防盗链时必须加的防护逻辑
只判断域名是否匹配?危险。Referer 完全可被伪造,只能作为辅助手段,不能替代权限校验。
立即学习“PHP免费学习笔记(深入)”;
- 先检查
$request->header('referer')是否非空,空值应放行或走备用策略(比如登录态校验) - 用
parse_url()解析后比对host,别用字符串strpos()匹配,避免example.com.hacker.com绕过 - 允许白名单多个域名,但别硬编码在控制器里,建议从配置文件读:
config('app.referer_whitelist') - 图片/CSS/JS 等静态资源防盗链,优先用 Web 服务器(Nginx/Apache)拦截,比 PHP 层快一个数量级
TP6 和 TP8 在 Referer 处理上的细微差异
TP8 把 header 读取逻辑进一步封装,但接口没变;真正要注意的是底层 PSR-7 实现变化带来的副作用。
- TP6 使用原生
$_SERVER+ 手动 normalize,对HTTP_REFERER环境变量兼容更好 - TP8 默认用 Swoole 或 Workerman 时,若未启用
enable_coroutine,$request->header('referer')可能因协程上下文丢失而返回空 - TP8 中
Request::instance()->header('referer')已废弃,必须用依赖注入或门面 - 所有版本都不支持从
Content-Type: multipart/form-data的 body 里解析 Referer —— 它只存在于 header











