search for in the  
<proc_niceproc_terminate>
Last updated: Thu, 19 May 2005

proc_open

(PHP 4 >= 4.3.0, PHP 5)

proc_open --  Execute a command and open file pointers for input/output

Description

resource proc_open ( string cmd, array descriptorspec, array &pipes [, string cwd [, array env [, array other_options]]] )

proc_open() is similar to popen() but provides a much greater degree of control over the program execution.

PHP 5 introduces pty support for systems with Unix98 ptys. This allows your script to interact with applications that expect to be talking to a terminal. A pty works like a pipe, but is bi-directional, so there is no need to specify a read/write mode. The example below shows how to use a pty; note that you don't have to have all descriptors talking to a pty. Also note that only one pty is created, even though pty is specified 3 times. In a future version of PHP, it might be possible to do more than just read and write to the pty.

Parameters

cmd

The command to execute

descriptorspec

An indexed array where the key represents the descriptor number and the value represents how PHP will pass that descriptor to the child process. 0 is stdin, 1 is stdout, while 2 is stderr.

The currently supported pipe types are file, pipe and pty.

The file descriptor numbers are not limited to 0, 1 and 2 - you may specify any valid file descriptor number and it will be passed to the child process. This allows your script to interoperate with other scripts that run as "co-processes". In particular, this is useful for passing passphrases to programs like PGP, GPG and openssl in a more secure manner. It is also useful for reading status information provided by those programs on auxiliary file descriptors.

pipes

Will be set to an indexed array of file pointers that correspond to PHP's end of any pipes that are created.

cwd

The initial working dir for the command. This must be an absolute directory path, or NULL if you want to use the default value (the working dir of the current PHP process)

env

An array with the environment variables for the command that will be run, or NULL to use the same environment as the current PHP process

other_options

Allows you to specify additional options. Currently only suppress_errors is supported, which suppresses errors generated by this function when it's set to TRUE

Return Values

Returns a resource representing the process, which should be freed using proc_close() when you are finished with it. On failure returns FALSE.

ChangeLog

VersionDescription
5.0.0. Added the cwd, env and other_options parameters. Added support for Unix98 ptys.

Examples

Example 1. A proc_open() example

<?php
$descriptorspec
= array(
  
0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
  
1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
  
2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
);

$cwd = '/tmp';
$env = array('some_option' => 'aeiou');

$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

if (
is_resource($process)) {
  
// $pipes now looks like this:
   // 0 => writeable handle connected to child stdin
   // 1 => readable handle connected to child stdout
   // Any error output will be appended to /tmp/error-output.txt

  
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
  
fclose($pipes[0]);

   echo
stream_get_contents($pipes[1]);
  
fclose($pipes[1]);

  
// It is important that you close any pipes before calling
   // proc_close in order to avoid a deadlock
  
$return_value = proc_close($process);

   echo
"command returned $return_value\n";
}
?>

The above example will output something similar to:

Array
(
    [some_option] => aeiou
    [PWD] => /tmp
    [SHLVL] => 1
    [_] => /usr/local/bin/php
)
command returned 0

Example 2. ptys usage

<?php
// Create a pseudo terminal for the child process
$descriptorspec = array(
  
0 => array("pty"),
  
1 => array("pty"),
  
2 => array("pty")
);
$process = proc_open("cvs -d:pserver:cvsread@cvs.php.net:/repository login", $descriptorspec, $pipes);
if (
is_resource($process)) {
  
// work with it here
}
?>

Notes

Note: Windows compatibility: Descriptors beyond 2 (stderr) are made available to the child process as inheritable handles, but since the Windows architecture does not associate file descriptor numbers with low-level handles, the child process does not (yet) have a means of accessing those handles. Stdin, stdout and stderr work as expected.

Note: If you only need a uni-directional (one-way) process pipe, use popen() instead, as it is much easier to use.



User Contributed Notes
proc_open
falstaff at arragon dot biz
20-Mar-2005 07:22
Using this function under windows with large amounts of data is apparently futile.

these functions are returning 0 but do not appear to be doing anything useful.
stream_set_write_buffer($pipes[0],0);
stream_set_write_buffer($pipes[1],0);

these functions are returning false and are also apparently useless under windows.
stream_set_blocking($pipes[0], FALSE);
stream_set_blocking($pipes[1], FALSE);

The magic max buffer size I found with winxp is 63488 bytes, (62k). Anything larger than this results in a system hang.
Andre Caldas
25-May-2004 05:13
About the comment by  ch at westend dot com
of 28-Aug-2003 08:46

File streams are buffers. The data is not actualy written if you do not flush the buffer. In your case, fclose has the side effect of flushing the buffer you are closing.

The program "hangs" because it tries to read some data that was not written (since it is buffered).

You must do something like:
<?php
  fwrite
($fp);
 
fflush($fp);
 
fread($fp);
?>

Good luck,
   Andre Caldas.
list[at]public[dot]lt
11-May-2004 05:21
if you push a little bit more data through the pipe, it will be hanging forever. One simple solution  on RH linux was to do this:

 stream_set_blocking($pipes[0], FALSE);
 stream_set_blocking($pipes[1], FALSE);

This did not work on windows XP though.
ralf at dreesen[*NO*SPAM*] dot net
09-Jan-2004 01:49
The behaviour described in the following may depend on the system php runs on. Our platform was "Intel with Debian 3.0 linux".

If you pass huge amounts of data (ca. >>10k) to the application you run and the application for example echos them directly to stdout (without buffering the input), you will get a deadlock. This is because there are size-limited buffers (so called pipes) between php and the application you run. The application will put data into the stdout buffer until it is filled, then it blocks waiting for php to read from the stdout buffer. In the meantime Php filled the stdin buffer and waits for the application to read from it. That is the deadlock.

A solution to this problem may be to set the stdout stream to non blocking (stream_set_blocking) and alternately write to stdin and read from stdout.

Just imagine the following example:

<?
/* assume that strlen($in) is about 30k
*/

$descriptorspec = array(
  
0 => array("pipe", "r"),
  
1 => array("pipe", "w"),
  
2 => array("file", "/tmp/error-output.txt", "a")
);

$process = proc_open("cat", $descriptorspec, $pipes);

if (
is_resource($process)) {
 
  
fwrite($pipes[0], $in);
  
/* fwrite writes to stdin, 'cat' will immediately write the data from stdin
   * to stdout and blocks, when the stdout buffer is full. Then it will not
   * continue reading from stdin and php will block here.
   */

  
fclose($pipes[0]);

   while (!
feof($pipes[1])) {
      
$out .= fgets($pipes[1], 1024);
   }
  
fclose($pipes[1]);

  
$return_value = proc_close($process);
}
?>
MagicalTux at FF.ST
24-Dec-2003 06:20
Note that if you need to be "interactive" with the user *and* the opened application, you can use stream_select to see if something is waiting on the other side of the pipe.

Stream functions can be used on pipes like :
 - pipes from popen, proc_open
 - pipes from fopen('php://stdin') (or stdout)
 - sockets (unix or tcp/udp)
 - many other things probably but the most important is here

More informations about streams (you'll find many useful functions there) :
http://www.php.net/manual/en/ref.stream.php
ch at westend dot com
28-Aug-2003 10:46
I had trouble with this function as my script always hung like in a deadlock until I figured out that I had to strictly keep the following
order. Trying to close all at the end did not work!
  proc_open();
  fwrite(pipes[0]); fclose(pipes[0]); # stdin
  fread(pipes[1]);  fclose(pipes[1]); # stdout
  fread(pipes[2]);  flcose(pipes[2]); # stderr
  proc_close();
daniela at itconnect dot net dot au
16-Apr-2003 04:01
Just a small note in case it isn't obvious, its possible to treat the filename as in fopen, thus you can pass through the standard input from php like
   $descs = array (
               0 => array ("file", "php://stdin", "r"),
               1 => array ("pipe", "w"),
               2 => array ("pipe", "w")
       );
       $proc = proc_open ("myprogram", $descs, $fp);
joeldegan AT yahoo.com
28-Dec-2002 07:54
I worked with proc_open for a while before realizing how it works with applications in real time.
This example loads up the eDonkey2000 client and reads data from it and passes in various commands and returns the results.
This is the base for an ncurses gui for edonkey I am writing in PHP.

<?
define
("DASHES", "-------------------------------------------------\n");
function
readit($pipes, $len=2, $end="> "){
  
stream_set_blocking($pipes[1], FALSE);
   while(
$ret = fread($pipes[1],$len)){
      
$retval .= $ret;
   if(
substr_count($ret, $end) > 0){ $pipes[1] = "" ; break;}
   }
   return
$retval;
}
//end fucntion
function sendto($pipes, $str){
  
fwrite($pipes[0], $str."\n");
}
//end function
function viewopts($pipes, $opt){
  
sleep(1);
  
sendto($pipes, $opt);
   return
readit($pipes);
}
//end function
function sendopts($pipes, $opt){
  
sendto($pipes, $opt);
  
usleep(50);
   return
readit($pipes);
}
//end function

$dspec = array(
  
0 => array("pipe", "r"),
  
1 => array("pipe", "w"),
  
2 => array("file", "/tmp/eo.txt", "a"),);
$process = proc_open("donkey", $dspec, $pipes);
if (
is_resource($process)) {
  
readit($pipes);
   echo
DASHES;
   echo
viewopts($pipes, "vo");
   echo
DASHES; echo SEP;echo DASHES;
   echo
sendopts($pipes, "name test".rand(5,5000));
   echo
DASHES; echo SEP; echo DASHES;
   echo
viewopts($pipes, "vo");
   echo
DASHES; echo SEP; echo DASHES;
   echo
sendopts($pipes, "temp /tmp");
   echo
DASHES; echo SEP; echo DASHES;
   echo
viewopts($pipes, "g");
   echo
DASHES;
  
sendto($pipes, "q");
  
sendto($pipes, "y");
  
readit($pipes);
  
fclose($pipes[0]);
  
fclose($pipes[1]);
  
$return_value = proc_close($process);
}
?>

returns what looks like the following
-----------------------------------------------------------------
Name:                  test2555
AdminName:              admin
AdminPass:              password
AdminPort:              79
Max Download Speed:    0.00
Max Upload Speed:      0.00
Line Speed Down:        0.00
Door Port:              4662
AutoConnect:            1
Verbose:                0
SaveCorrupted:          1
AutoServerRemove:      1
MaxConnections:        45
> ----------------------------------------------------------------
filippo at zirak dot it
19-Apr-2002 09:50
Example of emulating the press of the special key "F3":
   fwrite($pipes[0], chr(27)."[13~");
(for others special keys,  use the program 'od -c' on linux)

(NEEDED: a timeout for stdout pipe, otherwise a fgets on $pipes[1] can lag forever...)

<proc_niceproc_terminate>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 17:35:34 2005 CDT