symlink 本身无权限可改,chmod() 作用于符号链接无效,仅修改目标文件权限;其显示恒为 0777 是 Linux 内核行为,实际访问由目标文件权限和进程 UID/GID 决定。
symlink 本身没有权限可改
PHP 的 chmod() 对符号链接(symlink)调用无效,它只会修改目标文件的权限,而不是链接文件自身——因为 symlink 在 Linux/Unix 系统中不存储传统意义上的权限位(其权限恒为 0777,且被内核忽略)。你执行 chmod("mylink", 0644) 不会报错,但实际什么也没变,ls -l 仍显示 lrwxrwxrwx。
想控制访问,得改目标文件或目录权限
软链接的“可访问性”完全取决于目标路径的权限和所有者。用户能否通过 symlink 读/写/进入,由目标文件的 stat 权限和进程有效 UID/GID 决定。
- 若目标是文件:
chmod()必须作用于目标路径(如chmod("/real/path/file.txt", 0600)),而非 symlink 路径 - 若目标是目录:确保该目录有执行(
x)位,否则opendir()或chdir()会失败 - 注意 PHP 进程用户(如
www-data)必须对目标路径有相应权限,symlink 所有者无关紧要
用 readlink() + chmod() 安全地改目标权限
如果你只有 symlink 路径,又需要动态修改其指向的目标权限,必须先解析出真实路径:
$symlink = '/var/www/html/config.php';
$target = readlink($symlink);
if ($target === false) {
throw new RuntimeException("Not a valid symlink: $symlink");
}
// 注意:readlink 返回相对路径时需手动拼接
if (!is_absolute_path($target)) {
$target = dirname($symlink) . '/' . $target;
}
chmod($target, 0600); // 修改的是真实文件
⚠️ 风险提示:readlink() 不做路径遍历防护,若 symlink 指向恶意构造的路径(如 ../../etc/passwd),直接 chmod() 可能越权。务必校验 $target 是否在预期根目录内。