PHP的fopen()失败,即使有广泛的权限的文件

目前,我正在将我的LAMP从Windows Server迁移到运行Debian 6的VPS。大多数情况都可行,但其中一个PHP脚本无法写入其configuration的日志文件。 我无法确定为什么,所以我写了一个新的,简单的,人为的PHP脚本来testing这个问题。

<?php ini_set('display_errors', 1); error_reporting(E_ALL); echo exec('whoami'); $log = fopen('/var/log/apache2/writetest/writetest.log', 'a'); if ($log != NULL) { fflush($log); fclose($log); $log = NULL; } ?> 

但是,结果失败:

 www-data Warning: fopen(/var/log/apache2/writetest/writetest.log): failed to open stream: Permission denied in /var/www/_admin/phpwritetest.php on line 5 
  • 虽然我永远不会这样做,为了帮助诊断,我将/var/log/apache2/writetest/writetest.log设置为chmod 777。
  • 目录和文件都由www-data:www-data
  • 该文件是通过touch创build的。

我跑了strace来validation哪个进程正在执行打开:

 [pid 21931] lstat("/var/log/apache2/writetest/writetest.log", 0x7fff81677d30) = -1 EACCES (Permission denied) [pid 21931] lstat("/var/log/apache2/writetest", 0x7fff81677b90) = -1 EACCES (Permission denied) [pid 21931] open("/var/log/apache2/writetest/writetest.log", O_RDWR|O_CREAT|O_TRUNC, 0666) = -1 EACCES (Permission denied) 

我检查和PID 21931确实是在www-data下运行的apache2subprocess之一。 正如你所看到的,我还包括echo exec('whoami'); 在确认剧本是由www-data运行的脚本中。

其他说明:

  • PHP没有在安全模式下运行
  • PHP open_basedir没有设置
  • 版本信息: Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze3 with Suhosin-Patch mod_ssl/2.2.16 OpenSSL/0.9.8o
  • uname -a: 2.6.32-238.19.1.el5.028stab092.2 #1 SMP Thu Jul 21 19:23:22 MSD 2011 x86_64 GNU/Linux
  • 这是在OpenVZ下运行的VPS
  • ls -l(file):- -rwxrwxrwx 1 www-data www-data 0 Sep 8 18:13 writetest.log
  • ls -l(目录): drwxr-xr-x 2 www-data www-data 4096 Sep 8 18:13 writetest
  • Apache2的父进程在root下运行,subprocess在www-data
  • 没有安装selinux(感谢法比奥提醒我提及这一点)
  • 我已经多次重启apache并重启了服务器

请记住,为了达到一个文件,所有的父目录必须能被www-data读取。 你strace输出似乎表明,即使访问 /var/log/apache2/writetest失败。 确保www-data对以下目录具有权限:

  • / (rx)
  • /var (rx)
  • /var/log (rx)
  • /var/log/apache2 (rx)
  • /var/log/apache2/writetest (rwx)
  • /var/log/apache2/writetest/writetest.log (rw-)

执行写作的PHP文件是否设置了适当的权限? 尝试改变这些看看是否是这个问题。

可能是一个SELinux的问题,即使Debian没有在默认的安装中提供它可以启用它。 在/var/log查找消息

 grep -i selinux /var/log/{syslog,messages} 

如果这是原因,你需要禁用它,这里是说明:寻找文件/etc/selinux/config ,这里是默认的内容。 SELINUX指令更改为disabled并重新引导系统。

 # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - SELinux is fully disabled. SELINUX=disabled # SELINUXTYPE= type of policy in use. Possible values are: # targeted - Only targeted network daemons are protected. # strict - Full SELinux protection. SELINUXTYPE=targeted