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));
}
}