PHP Conference Japan 2024

umask

(PHP 4, PHP 5, PHP 7, PHP 8)

umask更改当前 umask

描述

umask(?int $mask = null): int

umask() 将 PHP 的 umask 设置为 mask & 0777 并返回旧的 umask。当 PHP 用作服务器模块时,在每个请求完成后都会恢复 umask。

参数

mask

新的 umask。

返回值

如果 masknullumask() 仅返回当前 umask,否则返回旧的 umask。

变更日志

版本 描述
8.0.0 mask 现在可以为空。

示例

示例 #1 umask() 示例

<?php
$old
= umask(0);
chmod("/path/some_dir/some_file.txt", 0755);
umask($old);

// 检查
if ($old != umask()) {
die(
'更改回 umask 时出错');
}
?>

注释

注意:

避免在多线程 Web 服务器中使用此函数。最好在创建文件后使用 chmod() 更改文件权限。使用 umask() 会导致并发运行的脚本和 Web 服务器本身出现意外行为,因为它们都使用相同的 umask。

添加注释

用户贡献的注释 14 个注释

librodot at ciberpiula dot net
15 年前
我认为理解 umask 的最佳方法是说 umask 用于撤销权限,而不是设置权限。

umask 设置在创建文件或目录时必须从系统默认值中删除哪些权限。

例如,掩码 0022 表示您不希望组和其他人修改文件。

默认 0666 rw-.rw-.rw-
umask 0022 ---.-w-.-w-
最终 0644 rw-.r--.r--

这意味着从现在起,任何文件都将具有 0644 权限。

重要的是要理解 umask 撤销、删除系统默认值中的权限,因此它无法授予系统默认值没有的权限。在上面的示例中,使用 666 系统默认值,无法使用 umask 创建具有执行权限的文件。如果要授予更多权限,请使用 chmod。

请注意,系统默认权限与 PHP 无关(它们取决于服务器配置)。PHP 具有应用于系统默认基本权限之后的默认 umask。并且文件和目录具有不同的系统默认基本权限。

通常,文件的系统默认权限为 666,目录的系统默认权限为 0777。通常,默认 PHP umask 为 0022
sean at awesomeplay dot com
17 年前
"最好在创建文件后使用 chmod() 更改文件权限。"

PHP 团队中通常缺乏安全知识再次显现。您*始终*希望以正确的权限创建文件。让我说明原因

(a) 您使用读取权限创建新文件
(b) 攻击性脚本打开文件
(c) 您使用 chmod 更改文件以删除读取权限
(d) 您将敏感数据写入文件

现在,您可能认为攻击性脚本在您使用 chmod 更改文件之前打开文件的可能性很低。你是对的。但低概率永远不够低——您希望零概率。

在创建需要提高权限的文件时,您始终需要以正确的权限创建文件,并且还需要设置 O_EXCL。如果您不进行排他创建,则最终会出现以下情况

(a) 攻击者创建文件,使其对所有人可写
(b) 您以受限权限打开文件,但由于文件已存在,因此仅打开文件并保留权限
(c) 您将敏感数据写入不安全的文

检测后一种情况是可能的,但这需要一些工作。您必须检查文件的所有者和组是否与脚本匹配(即 posix_geteuid(),而不是 myuid()),并检查权限——如果任何权限不正确,则文件是不安全的——您可以尝试 unlink() 它并重试,当然还要记录警告。

在创建文件后使用 chmod() 更改文件权限是合理或安全的唯一时间是当您想要授予额外权限而不是删除权限时。例如,将 umask 设置为 0077,然后对您随后创建的文件使用 chmod 更改权限是完全安全的。

在 PHP 中进行真正安全的编程本身就很困难,文档中的这种建议只会使事情变得更糟。记住,孩子们,任何适用于 C 或 UNIX 世界的安全内容都 100% 适用于 PHP。作为 PHP 程序员,您能为自己做的最好的事情就是学习和理解安全的 C 和 UNIX 编程技巧。
匿名
18 年前
使用 (cmask - umask) 计算新掩码是错误的方法

0022 - 0700 = 0656 错误
0700 & ~0022 = 0700 正确

正确的 php 代码
<?php
$rmask
= ($cmask & ~$umask);
?>
neon at neonjs dot com
13 年前
如果您不理解为什么需要“避免在多线程 Web 服务器中使用此函数”

这是因为此函数在进程级别更改 umask,而不是仅针对 PHP 或当前脚本。如果在 PHP 脚本运行的进程中有多个同时运行的线程,则更改将同时应用于所有这些线程,因此对于多线程使用而言,这不是安全的。

我理解,如果您正在使用 PHP 模块和 Apache 的 prefork MPM(不是多线程的),那么您至少不会遇到诸如这种竞争条件问题。但是,仍然值得注意的是,umask 设置(如果未重置)将持续存在于该进程的整个生命周期中,即使该进程被重复用于服务未来的 PHP 或非 PHP 请求也是如此。
Richard Snell
9 年前
需要注意的是,mask 参数将接受八进制以外的值,这会导致意外结果。

设置 umask(22) 可以预期将默认权限为 0666 的文件减少到 0644,方法是应用掩码 0022,但由于参数以十进制提供,因此它将被静默转换为八进制,实际上将应用掩码 0026,从而导致最终文件权限为 0642。

类似地,umask 返回的值为十进制格式。如果您使用 umask(0022) 正确应用掩码,然后使用 umask() 查询新设置,它将返回 18 的值(0022 八进制为 18 十进制)。

简而言之,在应用权限时,最好用零填充提供的值以创建八进制值(22 变成 0022),如果您想分析返回值,请记住将其转换为八进制以方便解释。
malcolm.murphy
8 年前
"mask & 0777" 的澄清

手册中的注释“umask() sets PHP's umask to mask & 0777 [...]”仅仅暗示该方法仅影响文件权限,而不影响setuid、setgid或粘滞位等特殊模式。奇怪的是,PHP本身并没有执行按位运算,而是假设它将由同名的系统调用完成。在某些系统(例如OS X)上,umask实际上将umask设置为mask & 07777,但多余的位不适用于随后的PHP调用(如mkdir())。Linux的umask确实使用了0777。它的手册条目有一个类似于PHP的注释,但有一个括号内的语句有助于解释它的含义

“umask() sets the calling process's file mode creation mask (umask) to mask & 0777 (i.e., only the file permission bits of mask are used) [...]”

尽管$mask & ~0777与$mask & 0777外观相似,但使用运算$mask & ~0777反转掩码来确定权限的事实是无关紧要的。后者运算会将$mask截断为前九个低位(即最右边的三个八进制数字[并注意,八进制表示法的开头零本身不是数字])。它不会改变其余的位。

例如,以下所有调用具有相同的效果:umask(0022)、umask(07022)、umask(261650)(0777022的十进制值)和umask(0b111000010010)(07022的二进制表示法)。
jphansen at uga dot edu
16年前
在大多数UNIX环境中,文件中推荐的默认umask(在/home/user/.profile或/etc/profile中定义)是022(chmod: 644)。在可信系统上,它是002。应用更宽松的设置时请谨慎。
webmaster at iacomputing dot co dot uk
14年前
您可以使用umask解决出现在多个PHP版本中的PHP会话错误。

<?php
umask
(0022);
session_start();
?>

这将防止创建权限不足的会话。
bishop
14年前
"最好在创建文件后使用 chmod() 更改文件权限。"

如果您认真对待该建议,请考虑设置您的umask,以便文件对您的用户私有创建,然后使用chmod打开它们。

<?php
// 文件将创建为 -rw-------
umask(0077);

// 创建文件,例如 fopen()

// 授予访问权限:-rw-r--r--
chmod('/path/to/file', 0644);
?>

只要合理,默认情况下关闭并根据需要打开(如上所示),而不是默认情况下打开并根据需要关闭。以上仍然存在竞争条件,但竞争条件将拒绝适当的访问权限,而不是授予不适当的访问权限。
ahmad dot mayahi at gmail dot com
7年前
简单来说,umask表示新文件/目录的默认权限

<?php
umask
(022);
?>

这分别设置了用户、组和其他人对文件的默认权限

• 0 - 读、写和执行
• 1 - 读和写
• 2 - 读和执行
• 3 - 只读
• 4 - 写和执行
• 5 - 只写
• 6 - 只执行
• 7 - 无权限
andi<at>splitbrain.org
19年前
要试用umask和权限,请使用以下小片段

<?
$umask = 0012;
$perm = 0777;
printf("umask: %04o perm: %04o result: %04o\n",
$umask,$perm,$perm & (0777 - $umask));
?>
maulwuff at gmx dot de
17 年前
umask从标准掩码777中减去给定的值。
图形视图更能说明这一点

标准
rwxrwxrwx = 777
使用umask 002获得
rwxrwxr-x = 775
或使用umask 077获得
rwx------ = 700

等等。
sam at totallydigital dot co dot nz
22年前
第一个注释可能没有完全清楚umask和权限之间的关系。

传递给命令的权限首先与当前umask的_反码_进行按位与运算,然后应用于文件。

例如,umask = 0011,权限 = 0775
0011的反码 = 0766

0775 AND 0766
= 111.111.101 AND 111.110.110
= 111.110.100
= 0764
ShaD@TW
18 年前
请注意,目录和文件有时会产生不同的结果。

<?php
umask
(0670); //- 设置umask
$handle = fopen('file', 'w'); //- 0006
mkdir("/path/dir"); //- 0107
?>

计算结果
<?php
$umask
= 0670;
umask($umask);
//- 如果你正在创建一个新目录,$permission = 0777;
//- 如果你正在创建一个新文件,$permission = 0666.
printf( "result: %04o", $permission & ( 0777 - $umask) );
?>

顺便说一句,如手册所说,umask() 的形式是“int umask ([int mask])”,因此,如果你想打印/回显任何umask,不要忘记将其从DEC(因为它返回一个“int”)转换为OCT。

<?php
$umask
= umask(); //- 返回当前umask,它是一个“int”
$umask = decoct($umask); //- 现在,$umask 是一个“string”
echo $umask;
?>

不要忘记参数也是一个“int”。

<?php
umask
(777); //- 错误!即使你在某些操作系统中可能使用“umask 777”。
umask(0777); //- 正确
?>

如果有任何错误,请更正我的陈述。
To Top