ChatGPT解决这个技术问题 Extra ChatGPT

Use PHP to create, edit and delete crontab jobs?

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?

possible duplicate of Cron jobs using php and a couple others
(hint) the crontab is just a file
@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?
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.

a
ajreal

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.


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.
You can use pipes instead of writing a temporary file
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).
@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.
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?
s
svarog

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


Nice. This will certainly come in handy... assuming it actually works :)
@Pacerier this project seems dead and has some issues. Try yzalis/crontab which is more active.
R
RafaSashi

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

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) )
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.
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 dougv.com/2006/12/…
thanks... how can i use cron_TZ using your project ??
F
Fred

This should do it

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

S
Sam Arul Raj T

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


A
Alnitak

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


t
thedom

Depends where you store your crontab:

shell_exec('echo "'. $job .'" >> crontab');

D
Dmitry Kireev

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.
A
Ajie Kurniyawan

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>

Remember to add exit; after header('Location: ...');. Also, this form is actually quite dangerous, as it can add cron job to "destroy" the server.
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.
C
Community

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.


Some people may be in a shared host so this may not work at all.
A
Alfred

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


Why not simply use cronjob?
d
dinesh kandpal

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'