利用Python和Thinkphp模仿Linux Crontab运行任务

本文介绍了如何在PHP中利用Crontab的格式解析类来检测定时任务,并结合Thinkphp框架,实现类似Linux Crontab的定时任务执行。文中详细讲解了一个Crontab时间格式解析类的实现,以及如何在任务调度时检查当前时间是否符合执行条件。此外,还提到了通过Thinkphp生成URL接口供Python定时调用,从而达到定时运行后台任务的目的,例如生成考勤系统的统计报表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux中是利用Crontab来执行系统定时任务,如:

*    *    *    *    *
-    -    -    -    -
|    |    |    |    |
|    |    |    |    +----- 星期中星期几 (0 - 6) (星期天 为0)
|    |    |    +---------- 月份 (1 - 12) 
|    |    +--------------- 一个月中的第几天 (1 - 31)
|    +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59)

我们在开发系统的时候,也需要像Linux一样的定时脚本来方便后台执行我们的程序,如生成统计、汇总报表等等。
例我们在开发考勤系统的时候,就需要每天运行任务脚本来执行任务,生成每月每日报表,下面,我们就来利用Thinkphp和Python开发一个定时任务。
首先,需要一个任务时间检测判断类,来检测当前时间是否有任务可以运行:

<?php
/**
 * crontab 时间格式php解析类(PHP 5 >= 5.1.0)
 * Author: http://www.daytime.cc
 * Linux Crontab格式时间判断
 */
namespace Tasks;

class Crontab {

	public $error = '';

	public function __construct(){
	}

    /**
     * 检查某时间($time)是否符合某个corntab时间计划($str_cron)
     *
     * @param int    $time     时间戳
     * @param string $str_cron corntab的时间计划,如,"30 2 * * 1-5"
     *
     * @return bool/string 出错返回string(错误信息)
     */
    public function check($time, $str_cron) {
        $format_time = $this->format_timestamp($time);
        $format_cron = $this->format_crontab($str_cron);
        if (!is_array($format_cron)) {
            return $format_cron;
        }
        return $this->format_check($format_time, $format_cron);
    }

    /**
     * 使用格式化的数据检查某时间($format_time)是否符合某个corntab时间计划($format_cron)
     *
     * @param array $format_time $this->format_timestamp()格式化时间戳得到
     * @param array $format_cron $this->format_crontab()格式化的时间计划
     *
     * @return bool
     */
    private function format_check(array $format_time, array $format_cron) {
        return (!$format_cron[0] || in_array($format_time[0], $format_cron[0]))
            && (!$format_cron[1] || in_array($format_time[1], $format_cron[1]))
            && (!$format_cron[2] || in_array($format_time[2], $format_cron[2]))
            && (!$format_cron[3] || in_array($format_time[3], $format_cron[3]))
            && (!$format_cron[4] || in_array($format_time[4], $format_cron[4]))
        ;
    }

    /**
     * 格式化时间戳,以便比较
     *
     * @param int $time 时间戳
     *
     * @return array
     */
    private function format_timestamp($time) {
        return explode('-', date('i-G-j-n-w', $time));
    }

    /**
     * 格式化crontab时间设置字符串,用于比较
     *
     * @param string $str_cron crontab的时间计划字符串,如"15 3 * * *"
     *
     * @return array/string 正确返回数组,出错返回字符串(错误信息)
     */
    private function format_crontab($str_cron) {
        //格式检查
        $str_cron = trim($str_cron);
        $reg = '#^((\*(/\d+)?|((\d+(-\d+)?)(?3)?)(,(?4))*))( (?2)){4}$#';
        if (!preg_match($reg, $str_cron)) {
			$this->error = '格式错误';
            return false;
        }

        try{
            //分别解析分、时、日、月、周
            $arr_cron = array();
            $parts = explode(' ', $str_cron);
            $arr_cron[0] = $this->parse_cron_part($parts[0], 0, 59);//分
            $arr_cron[1] = $this->parse_cron_part($parts[1], 0, 59);//时
            $arr_cron[2] = $this->parse_cron_part($parts[2], 1, 31);//日
            $arr_cron[3] = $this->parse_cron_part($parts[3], 1, 12);//月
            $arr_cron[4] = $this->parse_cron_part($parts[4], 0, 6);//周(0周日)
        } catch (Exception $e) {
			$this->error = $e->getMessage();
            return false;
        }

        return $arr_cron;
    }

    /**
     * 解析crontab时间计划里一个部分(分、时、日、月、周)的取值列表
     * @param string $part  时间计划里的一个部分,被空格分隔后的一个部分
     * @param int    $f_min 此部分的最小取值
     * @param int    $f_max 此部分的最大取值
     *
     * @return array 若为空数组则表示可任意取值
     * @throws Exception
     */
    private function parse_cron_part($part, $f_min, $f_max) {
        $list = array();

        //处理"," -- 列表
        if (false !== strpos($part, ',')) {
            $arr = explode(',', $part);
            foreach ($arr as $v) {
                $tmp  = $this->parse_cron_part($v, $f_min, $f_max);
                $list = array_merge($list, $tmp);
            }
            return $list;
        }

        //处理"/" -- 间隔
        $tmp  = explode('/', $part);
        $part  = $tmp[0];
        $step = isset($tmp[1]) ? $tmp[1] : 1;

        //处理"-" -- 范围
        if (false !== strpos($part, '-')) {
            list($min, $max) = explode('-', $part);
            if ($min > $max) {
				$this->error = '使用"-"设置范围时,左不能大于右';
				return false;
            }
        } elseif ('*' == $part) {
            $min = $f_min;
            $max = $f_max;
        } else {//数字
            $min = $max = $part;
        }

        //空数组表示可以任意值
        if ($min==$f_min && $max==$f_max && $step==1) {
            return $list;
        }

        //越界判断
        if ($min < $f_min || $max > $f_max) {
			$this->error = '数值越界。应该:分0-59,时0-59,日1-31,月1-12,周0-6';
			return false;
        }

        return $max-$min>$step ? range($min, $max, $step) : array((int)$min);
    }
}

然后在执行任务时,通过调用类检测当前任务是否可以运行:

			$crontab = new Crontab();
			$tasktime = time();
			foreach($tasks as $task){
				if($crontab->check($tasktime, $task['runtime'])){
					// 执行任务内容
				}
			}

最后,我们通过Thinkphp生成一个URL接口供Python定时调用,如每隔一分钟或10秒钟调用一次接口
如:http://www.daytime.cc/tasks/pytask/run?taskid=任务ID
到此,大功告成,你也可以像Linux Crontab一样优雅地运行系统任务了。
最终效果如下图所示:
在这里插入图片描述

THE END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值