exec

(PHP 3, PHP 4, PHP 5)

exec -- Execute an external program

说明

string exec ( string command [, array &output [, int &return_var]] )

exec() executes the given command.

参数

command

The command that will be executed.

output

If the output argument is present, then the specified array will be filled with every line of output from the command. Trailing whitespace, such as \n, is not included in this array. Note that if the array already contains some elements, exec() will append to the end of the array. If you do not want the function to append elements, call unset() on the array before passing it to exec().

return_var

If the return_var argument is present along with the output argument, then the return status of the executed command will be written to this variable.

返回值

The last line from the result of the command. If you need to execute a command and have all the data from the command passed directly back without any interference, use the passthru() function.

To get the output of the executed command, be sure to set and use the output parameter.

范例

例子 1. An exec() example

<?php
// outputs the username that owns the running php/httpd process
// (on a system with the "whoami" executable in the path)
echo exec('whoami');
?>

注释

警告

如果想允许用户输入的数据被传入本函数,则应使用 escapeshellarg()escapeshellcmd() 函数来确保用户不能欺骗系统从而执行任意命令。

注: 如果用本函数启动一个程序并希望保持在后台运行,必须确保该程序的输出被重定向到一个文件或者其它输出流去,否则 PHP 会在程序执行结束前挂起。

注: 在打开了安全模式时,只能执行在 safe_mode_exec_dir 之内的程序。为实用起见目前不能在指向程序的路径中包含 .. 成分。

警告

在打开了安全模式时,初始命令字符串之后的所有词都被看成一个单一的参数。因此,echo y | echo x 就成了 echo "y | echo x"


add a note add a note User Contributed Notes
sirnuke at gmail dot com
27-Sep-2006 01:26
Note that on Linux/UNIX/etc, both the command and any parameters you send is visible to anyone with access to ps.

For example, take some php code that calls an external program, and sends a sort of password as a parameter.

<?php
exec
("/usr/bin/secureprogram password");
?>

The entire string (actually probably something like "secureprogram password") will be visible to any user that executes ps -A -F.  If you are going to be doing a lot of external calling, or any of it needs to be somewhat secure, you are probably better off writing a php extension.
sinisa dot dukaric at gmail dot com
16-Aug-2006 10:10
Recently I had to do some "root" stuff via PHP - I could do it through cronjob based on the database, but since I was too lazy with doing that, I just wrote a shell script to create all the IMAP stuff, chown properly all the Maildirs and provision the user on the local system.

Executing that command as another user from inside of PHP was like this...

<code>
@exec("echo 'apache' | /usr/bin/sudo -u mail -S /var/www/html/mailset.sh $name");
</code>

"Advantage" is that you can run in this way commands as any sudoer on your system which can be fine-tuned and pretty useful. But again - password is echoed in cleartext and option "-S" tells sudo to take password from stdin which he does of course.
Major security risk - do it only if you really need to run some commands as different users (nologin users) and if you are really lazy :)

Now, my solution is a cronjob which runs every 5 mins and gets datasets from the MySQL table and does the work without exploiting any exec() from within PHP - which is the right way to do it.
lauri dot myllari at gmail dot com
13-Jul-2006 05:27
If you're getting random hangs with exec() or system(), see PHP bug #22526 (http://bugs.php.net/bug.php?id=22526) for a workaround.
Jelsamino
11-May-2006 08:41
If you need generate new data .htpasswd file:

$command="htpasswd -nb ".$login."".$password;
exec($command,$res);
echo $res[0];

Luck!!!!!!!
29-Mar-2006 08:12
I've done a C program to act as a "timeout controller" process, by forking itself and executing some other command received as parameter.

Then, in PHP I have a function that calls commands this way:

<?php
...
$command = "tout_controller <tout> <command_name> <command_args>"
exec($command,$status);
echo
"Exit status code of command is $status";
...
?>

I've noticed that exit status code returned from a C process is a "special" integer.

I wanted "command" exit status code to be returned to controller, and then controller to exit with same status code (to get this status from PHP).
Exit status was always 0 !!!

To solve this, i've found a C macro to use inside tout_controller:

<C code snippet>
..
waitpid(pid,&status,0); // wait for process that execs COMMAND
..
//exit(status); // that doesn't work
exit(WEXITSTATUS(ret)); // that's ok
..
</C code snippet>

It isn't exactly a PHP note, but may be useful to help some desperated programmer's ;)
hanno at theuprightape dot net
14-Feb-2006 08:10
(quoting rassehund) "Just find sudoers in your system and add there rights to NOBODY."

This is, of course, a MAJOR security risk. You don't need sudo if you use it like that, you might just as well change permissions for all commands and paths.

For remote server administration, if I don't use ssh, I would let root run cronjobs that look at configuration parameters which were set using a web interface, preferrably using a database (for comfort) and input checks (for security). The logging/status/statistical information that the cronjobs produce are also made available via a web interface.

That way, you don't have to perforate your security mechanisms. And one more personal opinion: sudo isn't that safe anyway: ever tried "sudo bash" or "sudo vi"? I would avoid using it, if you get groups and permissions right, you are not going to need it.
gmail.com [at] dmimms
01-Feb-2006 08:41
I just spent around 10 hours trying to figure out why sudo wouldn't work from exec.  It's because SELinux was enabled.  Changing that to permissive is the solution.
rassehund at gmail dot com
14-Dec-2005 04:34
I spent quite a lot time fixing problem of invoking scripts in Linux remotly. In the beginning I thought that it was a problem of exec() function, than I thought that something wrong in Apache server, cos through the web server you are NOBODY and have no rights to invoke scripts in Linux.

so for example in my php script I had such line :

exec ('pathToScript/script.sh &');

If to start my php script with such line in the linux shell like : php myphp.php everything is perfect. But if to do the same through the server than problem occurs.
I solved this problems with sudoers file in Linux. U needn't change anything in Apache or in php script. Just find sudoers in your system and add there rights to NOBODY.
amandato (at) gmail (period) com
07-Dec-2005 04:51
Running a command that may never time out on a windows server inspired the following code.  The PsExecute() function allows you to run a command and make it time out after a set period of time.  The sleep parameter is the number of seconds the script will pause becore checking if the process is complete.

Code utilizes the PsTools, found here: http://www.sysinternals.com/ntw2k/freeware/pstools.shtml

Copy and paste the following code into an include file:
<?php
// pstools.inc.php

  
function PsExecute($command, $timeout = 60, $sleep = 2) {
      
// First, execute the process, get the process ID
      
$pid = PsExec($command);
      
       if(
$pid === false )
           return
false;
      
      
$cur = 0;
      
// Second, loop for $timeout seconds checking if process is running
      
while( $cur < $timeout ) {
          
sleep($sleep);
          
$cur += $sleep;
          
// If process is no longer running, return true;
          
if( !PsExists($pid) )
               return
true; // Process must have exited, success!
      
}
      
      
// If process is still running after timeout, kill the process and return false
      
PsKill($pid);
       return
false;
   }
  
   function
PsExec($command) {
      
exec( dirname(__FILE__). "\\psexec.exe -s -d $command  2>&1", $output);

       while( list(,
$row) = each($output) ) {
          
$found = stripos($row, 'with process ID ');
           if(
$found )
               return
substr($row, $found, strlen($row)-$found-strlen('with process ID ')-1); // chop off last character '.' from line
      
}
      
       return
false;
   }
  
   function
PsExists($pid) {
      
exec( dirname(__FILE__). "\\pslist.exe $pid 2>&1", $output);

       while( list(,
$row) = each($output) ) {
          
$found = stristr($row, "process $pid was not found");
           if(
$found !== false )
               return
false;
       }
      
       return
true;
   }
  
   function
PsKill($pid) {
      
exec( dirname(__FILE__). "\\pskill.exe $pid", $output);
   }
?>

Place the above include file and the PsTools from (http://www.sysinternals.com/ntw2k/freeware/pstools.shtml) in the same directory.
simoncpu
30-Nov-2005 03:48
Sometimes, it is convenient to let exec() return the status of the executed command, rather than return the last line from the result of that command.  In Unix, just do:

   $ret = exec('foo; echo $?');

Remember not to overdo it though. ;)

[ simon.cpu ]
jkxx at mail dot bg
31-Oct-2005 03:31
In response to mbirth@webwriters.de's post:

"I now switched over to using exec('start /b ...') directly with the desired command (instead of writing it into a batch file and calling that) and played around with the line-length. Seems like the exec() command works with command-strings of up to 4096 characters in length. If the string is longer, it won't be executed."

I have had this issue ever since I started writing CGIs in Windows 2000 (NT 5.0 then). The "stdout" stream is subdivided into 4Kbyte chunks. As a result, when data is sent out by the CGI, there will be issues when that data goes over the 4K boundary. In my case I just appended enough whitespace to round the output to the nearest multiple of 4096 and all output made it to the destination. Not sure if this would be a practical solution for everyone, though.
Bob-PHP at HamsterRepublic dot com
19-Oct-2005 02:00
exec strips trailing whitespace off the output of a command. This makes it impossible to capture signifigant whitespace. For example, suppose that a program outputs columns of tab-delimited text, and the last column contains empty fields on some lines. The trailing tabs are important, but get thrown away.

If you need to preserve trialing whitespace, you must use popen() instead.
clive at pluton dot co dot uk
15-Oct-2005 06:35
When trying to run an external command-line application in Windows 2000 (Using IIS), I found that it was behaving differently from when I manually ran it from a DOS prompt.

Turned out to be an issue with the process protection. Actually, it wasn't the application itself that was having the problem but one it ran below it! To fix it, open computer management, right-click on Default Web Site, select the Home Directory tab and change Application Protection to 'Low (IIS Process)'.

Note, this is a rather dangerous thing to do, but in cases where it's the only option...
rivera at spamjoy dot unr dot edu
07-Oct-2005 04:17
windExec() reloaded:
* unique timestamp name was probably a good idea for multiple instances of function running @ same time
* includes handy FG/BG parameter

<?php
define
('EXEC_TMP_DIR', 'C:\tmp');

function
windExec($cmd,$mode=''){
  
// runs a command line and returns
   // the output even for Wind XP SP2
   // example: $cmd = "fullpath.exe -arg1 -arg2"
   // $outputString = windExec($cmd, "FG");
   // OR windExec($cmd);
   // (no output since it runs in BG by default)
   // for output requires that EXEC_TMP_DIR be defined

   // Setup the command to run from "run"
  
$cmdline = "cmd /C $cmd";

  
// set-up the output and mode
  
if ($mode=='FG'){
      
$outputfile = EXEC_TMP_DIR . "\\" . time() . ".txt";
      
$cmdline .= " > $outputfile";
      
$m = true;
   }
   else
$m = false;

  
// Make a new instance of the COM object
  
$WshShell = new COM("WScript.Shell");

  
// Make the command window but dont show it.
  
$oExec = $WshShell->Run($cmdline, 0, $m);

   if (
$outputfile){
      
// Read the tmp file.
      
$retStr = file_get_contents($outputfile);
      
// Delete the temp_file.
      
unlink($outputfile);
   }
   else
$retStr = "";

   return
$retStr;
}
ewilde
21-Sep-2005 07:55
To my way of thinking, it is a good idea to execute programs from the cgi-bin directory of the Web server, to get a little control over configuring a system (at install time, a pointer to the actual program can be symlinked from the cgi-bin directory and the code won't ever have to be changed).  If you'd like to do this, under Apache at least, the following should work:

  if (!($ProgInfo = apache_lookup_uri(/cgi-bin/myprog)))
   $ProgPath = /usr/bin/myprog;
  else
   {
   if (is_object($ProgInfo)) $ProgPath = $ProgInfo->filename;
   else $ProgPath = $ProgInfo["filename"];
   }

exec("$ProgPath ...");
mbirth at webwriters.de
14-Sep-2005 02:42
I had to combine many PDFs into a single one using pdftk and did this by writing the commands into a batch file and running it with exec('cmd /c blabla.cmd').

Using batch files under Windows, there's a line-length-limit of 1024 characters. So I made sure each line in the batch file doesn't exceed 1024 characters.

I now switched over to using exec('start /b ...') directly with the desired command (instead of writing it into a batch file and calling that) and played around with the line-length. Seems like the exec() command works with command-strings of up to 4096 characters in length. If the string is longer, it won't be executed.
nonnsi at gmail dot com
14-Sep-2005 03:25
I found this site to be very helpful when trying to add parameters to the "start" command in windows xp.
http://www.robvanderwoude.com/ntstart.html
I use:
exec( 'start "title" /Dpath /B program parameters' );
CJ [AT] TBG
09-Sep-2005 01:41
[EXEC] on [Windows]

Finally a simple way to get exec working w/o launching a black box window.

just do: exec('start /B "window_name" "path to your exe"',$output,$return);

The important part is the /B which makes it run in the background.
p dot koeman at wittenborg-university dot com
29-Aug-2005 09:22
Using sudo (http://www.sudo.ws/) to exec system commands from PHP

This is a secure way to use sudo from PHP to perform sysadmin tasks from a php webapplication. (can be used with exec or passthru)

- Make a PHP script in the WWW root directory : client.php

[/home/mywebdir/html/client.php]
<?
passthru
('echo hello world | sudo /usr/bin/php -f /home/server.php');
?>

- Make a PHP script outside the WWW directory : server.php

[/home/server.php]
<?
echo join('',file('php://stdin'));
?>

Add a line to /etc/sudoers

[in /etc/sudoers]
www    ALL=(ALL) NOPASSWD: /usr/bin/php -f /home/server.php

Now execute client.php in the webbrowser (as www user)
- client.php will execute sudo
- sudo will execute server.php by php as root !

In server.php you can do everything you like requiring root privileges. BEWARE ! every php script can now execute server.php, make it secure ! (filter parameters etc.)

I have tested this method and it works !
Kind regards, Pim Koeman
Wittenborg-University, Deventer, the Netherlands
http://www.wittenborg-university.com
vdweij at hotmail dot com
09-Aug-2005 07:18
It is possible to only capture the error stream (STERR). Here it goes...

(some_command par1 par2 > /dev/null) 3>&1 1>&2 2>&3

-First STDOUT is redirected to /dev/null.
-By using parenthesis it is possible to gain control over STERR and STOUT again.
-Then switch STERR with STOUT.

The switch is using the standard variable switch method -- 3 variables (buckets) are required to swap 2 variables with each other. (you have 2 variables and you need to switch the contents - you must bring in a 3rd temporary variable to hold the contents of one value so you can properly swap them).

This link gave me this information:
http://www.cpqlinux.com/redirect.html
juha at kuhazor dot idlegames dot com
04-Aug-2005 02:32
This technique was post posted by someone else earlier, however it did not work for me. This works with all Linux distros as long as path to your PHP processor is correct. The exec will return the PID for the process.

<?
$pid
=exec("/usr/local/bin/php run.php > /dev/null & echo \$!");

echo
$pid;
?>

My run.php script is here, it is good for testing.

<?

function getmicrotime()
{
   list(
$usec, $sec) = explode(" ", microtime());
   return ((float)
$usec + (float)$sec);
}

$starttime = getmicrotime();

$date=date("d/m/Y H:i",time());

echo
"Started sleeping\n";
sleep(30);
$endtime = getmicrotime();
echo
"Woke up\n";

echo
"Slept ".round(($endtime-$starttime),2)."\n";

?>
netshadow at madpoets dot org
05-Apr-2005 10:13
For Win2k/XP systems, and probably NT as well, after beating my head against a wall for a few days on this, I finally found a foolproof way of backgrounding processes and continuing the script. 

For some strange reason I just could not seem to get backgrounding to work with either system or exec, or with the wsh.run method for that matter.  I have used all three in the past with success, but it just wasn't happening this time.

What I finally wound up doing was using psexec from the pstools package found at http://www.sysinternals.com/ntw2k/freeware/pstools.shtml

You would use it like:

exec("psexec -d blah.bat");

which will start and immediately background blah.bat and immediately resume running the rest of the php script.
bitminer at example dot com
20-Mar-2005 02:24
I am posting this as I see quite a few people looking to create a web based interface to their MP3 player (XMMS or really what ever you want to call from the command line) on Linux.  Alas, I am not the only one, and  I did not think of it first ( suppose I have to result to other get rich quick schemes).  And even if there were a direct downloadable utility (as there is XMMS-Control) you, like me, probably want the bowl of porage that is just right.  Which means you want to make your own because current versions of X, Y, or Z just don't do what you want.

Most of the hard work is at the linux command shell (ugh! - I heard that!  Drop and give me 20 command line scripts!)

login as root

ensure /dev/dsp has the proper access privileges
chmod a+rw /dev/dsp

add apache to the local list of users for the xserver.
xhost +local:apache@

You should see the following if apache is not added to the xserver.

Xlib: connection to ":0.0" refused by server
Xlib: No protocol specified

** CRITICAL **: Unable to open display

And I am sure that error is as clear to you as it was to me!

NOTE !!! only change the following for testing purposes so that you can su to apache from root and test xmms !!!!

Temporarily change the line

apache:x:48:48:Apache:/var/www:/sbin/nologin

To
apache:x:48:48:Apache:/var/www:/bin/bash

so that you can test out apache access to the Xserver and XMMS.

su apache
xmms
!!! Play a file - Don't just read this actually play a file!!!  The reason is that if it fails xmms will likely give an error you can track down like a greyhound chases that little bunny at the dog track! (speaking of get rich quick schemes)

And for the grand finale!

If you can call xmms from the command line you can likely do the following (unless you are running php in safe mode).  Ensure that the wav, mp3, or whatever you decide to test it with is accessible to apache.  I put the file into /var/www/html/icould.wav and chmod a+rw icould.wav

<?php
echo ' Executing XMMS ';
// note you could use system too!
//echo system( '/usr/bin/xmms --play icould.wav', $retval );
exec ('/usr/bin/xmms --play icould.wav');
?>

At your browser ensure you hit shift+refresh(button) so your browser doesn't give you a cahed the web page.

Brian J. Davis
david houlder
22-Feb-2005 07:47
The note regarding how exec() works under safe_mode is wrong.

echo y | echo x does not become echo "y | echo x". It essentially becomes echo "y" "|" "echo" "x". The entire string is  passed through escapeshellcmd(), which effectively splits arguments at spaces. Note that this makes it impossible to reliably pass arguments containing spaces to exec() in safe_mode. Since 4.3.3 escapeshellcmd() tries to pass quoted arguments through (so you could try exec("cmd 'arg 1' 'arg 2'")), but not on win32, and will still wrongly backslash escape any punctuation characters inside the quotes.

Not only can the path not contain '..' components, but no directory or filename can contain the string '..'. e.g. /path/to/my..executable will refuse to run.
xyexz at yahoo dot com
22-Jan-2005 02:28
Ok, well after looking around for a long time on how to execute programs and not have them hanging in the processes in windows I have come up with a solution thats good for me but some of you may laugh.
Credit to msheakoski @t yahoo d@t com for the example script above here somewhere.
My problem was that I sometimes restart my server remotely and it doesn't turn on my ftp when my computer starts up, I do this so it will start up quicker.  But when I want my ftp open I was using a script that executed a .bat from php.  However I found this leaves processes running that were dead.
I saw msheakoski's solution:

<?
$WshShell
= new COM("WScript.Shell");
$oExec = $WshShell->Run("notepad.exe", 3, true);
?>

Well I tried sticking in my ftp program executible name where he had notepad.exe.
It didn't work.
Then I realized that windows will execute anything in the windows directory without including the entire path.
So I made a lnk file called FTP.link.  I then edited msheakoski's script to:

<?
$WshShell
= new COM("WScript.Shell");
$oExec = $WshShell->Run("FTP.lnk", 3, false);
?>

And voila! It runs my ftp program and cmd nor php.exe run in the background dead. Simple yet effective, (just how I like it).
Hope this helps you as much as it did me.
Brian
layton at layton dot tk
19-Jan-2005 07:52
This is the second time this one got me, I thought someone else might find this note useful too.

I am creating a long running exec'd process that I can access with page submissions up to 2 hours later. The problem is this, the first time I access the page everything works like it should. The second time the web browser waits and waits and never gets any messages -- the CPU time is not affected so it is apparent that something is blocked.

What is actually happening is that all of the open files are being copied to the exec'd process -- including the network connections. So the second time I try to access the web page, I am being given the old http network connection which is now being ignored.

The solution is to scan all file handles from 3 on up and close them all. Remember that handles 0, 1, and 2 are standard input, standard output, and standard error.
13-Jan-2005 08:38
I wanted my script to:

* execute an external command.
* check if the execution was ok. (i.e. the return level)
* log the error output if the execution wasn't ok.
* not print the command's output in my script's output.

I saw the exec, system, shell_exec and passthru functions, and deduced that the solution was to redirect the standard error (stderr) to the standard output (stdout). It's not very clean, since it mixes stderr with stdout, and I only wanted to log the stderr. But it seems to be the only solution (suggestions are welcome).

This is the code I use:

<?php

$com
= "ls";    # command

exec("$com 2>&1", $out, $err);                                         
if (
$err) my_log_func(join("\n", $out));

?>
chads2k2.yahoo.com
14-Dec-2004 02:38
This will execute a exectuable from the
command window without the command
window even being seen.

Much help was given by Michael Sheakoski
as he stated below this in one of his other
scripts.  The problem I had was that I want
to have arguments be sent to the .exe.

This will run the exe and then whatever it
returned will be dealt with.

Tested with:
Windows XP Pro SP1
Apache2
PHP 4.3.x
IIS6 as well

Here is the snippet.
<?php
// Get a good ol' timestamp.  Unique and it works.
$unixtime = time();

// Sets up your exe or other path.
$cmd = 'C:\\path\\to\\program\\argue2.exe';

// Setup an array of arguments to be sent.
$arg[] = '1';
$arg[] = '2';
$arg[] = '3';
$arg[] = '4';
$arg[] = '5';

// Pick a place for the temp_file to be placed.
$outputfile = 'C:\\path\\to\\tmp\\unixtime.txt';

// Setup the command to run from "run"
$cmdline = "cmd /C $cmd " . implode(' ', $arg) . " > $outputfile";

// Make a new instance of the COM object
$WshShell = new COM("WScript.Shell"); 

// Make the command window but don't show it.
$oExec = $WshShell->Run($cmdline, 0, true);

// Read the file file.
$output = file($outputfile);

// Delete the temp_file.
unlink($outputfile);

// Take the output and break the array apart. 
// If you don't know what is coming out do:
// print_r("$output");
foreach($output as $temp_output)
{
  
// Check the output's return code.
  
if($temp_output == 1)
   {
    
// Tell the user it was correct.
    
echo "All is good";
   }else{
    
// Tell the user something goofed.
    
echo "Didn't go smoothly.";
   }
}
?>
14-Oct-2004 12:46
if you want to use rsh and nohup, you should do this:

<?php
  
//...
  
exec("nohup  rsh -n *command* 1>/dev/null/ 2>&1 &");
  
//..
?>

or

<?php
  
//...
  
exec("nohup  rsh -n *command* 1>result.log 2>&1 &");
  
//...
?>
php-contrib at i-ps dot net
12-Oct-2004 09:30
I had a bit of trouble using exec with Windows when passing a parameter to a PHP script file. I found I needed to create a Windows batch "wrapper" file to get the script file to accept the optional argument.

1) PHP script file exists:
  c:\www\script.php

2) PHP is installed in:
  c:\www\php\

3) BAT file contains:
  @c:\www\php\cli\php.exe c:\www\script.php %1

and is saved as:
  c:\www\script.bat

4) Use exec statement from PHP:
  exec("c:\www\script.bat $arg", $output);

If you want to pass more than one argument, carry on with %2, %3, %4, ..., ... in your BAT file.

Hope this helps somebody
msheakoski @t yahoo d@t com
08-Jul-2004 11:40
I too wrestled with getting a program to run in the background in Windows while the script continues to execute.  This method unlike the other solutions allows you to start any program minimized, maximized, or with no window at all.  llbra@phpbrasil's solution does work but it sometimes produces an unwanted window on the desktop when you really want the task to run hidden.

start Notepad.exe minimized in the background:
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("notepad.exe", 7, false);

start a shell command invisible in the background:
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false);

start MSPaint maximized and wait for you to close it before continuing the script:
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("mspaint.exe", 3, true);

For more info on the Run() method go to:
http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp
llbra@phpbrasil
06-Jul-2004 08:30
If you want to run somenthing but php just keep processing data and dont answer until the program is closed (run in background mode, without interfering the program), from the note ( If you start a program using this function ... PHP will hang until the execution of the program ends ), jonas function will certainly be useful for you:

<?php
function execInBackground($path, $exe, $args = "") {
   global
$conf;
  
   if (
file_exists($path . $exe)) {
      
chdir($path);
       if (
substr(php_uname(), 0, 7) == "Windows"){
          
pclose(popen("start \"bla\" \"" . $exe . "\" " . escapeshellarg($args), "r"));   
       } else {
          
exec("./" . $exe . " " . escapeshellarg($args) . " > /dev/null &");   
       }
   }
}
?>

Thank you Jonas. It has been very useful for me.
until-june-04 at daniu dot de
14-May-2004 06:27
Hi!

I just want to add a note to the function "jonas DOT info AT gmx DOT net" contributed to keep processes running in the background.

Not like with the other exec/system/passthru etc. functions if you want to execute a batch file on a MS-machine you need to add a simple exit in the last line of your batch-file otherwise the CMD task does not close and your server will be filled with dead processes ... No idea what happens with other programs .
tr4nc3 at msn dot com
22-Feb-2004 06:43
I almost gave up trying to get Windows XP w/ Apache 2 to use either system(), or exec() to run a batch file.

If the batch file was this...

echo test > test.txt

it would work fine, creating test.txt...

but if the batch file was..

iexplore.exe "http://www.ibm.com"

I would get nothing. After hours and hours of messing around with this I figured it must be some type of permission problem. (dugh!)

Long story a little shorter.. You have to give Apache permission to "interact with the desktop".

Here's how...

Start>Run>services.msc
Right click "Apache...", select properties.
Click on the "LOG ON" tab
Check the box "Allow this service to interact with desktop"
Click OK
Restart Apache

Works great!
:D

HOPE THIS HELPS SOMEONE!
Too bad I didn't find a post like this before I figured it out myself. (I could have been working on something.)
alerque.com, look for contact info
22-Dec-2003 05:30
In order to execute a command have have it not hang your php script while it runs, the program you run must not output back to php. To do this, redirect both stdout and stderr to /dev/null, then background it.

> /dev/null 2>&1 &

In order to execute a command and have it spawned off as another process that is not dependent on the apache thread to keep running (will not die if somebody cancels the page) run this:

exec('bash -c "exec nohup setsid your_command > /dev/null 2>&1 &"');
camusatan at yahoo dot com
08-Nov-2003 04:22
I tried forever to figure out how to invoke a background process, _then_ get its PID so that I can later check on it. On Linux (with /bin/sh equalling /bin/bash), the following finally worked:

$shell_results= exec("wget -O - \"$myurl\" &>/dev/null & echo \$!",
       $results,$status);

The command I'm invoking is 'wget', and $shell_results will end up with the PID of the background wget process. The $results and $status variables I mostly just used for troubleshooting and getting this line working. I put a backslash in front of the dollar sign to keep PHP from trying to interpret it as a variable.
nehle at dragonball-se dot com
22-Oct-2003 05:59
Remember that some shell commands in *NIX needs you to set a TERM enviroment. For example:
<?php
exec
('top n 1 b i', $top, $error );
echo
nl2br(implode("\n",$top));
if (
$error){
  
exec('/usr/bin/top n 1 b 2>&1', $error );
   echo
"Error: ";
   exit(
$error[0]);
}
?>
This will echo "Error: TERM enviroment variable not set. " To fix it, add  TERM=xterm (Or some other terminal) to the exec-statement, like this

<?php
exec
('TERM=xterm /usr/bin/top n 1 b i', $top, $error );
echo
nl2br(implode("\n",$top));
if (
$error){
  
exec('TERM=xterm /usr/bin/top n 1 b 2>&1', $error );
   echo
"Error: ";
   exit(
$error[0]);
}
?>
colet at putnamhill dot net
27-Sep-2003 06:34
Technique for debuging php in *nix environments:

SSH to your php directory and enter the following:

   mkfifo -m 772 .debug
   tail -f .debug

Now in your php scripts direct debug messages to the debug FIFO with:

   exec("echo \"Some debug statement or $var\" > .debug");

When the php executes, you can watch the output in your terminal app.

This is helpful in situations where it's awkward to debug in a browser (i.e. header commands).
zitan at mediasculpt dot net
19-Sep-2003 01:19
If you're wondering how to catch error messages when calling exec, you simply need to use 2>&1 at the end of your command, and then error messages will get populated into your $output string  (i.e. STDERR to STDOUT). 

<?
exec
("$cmd 2>&1", $output);
echo
$output;

foreach(
$output as $outputline){
   echo(
"$outputline<br>");
}
?>
jonas DOT info AT gmx DOT net
13-Sep-2003 12:24
On WinXP with Apache2 and PHP 4.3.3 you cannot start a program in background with exec and start. you have to do the following. This function should work on Windows and Unix, too.

function execInBackground($path, $exe, $args = "") {
   global $conf;
  
   if (file_exists($path . $exe)) {
       chdir($path);
       if (substr(php_uname(), 0, 7) == "Windows"){
           pclose(popen("start \"bla\" \"" . $exe . "\" " . escapeshellarg($args), "r"));   
       } else {
           exec("./" . $exe . " " . escapeshellarg($args) . " > /dev/null &");   
       }
   }
}

I have this tested in Win XP and SUSE Linux with Apache and PHP 4.3.3.
mauroi at digbang dot com
04-Sep-2003 12:18
Well, after hours of fighting with output redirection, input redirection, error redirection, session_write_close (), blah blah blah, I think I found an easy way to execute a program in background. I used the following command:

Proc_Close (Proc_Open ("./command --foo=1 &", Array (), $foo));

With the second argument you tell proc_open not to open any pipe to the new process, so you don't have to worry about anything. The third argument is only needed because it's not optional. Also, with the '&' operator the program runs in background so the control is returned to PHP as soon as Proc_Close is executed (it doesn't have to wait).
In my case I don't use the user session in the executed script (there's no way it can be identified if it is not sended as a cookie or URL) so there's no need for session_write_close (correct me if I'm wrong with this).
It worked for me.
bishupaulose at yahoo dot com
20-Jun-2003 02:46
Using ping function in PHP
---------------------------------------

You can use the extended version of this program to check the network status and later you can add HTTP.FTP.POP3 and SMTP protocols as its part.

Access the content of exec from a variable, make radio buttons for each protocol and change the value of variable according to te radio button selection.

[Use ping with count and deadline]

<META http-equiv="Refresh" content="3">
<?php
  $str
=exec("ping -c 1 -w 1 192.168.1.216",$a,$a1);
  print
"<table>";
  if(
strlen($str)>1){
     print
"<tr><td bgcolor='#fff000'>present</td></tr>"
  }else{
     print
"<tr><td bgcolor='#000000'>Not present</td></tr>";     
  }
 print
"</table> ";
?>
hansarnholm at hotmail dot com
18-Jun-2003 03:00
After searching the web for some time, I finally found out why I was getting those Unable to pork warnings. I try and still use the
"exec("cmd /c [command]", $array);"

but in Windows XP using this command is not enough. You have to enable the IUSR_xxx user to read both cmd.exe and the file you want to execute. Where xxx is replaced by your computername.
Since Simple File Sharing by default is enabled in WindowsXP you cannot give the IUSR_xxx user access to cmd.exe without doing it in a dos-command-promt.

So open up cmd.exe: Start -> Run -> cmd

use the calcs command to edit the access rights for the files.

e.g.
C:\WINDOWS\system32>cacls cmd.exe /E /G CYPRES\IUSR_CYPRES:R

since CYPRES is my computername, this is the name I will use. When you do the command replace CYPRES with your computer name.

And thats it. Sorry for the long note, but I thought others might find it usefull... ;)
matt at nexxmedia dot com
12-Jun-2003 04:38
[ Editor's note: When passing multiple args in a URL like this, be sure to enclose the URL in quotes otherwise the & will be interpreted as a detachment flag and the rest of the command will be truncated. ]

The lynx browser can be used as simple way of executing a script from a remote location without waiting for it to complete:

$command = "/usr/bin/lynx -dump https://www.anotherserver.com?var=blah >/dev/null &";
exec($command);
nop at netissat dot bg
11-Apr-2003 12:49
SESSIONS + EXEC

>From: karl at cactuslab dot com
>22-Oct-2002 02:27
>Regarding the question from mightye at mightye dot org about exec leaving >programs running in the background causing PHP to lock up - at least for >your current session.
>
>I think this is due to the locking of session data? Try adding a >session_write_close() before your exec and see if that fixes it. Fixed it for me.

It seems that this is the right solution. ;]
I tried everything including registering new session(NEW SESSID) and destroyng the old one but this includes much more code and does not seem clean to me ...

doing session_write_close(); before exec solves the problem
nice end easy :)

-- NOP
marc at thewebguys dot com dot au
26-Feb-2003 11:51
I wrote a simple ping user function, useful for automatically determining wether to show high bandwidth content or calculating download times.

function PingUser() {
  global $REMOTE_ADDR;
  return ereg_replace(" ms","",end(explode("/",exec("ping -q -c 1 $REMOTE_ADDR"))));
  }

It returns a number representing the milli seconds it took to send and receive packets from the user.
iceburn at dangerzone dot c o m
10-Sep-2002 08:20
This seems to work for me on win2k server w/ iis 5  w/ php 4.2.2....

<?php
if(getenv("OS")!="Windows_NT")
 {
  echo
"This script runs only under Windows NT";
 }
 
 
$tmp = exec("usrstat.exe Domain", $results);

foreach (
$ping_results as $row) echo $row . "<br>";
 echo
"done";
?>

For those that don't know what usrstat is, it's a program that is the admin pack for win2k that lists users in a domain and thier last logon time.  I used it as the example to show that arguments can be passed (the domain).

The one "gotcha" is that usrstat.exe must be in the system path...ie if you are at the server w/ a command window, anything you can type w/o typing in a path, works.  Try it with ping, since that should be in system32 for just about everyone...

I've tried things like:
exec("c:\temp\usrstatexe...
exec("cmd /c c:\temp\usrstat.exe...

but can't seem to get anywhere with those...

even putting the exe on a shared drive with identical paths for the client and server to the exe doesn't work (don't know why that would fix it, but was just trying things...)
ronperrella at NOSPAM dot hotmail dot com
07-Aug-2002 02:04
I ran into the problem of not being able to set environment variables for my kornshell scripts. In other words, I could not use putenv() (at least to my understanding).

The solution I used was to write a script on the fly, then execute that script using exec().

$prgfile = tempnam("/tmp", "SH");
chmod($prgfile, 0755);
$fp = fopen($prgfile, "w");
fwrite($fp, "#!/bin/ksh\n");
fwrite($fp, "export MYENV=MYVALUE\n");
fwrite($fp, "ls -l\n"); // or whatever you wanna run
fclose($fp);
exec($prgfile, $output, $rc);

then delete the temp file (I keep it around for debugging.)
mightye at mightye dot org
30-Jul-2002 03:32
PHP pages will still hang waiting on exec()'d processes to finish before the server sends eof to the browser, at least with php4.1.2 on apache 1.3.24.  I'm trying to create a web-based interface to a MP3 player using mpg123.  I exec("mpg123 -v \"$HTTP_GET_VARS[item]\" > /tmp/mpg123status 2>&1 &");, and the rest of my script executes fine, but at the exit(); or end of the script, the browser just sits there holding its page until the mpg123 status either finishes on its own, or is terminated.  As under my setup, that means no further requests will be fulfilled to the php script that is still hanging, this becomes a problem.

I haven't been able to identify a means to allow the script to terminate, yet allow the sub process (mpg123) to continue, has anyone had luck obtaining this sort of result?  Halting the script via stop in the browser, or terminating on the command line allows the mpg123 process to continue, and further requests for my php script to be honored.
kop at meme dot com
08-Jul-2002 05:19
Nowhere is it mentioned that exec() strips off the end-of-line character(s) from the command's output.  This is true both in the return value and in the values assigned to the array in the second argument.

This makes it impossible to tell if the command output ends in a end-of-line character(s).
me at jcornelius dot com
16-May-2002 01:06
Note that when in 'Safe Mode' you must have the script or program you are trying to execute in the 'safe_mode_exec_dir'. You can find out what this directory is by using phpinfo().
hans at internit dot NO_SPAM dot com
02-Feb-2002 06:25
From what I've gathered asking around, there is no way to pass back a perl array into a php script using the exec function.

The suggestion is to just print out your perl array variables at the end of your script, and then grabbing each array member from the array returned by the exec function. If you will be passing multiple arrays, or if you need to keep track of array keys as well as values, then as you print each array or hash variable at the end of your perl script, you should concatenate the value with the key and array name, using an underscore, as in:
 
foreach (@array) print "(array name)_(member_key)_($_)" ;

Then you would simply iterate through the array returned by the exec function, and split each variable along the underscore.

Here I like to especially thank Marat for the knowledge. Hope this is useful to others in search for similar answer!
11-Jan-2002 09:39
When using escapeshellcmd and the stderr to stdout redirect '2>&1'. Append '2>&1' to the call to escapeshellcmd not within it, otherwise the returning string is empty rather than containing the error.

$cmd = escapeshellcmd("...")." 2>&1";
$string = exec($cmd,$array,$integer);
Yannis dot BRES at cma dot inria dot fr
08-Sep-2001 03:30
It seems that exec first launches a shell (command processor) under Linux, but not under Windows.  Therefore, redirection tricks like 2>&1 do not work under Windows.  In order to force the launching of an executable through a command processor under Windows, and be able to use redirection, prepend getenv( "COMSPEC" ) . " /C " to the name of your executable.
ryan at imagesmith dot com
17-Jul-2001 06:47
Some sites provide an htpasswd program that doesn't allow the -b switch (i.e. batch adding). 
  So I've used this to add a user.  (This is all one line of code.  Sorry it looks so intense here).

  system("perl -e \"print \\\"$UserName:\\\" . crypt('$Password', join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]) . \\\"\\n\\\";\" >> $path_to_pass_file");
ary at communicationfactory dot com
14-Jun-2001 07:10
Remember to use unix exit(o); on unix calls that use Unix redirection operator ">" . This was a real problem for me, I was not getting a response back in the following code until I added exit(0);

<?PHP
function myspawn()
{
 
$command="/usr/local/bin/mybinary infile.txt > outfile.tx2";
 
exec($command);
 
## nothing worked for me until I added this next line.
 
exec("exit(0)");
}
?>
<html>
<head>
<title>New Page 1</title>
</head>
<body>
Creating output file now
<?  myspawn();?>
</body>
</html>
auriane at bigfoot dot com
13-May-2001 05:10
If you want to use the exec command to change passwords in a .htaccess file, it's possible, but do not use the direct exec command, that didn't work for me.

What works perfectly; (on Linux)
$Htuserfile    = "/home/userssite";
$Pathhtpasswd = "/usr/local/apache/bin/htpasswd -b";
$test=shell_exec($Pathhtpasswd." ".$Htuserfile." ".strtolower($Login_Name)." $Password");
pkshifted at slackin dot com
08-Mar-2001 03:24
If you want to use exec() to start a program in the background, and aren't worried about load (because the program can only run one instance or you will manually stop it before starting it again) you can use either of these methods to leave it running in the background indefinately.

Add set_time_limit(some ridiculously huge number)  to your script, cause even though it won't stop it, it does seem to allow it to run longer than usual.
...or...
exec("nohup *command* 1>/dev/null/ 2>&1 &");

Thanks to the guys on the php list for helping me solve this unusual(?) problem.
bens_nospam at benjamindsmith dot com
16-Feb-2001 05:19
ON A LINUX SYSTEM:

Note that the exec() function calls the program DIRECTLY without any intermediate shell. Compare this with the backtick operator that executes a shell which then calls the program you ask for.

This makes the most difference when you are trying to pass complex variables to the program you are trying to execute - the shell can interpret your parameters before passing them thru to the program being called - making a dog's breakfast of your input stream.

Remember: exec() calls the program DIRECTLY - the backtick (and, I THINK, the system() call) execute the program thru a shell.

-Ben