PHP:文件写入权限

4

我已经头疼了很长一段时间,因为这个问题...

我正在尝试在我的虚拟服务器(CentOS 7、Apache Http Server、PHP 5.4.3)上安装MyBB论坛,并遇到文件权限问题。MyBB需要两个文件具有可写权限,其中一个是 config.php,另一个是 settings.php,它们都在目录 inc 中。

我将这两个文件的权限设置为 666。我编写了一个简单的测试PHP页面,模拟MyBB测试写入能力的方式:

<?php
echo('config: ');
$configwritable = @fopen('forum/inc/config.php', 'w');
if ($configwritable) {
        echo('yes');
} else {
        echo('no');
}
echo('<br/>');
echo('settings: ');
$configwritable = @fopen('forum/inc/settings.php', 'w');
if ($configwritable) {
    echo('yes');
} else {
    echo('no');
}
?>

页面输出是:
config: no
settings: yes

但是,如果我列出文件,它们会显示如下。
root@localhost# ls -l forum/inc/config.php forum/inc/settings.php 
-rw-rw-rw-. 1 krkavec krkavec 0  2. říj 22.49 forum/inc/config.php
-rw-rw-rw-. 1 krkavec krkavec 0  2. říj 22.51 forum/inc/settings.php

怎么可能呢?这两个文件属于同一用户、同一组,大小相同(为零),在同一目录下,权限相同,修改时间也几乎相同(只相差两分钟),除了它们的名称不同外,其他一切都相同。

更加奇怪的是,我尝试删除并重新创建这些文件,看:

1:删除两个文件

root@localhost# rm -f forum/inc/config.php forum/inc/settings.php

以及页面输出:

config: no
settings: no

这没问题,因为inc目录不应该是可写的。

2:创建settings.php

root@localhost# F=forum/inc/settings.php ; touch $F ; chown krkavec:krkavec $F ; chmod 666 $F
root@localhost# ls -l forum/inc/settings.php forum/inc/config.php
ls: cannot access forum/inc/config.php: No such file or directory
-rw-rw-rw-. 1 krkavec krkavec 0  2. říj 23.15 forum/inc/settings.php

并且页面输出:

config: no
settings: yes

这是完全可以预料的情况 - 文件已经存在并且具有可写权限。

3: 创建config.php文件。

root@localhost# F=forum/inc/config.php ; touch $F ; chown krkavec:krkavec $F ; chmod 666 $F
root@localhost# ls -l forum/inc/settings.php forum/inc/config.php
-rw-rw-rw-. 1 krkavec krkavec 0  2. říj 23.23 forum/inc/config.php
-rw-rw-rw-. 1 krkavec krkavec 0  2. říj 23.15 forum/inc/settings.php

并且页面输出:

config: no
settings: yes

哇!我完全期望配置文件是可写的。

非常感谢任何帮助。

编辑:根据Marc B和drew010的建议,我修改了测试页面。

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

echo('config var_dump: ');
var_dump(stat('forum/inc/config.php'));
echo('<br/>config: ');
$configwritable = fopen('forum/inc/config.php', 'w');
if ($configwritable) {
    echo('yes');
} else {
    echo('no');
}
echo('<br/>');
echo('settings var_dump: ');
var_dump(stat('forum/inc/settings.php'));
echo('<br/>settings: ');
$configwritable2 = fopen('forum/inc/settings.php', 'w');
if ($configwritable2) {
    echo('yes');
} else {
    echo('no');
}
?>

并且页面的输出(在两个文件都存在的情况下)为:

config var_dump: array(26) { [0]=> int(64768) [1]=> int(19155212) [2]=> int(33206) [3]=> int(1) [4]=> int(1000) [5]=> int(1000) [6]=> int(0) [7]=> int(0) [8]=> int(1443821772) [9]=> int(1443821772) [10]=> int(1443821772) [11]=> int(4096) [12]=> int(0) ["dev"]=> int(64768) ["ino"]=> int(19155212) ["mode"]=> int(33206) ["nlink"]=> int(1) ["uid"]=> int(1000) ["gid"]=> int(1000) ["rdev"]=> int(0) ["size"]=> int(0) ["atime"]=> int(1443821772) ["mtime"]=> int(1443821772) ["ctime"]=> int(1443821772) ["blksize"]=> int(4096) ["blocks"]=> int(0) } 
config: 
Warning: fopen(forum/inc/config.php): failed to open stream: Permission denied in /var/www/html/test.php on line 8
no
settings var_dump: array(26) { [0]=> int(64768) [1]=> int(19155069) [2]=> int(33206) [3]=> int(1) [4]=> int(1000) [5]=> int(1000) [6]=> int(0) [7]=> int(0) [8]=> int(1443821763) [9]=> int(1443823158) [10]=> int(1443823158) [11]=> int(4096) [12]=> int(0) ["dev"]=> int(64768) ["ino"]=> int(19155069) ["mode"]=> int(33206) ["nlink"]=> int(1) ["uid"]=> int(1000) ["gid"]=> int(1000) ["rdev"]=> int(0) ["size"]=> int(0) ["atime"]=> int(1443821763) ["mtime"]=> int(1443823158) ["ctime"]=> int(1443823158) ["blksize"]=> int(4096) ["blocks"]=> int(0) } 
settings: yes

第一步:删除@符号 - Michael
@Michael 去掉 @ 符号并没有改变行为,除了 Apache 的日志中现在有一个关于没有权限的警告(因此 PHP 真的认为它无法打开文件进行写入)。 - zegkljan
你能发布精确的警告信息吗?如果你将inc目录设为可写,你尝试过是否可以工作吗? - Michael
这段代码片段所包含的当前测试文件的uidgid是什么? - revo
所以您确认只有settings.php文件具有写入权限,而同一目录中具有不同名称的其他文件没有这个权限吗? - revo
显示剩余10条评论
1个回答

3
出于某种神秘、未知的原因,当我将settings.php重命名为config.php,然后创建新的settings.php并适当设置权限时,两个文件都是可写的。
然而,我完全不知道为什么必须重命名该文件。结果与问题描述中的第3步相同,只是它可以正常工作。
欢迎任何建议,解释这一做法的原因。
编辑:这是由SELinux安全上下文引起的,它防止Apache向文件写入。运行chcon -t httpd_sys_rw_content_t config.php解决了这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接