├── composer.json ├── README.md └── src └── Crontab └── Crontab.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egersdorfer/crontab", 3 | "type": "library", 4 | "description": "PHP Cronjob manager", 5 | "keywords": ["crontab", "cronjob", "cron"], 6 | "homepage": "https://github.com/codeChap/crontab", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Derrick Egersdorfer", 11 | "email": "derrick@egersdorfer.co.za", 12 | "role": "Developer" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3.0" 17 | }, 18 | "autoload": { 19 | "psr-0": {"Crontab": "src/"} 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Crontab 2 | ======= 3 | 4 | Simple, independant and local PHP Crontab package 5 | 6 | The package helps you manage your local cron jobs using PHP. You can list, append and remove your jobs and set your log file. 7 | 8 | ## Requirements 9 | Should work on monst Linux flavoured systems. 10 | 11 | ## Usage Example 12 | Use [composer](http://getcomposer.org) to install it or simply include the file somewhere: require("crontab/src/Crontab/Crontab.php"); 13 | 14 | Append two new jobs and set them to run every minute: 15 | 16 | ```php 17 | $cron = new \Crontab\Crontab(); 18 | $cron->setMinute("*"); 19 | $cron->setHour("*"); 20 | $cron->setDayOfMonth("*"); 21 | $cron->setMonth("*"); 22 | $cron->setDayOfWeek("*"); 23 | $cron->append(array( 24 | "date", 25 | "ls -all" 26 | ) 27 | ); 28 | $commandsList = $cron->execute(); 29 | ``` 30 | 31 | ## Methods 32 | 33 | #### append($command) 34 | 35 | Appends a new job to the current cronjob list 36 | 37 | Parameters: $command : String or array of commands. 38 | 39 | ```php 40 | $cron = new \Crontab\Crontab(); 41 | $cron->setMinute("*"); 42 | $cron->setHour("*"); 43 | $cron->setDayOfMonth("*"); 44 | $cron->setMonth("*"); 45 | $cron->setDayOfWeek("*"); 46 | $cron->append("date"); 47 | $cron->execute(); 48 | ``` 49 | 50 | #### remove($command) 51 | 52 | Removes a job from the current cronjob list. You must recreate the exact job to remove it. 53 | 54 | Parameters: $command : String or array of commands 55 | 56 | ```php 57 | $cron = new \Crontab\Crontab(); 58 | $cron->setMinute("*"); 59 | $cron->setHour("*"); 60 | $cron->setDayOfMonth("*"); 61 | $cron->setMonth("*"); 62 | $cron->setDayOfWeek("*"); 63 | $cron->remove("date"); 64 | $cron->execute(); 65 | ``` 66 | 67 | #### getJobs() 68 | Return a current list of jobs with there hashed keys 69 | 70 | ```php 71 | $cron = new \Crontab\Crontab(); 72 | $cron->setMinute("*"); 73 | $cron->setHour("*"); 74 | $cron->setDayOfMonth("*"); 75 | $cron->setMonth("*"); 76 | $cron->setDayOfWeek("*"); 77 | $cron->remove("date"); 78 | $cron->execute(); 79 | ``` 80 | 81 | #### removeByKey($key) 82 | 83 | Removes a job from the current cronjob list by a hash key. Found by running execute() or getJobs() 84 | 85 | Parameters: $key : String or array of keys 86 | 87 | ```php 88 | $cron = new \Crontab\Crontab(); 89 | $cron->removeByKey("1231231231231231231"); 90 | $cron->execute(); 91 | ``` 92 | 93 | #### execute() 94 | Applies and writes the new cronjob list. 95 | ```php 96 | $cron->setMinute("*"); 97 | $cron->setHour("*"); 98 | $cron->setDayOfMonth("*"); 99 | $cron->setMonth("*"); 100 | $cron->setDayOfWeek("*"); 101 | $cron->append("date"); 102 | $cron->execute(); 103 | ``` 104 | 105 | #### clear() 106 | Simply removes all running jobs by executing crontab -r 107 | ``` 108 | $cron = new \Crontab\Crontab(); 109 | $cron->clear(); 110 | ``` 111 | 112 | ## Settings 113 | Settings can also be applied to the constuct method like so: 114 | ```php 115 | $conf = array( 116 | 'minute' => '*', 117 | 'hour' => '*', 118 | 'dayOfMonth' => '*', 119 | 'month' => '*', 120 | 'dayOfWeek' => '*', 121 | 'logFile' => 'log.txt', 122 | 'tmpFile' => 'jobs.txt' 123 | ); 124 | 125 | $cron = new \Crontab\Crontab($conf); 126 | ``` 127 | 128 | ### Setting functions (Defaults are all "*" here) 129 | ``` 130 | setMinute($m) : Sets the minute. 131 | setHour($h) : Sets the hour. 132 | setDayOfMonth($dom) : Sets the date of the month. 133 | setMonth($m) : Sets the month. 134 | setDayOfWeek($dow) : Sets the day of the week. 135 | ``` 136 | 137 | ### Log and tempory file settings 138 | ``` 139 | setLogFile($v) : Sets the log file and will attempt to create it. The default is /dev/null ie: nothing logged 140 | setTmpFile($v) : Sets the tempory file used by crontab to read from, this file is automatically removed. The default is "jobs.txt" 141 | ``` 142 | 143 | ## Helpers 144 | Execute this job in 5 minutes from now. 145 | ```php 146 | $cron = new \Crontab\Crontab(); 147 | $cron->minuteFromNow(5); 148 | $cron->execute(); 149 | ``` 150 | 151 | ## Help understanding cronjobs 152 | A Google search should provied plenty of links but check out: [Kevin van Zonneveld's blog](http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/) if you need help. 153 | 154 | ## Todo 155 | 156 | - Email instead of log or both. 157 | - Build in more heler functions. 158 | - Unit tests 159 | 160 | ## Disclaimer 161 | Use this library at your own risk. 162 | -------------------------------------------------------------------------------- /src/Crontab/Crontab.php: -------------------------------------------------------------------------------- 1 | &1"; // Log nothing by default 26 | 27 | public function __construct(array $config = array()) 28 | { 29 | // Get all variables of this class 30 | $params = array_keys( get_class_vars( get_called_class() ) ); 31 | 32 | // Loop and set config values 33 | foreach( $params as $key ){ 34 | if(array_key_exists($key, $config)){ 35 | if( ! call_user_func(array($this, 'set'.ucFirst(strtolower($key))), $config[$key])){ 36 | throw new \Exception("Could not set $key to " . $config[$key] . ": " . implode($this->error) ); 37 | } 38 | } 39 | } 40 | 41 | // Done 42 | return true; 43 | } 44 | 45 | 46 | 47 | public function setMinute($data) 48 | { 49 | $this->minute = $data; 50 | } 51 | 52 | public function setHour($data) 53 | { 54 | $this->hour = $data; 55 | } 56 | 57 | public function setDayOfMonth($data) 58 | { 59 | $this->dayOfMonth = $data; 60 | } 61 | 62 | public function setMonth($data) 63 | { 64 | $this->month = $data; 65 | } 66 | 67 | public function setDayOfWeek($data) 68 | { 69 | $this->dayOfWeek = $data; 70 | } 71 | 72 | public function setTempFile($data) 73 | { 74 | // Check for the file and attempt to create it 75 | if( ! file_exists($data)){ 76 | 77 | if($fh = fopen($data, 'a')){ 78 | fclose($fh); 79 | $this->tempFile = $data; 80 | return true; 81 | } else { 82 | throw new \Exception("Could not create temp file: $data"); 83 | } 84 | } 85 | 86 | // Ok 87 | $this->tempFile = $data; 88 | return true; 89 | } 90 | 91 | public function setLogFile($data) 92 | { 93 | // Check for the file and attempt to create it 94 | if( ! file_exists($data)){ 95 | 96 | if($fh = fopen($data, 'a')){ 97 | fclose($fh); 98 | $this->logFile = $data; 99 | return true; 100 | } else { 101 | throw new \Exception("Could not create log file: $data"); 102 | } 103 | } 104 | 105 | // Ok 106 | $this->logFile = $data; 107 | return true; 108 | } 109 | 110 | 111 | 112 | /** 113 | * Helper function to execute so many minutes from now 114 | */ 115 | public function minuteFromNow($min = 1) 116 | { 117 | $time = strtotime("+$min minute"); 118 | $this->setMinute(date('i', $time)); 119 | $this->setHour(date('H', $time)); 120 | $this->setDayOfMonth(date('j', $time)); 121 | $this->setMonth(date('n', $time)); 122 | $this->setDayOfWeek(date('w', $time)); 123 | } 124 | 125 | 126 | 127 | 128 | /** 129 | * Ads a cronjob command to the system 130 | * @param array 131 | */ 132 | public function append($command) 133 | { 134 | // Convert to array 135 | $command = is_string($command) ? array($command) : $command; 136 | 137 | // Build cron command lines 138 | foreach($command as $k => $v){ 139 | $cmds[] = $this->buildCommandLine($v); 140 | } 141 | 142 | // Get currently set jobs and append new jobs 143 | $jobs = $this->buildExistingJobsArray($cmds); 144 | 145 | // Update Jobs 146 | $this->update = $jobs; 147 | } 148 | 149 | /** 150 | * Removes a cronjob command from the system 151 | * @param commands to remove 152 | */ 153 | public function remove($command) 154 | { 155 | // Convert to array 156 | $command = is_string($command) ? array($command) : $command; 157 | 158 | // Build cron command lines 159 | foreach($command as $k => $v){ 160 | $cmds[] = $this->buildCommandLine($v); 161 | } 162 | 163 | // Get existing jobs 164 | $jobs = array_flip($this->buildExistingJobsArray()); 165 | 166 | // Loop to find and remove jobs 167 | foreach($cmds as $k => $v){ 168 | if(array_key_exists($v, $jobs)){ 169 | unset($jobs[$v]); 170 | } 171 | } 172 | 173 | // Flip back and ready to rewrite the new cronjob file 174 | $jobs = array_flip($jobs); 175 | 176 | // Update Jobs 177 | $this->update = $jobs; 178 | } 179 | 180 | /** 181 | * Removes a cronjob command from the system by its unique hash 182 | * @param key hashs to remove 183 | */ 184 | public function removeByKey($hash) 185 | { 186 | // Convert to array 187 | $hash = is_string($hash) ? array($hash) : $hash; 188 | 189 | // Get existing jobs 190 | $jobs = $this->buildExistingJobsArray(); 191 | 192 | // Loop to find and remove jobs 193 | foreach($hash as $k => $v){ 194 | if(array_key_exists($v, $jobs)){ 195 | unset($jobs[$v]); 196 | } 197 | } 198 | 199 | // Update Jobs 200 | $this->update = $jobs; 201 | } 202 | 203 | /** 204 | * Returns an array of running jobs 205 | */ 206 | public function getJobs() 207 | { 208 | return $this->buildExistingJobsArray(); 209 | } 210 | 211 | /** 212 | * Removes all cronjobs 213 | */ 214 | public function clear() 215 | { 216 | exec("crontab -r"); 217 | } 218 | 219 | /** 220 | * Update the systems contab file with 221 | * @param jobs array 222 | * @return array of current cron jobs 223 | */ 224 | public function execute() 225 | { 226 | // Write the new cronjob data 227 | $this->writeTmpCronFile($this->update); 228 | 229 | // Set cron to temp cronfile 230 | exec("crontab " . $this->tempFile, $output, $status); 231 | //exec("crontab " . $this->tempFile . " 2>&1 >> log.txt", $output, $status); 232 | 233 | if(count($output) > 0){ 234 | print_r($output); 235 | } 236 | 237 | // Return list of current jobs 238 | return $this->update; 239 | } 240 | 241 | /** 242 | * Builds a single command line entry for the contab temp file 243 | * @param string 244 | * @return string 245 | */ 246 | private function buildCommandLine($command) 247 | { 248 | // Build command line time 249 | $time = array( 250 | $this->minute, 251 | $this->hour, 252 | $this->dayOfMonth, 253 | $this->month, 254 | $this->dayOfWeek 255 | ); 256 | $line = implode(" ", $time) . " " . trim($command) . " > " . $this->logFile . " 2>&1"; 257 | 258 | // Check the command 259 | if( preg_match("/".$this->buildRegexp()."/", $line) !== 0 ){ 260 | return $line; 261 | } 262 | 263 | // Exit if no good. 264 | throw new \Exception("$line is not a valid command"); 265 | } 266 | 267 | /** 268 | * Builds an array of active cronjob command on the system 269 | * @param string of a new command 270 | * @return array 271 | */ 272 | private function buildExistingJobsArray($append = false) 273 | { 274 | // Existing jobs 275 | exec("crontab -l ", $output, $status); 276 | 277 | // Clean up contab array just incase 278 | if(count($output) > 0){ 279 | foreach($output as $k => $v){ 280 | $array[md5($v)] = trim($v); 281 | } 282 | } 283 | 284 | // Append new jobs 285 | if($append){ 286 | 287 | // Convert to array if need be 288 | $append = is_string($append) ? array($append) : $append; 289 | 290 | // Append to exisiting array or new array 291 | foreach($append as $k => $v){ 292 | $array[md5($v)] = trim($v); 293 | } 294 | } 295 | 296 | // Done 297 | return isset($array) ? array_unique($array) : array(); 298 | } 299 | 300 | /** 301 | * Writes a temp file for the crontab program to read 302 | * @param $content = new command 303 | * @return boolean 304 | */ 305 | private function writeTmpCronFile($content) 306 | { 307 | // Convert to array 308 | $content = is_string($content) ? array($content) : $content; 309 | 310 | // Set string 311 | $string = null; 312 | 313 | // Cleanup content if array 314 | if( ! empty($content)){ 315 | foreach($content as $k => $v){ 316 | $string[] = trim($v); 317 | } 318 | $string = implode(PHP_EOL, $string).PHP_EOL; 319 | } 320 | 321 | // Set temp file 322 | $filename = $this->tempFile; 323 | 324 | // Open the temp file 325 | if ( ! $handle = fopen($filename, 'w')) { 326 | throw new \Exception("Cannot open $filename"); 327 | exit; 328 | } 329 | 330 | // And write in content 331 | if (fwrite($handle, $string) === FALSE) { 332 | throw new \Exception("Cannot write to $filename"); 333 | exit; 334 | } 335 | 336 | // Done 337 | fclose($handle); 338 | return true; 339 | } 340 | 341 | /** 342 | * Builds a regular expression to check the cronjob 343 | * Thanks to Jordi Salvat 344 | */ 345 | private function buildRegexp() 346 | { 347 | $numbers= array( 348 | 'min'=>'[0-5]?\d', 349 | 'hour'=>'[01]?\d|2[0-3]', 350 | 'day'=>'0?[1-9]|[12]\d|3[01]', 351 | 'month'=>'[1-9]|1[012]', 352 | 'dow'=>'[0-7]' 353 | ); 354 | 355 | foreach($numbers as $field=>$number) { 356 | $range= "($number)(-($number)(\/\d+)?)?"; 357 | $field_re[$field]= "\*(\/\d+)?|$range(,$range)*"; 358 | } 359 | 360 | $field_re['month'].='|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec'; 361 | $field_re['dow'].='|mon|tue|wed|thu|fri|sat|sun'; 362 | 363 | $fields_re= '('.join(')\s+(', $field_re).')'; 364 | 365 | $replacements= '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly'; 366 | 367 | return '^\s*('. 368 | '$'. 369 | '|#'. 370 | '|\w+\s*='. 371 | "|$fields_re\s+\S". 372 | "|($replacements)\s+\S". 373 | ')'; 374 | } 375 | 376 | /** 377 | * Clean up 378 | */ 379 | public function __destruct() 380 | { 381 | if(file_exists($this->tempFile)){ 382 | exec("rm " . $this->tempFile); 383 | } 384 | } 385 | } --------------------------------------------------------------------------------