realpath() 不解决安全问题,仅作路径规范化;返回 false 常因权限不足、路径不存在、phar 虚拟路径或 windows 符号链接限制;必须严格判断 false、校验类型并锁定基目录。

直接说结论:realpath() 本身不解决安全问题,反而可能掩盖路径校验缺失——它只做路径规范化,不自动拦截目录遍历或越权访问。
realpath() 返回 false 的常见原因不是“路径写错了”,而是权限或存在性问题
很多人看到 realpath() 返回 false 就去改路径字符串,其实更可能是以下任一情况:
- 路径中某一级目录缺少执行权限(
x),比如/var/www/app/../etc/passwd中/var/www/app/..虽然逻辑上可达,但脚本对/var或/var/www没有执行权限,realpath()直接返回false - 目标文件或目录根本不存在(注意:BSD 系统在纯路径不存在时可能不返回
false,行为不一致) - 传入的是 Phar 内部路径(如
phar://archive.phar/config.ini),realpath()不支持虚拟路径,必返回false - Windows 上符号链接只展开一级,若链式嵌套超过一层,结果可能不符合预期
用 realpath() 做路径校验前,必须先检查返回值是否为 false
realpath() 失败时不抛异常,也不报错,只是静默返回 false。如果直接拿这个结果去 fopen() 或 include,就会触发 Warning 或致命错误。
正确做法是:
- 始终用
=== false严格判断返回值,不能只用if (!$path)(空字符串、0、null 都会误判) - 确认路径存在后,再用
is_file()或is_dir()明确类型,避免把目录当文件打开 - 若用于用户输入的路径(如 URL 参数
?file=../../etc/passwd),必须在调用realpath()前做白名单过滤或根目录约束,否则攻击者可能绕过
realpath() 不等于“安全路径”,它不阻止目录遍历攻击
这是最容易踩的坑:realpath() 会把 ../../../etc/passwd 规范成 /etc/passwd —— 它忠实还原了路径语义,但没做任何访问控制。
典型错误写法:
$user_input = $_GET['file'];
$abs = realpath($user_input); // 这里 /etc/passwd 已被合法化
if ($abs) {
readfile($abs); // 直接读取,危险!
}
安全做法应是:
- 先限定基目录,比如
$base = '/var/www/app/uploads/' - 拼接后用
realpath(),再用strpos($abs, $base) === 0确认结果仍在基目录内 - 或用
dirname($abs) !== $base检查父级是否越界(注意 Windows 路径大小写和反斜杠)
真正关键的不是怎么调用 realpath(),而是它返回的路径你敢不敢信——只要没做基目录锁定和类型校验,它就只是个“更干净的字符串”,不是“可信路径”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











