Bing
Bing

Reputation: 3171

Shell via PHP: Trouble adding new cron job to crontab

I have several scripts scheduled to run in my crontab, but can only see them as root (or using sudo). I need to have a PHP script (which is being run as nginx) be able to add a new line to the crontab file. To do this I created a shell script (owned by root) and gave the nginx user permission to sudo it via the /etc/sudoers file.

The last line of the /etc/sudoers file:

nginx ALL=NOPASSWD: /etc/nginx/addcron.sh

The PHP call to execute the script:

chdir("/etc/nginx/");
echo exec("2>&1 ./addcron.sh $custname", $output);
echo "<pre>".print_r($output, true)."</pre>";

My current crontab:

[ec2-user@ip-172-31-xx-xxx nginx]$ sudo crontab -l
* * * * * env > /tmp/env.output
* * * * * /usr/bin/php -f /var/www/html/example/cron/cron.php
* * * * * /usr/bin/php -f /var/www/html/demo/cron/cron.php
0 23 * * * rm /tmp/cachegrind.out.*

Meta information about my addcron.sh file:

[ec2-user@ip-172-31-xx-xxx nginx]$ pwd
/etc/nginx
[ec2-user@ip-172-31-xx-xxx nginx]$ ls -al addcron.sh
-rwxr-xr-x 1 root root 129 Nov 24 22:16 addcron.sh

The contents of addcron.sh:

#!/bin/bash
custname="$1"
(crontab -l; echo \"* * * * * /usr/bin/php -f /var/www/html/$custname/cron/cron.php\" ) | crontab -

When I try to run this though, I get the following error:

errors in crontab file, can't install.
Array
(
    [0] => "-":102: bad minute
    [1] => errors in crontab file, can't install.
)

It seems like it doesn't like the - mark in addcron.sh, but my Google searches suggest this is correct. Also, I have tried adding sudo to the PHP's exec command, but then I just get the following error:

sorry, you must have a tty to run sudo

What am I doing wrong or missing, and why?

Upvotes: 0

Views: 231

Answers (2)

MerlinTheMagic
MerlinTheMagic

Reputation: 605

I recently published a project that allows PHP to obtain and interact with a real Bash shell. Get it here: https://github.com/merlinthemagic/MTS

After downloading you would simply use the following code:

$custname= "someone";
$strCmd = "echo \"* * * * * /usr/bin/php -f /var/www/html/".$custname."\" >> /cron/cron.php";

$shell    = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1  = $shell->exeCmd($strCmd);
//assuming your distribution reloads / restarts using 'service'
$return2  = $shell->exeCmd('service crond restart');

this will append your line to the cron file.

Upvotes: 0

Dan Cornilescu
Dan Cornilescu

Reputation: 39824

Side note: running cron jobs unrelated to the system admin under the root's account is a BAD IDEA from the security prospective. Install your crons under the nginx user.

The issue is caused by the escaping of the quotes in your bash script (which you can check directly in bash, piece by piece, btw):

> (crontab -l; echo \"* * * * * /usr/bin/php -f /var/www/html/$custname/cron/cron.php\" )
no crontab for username
"* ... <all kinds of filenames in here> ... /usr/bin/php -f /var/www/html/the_customer/cron/cron.php"

Without the quote escaping things work a bit better:

> (crontab -l; echo "* * * * * /usr/bin/php -f /var/www/html/$custname/cron/cron.php" )
no crontab for username
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php

You might want to add some protection against duplicating the entries, here's how crontab looks after a few invocations:

> crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Tue Nov 24 20:54:10 2015)
# (Cronie version 4.2)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Tue Nov 24 20:54:09 2015)
# (Cronie version 4.2)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Tue Nov 24 20:54:09 2015)
# (Cronie version 4.2)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Tue Nov 24 20:54:08 2015)
# (Cronie version 4.2)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Tue Nov 24 20:54:07 2015)
# (Cronie version 4.2)
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php
* * * * * /usr/bin/php -f /var/www/html/the_customer/cron/cron.php

Upvotes: 1

Related Questions