update page now

shell_exec

(PHP 4, PHP 5, PHP 7, PHP 8)

shell_execExecute command via shell and return the complete output as a string

Description

shell_exec(string $command): string|false|null

This function is identical to the backtick operator.

Note:

On Windows, the underlying pipe is opened in text mode which can cause the function to fail for binary output. Consider to use popen() instead for such cases.

Parameters

command

The command that will be executed.

Return Values

A string containing the output from the executed command, false if the pipe cannot be established or null if an error occurs or the command produces no output.

Note:

This function can return null both when an error occurs or the program produces no output. It is not possible to detect execution failures using this function. exec() should be used when access to the program exit code is required.

Errors/Exceptions

An E_WARNING level error is generated when the pipe cannot be established.

Examples

Example #1 A shell_exec() example

<?php
$output
= shell_exec('ls -lart');
echo
"<pre>$output</pre>";
?>

See Also

add a note

User Contributed Notes 13 notes

up
247
trev at dedicate.co.uk
14 years ago
If you're trying to run a command such as "gunzip -t" in shell_exec and getting an empty result, you might need to add 2>&1 to the end of the command, eg:

Won't always work:
echo shell_exec("gunzip -c -t $path_to_backup_file");

Should work:
echo shell_exec("gunzip -c -t $path_to_backup_file 2>&1");

In the above example, a line break at the beginning of the gunzip output seemed to prevent shell_exec printing anything else. Hope this saves someone else an hour or two.
up
54
alexandre dot schmidt at gmail dot com
10 years ago
To run a command in background, the output must be redirected to /dev/null. This is written in exec() manual page. There are cases where you need the output to be logged somewhere else though. Redirecting the output to a file like this didn't work for me:

<?php
# this doesn't work!
shell_exec("my_script.sh 2>&1 >> /tmp/mylog &");
?>

Using the above command still hangs web browser request.

Seems like you have to add exactly "/dev/null" to the command line. For instance, this worked:

<?php
# works, but output is lost
shell_exec("my_script.sh 2>/dev/null >/dev/null &");
?>

But I wanted the output, so I used this:

<?php
shell_exec("my_script.sh 2>&1 | tee -a /tmp/mylog 2>/dev/null >/dev/null &");
?>

Hope this helps someone.
up
5
smcbride at msn dot com
5 years ago
proc_open is probably a better solution for most use cases as of PHP 7.4.  There is better control and platform independence.  If you still want to use shell_exec(), I like to wrap it with a function that allows better control.

Something like below solves some problems with background process issues on apache/php.  It also 

public function sh_exec(string $cmd, string $outputfile = "", string $pidfile = "", bool $mergestderror = true, bool $bg = false) {
  $fullcmd = $cmd;
  if(strlen($outputfile) > 0) $fullcmd .= " >> " . $outputfile;
  if($mergestderror) $fullcmd .= " 2>&1";
  if($bg) {
    $fullcmd = "nohup " . $fullcmd . " &";
    if(strlen($pidfile)) $fullcmd .= " echo $! > " . $pidfile;
  } else {
    if(strlen($pidfile) > 0) $fullcmd .= "; echo $$ > " . $pidfile;
  }
  shell_exec($fullcmd);
}
up
13
Rgemini
17 years ago
A simple way to handle the problem of capturing stderr output when using shell-exec under windows is to call ob_start() before the command and ob_end_clean() afterwards, like this:

<?php
ob_start()
$dir = shell_exec('dir B:');
if is_null($dir)
{   // B: does not exist
    // do whatever you want with the stderr output here
}
else
{  // B: exists and $dir holds the directory listing
   // do whatever you want with it here
}
ob_end_clean();   // get rid of the evidence :-)
?>

If B: does not exist then $dir will be Null and the output buffer will have captured the message: 

  'The system cannot find the path specified'. 

(under WinXP, at least). If B: exists then $dir will contain the directory listing and we probably don't care about the output buffer. In any case it needs to be deleted before proceeding.
up
6
joelhy
16 years ago
Here is a easy way to grab STDERR and discard STDOUT:
    add  '2>&1 1> /dev/null' to the end of your shell command

For example:
<?php
$output = shell_exec('ls file_not_exist 2>&1 1> /dev/null');
?>
up
2
pedroxam at gmail dot com
6 years ago
Here is my gist to all:

function execCommand($command, $log) {

    if (substr(php_uname(), 0, 7) == "Windows")
    {
        //windows
        pclose(popen("start /B " . $command . " 1> $log 2>&1", "r"));
    }
    else
    {
        //linux
        shell_exec( $command . " 1> $log 2>&1" );
    }
    
    return false;
}
up
4
eric dot peyremorte at iut-valence dot fr
18 years ago
I had trouble with accented caracters and shell_exec.

ex :

Executing this command from shell :

/usr/bin/smbclient '//BREZEME/peyremor' -c 'dir' -U 'peyremor%*********' -d 0 -W 'ADMINISTRATIF' -O 'TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE SO_RCVBUF=8192 SO_SNDBUF=8192' -b 1200 -N 2>&1

gave me that :

Vidéos                             D        0  Tue Jun 12 14:41:21 2007
  Desktop                            DH        0  Mon Jun 18 17:41:36 2007

Using php like that :

shell_exec("/usr/bin/smbclient '//BREZEME/peyremor' -c 'dir' -U 'peyremor%*******' -d 0 -W 'ADMINISTRATIF' -O 'TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE SO_RCVBUF=8192 SO_SNDBUF=8192' -b 1200 -N 2>&1")

gave me that :

  Vid  Desktop                            DH        0  Mon Jun 18 17:41:36 2007

The two lines were concatenated from the place where the accent was.

I found the solution : php execute by default the command with LOCALE=C. 

I just added the following lines before shell_exec and the problem was solved :

$locale = 'fr_FR.UTF-8';
setlocale(LC_ALL, $locale);
putenv('LC_ALL='.$locale);

Just adapt it to your language locale.
up
3
jack dot harris-7ot2j4ip at yopmail dot Com
11 years ago
On Windows, if shell_exec does NOT return the result you expected and the PC is on an enterprise network, set the Apache service (or wampapache) to run under your account instead of the 'Local system account'. Your account must have admin privileges.

To change the account go to console services, right click on the Apache service, choose properties, and select the connection tab.
up
4
Anonymous
21 years ago
Be careful as to how you elevate privileges to your php script.  It's a good idea to use caution and planing.  It is easy to open up huge security holes.  Here are a couple of helpful hints I've gathered from experimentation and Unix documentation.

Things to think about:

1. If you are running php as an Apache module in Unix then every system command you run is run as user apache.  This just makes sense.. Unix won't allow privileges to be elevated in this manner.  If you need to run a system command with elevated privileges think through the problem carefully!

2. You are absolutely insane if you decide to run apache as root.  You may as well kick yourself in the face.  There is always a better way to do it.

3. If you decide to use a SUID it is best not to SUID a script.  SUID is disabled for scripts on many flavors of Unix.  SUID scripts open up security holes, so you don't always want to go this route even if it is an option.  Write a simple binary and elevate the privileges of the binary as a SUID.  In my own opinion it is a horrible idea to pass a system command through a SUID-- ie have the SUID accept the name of a command as a parameter.  You may as well run Apache as root!
up
3
kamermans at teratechnologies dot net
18 years ago
I'm not sure what shell you are going to get with this function, but you can find out like this:

<?php
$cmd = 'set';
echo "<pre>".shell_exec($cmd)."</pre>";
?>

On my FreeBSD 6.1 box I get this:

USER=root
LD_LIBRARY_PATH=/usr/local/lib/apache2:
HOME=/root
PS1='$ '
OPTIND=1
PS2='> '
LOGNAME=root
PPID=88057
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
SHELL=/bin/sh
IFS='     
'

Very interesting.  Note that the PATH may not be as complete as you need.  I wanted to run Ghostscript via ImageMagik's "convert" and ended up having to add my path before running the command:

<?php
$cmd = 'export PATH="/usr/local/bin/"; convert -scale 25%x25% file1.pdf[0] file2.png 2>&1';
echo "<pre>".shell_exec($cmd)."</pre>";
?>

ALSO, note that shell_exec() does not grab STDERR, so use "2>&1" to redirect it to STDOUT and catch it.
up
3
jessop <AT> bigfoot <DOT> com
22 years ago
Just a quick reminder for those trying to use shell_exec on a unix-type platform and can't seem to get it to work. PHP executes as the web user on the system (generally www for Apache), so you need to make sure that the web user has rights to whatever files or directories that you are trying to use in the shell_exec command. Other wise, it won't appear to be doing anything.
up
1
Martin Rampersad
22 years ago
I have PHP (CGI) and Apache. I also shell_exec() shell scripts which use PHP CLI. This combination destroys the string value returned from the call. I get binary garbage.  Shell scripts that start with #!/usr/bin/bash return their output properly.

A solution is to force a clean environment.  PHP CLI no longer had the CGI environment variables to choke on.

<?php

// Binary garbage.
$ExhibitA = shell_exec('/home/www/myscript');

// Perfect.
$ExhibitB = shell_exec('env -i /home/www/myscript');

?>

-- start /home/www/myscript
#!/usr/local/bin/phpcli
<?php

echo("Output.\n");

?>
-- end /home/www/myscript
up
1
rustleb at hotmail dot com
19 years ago
For capturing stdout and stderr, when you don't care about the intermediate files, I've had better results with . . .
<?php
function cmd_exec($cmd, &$stdout, &$stderr)
{
    $outfile = tempnam(".", "cmd");
    $errfile = tempnam(".", "cmd");
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("file", $outfile, "w"),
        2 => array("file", $errfile, "w")
    );
    $proc = proc_open($cmd, $descriptorspec, $pipes);
    
    if (!is_resource($proc)) return 255;

    fclose($pipes[0]);    //Don't really want to give any input

    $exit = proc_close($proc);
    $stdout = file($outfile);
    $stderr = file($errfile);

    unlink($outfile);
    unlink($errfile);
    return $exit;
}
?>

This isn't much different than a redirection, except it takes care of the temp files for you (you may need to change the directory from ".") and it blocks automatically due to the proc_close call.  This mimics the shell_exec behavior, plus gets you stderr.
To Top