问题描述
我有这个目录:
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 ,显然会导致不良行为和不可预测的行为。幸运的是,就我而言,我可以确定所有目录创建都是在单线程上下文中完成的(本质上是在脚本的第一次测试运行中),因此我感到很安全。因此,这是一个有用的解决方法,但不是一种通用解决方案。