通过 exec() 的 Crontab 不适用于 PHP 7.4 / Deb 10

Crontab via exec() not working with PHP 7.4 / Deb 10

调试起来有点困难,因为我在新服务器上同时使用新版本的 PHP 和新的 OS。

我在 PHP 中有一个 cron 管理系统,它允许我添加/删除或启用/禁用 cronjobs。

在另一台 PHP 7.2 的当前 Deb 8 服务器上,它可以完美地使用以下函数创建作业...

public static function createCronjob($job)
{
    exec('echo -e "`crontab -l`\n'. $job .'" | crontab -', $output);
    return $output;
}

其中 $job 类似于:

10 0 * * * wget -O - https://website.com/cxs?job=jobTitle >/dev/null 2>&1

而且我还可以用这个列出 crontab 的内容,它也吐出两个单独的数组,一个用于活动作业,一个用于非活动作业...

public static function getCronjobs()
{
    exec('crontab -l', $data);
    
    $active = [];
    $inactive = [];
    foreach ($data as $j) {
        if (!empty($j)) {
            if (substr($j,0,1) == '#') {
                array_push($inactive, $j);
            } else {
                array_push($active, $j);
            }
        }
    }

    $arr = [
        'active' => $active,
        'inactive' => $inactive
    ];

    return $arr;
}

但我刚刚用 PHP 7.4 和 none 设置了一个新的 Debian 10 服务器,这似乎还能做什么?它不会添加工作并且 crontab -l 总是 returns 一个空数组(我认为这是因为没有找到工作)。

我检查过 exec() 是否正常工作,并尝试按照我发现的几篇文章的建议将 www-data 用户添加到 /etc/cron.allow,尽管我从来没有这样做过在 Deb 8 服务器上,但我一点也不高兴。

在 Deb 10 或 PHP 7.4 中是否引入了新的安全措施或代码更改,我不知道这会阻止它的工作,或者我在这里明显遗漏了什么?

-- 编辑以包括下面@summea 友情提供的解决方案--

我敢肯定其他人会偶然发现这个,所以这里是答案:

a) PHP 7.4(似乎是 7.3)需要 exec()

echo 的完整路径
public static function createCronjob($job)
{
    exec('/usr/bin/echo -e "`crontab -l`\n'. $job .'" | crontab -', $output);
    return $output;
}

但奇怪的是 crontab 的完整路径 不需要 (但可能是好的做法),因为这仍然有效:

exec('crontab -l', $data);

b) 创建 /etc/cron.allow 对我来说是个错误。它拒绝未在此文件中声明的所有其他用户访问 crontab。在我删除它并重新启动 cron 服务后 /etc/init.d/cron restart 一切正常。

真的希望这能为其他人节省一些时间,因为它是一个错误!

我的本地计算机上有一个 Debian 10 虚拟机,上面装有 PHP 7.3.19。经过大量时间尝试不同的方法来解决您所面临的问题,在我这边,问题原来与需要包含 echo 程序的完整路径有关。我不知道 PHP 在我的机器上是否有其他 echo 程序在不同的路径或其他地方找到(这可能与 ). At one point I was wondering if the backticks in the command were causing a problem with PHP, because the shell_exec() is evidently like the PHP backtick operator.[=23 间接相关) =]

以下是我从 PHP 方面成功将您的 createCronjob() 升级为 运行 所做的工作:

// ref: q21.php
function createCronjob($job)
{
    exec('/usr/bin/echo -e "`crontab -l`\n'. $job .'" | crontab -', $output);
    return $output;
}

当我将完整路径添加到 echo 命令时,它开始工作了。您的 echo 路径可能不同,但可能相同,因为我们应该使用相似的系统。

我使用这个命令找到了 echo 路径:

which echo

它返回了这个位置:

/usr/bin/echo

此外,为了将来参考,我不知道在这种情况下,将来使用 escapeshellcmd() 是否是个好主意?我不是很熟悉它,所以我不确定在这种情况下您是否希望将它包含在 shell 命令的某处(并且它可能会使命令不是 运行 作为无论如何都打算),但想提一下!