fileperms返回的是十进制整数,但高位包含文件类型标志(如100表示普通文件),需用fileperms($path) & 0777提取纯权限值(如420对应0644),再进行位运算或chmod操作。

fileperms 返回的是十进制还是八进制?
fileperms 返回的是一个十进制整数,但它**代表的是底层 stat 结构中的 mode 字段**,包含文件类型(如 S_IFDIR、S_IFREG)和权限位(如 S_IRUSR)。它不是你 ls -l 看到的三位八进制数(如 0755),也不能直接用 decoct() 转成“习惯上的权限字符串”就完事——因为高位还混着文件类型标志。
常见错误:直接 echo decoct(fileperms('test.txt')) → 得到类似 100644,开头的 100 是文件类型(普通文件),后面 644 才是权限。不剥离类型位,后续按位操作会出错。
- 正确做法:用位与
&清除文件类型位,只保留权限部分:fileperms($path) & 0777 - 这样得到的就是纯权限值(如 420 对应 0644),可安全用于
chmod或比较 - 若要格式化显示为三位八进制字符串:
sprintf('%03o', fileperms($path) & 0777)
如何安全地“取当前权限 + 修改某几位”?
直接读取再加减权限(比如 + 0004)极易出错——权限位是位掩码,不是算术值。必须用位运算:保留原权限,再用 | 设置位、& ~ 清除位。
例如:给文件加上“组可执行”,但不改动其他任何权限:
立即学习“PHP免费学习笔记(深入)”;
```php $mode = fileperms($path) & 0777; // 取纯权限 $newMode = $mode | 0010; // 设置组执行位(S_IXGRP) chmod($path, $newMode); ```
- 要移除“其他可写”:用
$newMode = $mode & ~0002 - 要同时设“所有者可读可写”且“清除其他执行”:
$newMode = ($mode | 0600) & ~0001 - 永远不要写
$mode + 0010—— 若原权限已有该位,加法会溢出破坏其他位
chmod 第二个参数必须是八进制整数?
不是。PHP 的 chmod 接收的是整型权限值,**写成 0755、493、0b111101101 都合法**,只要数值对就行。但实践中强烈建议用带前导 0 的八进制字面量(如 0755),原因有二:
- 语义清晰:一眼看出是权限,而非随机整数
- 避免十进制误写:比如本意是 0644,手误写成 644 → 实际传入的是十进制 644,等价于八进制
1204,远超常规权限范围,可能导致意外行为 - 注意:
0755在 PHP 中是整数字面量,不是字符串;写成'0755'会触发类型转换警告,且结果不可控
为什么有时 chmod 失败但没报错?
chmod 返回布尔值,但失败常因权限不足(非 root 用户无法修改不属于自己的文件)、文件系统挂载为 noexec/nosuid、或路径是符号链接而未启用 follow 选项。尤其注意:
-
fileperms和chmod对符号链接默认操作的是**链接本身**,不是目标文件。要改目标权限,需先realpath()或确保路径已解析 - 某些共享主机禁用
chmod,此时函数返回false,需显式检查:if (!chmod($path, $newMode)) { /* handle error */ } - Windows 下
chmod仅模拟部分行为(主要影响只读属性),fileperms返回值也受限,跨平台代码需规避强依赖
实际操作中最容易被跳过的,是 fileperms 返回值高位含文件类型这个事实——漏掉 & 0777 这一步,后面所有位运算都可能偏离预期。











