
PHP 中 $_SERVER['PHP_SELF'] 是什么,它到底干啥用的
它不是“关键字”,是 $_SERVER 超全局数组里的一个预定义键,值为当前执行脚本的文件路径(相对于 Web 根目录),比如访问 /user/profile.php,$_SERVER['PHP_SELF'] 就是 /user/profile.php。常被误当成安全的表单提交地址——但其实它根本不校验来源、不防篡改、也不处理 URL 参数。
为什么直接写 <form action="<?=%24_SERVER['PHP_SELF']?>"></form> 很危险
因为攻击者能通过 URL 注入任意内容,比如访问 /login.php/%22%3E%3Cscript%3Ealert(1)%3C/script%3E,$_SERVER['PHP_SELF'] 会原样返回带闭合引号和 script 标签的路径,导致 XSS。
- 浏览器看到的是:
<form action="/login.php/"> <script>alert(1)</script>"></form> - 表单标签被提前闭合,后面 script 执行
- 即使你对用户输入做了过滤,
$_SERVER['PHP_SELF']的值根本没经过你的过滤逻辑 - 它还可能包含查询参数(如
?id=123),导致重复提交时 URL 越来越长
更安全的替代方案:明确指定目标脚本或用空字符串
多数场景下,你根本不需要动态拼路径。表单提交给自己,就该知道自己的文件名;如果不确定,宁可硬编码或用更可控的方式生成路径。
- 最稳妥:
<form action="profile.php"></form>(明确文件名) - 同目录提交可留空:
<form action=""></form>(浏览器自动提交到当前 URL,不含查询参数) - 需要保留 GET 参数?别依赖
$_SERVER['PHP_SELF'],自己用http_build_query()拼接:$safe_action = $_SERVER['SCRIPT_NAME'] . '?' . http_build_query($_GET);,注意SCRIPT_NAME不含查询串,比PHP_SELF更干净 - 绝对不要用
htmlspecialchars($_SERVER['PHP_SELF'])来“修复”——它只能防部分 XSS,但无法阻止路径遍历或参数污染,属于掩耳盗铃
$_SERVER['PHP_SELF'] 唯一还算合理的使用场景
仅限服务端内部日志、调试或路由分发(且必须配合白名单校验)。比如一个简易前端控制器判断请求是否命中某个模块:
立即学习“PHP免费学习笔记(深入)”;
$path = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH);
if (in_array($path, ['/admin.php', '/api.php'])) {
// 允许的入口点
}
这里关键在 in_array() 白名单校验——没有这层,PHP_SELF 的任何用途都等同于把解析权交给攻击者。
真正容易被忽略的是:它返回的路径是未经解码的原始 URL 路径,%2F 不会被自动转成 /,parse_url() 或 basename() 处理前,得先 urldecode(),否则白名单校验会失效。











