2016/08/17

php管理crontab


这段时间在为公司做一款手游的管理后台,在游戏数据统计方面,需要使用到 crontab 定时去触发php进行数据 统计。因为服务器有相关运维人员去维护的,所以每次需要增删改查定时器时都要麻烦到运维人员。基于以上情况, 我在管理后台开发了一个基于web去维护crontab的程序。


crontab预备知识

先来看下crontab给出的指令支持

crontab file [-u user]      #用指定的文件替代目前的crontab。
crontab - [-u user]         #用标准输入替代目前的crontab.
crontab -l [user]           #列出用户目前的crontab.
crontab -e [user]           #编辑用户目前的crontab.
crontab -d [user]           #删除用户目前的crontab.
crontab -c dir              #指定crontab的目录。

crontab -l会列出当前用户目前的crontab,但是它会全文列出,包括相关注释信息

root@ubuntu:~# crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command
* * * * * mkdir test

现在我们对crontab -l添加grep进行过滤,只匹配出已生效内容

root@ubuntu:~# crontab -l | grep ^[*1-9]
* * * * * mkdir test

编辑crontab内容,我们可以通过 crontab -e 执行文字编辑器来设定时程表,内定的文字编辑器是 vi。或者 可以通过标准输入crontab -来设定。例如

root@ubuntu:~# echo "* * * * * echo test" | crontab -
root@ubuntu:~#
root@ubuntu:~# crontab -l
* * * * * echo test

可以留意到,如果我们用标准输入把指令写入crontab,它会重置掉之前的所有内容。我们可以在写入前,先把之前 的指令全部读取出来,然后把新的指令拼接到最后,接着再写入。代码如下

#!/bin/bash
crontab_comm=`echo test`
oldCrontabList=`crontab -l`
newCrontabList=`echo "${oldCrontabList}"; echo "${crontab_comm}"`
echo "${newCrontabList}" | crontab -

同样道理,如果我们要做删除某条指令操作,我们只需要把内容读出,然后把匹配到指令那一行删除,接着通过标准 输入从新把指令写入即可。


php管理crontab

有了以上思路我们就可以通过 php+exec 对 crontab 进行增删改查。下面是核心的代码

<?php

class cron_mgr {

    // 解析crontab内容
    private function parse_crontab($crontab) {
        $data = array();
        foreach ($crontab as $cron) {
            $tmp = array();
            $slices = preg_split("/[\s]+/", $cron, 6);
            if (count($slices) !== 6) continue;
            $tmp['cmd'] = array_pop($slices);
            $cron_time = implode(' ', $slices);
            $tmp['cron'] = preg_split("/[\s]+/i",trim($cron_time));
            $tmp['cron_str'] = $cron;
            array_push($data, $tmp);
        }
        return $data;
    }

    // 读取生效的crontab指令
    private function get_crontab() {
        $retval = array();
        $last_line = exec('crontab -l | grep ^[*1-9]', $retval);
        return $retval;
    }

    // 读取crontab所有内容(包含注释)
    private function get_crontab2() {
        $retval = array();
        $last_line = exec('crontab -l', $retval);
        return $retval;
    }

    // 使用当前命令重置crontab
    private function recharge_crontab($cmds) {
        $cmds = implode("\n", $cmds);
        $query = 'echo "'.$cmds.'" | crontab -';
        $last_line = exec($query);
        if ($last_line === "") {
            return TRUE;
        }
    }

    // 在crontab底部添加新的指令
    private function add_crontab($cmds) {
        $crontab = $this->get_crontab2();
        $cmds = array_merge($crontab, $cmds);
        return $this->recharge_crontab($cmds);
    }
}

我这边管理后台效果图 /blog/img/php_cron_01.png