규도자 개발 블로그

PHP로 리눅스(linux) 크론(cronjob, crontab) 제어하기 본문

PHP/PHP

PHP로 리눅스(linux) 크론(cronjob, crontab) 제어하기

규도자 (gyudoza) 2018. 11. 10. 12:54

PHP로 리눅스(linux) 크론(cronjob, crontab) 제어하기

  • 2018-12-19
    • CentOS에서는 정상적으로 작동하였으나 우분투에서는 에러를 일으켜
      명령어가 좀 더 안정적인 것으로 변경됨. 자세한 변경내역 →깃허브

반복된 작업을 알아서 실행해주는 crontab. 로그를 쌓을 때나, 자동 갱신 시스템을 만들 때 등 은근히 많이 쓰이게 된다. 하지만 crontab을 수정할 때마다 항상 불편했는데... 보통 iptables나 dbms처럼 명령어를 통해 cronjob을 등록하고 삭제하는 등의 행동은 수행할 수가 없었다. 항상 crontab -e라는 명령어를 통해 텍스트에디터형식으로 열고 편집하고 저장하고 하는 식으로 작업했지.

 그게 불편해서 php에서 원하는 모든 cronjob행동을 제어할 수 있게 코드로 만들어봤다.

<?php
/*
 * @author     : this-programmer
 * @mail       : jujumilk3@gmail.com
 * @homepage   : https://this-programmer.tistory.com/
 * @version    : 1.0.0
 * @repository : https://github.com/jujumilk3/PHPCronManager
 */
class CronManager
{
    protected $version;
    protected $service_executor;
    public function __construct()
    {
        $this->version = '1.0.0';
        $this->service_executor = `whoami`;
    }
    
    
    /**
     * @breif : returns `crontab -l` result
     */
    public function get_crontab(): array
    {
        exec("crontab -l", $output, $exitcode);
        $result = false;
        if ($exitcode === 0) {
            $result = $output;
        }
        return $result;
    }//end of function get_crontab
    
    
    /**
     * @brief : only returns working cronjobs except for comment and blank
     */
    public function get_listed_cronjob(): array
    {
        exec("crontab -l", $output, $exitcode);
        $result = false;
        if ($exitcode === 0) {
            $result = [];
            foreach ($output as $cronjob_index => $cronjob) {
                if ($cronjob && (substr($cronjob, 0, 1) != '#')) {
                    $result[] = $cronjob;
                } else {
                    continue;
                }
            }
        }
        return $result;
    }//end of function get_listed_cronjob
    
    
    public function cron_duplication_checker($cron_tag): bool
    {
        $listed_cronjob = $this->get_listed_cronjob();
        $result = false;
        if ($listed_cronjob) {
            foreach ($listed_cronjob as $line => $cronjob) {
                $cron_duplication_check = strpos($cronjob, '#CRONTAG='.$cron_tag);
                if ($cron_duplication_check) {
                    $result = true;
                }
            }
        }
        return $result;
    }//end of function cron_duplication_checker
    
    
    public function add_cronjob($command, $cron_tag): array
    {
        $result = array(
            'status' => 'status',
            'msg'    => 'msg',
            'data'   => 'data'
        );
        $cron_duplication_check = $this->cron_duplication_checker($cron_tag);
        $managed_command = 'echo -e "`crontab -l`\n'.$command.' #CRONTAG='.$cron_tag.'" | crontab -';
        if (!$cron_tag) {
            $result['status'] = 'INPUT_ERROR';
            $result['msg'] = 'cron_tag is required';
            $result['data'] = $managed_command;
        } else if ($cron_duplication_check) {
            $result['status'] = 'FAILED';
            $result['msg'] = 'duplicated cron tag exists';
            $result['data'] = $cron_duplication_check;
        } else {
            exec($managed_command, $output, $exitcode);
            $result['data'] = array(
                'cron_add_output'   => $output,
                'cron_add_exitcode' => $exitcode,
                'managed_command'   => $managed_command
            );
            if ($exitcode === 0) {
                $result['status'] = 'SUCCESS';
                $result['msg'] = 'added new cronjob';
            } else if ($exitcode === 127) {
                $result['status'] = 'ERROR';
                $result['msg'] = 'crond is not running or not installed';
            } else {
                $result['status'] = 'ERROR';
                $result['msg'] = 'error occurred in progress to register new cron job';
            }
        }
        return $result;
    }//end of function add_cronjob
    
    
    public function remove_cronjob($cron_tag): bool
    {
        $cron_duplication_check = $this->cron_duplication_checker($cron_tag);
        $result = false;
        if ($cron_duplication_check) {
            exec("crontab -l | sed '/\(.*#CRONTAG=$cron_tag\)/d' | crontab ", $output, $exit_code);
            if ($exit_code === 0) {
                $result = true;
            }
        }
        return $result;
    }//end of remove_cronjob
    
    
}//end of class CronManager

깃허브에도 등록해놨다. 레포에도 써있다시피 위험한 커맨드에 대한 처리는 안돼있으니(e.g : rm -rf [somethings], halt, reboot, shutdown등등) 알아서 잘 써야 한다... 최대한 심플한 상태로 유지시키기 위해 이런 식으로 작성하였고 #CRONTAG라는, cronjob 맨 뒤에 붙는 주석형식의 태그를 이용하여 관리하기 쉽게 하였다.

 어디든 막 갖다 써도 되고 퍼가도 되지만 해당 코드를 사용함으로서 생긴 문제는 책임지지 않는다... 새로운 아이디어나 개선사항 모두 환영하는 바이다. 자세한 사용법은 깃허브를 참조하면 된다!

Comments