Run shell commands in your Web applications

Command-line overview

This article considers the tools built into PHP that allow you to tap into the underlying shell environment and file system PHP is running on. PHP provides a number of functions for executing external commands, among them shell_exec(), exec(), passthru(), and system(). These commands are similar, but provide different interfaces to the external program you’re running. Each of these commands spawns a child process to run the command or script you designate, and each captures the output of your command as it’s written to standard output (stdout).


The shell_exec() command is actually just an alias for the backtick (`) operator. If you’ve been doing any shell or Perl scripting at all, you know you can capture the output of other commands inside backtick operators. For example, Listing 1 shows how to use the backtick to obtain a word count for every text (.txt) file in the current directory.

Listing 1. Using backtick for word count #! /bin/sh number_of_words=`wc -w *.txt` echo $number_of_words #result would be something like: #165 readme.txt 388 results.txt 588 summary.txt #and so on…. In your PHP script, you can run that simple command inside shell_exec(), as shown in Listing 2, and get the results you need, assuming you have some text files in the same directory.

Listing 2. Running the same command in shell_exec()

 $results = shell_exec('wc -w *.txt');
 echo $results;

As you can see in Figure 1, you get the same results as you would from the shell script. That’s because shell_exec() lets you run an external program via the shell, then returns the result as a string.

Figure 1. Results of running a shell command through shell_exec()
A shell_exec() result example

$results = shell_exec('wc -w *.txt | head -5');
echo "<pre>".$results . "</pre>";

Results of running a more complex shell command through shell_exec()
Later in this article, you’ll learn how to pass arguments to these scripts using PHP. For now, you can think of it as a way to run shell commands, as long as you remember that you’ll only see standard output. If there are errors in your script or command, you won’t see a standard error (stderr) unless you pipe it to stdout.


The passthru() command lets you run an external program and display its results on the screen. You don’t need to use echo or return to see these results; they simply display in the browser. You can add an optional argument, a variable that holds the return code from the external program, such as 0 for success, which provides a better mechanism for debugging.

In Listing 6, I use the passthru() command to run the little word-count script I ran in the previous section. As you can see, I also add a $returnval variable that contains the return code.

Listing 6. Using the passthru() command to run word-count script
passthru('wc -w *.txt | head -5',$returnval);
echo "<hr/>".$returnval;
Notice that I don't have to echo anything out. The results just end up on the screen, as shown below.

Figure 3. Results of running the passthru() command with a return code
passthru() command example
In Listing 7, I introduce a small error in the code by removing the dash before the 5 in the head portion of the script.

Listing 7. Introducing an error to the word-count script
//we introduce an error below (removing - from the head command)
passthru('wc -w *.txt | head 5',$returnval);
echo "<hr/>".$returnval;
Notice that the script does not run as intended. As shown in Figure 4, you get a blank screen, a horizontal rule, and a return value of 1. This return code usually indicates some kind of error has occurred. Being able to test for this return code makes it easier to figure out what needs fixing.

Figure 4. Seeing the error code when using passthru()
passthru() error return code
The exec() command is similar to shell_exec(), except it returns the last line of the output and, optionally, populates an array with the full output of the command, along with the error code. Listing 8 is an example of what happens if you run exec() without capturing the results in a data array.

Listing 8. Running exec() without capturing the results in a data array
$results = exec('wc -w *.txt | head -5');
echo $results;
#would print out just the last line or results, i.e.:
#3847 myfile.txt
To capture the results in an array, add the name of the array as a second argument to exec(). I do this in Listing 9, using $data as my array name.
Listing 9. Capturing the results from exec() in a data array

$results = exec('wc -w *.txt | head -5',$data);
#would print out the data array:
#Array ( [0]=> 555 text1.txt [1] => 283 text2.txt) 
After you capture the results in an array, you can do something with each line. For example, you can split on the first space you find and store the discreet values in a database table, or you can apply specific formatting or tags to each line.

The system() command, shown in Listing 10, is something of a hybrid. Like passthru(), it outputs anything it receives directly from the external program. Like exec(), it also returns the last line and makes the return code available.

Listing 10. The system() command

system('wc -w *.txt | head -5');
#would print out:
#123 file1.txt 332 file2.txt 444 file3.txt
#and so on
Some examples
Now that you've learned how to use all these PHP commands, you probably have questions. For instance, which commands should you use and when? This is entirely up to you and the needs you have.

Most of the time, I use the exec() command with the data array to do any processing. Otherwise, I use shell_exec() for simpler commands, especially if I don’t care about the output. If I just need to run a shell script, I use passthru(). Often, I find myself using the functions for different reasons and sometimes interchangeably. It all depends on my mood and what I’m trying to accomplish.

Another question you might have is “What is all this stuff good for?” In case you’re stuck for ideas or a project that just jumps out as a good way to use shell commands hasn’t presented itself, I offer a few ideas here.

If you are writing an application that offers any kind of backup or file transfer capabilities, you’d be smart to use shell_exec() or one of the other commands here to run an rsync-powered shell script. You can write the shell script that contains the necessary rsync commands, then use passthru() to execute it based on a user command or a cron job.

For example, a user with the appropriate privileges in your application, such as admin, might need to transfer 50 PDFs from one server to another. The user would navigate to the correct place in your application, click Transfer, select the PDFs to transfer, then click Submit. As its action, the form would have a PHP script that runs your rsync script via passthru() with a return option variable so you know if a problem occurs, as shown below.

Listing 11. Sample PHP script that runs an rsync script via passthru()

if ($returnvalue != 0){
 //we have a problem!
 //add error code here
 //we are okay
 //redirect to some other page
If you have an application that needs to list processes or files, or some data about those processes or files, you can easily use any of the commands summarized in this article to do just that. For example, a simple grep command can help you find files that match certain search criteria. Using this in concert with the exec() command and dumping the results to an array allows you to build an HTML table or form that then allows you to run other commands.

So far, I’ve discussed user-generated events — if the user presses a button or clicks a link, PHP runs a script. You can also achieve some interesting effects by running stand-alone PHP scripts with cron or another scheduler. For example, if you have a backup script, you can run it stand-alone via cron, or you can wrap it in a PHP script and then run it. Why would you want to do that? It sounds redundant and wasteful, right? Well, no — not if you consider that you can run the backup script through exec() or passthru(), then perform some behavior based on the return code. If you get an error, you can write an entry in an error log or a database, or send a warning e-mail message. If the script succeeds, you can dump the raw output of the script to the database (for example, rsync has a verbose mode useful in diagnosing problems later on).

One quick statement here about security: If you’re accepting user input and passing that information along to the shell, you better sanitize that user input. Strip out any commands that you think might be harmful and disallow things, such as sudo (running with superuser privileges) or rm (delete). In fact, you might want to disallow users from sending in open requests and only allow them to choose from a list of possible alternatives.

For example, if you are running a transfer program that accepts a list of files as an argument, you might list all your files in a row with a checkbox next to each one. Users can select and deselect files and click Submit to activate the rsync shell script. They wouldn’t be allowed to type in a list of files or use some kind of regular expression.

In this article, I showed the basics of using PHP commands like shell_exec(), exec(), passthru() and system() to run shell scripts and other commands. It’s now up to you to put this knowledge to use in your own applications.

PHP reading shell_exec live output

 * Execute the given command by displaying console output live to the user.
 *  @param  string  cmd          :  command to be executed
 *  @return array   exit_status  :  exit status of the executed command
 *                  output       :  console output of the executed command
function liveExecuteCommand($cmd)

    while (@ ob_end_flush()); // end all output buffers if any

    $proc = popen("$cmd 2>&1 ; echo Exit status : $?", 'r');

    $live_output     = "";
    $complete_output = "";

    while (!feof($proc))
        $live_output     = fread($proc, 4096);
        $complete_output = $complete_output . $live_output;
        echo "$live_output";
        @ flush();


    // get exit status
    preg_match('/[0-9]+$/', $complete_output, $matches);

    // return exit status and intended output
    return array (
                    'exit_status'  => intval($matches[0]),
                    'output'       => str_replace("Exit status : " . $matches[0], '', $complete_output)

Sample Usage :

$result = liveExecuteCommand('ls -la');

if($result['exit_status'] === 0){
   // do something if command execution succeeds
} else {
    // do something on failure