通过exec()的Crontab不适用于PHP 7.4/Deb 10
在使用新版本的PHP和新服务器上的新OS时,很难调试.
Bit of a hard one to debug as I'm working with both a new version of PHP and a new OS on a new server.
我有一个使用PHP的cron管理系统,该系统也允许我添加/删除或启用/禁用cronjobs.
I have a cron management system in PHP that allows me too add / remove or enable / disable cronjobs.
在另一台当前使用PHP 7.2的Deb 8服务器上,它可以使用以下功能完美地运行作业...
On another current Deb 8 server with PHP 7.2 it works flawlessly using the following function to create a job...
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的内容,它还会吐出两个单独的数组,一个用于活动作业,一个用于非活动作业...
And I can also list the contents of the crontab with this, which also spits out two separate arrays, one for active jobs and one for inactive ones...
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 始终返回一个空数组(我认为这是因为找不到作业).
But I've just set up a new Debian 10 server with PHP 7.4 and none of this seems to do anything anymore? It doesn't add jobs and crontab -l
always returns an empty array (which I assume is because there are no jobs to be found).
我检查了 exec()
是否正常工作,还尝试将 www-data
用户添加到/etc/cron.allow
正如我发现的几篇文章所建议的那样,尽管我从来没有在Deb 8服务器上这样做,但是我一点都没有感到高兴.
I've checked that exec()
is working and also tried adding the www-data
user to /etc/cron.allow
as suggested by a few articles I found, although I never had to do that on the Deb 8 server, but I'm getting no joy at all.
我不知道Deb 10或PHP 7.4中引入了新的安全措施或代码更改是否会阻止其运行,或者我在这里显然缺少什么?
Were there new security measures or code changes introduced in Deb 10 or PHP 7.4 that I'm unaware of that would be preventing this from working or is there something obvious I'm missing here?
-编辑以包括下面@summea所提供的解决方案-
我敢肯定其他人会偶然发现这一点,所以答案就在这里:
I'm sure others are going to stumble upon this so here is the answer :
a)PHP 7.4(似乎是7.3)需要 exec()
a) PHP 7.4 (and 7.3 it seems) require the full path to echo
in exec()
public static function createCronjob($job)
{
exec('/usr/bin/echo -e "`crontab -l`\n'. $job .'" | crontab -', $output);
return $output;
}
但是奇怪的是,不需要到 crontab
的完整路径(但可能是很好的做法),因为这仍然可行:
But strangely the full path to crontab
is NOT required (but probably good practice) as this still works :
exec('crontab -l', $data);
b)创建/etc/cron.allow
对我来说是一个错误.它拒绝此文件中未声明的所有其他用户访问 crontab
.在删除它并重新启动cron服务/etc/init.d/cron restart
后,一切正常.
b) Creating /etc/cron.allow
was a mistake for me. It was refusing access to the crontab
to every other user that wasn't declared in this file. After I deleted it and restarted the cron service /etc/init.d/cron restart
everything works as it should.
真的希望这可以节省别人的时间,因为它是个虫子!
Really hopes this saves somebody else some time as it's a bugger!
我在本地计算机上有Debian 10 VM,并在上面装有PHP 7.3.19.经过大量时间尝试使用不同的方法来解决您所面临的问题,在我这边,问题却与需要包含 echo
程序的完整路径有关.我不知道我的机器上是否有其他 echo
程序,PHP在其他路径或其他内容中找到了该程序(这可能与
I have a Debian 10 VM on my local computer and have PHP 7.3.19 on it. After lots of time trying different approaches to the issue you're facing, on my side the issue turned out to relate to needing to include the full path to the echo
program. I don't know if there is some other echo
program on my machine that PHP was finding in a different path or something (and this might indirectly relate to what Michael was saying in the comment from earlier). 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.
这是我要做的,以使您的 createCronjob()
从PHP方面成功运行:
Here is what I did to get your createCronjob()
to run successfully from the PHP side of things:
// ref: q21.php
function createCronjob($job)
{
exec('/usr/bin/echo -e "`crontab -l`\n'. $job .'" | crontab -', $output);
return $output;
}
当我将完整路径添加到 echo
命令时,它开始起作用.您的 echo
路径可能不同,但是可能相同,因为我们应该使用类似的系统.
When I added the full path to the echo
command, it began to work. Your echo
path might be different, but it might be the same because we should be using similar systems.
我使用以下命令找到了 echo
路径:
I found out the echo
path by using this command:
回显
它返回了这个位置:
/usr/bin/echo
Also, for future reference, I don't know if this is a case where using the escapeshellcmd()
might be a good idea in the future? I'm not very familiar with it, so I'm not sure if this is a situation where you would want to include it somewhere on your shell command (and it might make the command not run as intended anyway), but wanted to mention it!