1.在服务器增加一个每分钟执行的任务(入口文件)
* * * * * php root/****/Crontab.php 1
2.创建入口文件Crontab.php
//设备ID,服务器的设备编号
$device_id = $_SERVER['argv'][1];
if(!$device_id){
exit("缺少设备ID参数");
}
$crontab = new CrontabModel($device_id);
$crontab->actionRun();
3.创建CrontabModel文件,其中的配置文件可以提出来,配置在数据库中。
class CrontabModel
{
//当前服务器的命令集合
private $cronJobs = [];
//所有服务器的命令集合
private $all_Jobs = [];
public function __construct($device_id)
{
$all_Jobs = array(
'1' => array(//设备1
'cronJobs' => array(
'sleep 10; ***/php ***.php' => '*/30 * * * *',
'***/php ***.php' => '*/30 * * * *',
),
),
'2' => array(//设备2
'cronJobs' => array(
'sleep 10; ***/php ***.php' => '*/30 * * * *',
'***/php ***.php' => '*/30 * * * *',
),
),
);
$this->cronJobs = $all_Jobs[$device_id]['cronJobs'];
}
public function actionRun()
{
// 格式化当前时间戳并转成 分 时 日 月 周 格式
/*
|i 有前导零的分钟数 00 到 59>
|G 小时,24 小时格式,没有前导零 0 到 23
|j 月份中的第几天,没有前导零 1 到 31
|n 数字表示的月份,没有前导零 1 到 12
|w 星期中的第几天,数字表示 0(表示星期天)到 6(表示星期六)
*/
$now = explode(' ', date('i G j n w', time()));
$raw = $this->parseCron($this->cronJobs);
foreach ($raw as $command => $cron) {
// 上面已经列出了所有的情况,所以当前时间循环时如果有一项不符合则不能向下执行
foreach ($now as $k => $piece) {
if (!in_array($piece, $raw[$command][$k])) {
continue 2;
}
}
// 下面是调用系统函数执行shell命令
$this->runCommandBackground($command);
}
}
/**
* 解析需要执行的命令
* @param $cronJobs
* @return array
*/
public function parseCron($cronJobs)
{
// 解析后的数组
$raw = [];
foreach ($cronJobs as $command => $cron) {
// $command -> hello/index $cron -> */5 * * * *
// 将命令用空格分割成数组
$cronArr = explode(' ', $cron, 5); // ['*/5', '*', '*', '*', '*']
// 针对每一个位置进行解析
$dimensions = array(
array(0, 59), //Minutes
array(0, 23), //Hours
array(1, 31), //Days
array(1, 12), //Months
array(0, 6), //Weekdays
);
foreach ($cronArr as $key => $item) {
// 标记是哪种命令格式,通过使用的crontab命令可以分为两大类
// 1.每几分钟或每小时这样的 */10 * * * *
// 2.几点几分这样的 10,20,30-50 * * * *
list($repeat, $every) = explode('/', $item, 2) + [false, 1];
if ($repeat === '*') {
$raw[$command][$key] = range($dimensions[$key][0], $dimensions[$key][1]);
} else {
// 处理逗号拼接的命令
$tmpRaw = explode(',', $item);
foreach ($tmpRaw as $tmp) {
// 处理10-20这样范围的命令
$tmp = explode('-', $tmp, 2);
if (count($tmp) == 2) {
$raw[$command][$key] = array_merge($raw[$command][$key],
range($tmp[0], $tmp[1]));
} else {
$raw[$command][$key][] = $tmp[0];
}
}
}
// 判断*/10 这种类型的
if ($every > 1) {
foreach ($raw[$command][$key] as $k => $v) {
if ($v % $every != 0) {
unset($raw[$command][$key][$k]);
}
}
}
}
}
return $raw;
}
/**
* 以守护进程模式执行命令
* @param $command
*/
public function runCommandBackground($command)
{
echo "执行";
echo $command;
system($command . ' &');
}
}