如何在 PHP 中设置 SGID?

How do I set SGID in PHP?

我无法设置 PHP 的 SGID 位。

我有这个目录:

  4 drwxrwsr-x 12 www-data mygroup  4096 Oct  7 16:05 mydir

注意 SGID 位。所以,如果我简单地从 shell 和 mkdir test 创建一个目录到它,我得到

  4 drwxr-sr-x  2 myuser   mygroup   4096 Oct  7 16:22 test

请注意,SGID 位是继承的。但我希望它组可写(我的 umask 22 不允许)所以我可以简单地 chmod 02775 test 我非常高兴:

  4 drwxrwsr-x  2 myuser   mygroup   4096 Oct  7 16:22 test

现在我想从 PHP 脚本做同样的事情。当然,我希望它能起作用:

mkdir("/mydir/test2");
chmod("/mydir/test2", 02775);

但它没有,我得到了这个(SGID 已重置):

  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 16:30 test2

这里有一些其他有用的实验:

mkdir("/mydir/test3");
mkdir("/mydir/test4");
passthru("chmod 02775 '/mydir/test4'");
mkdir("/mydir/test5");
passthru("chmod g+w '/mydir/test5'");

结果是

  4 drwxr-sr-x  2 www-data mygroup   4096 Oct  7 16:39 test3
  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 16:39 test4
  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 17:06 test5

有趣的是,mkdir() 单独保留了 SGID,但 chmod() 重置了它,甚至通过 passthru()

我知道 PHP 手册说 chmod 该命令只需要三个八进制数字,但我也读到 this Whosebug question and it looks like the manual contains obsolete information and others can affect the SGID. Besides, it should not affect the passthru() versions, should it? The same Whosebug question 提到了一些关于 chmod() 需要在 chown()chgrp() 之后是“最后一个被调用的”,但我没有使用其中任何一个。

我做错了什么?

这是在 Web 服务器上 运行ning 还是仅作为 CLI 脚本?如果是 CLI,用户还是 root?

另外,为什么是目录? SGID 用于程序文件,以允许用户 运行 a program/script 作为另一个用户,如“sudo”。您是否尝试过在文件而不是目录上进行测试?

最后,我能找到获得我需要的权限的唯一方法是利用 mkdir() 的正确行为并避免调用 chmod() 这似乎重置了 SGID 位 no有什么关系。我能想到的唯一方法是将 umask 更改为 umask():

$myumask = umask(2);
mkdir("/mydir/test6");
umask($myumask);

这似乎工作正常:

  4 drwxrwsr-x  2 www-data mygroup   4096 Oct  9 14:22 test6

这给我留下了 https://www.php.net/manual/en/function.umask.php 注释中提出的问题:多线程网络服务器的所有线程共享相同的 umask,显然会导致不希望的和不可预测的行为。幸运的是,就我而言,我可以确定所有目录创建都是在单线程上下文中完成的(基本上,在脚本的第一次测试 运行 中),因此我感到安全。因此,这是一个有用的解决方法,但不是通用解决方案。