重装系统后,重新配置了一遍开发环境,出现了一个神奇的PHP权限问题,记录如下。
/var/www/xxx/ —— 项目根目录,所有者tongyifan:tongyifan
/var/www/xxx/yyy/ —— 需要写入文件的目录,所有者tongyifan:tongyifan
nginx和php-fpm使用http:http运行
首先,尝试了一下如下代码
<?php
var_dump(is_writable("/var/www/xxx/yyy/"))
不出所料,返回了 bool(false)
。
第一反应是这个文件夹的权限没给够,遂直接运行了
sudo chown -R http:http /var/www/xxx/yyy
sudo chmod -R 777 /var/www/xxx/yyy
再运行了一下上面的代码,并没有什么变化,这就比较让人迷惑了。
去网上一番查找,有说是SELinux的问题,然而Manjaro并没有SELinux这种没有用的东西,再试了一下使用http用户直接在这个文件夹创建文件,可以直接创建,因此排除了系统权限的问题,把目标直接指向PHP。
sudo runuser -uhttp touch /var/www/xxx/yyy/test
继续查下去,还有说是 php.ini
中的 open_basedir
配置项的问题,这个配置项会限制php脚本仅可以访问指定的目录,具体见PHP文档,然而打开 php.ini
看了一下,这个配置项并没有被配置。
按照stackoverflow的一个问题「Why can't PHP create a file, even with 777 permissions?」中的代码尝试了一下 fopen
,发现了一个神奇的报错。
<?php
fopen("/var/www/xxx/yyy/test", "c");
// Warning: fopen(/var/www/xxx/yyy/test): failed to open stream: Read-only file system in /usr/share/nginx/html/xxx/test.php on line 17
最终,在serverfault的一个问题「“failed to open stream: Read-only file system” when trying to create file outside webroot with php」中找到了答案,我们打开 /usr/lib/systemd/system/php-fpm.service
可以看到一个配置项:
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by this unit.
ProtectSystem=full
查了查发现这个配置项在2018年底被引入到php-fpm.service中以保护系统安全,见[email protected],然而却卡了我这么久= =注释掉后问题解决。