首页 > 解决方案 > 通过 exec() 的 Crontab 不适用于 PHP 7.4 / Deb 10

问题描述

当我在新服务器上同时使用新版本的 PHP 和新操作系统时,调试起来有点困难。

我在 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 设置了一个新的 Debian 10 服务器,而这些似乎都不再起作用了?它不添加作业,并且crontab -l总是返回一个空数组(我认为这是因为找不到作业)。

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

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

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

我相信其他人会偶然发现这一点,所以这里是答案:

a) PHP 7.4(和似乎是 7.3)需要完整echo路径exec()

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一切正常。

真的希望这可以节省其他人一些时间,因为它是一个虫子!

标签: phpcrondebian-buster

解决方案


我的本地计算机上有一个 Debian 10 VM,上面有 PHP 7.3.19。经过大量时间尝试解决您面临的问题的不同方法后,在我看来,问题与需要包含echo程序的完整路径有关。我不知道echo我的机器上是否有其他程序 PHP 在不同的路径中找到了或其他东西(这可能与Michael 在之前的评论中所说的间接相关)。有一次我想知道命令中的反引号是否导致 PHP 出现问题,因为shell_exec()它显然类似于 PHP 反引号运算符

这是我为使您createCronjob()从 PHP 方面成功运行所做的工作:

// 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 命令中的某个地方(并且它可能会使命令无论如何都不能按预期运行),但想提一下它!


推荐阅读