Reputation: 3961
I have a PHP script that execute some shell commands.
Once I manually executed it. It worked very fine.
But after I used crontab to execute, the result from some shell commands are missing.
These are 2 commands.
ip route
iptables -t nat -L | grep 8800
and here is a sample PHP code.
#!/usr/bin/php -q
<?
$route = exec('ip route');
$iptable = exec('iptables -t nat -L | grep 8800');
echo $route;
echo $iptables;
?>
The above code worked well with manually execute but not crontab.
I found that some commands worked well with both. For example
ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'
cat /tmp/example | grep test
Any ideas for this problem, and thank you in advance.
Upvotes: 1
Views: 489
Reputation: 76395
A couple of things worth noting:
The exec
function's signature is
string exec ( string $command [, array &$output [, int &$return_var ]] )
To get the full output of a command you'll have to call it like so:
$output = array();//declare in advance is best because:
$lastLine = exec('ip route', $status, $output);//signature shows reference expected
print_r($output);//full output, array, each index === new line
echo PHP_EOL, 'The command finished ', $status === 0 ? 'well' : 'With errors: '.$status;
You're using the exec
command as though it were passthru
, which might be worth a look in your case:
The last line from the result of the command. If you need to execute a command and have all the data from the command passed directly back without any interference, use the passthru() function.
It's important to not that, when you run the command manually, it has access to all your environment variables, loaded when you log in (and any additional vars set in your .profile
or .basrc
file). This is not the case when running a command using crontab or over ssh.
Perhaps, the $PATH
environment variable is set so, that you don't have access to ip
and other commands. There are easy fixes for this:
exech('/sbin/ip route');//if that's the correct path
Or, have a second script at the ready, and change your PHP script to:
if (!exec('which ip'))
{//ip command not found
return exec('helper.sh '.implode(' ', $argv));//helper script
}
With the helper script looking like this:
#/bin/bash
source /home/user/.bashrc
$*
Where $*
merely calls the original PHP script again, only this time, the profile has been loaded. You could replace the source
call with export PATH=$PATH:/sbin
or something, and just set the environment variables up the way you need them.
The third, and final part uses pipes, and proc_open
. It's a PHP-only way of loading the profile and calling the script recursively:
if(!$_SERVER['FOO'])
{//where FOO is an environment variable that is loaded in the .profile/.bashrc file
$d = array(array('pipe','r'),array('pipe','w'));
$p = proc_open('ksh',$d,$pipes);
if(!is_resource($p) || end($argv) === 'CalledFromSelf')
{//if the last argument is calledFromSelf, we've been here before, and it didn't work
die('FFS');//this is to prevent deadlock due to infinite recursive self-calling
}
fwrite($pipes[0],'source /home/user/.profile'."\n");
fwrite($pipes[0],implode(' ',$argv).' CalledFromSelf'."\n");
fclose($pipes[0]);
usleep(15);//as long as you need
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($p);
exit();
}
echo $_SERVER['FOO'].PHP_EOL;//actual script goes here, we can use the FOO env var
This is how I solved an old question of mine where I encountered difficulties with environment variables not being set
Last thing to note is: Does the user running crontab have the permissions required to do what needs to be done?
Upvotes: 4
Reputation: 455
Pay attention to what user runs the script. May be the user (which you add crontab task) haven't got enough permissions.
Upvotes: 0