LoginSignup
46
53

More than 5 years have passed since last update.

PHPを利用して crontab や at にジョブを登録する

Posted at

php から cron や at にジョブを登録するための処理です。
基本的な処理と全体の流れを示すためにエラーチェックや入力値のチェック処理は示していませんが、実際にユーザから入力された情報を元に cron や at に登録する場合は入力値のチェック処理は必須です。

cron

/usr/bin/crontab - を実行してジョブを登録します。

実行頻度(frequency) に応じて以下の値が必須になります。

頻度 内容 必須項目
MONTH 毎月指定日に実行する $date, $time
WEEK 毎週指定曜日に実行する $dayofweek, $time
DAY 毎日指定時間に実行する $time

最近の crontab で利用できる @hourly 等のを使った文字列での指定や、 ',''-' を使った範囲指定、 '/' を利用した間隔の指定には対応していません。
実行時間の指定は必須です。

    /*
     * 毎月/毎週/毎日 実行されるコマンドを cron に登録する
     *
     * $date:       毎月実行を指定した場合に実行される日を指定
     * $time:       毎日実行を指定した場合に実行される時間を指定
     * $dayofweek:  毎週実行を指定した場合に実行される曜日を指定
     * $frequency:  実行の頻度 ("MONTH" | "WEEK" | "DAY")
     * $command:    実行するコマンド
     */

    /* cron への登録 */
    if(($cron = popen("/usr/bin/crontab -", "w"))){
        fputs($cron, _cronline($date, $time, $dayofweek, $frequency, $command));

        pclose($cron);
    }

    /* crontab に登録する行情報を生成 */
    function    _cronline($date, $time, $dayofweek, $frequency, $command)
    {

        $name = array(
            "MONTH" => array("day", $date),
            "WEEK" => array("dow", $dayofweek),
            "DAY" => array("dummy", null),
        );

        /* デフォルトは '*' */
        $day = $month = $dow = "*";

        /*
         * MONTH の場合は $day に $date を代入
         * WEEK の場合は $dow に $dayofweek を代入
         * DAY の場合は未使用なので $dummy とする
         */
        ${$name[$frequency][0]} = preg_replace("!.*/!", "", $name[$frequency][1]);
        list($hour, $min) = split(":", $time);

        return(sprintf("%s  %s  %s  %s  %s  %s\n",
            $min, $hour, $day, $month, $dow, $command));

    }

at

/usr/bin/at を実行してジョブを登録します。
実行する月日時間の指定が必須です。
正しく登録された場合にジョブ番号をリターンします。

    /*
     * 日時指定で1度だけ実行されるコマンドを at に登録する
     *
     * $hour:       実行する時を指定
     * $min:        実行する分を指定
     * $month:      実行する月を指定
     * $day:        実行する日を指定
     * $command:    実行するコマンド
     */

    $year = date("Y");              /* 年を取得 */
    $now = time() + 60;             /* 1分後を取得 (マージン) */
    if($now > mktime($hour, $min, 0, $month, $day))
        $year++;                    /* 過去の月日なら来年を仮定 */

    /* at に登録 */
    $job = _atline($year, $month, $day, $hour, $min, $command);

    /* at コマンドへの登録処理 */
    function    _atline($year, $month, $day, $hour, $min, $command)
    {

        /*
         * at コマンドでジョブを登録すると job 番号が取得できる。
         * 後に atrm する場合に job 番号が必要なために
         * proc_open() を利用して at(1) と双方向通信を行う
         */

        /* at コマンドの入出力用パイプ */
        $desc = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w"),
        );

        /* at コマンド実行 (at hhmm MMDDYYYY) */
        if(($proc = proc_open(sprintf("%s %02d%02d %02d%02d%04d",
                "/usr/bin/at", $hour, $min, $month, $day, $year), $desc, $pipe))){

            /* コマンド登録 */
            fputs($pipe[0], $command);
            fclose($pipe[0]);

            /* job 番号を STDERR から取得 */ 
            $buf = trim(fgets($pipe[2], 4096));
            fclose($pipe[2]);

            /* STDOUT close */
            fclose($pipe[1]);

            proc_close($proc);

            /* job 番号をリターン */
            return(preg_replace("/^job\s+(\d+).*$/", "$1", $buf));

        }
    }

46
53
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
53