PHP fopen() 在文件上失败,即使具有广泛的开放权限

发布于 2024-12-03 13:26:50 字数 2113 浏览 0 评论 0原文

我目前正在将 LAMP 从 Windows Server 迁移到运行 Debian 6 的 VPS。大多数情况都正常,但是其中一个 PHP 脚本无法写入其配置的日志文件。我无法确定原因,因此我编写了一个新的、简单的、人为的 PHP 脚本来测试该问题。

<?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 创建的。

我运行了 strace 来验证哪个进程正在执行打开:

[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 下运行的 apache2 子进程之一。正如您所看到的,我还在脚本中添加了 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 ls -l 下运行的 VPS 上
  • (文件): <代码>-rwxrwxrwx 1 www-data www-data 0 Sep 8 18:13 writetest.log
  • ls -l (directory): drwxr-xr-x 2 www-data www-data 4096 Sep 8 18:13 writetest
  • Apache2 的父进程在 root,并且www-data下的子进程
  • selinux没有安装(感谢Fabio提醒我提到这一点)
  • 我已经重新启动了apache很多次次并重新启动服务器

I'm currently migrating my LAMP from my Windows Server to a VPS running Debian 6. Most everything is working, however, one of the PHP scripts was failing to write to its configured log file. I could not determine why, so I wrote a new, simple, contrived PHP script to test the problem.

<?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;
        }
?>

However, it fails with the result:

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 
  • While I would never do it normally, to help diagnose, I set /var/log/apache2/writetest/writetest.log to chmod 777.
  • Both the directory and the file are owned by www-data:www-data.
  • The file was created with touch.

I ran strace to verify which process was performing the open:

[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)

I checked and pid 21931 was indeed one of the apache2 child processes running under www-data. As you can see, I also included echo exec('whoami'); in the script which confirmed the script was being run by www-data.

Other notes:

  • PHP is not running in safe mode
  • PHP open_basedir is not set
  • Version info: 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
  • This is on a VPS running under OpenVZ
  • ls -l (file): -rwxrwxrwx 1 www-data www-data 0 Sep 8 18:13 writetest.log
  • ls -l (directory): drwxr-xr-x 2 www-data www-data 4096 Sep 8 18:13 writetest
  • Apache2's parent process runs under root, and the child processes under www-data
  • selinux is not installed (thanks to Fabio for reminding me to mention this)
  • I have restarted apache many times and rebooted the server as well

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事灯 2024-12-10 13:26:50

请记住,为了访问文件,所有父目录都必须可由 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-)

Remember that in order to reach a file, ALL parent directories must be readable by www-data. You strace output seems to indicate that even accessing /var/log/apache2/writetest is failing. Make sure that www-data has permissions on the following directories:

  • / (r-x)
  • /var (r-x)
  • /var/log (r-x)
  • /var/log/apache2 (r-x)
  • /var/log/apache2/writetest (rwx)
  • /var/log/apache2/writetest/writetest.log (rw-)
苏璃陌 2024-12-10 13:26:50

进行写入的 php 文件是否设置了适当的权限?尝试更改这些内容以查看是否是问题所在。

Does the php file doing the writing have proper permissions set? Try changing those to see if that's the issue.

差↓一点笑了 2024-12-10 13:26:50

可能是 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

Could be a SELinux issue, even if Debian doesn't ship it in the default installation your provider could have enabled it. Look for messages in /var/log with

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

If that's the cause and you need to disable it, here are instructions: look for file /etc/selinux/config, here it's default content. Change SELINUX directive to disabled and reboot the system.

# 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文