13

If I type crontab -l in the command-line I can see the following line:

# * * * * * /usr/bin/php /home/user/every_minute_script.php

To start this cronjob, I need to edit the file using crontab -e command, remove the comment character at the beginning of the line, save the edited file, and exit the editor.

To stop this cronjob, the same steps, but adding the comment character at the beginning of the line.

I want to achieve exactly the same effect using a PHP script, instead of manually editing the file.

J. Bruni
  • 19,262
  • 11
  • 70
  • 90

5 Answers5

12

I did some research and found in a forum, the following message:

Call "crontab -e" with the EDITOR environment variable set to a php script. That script can modify the file and when it exits crontab will re-read the file and update.

So, I have tried something, and it worked. I will paste the working code below:

#!/usr/bin/php
<?php

$on  = "* * * * * /usr/bin/php /home/user/every_minute_script.php\n";
$off = "# * * * * * /usr/bin/php /home/user/every_minute_script.php\n";

$param    = isset( $argv[1] ) ? $argv[1] : '';
$filename = isset( $argv[2] ) ? $argv[2] : '';

if ( $param == 'activate' )
{
    shell_exec( 'export EDITOR="/home/user/cron.php on"; crontab -e' );
}
elseif( $param == 'deactivate' )
{
    shell_exec( 'export EDITOR="/home/user/cron.php off"; crontab -e' );
}
elseif( in_array( $param, array( 'on', 'off' ) ) )
{
    if ( !is_writable( $filename ) )
        exit();

    $crontab = file( $filename );
    $key = array_search( $param == 'on' ? $off : $on, $crontab );

    if ( $key === false )
        exit();

    $crontab[$key] = $param == 'on' ? $on : $off;
    sleep( 1 );
    file_put_contents( $filename, implode( '', $crontab ) );
}

exit();

?>

As it is, we have a single script named cron.php located at /home/user folder, set to be executable (chmod a+x cron.php) and called from the command-line (PHP-CLI). Later I will tweak it to run from the web, which is my intent.

Usage: ./cron.php activate to enable the cronjob and ./cron.php deactivate to disable it.

The script sets the EDITOR environment variable properly (to itself) and then calls crontab -e, which on its turn calls the EDITOR (which is now the same cron.php script) passing the temporary crontab file location as an argument. Then, the proper crontab line is found and changed, and the modified version is saved, substituting the temporary file. When the script exits, crontab will update.

This does exactly what I wanted, and fit my needs.

The other answers are nice and may fit different needs and scenarios, and I want to thank everybody who contributed.

J. Bruni
  • 19,262
  • 11
  • 70
  • 90
  • when i execute ./cron.php activate i am getting `?php: No such file or directory` error – Hunt Jul 03 '12 at 15:54
  • @Hunt: make sure you are using valid paths and file names... you need to change `/home/user` for an existent path – J. Bruni Jul 06 '12 at 10:12
7

Rather than messing programatically with crontab (which is subtle and quick to anger), I'd suggest making a check inside your every_minute_script.php:

if (!file_exists('/your/path/run_every_minute_script')) {
  exit;
}

This way, the script will still start every minute, but if the condition isn't met (/your/path/run_every_minute_script doesn't exist), it will terminate immediately without further processing.

(Of course, you can substitute different conditions there, e.g. checking the database for permission etc.)


If you need the output mailed, you can use a wrapper script. Crontab:

* * * * * /your/path/wrapper.sh > /dev/null 2> /dev/null

The wrapper script then runs the job proper, collects its output and errors, and if those aren't empty, mails them out (note that you could also make the check inside the wrapper script; we didn't, as it relied on database).

Piskvor left the building
  • 87,797
  • 43
  • 170
  • 220
5

Here's a pretty cool tutorial for creating exactly this kind of functionality with PHP.

Uku Loskit
  • 37,259
  • 9
  • 85
  • 88
2

Put your stop/start condition at the start of every_minute_script.php

if($condition == false) {
    exit();
}
Adam Hopkinson
  • 26,835
  • 7
  • 57
  • 87
  • Sounds good, and I thought about it. The problem is that I need the output of the cronjob to be mailed for me (can't use /dev/null). And in my setup, even with an "exit" in the start of the PHP script, I would receive an email (every minute!)... – J. Bruni Jul 01 '11 at 13:50
  • @J. Bruni: What we did was use a wrapper: `* * * * * /x/y/z/blah.sh &> /dev/null`; and blah.sh was a script which ran the actual job, got its output, and mailed that, unless there was no output. – Piskvor left the building Jul 01 '11 at 13:55
  • @J. Bruni - I thought there was only an email if there was output from the script? – Adam Hopkinson Jul 01 '11 at 14:46
2

Could you place some kind of logic at the beginning of every_minute_script.php that checks a flag to see if it should do anything? That way it could spin up and then just quickly stop if there is no work to do.

Or is that too inefficient for your purposes?

Justin Ethier
  • 122,367
  • 49
  • 219
  • 273
  • I just commented adam's answer (similar to yours). This idea is nice, and perhaps the final answer to a lot of scenarios. In my case, if possible, I prefer not to run `every_minute_script.php` at all. – J. Bruni Jul 01 '11 at 13:52
  • Can you do something along the lines of what @Piskvor is suggesting, and only send an email when the script actually runs and produces output? – Justin Ethier Jul 01 '11 at 14:03