【问题标题】:Crontab via exec() not working with PHP 7.4 / Deb 10通过 exec() 的 Crontab 不适用于 PHP 7.4 / Deb 10
【发布时间】:2021-03-04 08:13:46
【问题描述】:

当我在新服务器上同时使用新版本的 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)需要 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 后,一切正常。

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

【问题讨论】:

  • 首先要尝试的是你的可执行文件/usr/bin/crontab 的完整路径,因为你永远不能假设 www-data 正在使用你期望的$PATH 运行
  • 迈克尔大喊大叫,刚刚尝试过,但它仍然没有做任何事情。还有什么你能想到的我可以尝试的吗?我确实尝试通过 cli 手动将作业添加到 www-data crontab,该作业添加得很好,但是当我尝试使用 exec() 列出它们时仍然显示我没有作业。
  • 个人会推荐jenkins而不是crontab。话虽如此,您需要查看 exec 得到的错误。将 stderr 重定向到 stdout 并查看它的内容:将 2>&1 添加到命令末尾。 stackoverflow.com/q/2320608/1301076 的其他一些选项

标签: php cron debian-buster


【解决方案1】:

我的本​​地计算机上有一个 Debian 10 虚拟机,上面有 PHP 7.3.19。经过大量时间尝试解决您面临的问题的不同方法后,在我看来,问题与需要包含echo 程序的完整路径有关。我不知道我的机器上是否还有其他一些echo 程序,PHP 在不同的路径或其他东西中找到了(这可能与Michael was saying in the comment from earlier 的内容间接相关)。有一次我想知道命令中的反引号是否导致 PHP 出现问题,因为 shell_exec() is evidently like the PHP backtick operator.

这是我为使您的 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 命令中某处的情况(并且它可能会使命令无法按预期运行),但想提一下它!

【讨论】:

  • 如果你在php中使用exec运行which echo会返回什么?我想这个问题一定和this有关
  • 嗨@AliTou,嗯,我尝试运行<?php exec('which echo', $output); echo $output[0], "\n"; ?> 来检查这一点,但最终得到/usr/bin/echo 作为我这边的结果。感谢您让我知道that other thread 中与 bash 相关的回声差异!也许这里发生了类似的事情,但我目前不确定。
  • 好吧,你说的完全正确。将完整路径添加到 echo DID 解决了我的问题。我遇到的问题是我创建了/etc/cron.allow 文件并添加了www-data 用户,事实证明这会阻止任何其他用户访问crontab。即使脚本是通过 Apache/Nginx 运行的,PHP 也必须使用不同的用户?再次感谢伙计,我怀疑我是否曾经考虑过添加完整的 echo 路径作为解决方案。
  • @spice 很高兴听到它对您有用!此外,看起来可能有一种方法可以检查哪个用户与正在使用this code example 运行的 PHP 进程或脚本相关。如果你好奇的话,也许这会更清楚地说明用户的问题!
  • @summea 再次感谢,这是一个超级sn-p 的代码供未来使用。
猜你喜欢
  • 2022-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多