php fopen() 创建文件默认权限由系统 umask 决定,不显式指定权限时无固定值;需配合 chmod() 设置如 0644,且 mkdir() 等函数权限参数必须用八进制(如 0755)才正确。

PHP fopen() 创建文件默认权限是多少?
不是你想象的 644,也不是系统 umask 的直接结果——PHP 在调用 fopen()(带 "w" 或 "a" 模式)创建新文件时,**不显式指定权限,就完全依赖系统 umask**。这意味着:即使你期望是 644,实际可能是 600、622,甚至 666(极少见)。fopen() 本身没有权限参数,它只管读写,不管 chmod。
实操建议:
- 永远不要假设
fopen("log.txt", "w")写出的文件能被 Web 服务器其他进程读取——很可能因 umask=0022 导致权限为 600,Nginx/Apache 就读不了 - 如果需要确定权限,必须在
fopen()后立刻调用chmod(),例如:fopen("config.json", "w"); chmod("config.json", 0644); - 注意:Windows 忽略文件权限,该问题仅影响 Linux/macOS 部署环境
为什么 mkdir() 要传 0755 却要加 0 前缀?
PHP 的权限参数是八进制整数,不是字符串或十进制数。mkdir("cache", 755) 实际等价于十进制 755 → 权限位是 1011101011(完全不对),而 mkdir("cache", 0755) 中的 0 前缀才让 PHP 解析为八进制 755 → 对应二进制 111101101 → 即 rwxr-xr-x。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
-
mkdir("tmp", 755)创建目录后权限显示为 693(十进制 755 的八进制表示),Web 服务无法进入 - 错误信息类似:
Warning: mkdir(): Permission denied(其实是权限位错乱导致内核拒绝) - 正确写法只有两种:
0755(八进制)或0b111101101(二进制),但前者是事实标准
755 和 644 权限在 Web 场景中到底差在哪?
区别不在“数字大小”,而在“执行位是否开启”——这对目录和文件有完全不同的意义。
使用场景与风险:
-
0755:适用于**目录**(如uploads/、vendor/)。其中的x(执行位)对目录来说 = “可进入”,没有它,Web 服务器连opendir()都失败 -
0644:适用于**普通文件**(如config.php、data.json)。文件不需要执行位;设成 744 反而可能被意外执行(尤其配合 CGI 或旧版 Apache) - 危险组合:
0777目录 —— 不仅开放写入,还允许任何用户 cd 进去并列出内容,常被扫描器利用 - 安全底线:Web 可写目录(如
cache/)用0755+ 所属组为 web 用户,比0777更可控
用 umask() 统一控制新建文件权限靠谱吗?
不推荐。PHP 的 umask() 是进程级全局设置,会影响所有后续系统调用(包括 fopen()、mkdir()、甚至第三方扩展的文件操作),且线程不安全,在 FPM 多 worker 场景下极易互相覆盖。
实操建议:
- 避免在脚本开头写
umask(0002)——看似统一,实则不可控 - 真正需要统一策略时,封装自己的函数,例如:
safe_file_put_contents($path, $data) { file_put_contents($path, $data); chmod($path, 0644); } - 注意:
file_put_contents()也没有权限参数,同样受 umask 影响,必须补chmod()
最易被忽略的一点:很多框架的缓存/日志组件内部用 fopen() 或 file_put_contents() 创建文件,却没做 chmod(),上线后发现日志写入失败或缓存不可读——这时得翻源码确认,而不是只查自己写的部分。











