Use command-line tools in PHP
Run shell commands in your Web applications
If you've been working with PHP, you know it's an excellent tool for creating feature-rich Web pages. As a general scripting language, PHP:
- Is easy to learn.
- Has many powerful frameworks, such as CakePHP and CodeIgniter, to make you as productive as any Rails programmer.
- Can communicate with MySQL, PostgreSQL, Microsoft® SQL Server, and even Oracle.
- Easily integrates with JavaScript frameworks, such as script.aculo.us and jQuery.
At some point, though, you want to do more, or you're forced to do more. By that, I mean you have to work directly with the file system of the server PHP is running on. You end up needing to work with files on the file system, understand what processes are running, or perform some other task.
At first, you're content using commands like file()
in PHP to
open files. At some point, though, the only way to get something done is
to be able to run shell commands on the server and get back some type of
output. For example, you might need to know how many files live in a
certain directory. Or you may need to know how many lines have been
written to a group of log files. Or you may need to operate on those files
to copy them to another directory or use rsync
to transport
them to another location.
In "Command-line PHP? Yes, you can!," Roger McCoy shows how to use PHP directly from the command line — no Web browser needed. In this article, I approach the subject from the other point of view, showing you how to integrate closely with underlying shell commands and folding any return values into your interfaces and processes.
This kind of thing only works if you're running on Linux®, Berkeley Software Distribution (BSD), or some other flavor of UNIX®. I assume that you're running on a Linux-Apache-MySQL-PHP (LAMP) stack. Your mileage may vary if you're running a different UNIX flavor because availability of commands varies from installation to installation. I know many of you are also developing on Mac OS X, which runs a flavor of BSD, so I keep the sample commands as generic as possible to ensure portability.
Command-line overview
The PHP Command Line Interface (CLI) Server Application Programming Interface (SAPI) was released experimentally in PHP V4.2.0. As of V4.3.0, it is fully supported and enabled by default. The PHP CLI SAPI allows you to develop shell- and even desktop-based scripts powered with PHP. Indeed, it is possible to create tools in PHP that run directly from the command line. Working in this fashion, PHP developers can be as productive as Perl, AWK, Ruby, or shell scripters in that context.
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
).
shell_exec()
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()
<?php $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()

Please note you get the same results if you just use the backtick operators, as shown below.
Listing 3. Using only the backtick operators
<?php $results = `wc -w *.txt`; echo $results; ?>
Listing 4 shows an even simpler method.
Listing 4. A simpler method
<?php echo `wc -w *.txt`; ?>
It's important to note that pretty much whatever you can do on the UNIX command line or in a shell script is allowed here. For example, you can use pipes to string together commands. You can even create a shell script with all your operations in it and just call the shell script, with or without arguments, as needed.
For example, if you want to count only the words in the first five text
files in the directory, you can use a pipe (|
) to hook the
wc
and head
commands together. Furthermore, you
can wrap the output results in pre
tags to make it more
palatable in the Web browser, as shown below.
Listing 5. A more complex shell command
<?php $results = shell_exec('wc -w *.txt | head -5'); echo "<pre>".$results . "</pre>"; ?>
Figure 2 shows the results of running the script from Listing 5.
Figure 2. 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
.
passthru()
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
<?php 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

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
<?php //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()

exec()
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
<?php $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
<?php $results = exec('wc -w *.txt | head -5',$data); print_r($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.
system()
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
<?php 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()
<?php passthru('xfer_rsync.sh',$returnvalue); if ($returnvalue != 0){ //we have a problem! //add error code here }else{ //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).
Security
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.
Summary
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.
Downloadable resources
Related topics
- Learn more about the
exec()
,passthru()
,shell_exec()
, andsystem()
commands. - PHP.net is the central resource for PHP developers.
- Check out the "Recommended PHP reading list."
- Follow developerWorks on Twitter.
- Using a database with PHP? Check out the Zend Core for IBM, a seamless, out-of-the-box, easy-to-install PHP development and production environment that supports IBM DB2 V9.
- Start developing with product trials, free downloads, and IBM Bluemix services.