
is_dir() 判断目录时依赖相对路径,若未显式指定完整路径,会基于当前脚本执行目录(而非 scandir() 的扫描路径)进行判断,导致在子目录中调用时误判所有非当前目录项为“非目录”。
`is_dir()` 判断目录时依赖相对路径,若未显式指定完整路径,会基于当前脚本执行目录(而非 `scandir()` 的扫描路径)进行判断,导致在子目录中调用时误判所有非当前目录项为“非目录”。
在 PHP 中,is_dir() 是一个路径敏感函数——它检查的是传入字符串所代表的文件系统路径是否为有效目录,但该路径默认被解释为相对于当前工作目录(current working directory),而非 scandir() 所扫描的目标目录。这正是问题的根本原因。
你调用 scandir($_SERVER["DOCUMENT_ROOT"]) 确实正确列出了根目录下的全部条目(如 directory1, img, imports 等),但后续使用 array_filter($dirs, 'is_dir') 时,is_dir() 接收到的只是裸文件名(例如 'directory1'),它会在当前脚本所在目录下查找 ./directory1,而非 $_SERVER["DOCUMENT_ROOT"]/directory1。
- ✅ 在
/index.php中执行:当前工作目录通常等于DOCUMENT_ROOT(如/var/www/html),所以'directory1'被解释为/var/www/html/directory1→ 判断成功; - ❌ 在
/directory1/index.php中执行:当前工作目录变为/var/www/html/directory1,此时'directory1'被解释为/var/www/html/directory1/directory1(不存在)→is_dir()返回false;同理,'img'、'imports'等均被错误地在子目录下查找,全部失败,仅.和..始终存在,故仅剩这两个被保留。
✅ 正确做法:显式拼接绝对路径
应将每个条目与 $_SERVER["DOCUMENT_ROOT"] 拼接后传给 is_dir():
$dirs = scandir($_SERVER["DOCUMENT_ROOT"]);
$dirs = array_filter($dirs, function($dir) {
// 构造完整绝对路径,确保 is_dir() 检查的是真实目标位置
$fullPath = $_SERVER["DOCUMENT_ROOT"] . '/' . $dir;
return is_dir($fullPath) && $dir !== '.' && $dir !== '..';
});
// 移除预定义排除项(注意:此时已过滤掉 . 和 ..,可直接排除 img/imports)
$dirs = array_diff($dirs, ['img', 'imports']);? 关键提示:
array_diff()应在is_dir()过滤之后执行,否则可能因索引错位导致意外结果(如稀疏数组)。更健壮的做法是合并逻辑,在闭包中一并处理排除规则。立即学习“PHP免费学习笔记(深入)”;
✅ 推荐优化版代码(含安全与可读性增强)
<?php
$root = $_SERVER["DOCUMENT_ROOT"];
$excluded = ['img', 'imports', '.', '..'];
$dirs = array_filter(
scandir($root),
function($dir) use ($root, $excluded) {
if (in_array($dir, $excluded)) return false;
return is_dir($root . '/' . $dir);
}
);
foreach ($dirs as $dir) {
$urlSafe = rawurlencode($dir); // 防止 URL 中含特殊字符
$display = ucwords(str_replace('-', ' ', $dir));
echo "<a href=\"/$urlSafe\"><p>$display</p></a>";
}
?>⚠️ 注意事项
- 不要依赖
getcwd()或chdir()来“修复”工作目录——它不可靠且易引发副作用; - 始终对用户可控路径(如
$_SERVER["DOCUMENT_ROOT"])保持信任前提,但在生产环境建议校验其合法性(如realpath()+ 白名单); - 若需跨平台兼容,使用
DIRECTORY_SEPARATOR替代/(尽管$_SERVER["DOCUMENT_ROOT"]在绝大多数 Web 服务器上均为 Unix 风格路径); -
scandir()返回结果包含.和..,务必显式排除,避免生成无效链接(如/<a href="/."></a>)。
通过显式构造绝对路径,即可彻底解决 is_dir() 因上下文目录变化导致的行为不一致问题,确保导航栏动态生成逻辑在任意深度的子页面中稳定运行。



















