如何在PHP中设置SGID?

问题描述

我无法通过PHP设置sgiD位。

我有这个目录:

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

注意sgiD位。因此,如果我只是使用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 stackoverflow question,看起来该手册包含过时的信息,而其他信息可能会影响sgiD。此外,它应该不会影响passthru()版本,对吗?相同的stackoverflow question提到了chmod()必须在chown()chgrp()之后成为“最后一个被呼叫”的地方,但是我没有使用任何这些东西。

我在做什么错了?

解决方法

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

还有,为什么要目录? SGID用于程序文件,以允许用户以另一个用户(如“ sudo”)的身份运行程序/脚本。您是否尝试过对文件而不是目录进行测试?

,

最后,我能找到的唯一获得权限的方法是利用mkdir()的正确行为,避免调用chmod(),无论如何,它似乎都会重置SGID位。我想到的唯一方法是用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注释中提出的问题:多线程Web服务器的所有线程都共享相同的 umask ,显然会导致不良行为和不可预测的行为。幸运的是,就我而言,我可以确定所有目录创建都是在单线程上下文中完成的(本质上是在脚本的第一次测试运行中),因此我感到很安全。因此,这是一个有用的解决方法,但不是一种通用解决方案。