I would suggest shell_exec()
together with escapeshellcmd()
and escapeshellarg()
.
To clarify (I was on the go when I first posted this answer): The right way to secure a shell command is:
$exe = 'cat';
$args = array('/etc/passwd');
$args = array_map('escapeshellarg', $args);
$escaped = escapeshellcmd($exe . ' ' . implode(' ', $args));
Here's a legitimate demo (and a nefarious demo as well) of the above code.
The above is just a dummy example, of course. But the main idea is that you apply escapeshellarg()
to each argument and then call escapeshellcmd()
on the whole command string (including the path to the executable and the previously escaped arguments). This is critical in arbitrary commands.
Note: By secure, I mean making it impossible to perform shell injection attacks by escaping characters that have special meaning like >
, <
, &&
, |
and more (see the Wikipedia link) while at the same time properly quoting spaces and other characters that may also have special interpretations by the shell.
With that aside, if you're already white-listing all the commands allowed, you already have the best possible security and you don't need the above functions (althought it doesn't hurt to use them anyway).
Regarding the actual calling function, they all pretty much do the same thing with a few quirks. Personally, I prefer shell_exec()
since its return value is more versatile (from this page):
- exec(): returns the last line of output from the command and flushes nothing.
- shell_exec(): returns the entire output from the command and flushes nothing.
- system(): returns the last line of output from the command and tries to flush the output buffer after each line of the output as it goes.
- passthru(): returns nothing and passes the resulting output without interference to the browser, especially useful when the output is in binary format.
Except from the system()
exit return code, you can mimic the behavior of all the other functions with the return value of shell_exec()
. However, the inverse it's either harder to do, or just not possible.
I hope this clears things up for you.