proc_open tutorial and examples



A great advantage of Unix-based systems is the wealth of powerful command line tools. Very often it is quite useful to use tools such as sed, grep, or programs written in other programming languages instead of recoding in PHP. PHP has a very powerful function that allow you to execute external programs from your PHP script; proc_open(). proc_open() is very powerful but also difficult to understand.

proc_open() is used open a process which it returns as a resource (running process in our case). It takes the following parameters as input:

  1. command as string: This is what you type in the command line, e.g. ls -al
  2. array of descriptors
  3. array of pipes
  4. working directory
  5. environment variables

proc_open() STDIN, STDOUT, STDERR

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

The child process would read from the pipe define in the second line and write to the pipe defined in the third line. All errors would be written to the error log file defined in the third line.

Calling shell from PHP

In this example, we call '/bin/sh' and run the 'cal -3' command.

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

// define current working directory where files would be stored
$cwd = './' ;
// open process /bin/sh
$process = proc_open('/bin/sh', $descriptorspec, $pipes, $cwd) ;

if (is_resource($process)) {

  // anatomy of $pipes: 0 => stdin, 1 => stdout, 2 => error log
  fwrite($pipes[0], 'cal -3') ;
  fclose($pipes[0]) ;

  // print pipe output
  echo stream_get_contents($pipes[1]) ;

  // close pipe
  fclose($pipes[1]) ;
 
  // all pipes must be closed before calling proc_close. 
  // proc_close() to avoid deadlock
  proc_close($process) ;
}

In this program, we call /bin/sh. We then pipe the command 'cal -3' to it. Finally, we print the output of process. It is important to close the pipes in before close the process with proc_close(). proc_close() must be called to avoid deadlocks and also for security reasons.

The program should print you the calendar for 3 months.

Executing Perl code from PHP

proc_open can execute processes regardless of the language the the tool was coded in. Here I would execute a simple Perl program as an example.

reprint.pl
This Perl program simply reprints the command argument.

#!/usr/bin/perl
print @ARGV;

proc_open_perl_test.php
This PHP programs opens a process to execute a Perl program, passes it an argument and then prints the piped output of the Perl program.

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

// define current working directory where files would be stored
$cwd = './' ;

// open process reprint.pl and pass it an argument
$process = proc_open('./reprint.pl ' . $argv[1], $descriptorspec, $pipes, $cwd) ;

if (is_resource($process)) {

  // print pipe output
  echo stream_get_contents($pipes[1]) ;

  // close pipe
  fclose($pipes[1]) ;
 
  // close process
  proc_close($process) ;
}

To run this program, type:

php proc_open_perl_test.php argument

The program should return the argument you typed.

Debugging

The code would generate errors, if you do not give write permissions to your working directory.
The external files you call must also have sufficient right for you script to be able to read or execute them.