117

Is it possible to use PHP to create, edit and delete crontab jobs?

I know how to list the current crontab jobs of the Apache user:

$output = shell_exec('crontab -l');
echo $output;

But how to add a cron job with PHP? 'crontab -e' would just open a text editor and you will have to manually edit the entries before saving the file.

And how to delete a cron job with PHP? Again you have to manually do this by 'crontab -e'.

With a job string like this:

$job = '0 */2 * * * /usr/bin/php5 /home/user1/work.php';

How do I add it to the crontab jobs list with PHP?

datasn.io
  • 11,652
  • 27
  • 102
  • 142
  • 2
    possible duplicate of [Cron jobs using php](http://stackoverflow.com/questions/2264756/cron-jobs-using-php) and a [couple others](http://stackoverflow.com/search?q=cron+php) – Gordon Dec 12 '10 at 09:42
  • 14
    *(hint)* the crontab is just a *file* – Gordon Dec 12 '10 at 09:46
  • 1
    @Gordon, thanks. I know everything is a file but are they storing crontab jobs at the same path across different distros? Plus it would need to get the user of Apache, such as www-data, and have the privileges of root? – datasn.io Dec 12 '10 at 11:09
  • 1
    I'm not sure if the path changes across distros, but you're doing good to make the path a configurable value in your code and set it at runtime then. As for the user and permissions: every user can have a crontab that runs jobs with the rights assigned to that user, so this is individual for your system setup. – Gordon Dec 12 '10 at 12:13
  • Also see http://stackoverflow.com/q/3186471/632951 – Pacerier Feb 03 '15 at 16:28
  • Try [yzalis/crontab](https://packagist.org/packages/yzalis/crontab) – Jeff Puckett Nov 10 '16 at 21:07

12 Answers12

136

crontab command usage

usage:  crontab [-u user] file
        crontab [-u user] [ -e | -l | -r ]
                (default operation is replace, per 1003.2)
        -e      (edit user's crontab)
        -l      (list user's crontab)
        -r      (delete user's crontab)
        -i      (prompt before deleting user's crontab)

So,

$output = shell_exec('crontab -l');
file_put_contents('/tmp/crontab.txt', $output.'* * * * * NEW_CRON'.PHP_EOL);
echo exec('crontab /tmp/crontab.txt');

The above can be used for both create and edit/append provided the user has the adequate file write permission.

To delete jobs:

echo exec('crontab -r');

Also, take note that apache is running as a particular user and that's usually not root, which means the cron jobs can only be changed for the apache user unless given crontab -u privilege to the apache user.

ajreal
  • 44,929
  • 10
  • 81
  • 118
  • 4
    Wouldn't 'crontab -r' delete all the jobs of the user? Is there any way to delete a specific line of job in the crontabs of the user? Loading, searching and then deleting the found line seems to be the only way. – datasn.io Dec 12 '10 at 11:26
  • 3
    You can use pipes instead of writing a temporary file – realmfoo Feb 03 '12 at 08:34
  • 7
    Nice solution but `shell_exec('crontab -l')` will only return the last line. I used `exec('crontab -l', $output)`. Then implode the $output array into a string (with \n as the glue). – David Fairbanks Dec 23 '12 at 01:35
  • @ajreal, I +1ed your comment as a happy DO newcomer myself :) but then I realized that not everybody wants to work as (or hire) a sysadmin in addition to his normal dev. tasks. – Sz. May 17 '14 at 19:46
  • 1
    @Rahul if server providers didn't provide shell commands like `system()`, `passthru()` , `shell_exec()` and `exec()`, try using the control panel that comes with the hosting, such as cPanel or Plesk. – Raptor Jul 10 '14 at 03:15
  • 3
    this will keep on appending the same job each time in a file. (checked) is there a way to remove the matching jobs first then write a new one? – R T Dec 17 '14 at 08:03
  • exec functions are evil, most of the time you do not want them running in your webserver – Crasher Dec 05 '17 at 19:52
  • Also this solution does not work, as stated above it doesn't append the existing content. – Crasher Dec 12 '17 at 04:00
20

We recently prepared a mini project (PHP>=5.3) to manage the cron files for private and individual tasks. This tool connects and manages the cron files so you can use them, for example per project. Unit Tests available :-)

Sample from command line:

bin/cronman --enable /var/www/myproject/.cronfile --user www-data

Sample from API:

use php\manager\crontab\CrontabManager;

$crontab = new CrontabManager();
$crontab->enableOrUpdate('/tmp/my/crontab.txt');
$crontab->save();

Managing individual tasks from API:

use php\manager\crontab\CrontabManager;

$crontab = new CrontabManager();
$job = $crontab->newJob();
$job->on('* * * * *');
$job->onMinute('20-30')->doJob("echo foo");
$crontab->add($job);
$job->onMinute('35-40')->doJob("echo bar");
$crontab->add($job);
$crontab->save();

github: php-crontab-manager

svarog
  • 8,471
  • 4
  • 55
  • 66
Chris Suszyński
  • 1,318
  • 14
  • 21
  • Nice. This will certainly come in handy... assuming it actually works :) – Baraka Apr 19 '12 at 06:11
  • @Pacerier this project seems dead and has some issues. Try [yzalis/crontab](https://packagist.org/packages/yzalis/crontab) which is more active. – Jeff Puckett Nov 10 '16 at 21:07
10

Check a cronjob

function cronjob_exists($command){

    $cronjob_exists=false;

    exec('crontab -l', $crontab);


    if(isset($crontab)&&is_array($crontab)){

        $crontab = array_flip($crontab);

        if(isset($crontab[$command])){

            $cronjob_exists=true;

        }

    }
    return $cronjob_exists;
}

Append a cronjob

function append_cronjob($command){

    if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){

        //add job to crontab
        exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);


    }

    return $output;
}

Remove a crontab

exec('crontab -r', $crontab);

Example

exec('crontab -r', $crontab);

append_cronjob('* * * * * curl -s http://localhost/cron/test1.php');

append_cronjob('* * * * * curl -s http://localhost/cron/test2.php');

append_cronjob('* * * * * curl -s http://localhost/cron/test3.php');
RafaSashi
  • 14,170
  • 8
  • 71
  • 85
  • function append_cronjob doesn't work for me. I get the output '-' does not exist: Array ( [0] => '-' does not exist. [1] => usage: crontab file [2] => crontab [ -e | -l | -r ] [3] => -e (edit user's crontab) [4] => -l (list user's crontab) [5] => -r (delete user's crontab) ) – user1307016 Jan 05 '15 at 12:42
  • exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output); is it correct. I am getting no crontab for www-data "-":0: bad minute errors in crontab file, can't install. – Rahul Tailwal Jan 31 '15 at 04:52
  • Crontab delimits jobs with line breaks (newlines). Each job occupies one line. Therefore, if crontab sees anything other than an integer in the first column of a line, it throws the “bad minute” error, since the minute argument is the first one crontab encounters. check this out https://www.dougv.com/2006/12/fixing-a-bad-minute-error-message-when-trying-to-use-crontab-with-certain-unix-text-editors/ – RafaSashi Jan 31 '15 at 07:39
  • thanks... how can i use cron_TZ using your project ?? – Salem Ahmed May 09 '17 at 06:01
5

This should do it

shell_exec("crontab -l | { cat; echo '*/1    *    *    *    *    command'; } |crontab -");
Fred
  • 51
  • 1
  • 1
5

I tried the solution below

class Crontab {

// In this class, array instead of string would be the standard input / output format.

// Legacy way to add a job:
// $output = shell_exec('(crontab -l; echo "'.$job.'") | crontab -');

static private function stringToArray($jobs = '') {
    $array = explode("\r\n", trim($jobs)); // trim() gets rid of the last \r\n
    foreach ($array as $key => $item) {
        if ($item == '') {
            unset($array[$key]);
        }
    }
    return $array;
}

static private function arrayToString($jobs = array()) {
    $string = implode("\r\n", $jobs);
    return $string;
}

static public function getJobs() {
    $output = shell_exec('crontab -l');
    return self::stringToArray($output);
}

static public function saveJobs($jobs = array()) {
    $output = shell_exec('echo "'.self::arrayToString($jobs).'" | crontab -');
    return $output; 
}

static public function doesJobExist($job = '') {
    $jobs = self::getJobs();
    if (in_array($job, $jobs)) {
        return true;
    } else {
        return false;
    }
}

static public function addJob($job = '') {
    if (self::doesJobExist($job)) {
        return false;
    } else {
        $jobs = self::getJobs();
        $jobs[] = $job;
        return self::saveJobs($jobs);
    }
}

static public function removeJob($job = '') {
    if (self::doesJobExist($job)) {
        $jobs = self::getJobs();
        unset($jobs[array_search($job, $jobs)]);
        return self::saveJobs($jobs);
    } else {
        return false;
    }
}

}

credits to : Crontab Class to Add, Edit and Remove Cron Jobs

Sam Arul Raj T
  • 1,652
  • 16
  • 20
4

You could try overriding the EDITOR environment variable with something like ed which can take a sequence of edit commands over standard input.

Alnitak
  • 313,276
  • 69
  • 379
  • 466
3

Nice...
Try this to remove an specific cron job (tested).

<?php $output = shell_exec('crontab -l'); ?>
<?php $cron_file = "/tmp/crontab.txt"; ?>

<!-- Execute script when form is submitted -->
<?php if(isset($_POST['add_cron'])) { ?>

<!-- Add new cron job -->
<?php if(!empty($_POST['add_cron'])) { ?>
<?php file_put_contents($cron_file, $output.$_POST['add_cron'].PHP_EOL); ?>
<?php } ?>

<!-- Remove cron job -->
<?php if(!empty($_POST['remove_cron'])) { ?>
<?php $remove_cron = str_replace($_POST['remove_cron']."\n", "", $output); ?>
<?php file_put_contents($cron_file, $remove_cron.PHP_EOL); ?>
<?php } ?>

<!-- Remove all cron jobs -->
<?php if(isset($_POST['remove_all_cron'])) { ?>
<?php echo exec("crontab -r"); ?>
<?php } else { ?>
<?php echo exec("crontab $cron_file"); ?>
<?php } ?>

<!-- Reload page to get updated cron jobs -->
<?php $uri = $_SERVER['REQUEST_URI']; ?>
<?php header("Location: $uri"); ?>
<?php exit; ?>
<?php } ?>

<b>Current Cron Jobs:</b><br>
<?php echo nl2br($output); ?>

<h2>Add or Remove Cron Job</h2>
<form method="post" action="<?php $_SERVER['REQUEST_URI']; ?>">
<b>Add New Cron Job:</b><br>
<input type="text" name="add_cron" size="100" placeholder="e.g.: * * * * * /usr/local/bin/php -q /home/username/public_html/my_cron.php"><br>
<b>Remove Cron Job:</b><br>
<input type="text" name="remove_cron" size="100" placeholder="e.g.: * * * * * /usr/local/bin/php -q /home/username/public_html/my_cron.php"><br>
<input type="checkbox" name="remove_all_cron" value="1"> Remove all cron jobs?<br>
<input type="submit"><br>
</form>
Ajie Kurniyawan
  • 383
  • 2
  • 17
  • Remember to add `exit;` after `header('Location: ...');`. Also, this form is actually quite dangerous, as it can add cron job to "destroy" the server. – Raptor Jul 10 '14 at 02:51
  • 1
    Note for beginners: We do not actually wrap every line of PHP in PHP tags. One at the beginning of PHP and optionally one at the end will suffice. – ekerner Jun 03 '15 at 16:43
3

Depends where you store your crontab:

shell_exec('echo "'. $job .'" >> crontab');
thedom
  • 2,478
  • 18
  • 26
3

You can put your file to /etc/cron.d/ in cron format. Add some unique prefix to the filenaname To list script-specific cron jobs simply work with a list of files with a unique prefix. Delete the file when you want to disable the job.

  • I like this solution better because it avoids manipulating the entire cron file and is easy to remove vs having to add and remove a specific cron task on a huge cron file. – Jovanni G Feb 21 '18 at 04:43
0

The easiest way is to use the shell_exec command to execute a bash script, passing in the values as parameters. From there, you can manipulate crontabs like you would in any other non-interactive script, and also ensure that you have the correct permissions by using sudo etc.

See this, Crontab without crontab -e, for more info.

Community
  • 1
  • 1
Codemwnci
  • 51,224
  • 10
  • 90
  • 127
-1

Its simple You can you curl to do so, make sure curl installed on server :

for triggering every minute : * * * * * curl --request POST 'https://glassdoor.com/admin/sendBdayNotification'

        • *

    minute hour day month week

Let say you want to send this notification 2:15 PM everyday You may change POST/GET based on your API:

15 14 * * * curl --request POST 'url of ur API'

dinesh kandpal
  • 641
  • 7
  • 12
-2

Instead of crontab you could also use google's app engine task queue. It has a generous free quota, is fast, scalable, modifiable.

Alfred
  • 56,245
  • 27
  • 137
  • 181