为什么 PHP 7.2 fopen(/tmp, a) 不写入文件?

Why doesn't PHP 7.2 fopen(/tmp, a) write to the file?

我有一个旧的 "PHPDBG" 函数可以让我 "printf" 到一个文本文件。

我有 PHPDBG.inc "since forever"(至少从 PHP 4.x 天开始),但它没有它似乎在我当前的配置中工作(ubuntu18、Apache 2.4.29 和 PHP 7.2)。

具体来说:

这里是测试代码:

test.php:

<?php
  function PHPDBG ($s) {
    $fp = fopen ("/tmp/PHPDBG.txt", "a");
    if ($fp) {
      // Successful open ... but nothing written!
      fputs($fp, $s . "\n");
      fclose($fp);
    } else {
      echo "<h3>FILE OPEN ERROR</h3>\n";
      echo "<p>" . print_r(error_get_last()) . "</p>\n";
      echo "<p>" . $php_errormsg . "</p>\n";
    }
  }

  PHPDBG('>>Hello');
  phpinfo();
  PHPDBG('<<Goodbye');
 ?>

问题:

Q1:知道 $fp = fopen ("/tmp/PHPDBG.txt", "a"); 有什么问题吗?

问题 2:如果 "fopen()" 失败,我该怎么做才能获得有意义的错误消息?


附加信息:假设 error_get_last() 返回“1: EPERM 1 /* 不允许操作 */”,然后我手动创建 /tmp/PHPDBG.txt、chmod +rw,并尝试 "test.php" 再次。不行:我得到了完全相同的结果:$fp 为空,没有有意义的错误消息,并且 /tmp/PHPDBG.txt 没有改变:

root@ubuntu18:/tmp# umask 0
root@ubuntu18:/tmp# touch PHPDBG.txt
root@ubuntu18:/tmp# ls -l PHPDBG.txt
-rw-rw-rw- 1 root root 0 Mar  5 18:13 PHPDBG.txt
 <= Re-ran test here... failed exactly like before...
root@ubuntu18:/tmp# ls -l PHPDBG.txt
-rw-rw-rw- 1 root root 0 Mar  5 18:13 PHPDBG.txt

补充说明:

  1. Ibu 指出了我发布的代码的原始版本中的一个愚蠢的拼写错误。哎呀!它是在最后一刻悄悄出现的,错字 不是 的问题。我仍然无法 "fopen()" /tmp 中的文件并从 PHP 7.2 写入它。我曾经能够在 PHP.

  2. 的早期(更早!)版本中做到这一点
  3. 我刚刚仔细检查:我 AM 能够写入文件,如果它恰好在本地目录中:

    // $fp = fopen ("/tmp/PHPDBG.txt", "a");  // Opens, but fails to write anything
    $fp = fopen ("PHPDBG.txt", "a");  // Works OK
    

问:为什么????

更新

"it used to work" 的原因是 systemd 被引入到 Linux 的(较新版本),带来了 "PrivateTmp".

我的解决方法是为Apache/PHP禁用这个"feature"。我编辑 /etc/systemd/system/multi-user.target.wants/apache2.service 如下:

[Service]
...
PrivateTmp=true  <-- Changed this to "false"

附加说明是

你的条件反转了:if (!$fp).

你是说如果不处理,就写入文件。应该是相反的。

<?php
  function PHPDBG ($s) {
    $fp = fopen ("/tmp/PHPDBG.txt", "a");
    if ($fp) { // fixed condition.
      fputs($fp, $s . "\n");
      fclose($fp);
    } else {
      echo "<h3>FILE OPEN ERROR</h3>\n";
      echo "<p>" . print_r(error_get_last()) . "</p>\n";
      echo "<p>" . $php_errormsg . "</p>\n";
    }
  }

  PHPDBG('>>Hello');
  phpinfo();
  PHPDBG('<<Goodbye');
?>

我发现好像没有创建的文件:

  1. PHP代码:$fp = fopen ("/tmp/PHPDBG.txt", "a");

  2. 预期位置:/tmp/PHPDBG.txt.

  3. 实际位置:/tmp/systemd-private-c6f7629309e647818680f8a6ee1105d6-apache2.service-lGKGc6/tmp/PHPDBG.txt

相关链接:

所以这听起来像是某种 systemd "feature"(Grrr!!!!)。这解释了为什么它 "used to work"(在以前的 Apache 版本中,PHP 和 Linux)。

解决方法

我编辑了 /etc/systemd/system/multi-user.target.wants/apache2.service:

[Service]
...
PrivateTmp=true  <-- Changed this to "false"

真正的问题是权限问题。

创建私有 tmp 文件时,它仅具有 root 权限。

httpd的权限应该是httpd等等。

这是systemd可配置项吗?似乎 systemd 解决了一个问题只是为了防止存在问题的实际使用。 httpd 的 /tmp 应该可以由 httpd 写入,但事实并非如此。