Monday, July 03, 2006

PHP Shell_exec problems

For a week, I struggled to execute a Perl script and grab it’s output, all to be done within a PHP program. Finally, after an exhaustive search, I found my savior – “Shell_exec” command in PHP. Although, the “shell_exec” command does exactly what I wanted, the road ahead was full of thorny issues. To help developers in the similar situation as of mine, here I present a structured document on the problems that one might encounter while trying to run “shell_exec” command.

Problem 1: Shell_exec() [function.shell-exec]: Cannot execute….. in Safe Mode:

Solution: In this case, the potential problem might be that your php is running in safe mode. Open php.ini file in a text editor and search for “safe_mode”. Make sure that it is turned off i.e

safe_mode = Off

Restart your webserver and try to run the php program again. "Shell_exec" command should be working now.

Problem 2: Able to execute simple commands such as “cmd”, “cd”, etc., but not perl script

Problem 3: Able to run perl script via command prompt but not using shell_exec

Solution: Problem 2 and 3 are related and, in most cases, are caused by the same problem. In both cases, probably, including the full path of perl.exe might solve the problem of running a perl script. For example

Shell_exec(“perl hello.pl”) // originally I was trying this

Shell_exec(“c:\usr\perl\bin\perl.exe hello.pl”); // by providing full path to perl.exe, my problem 2 and 3 got solved.

Another useful function that might was to consider is runExternal. It was contributed by one of the developers and is available on www.php.net. A copy of the runExternal function is below.

function runExternal($cmd,&$code) {
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a file to write to
);

$pipes= array();
$process = proc_open($cmd, $descriptorspec, $pipes);

$output= "";

if (!is_resource($process)) return false;

#close child's input imidiately
fclose($pipes[0]);

stream_set_blocking($pipes[1],false);
stream_set_blocking($pipes[2],false);

$todo= array($pipes[1],$pipes[2]);

while( true ) {
$read= array();
if( !feof($pipes[1]) ) $read[]= $pipes[1];
if( !feof($pipes[2]) ) $read[]= $pipes[2];

if (!$read) break;

$ready= stream_select($read, $write=NULL, $ex= NULL, 2);

if ($ready === false) {
break; #should never happen - something died
}

foreach ($read as $r) {
$s= fread($r,1024);
$output.= $s;
}
}

fclose($pipes[1]);
fclose($pipes[2]);

$code= proc_close($process);

return $output;
}
?>

here is how to use it:


$result= runExternal("ls -l some-file.txt",$code);

print "

";
print $result;
print "
\n";

print "code: $code\n";
?>

As you might already noticed, runExternal command replaces shell_exec. While shell_exec only returns output and no errors, runExternal returns output as well as errors. Thus runExternal is a useful during debugging process.

1 comment:

erectile dysfunction drugs said...

Hello There. I found your blog using msn. This is an extremely well written article. I'll make sure to bookmark it and return to read more of your useful information. Thanks for the post. I will certainly comeback.