NYCPHP Meetup

NYPHP.org

[nycphp-talk] fun with proc_open

Dan Cech dcech at phpwerx.net
Wed Oct 5 17:09:54 EDT 2005


Hi all,

Firstly, apologies for the long email, I couldn't think of a less 
verbose way to describe the issues I'm experiencing.

I'm in the midst of writing a little program for executing long-running 
processes in the background from php and monitoring their output as they 
run.

The problem I'm running into is that when I execute a process using 
proc_open and try to read any output from stdout and stderr I am running 
into some odd behavior.

This only seems to happen under windows, running the same script on my 
debian server works as expected.

The first read from stdout is fine, but then it doesn't get any more 
output from stdout until the end of the script.

Is there some issue with using stdout and stderr together in this way 
that I don't know about?

My test code looks like this:

<?php

// allow script to run for 5 minutes
set_time_limit(300);

// maximum length of blocks to read from process
define('FREAD_LENGTH',1024*10);

$cmd = 'php '.dirname(__FILE__).DIRECTORY_SEPARATOR.'sleep.php';

$descriptorspec = array(
   1 => array('pipe','w'), // stdout
   2 => array('pipe','w'), // stderr
);

$process = proc_open($cmd,$descriptorspec,$pipes);

if (!is_resource($process)) {
   echo 'failed'."\n";
   exit(1);
}

// don't block process stdout or stderr
stream_set_blocking($pipes[1],0);
stream_set_blocking($pipes[2],0);

// don't buffer stdout or stderr
stream_set_write_buffer($pipes[1],0);
stream_set_write_buffer($pipes[2],0);

while (true) {
   // read process stdout
   $stdout = fread($pipes[1],FREAD_LENGTH);
   if (strlen($stdout) > 0) {
     echo 'stdout:'. $stdout;
     flush();
   }

   // read process stderr
   $stderr = fread($pipes[2],FREAD_LENGTH);
   if (strlen($stderr) > 0) {
     echo 'stderr:'. $stderr;
     flush();
   }

   // end when both pipes are closed
   if (feof($pipes[1]) && feof($pipes[2])) {
     break;
   }

   // wait for more output
   sleep(1);
}

// close process stdout and stderr
fclose($pipes[1]);
fclose($pipes[2]);

// grab exit code
$exitcode = proc_close($process);

echo 'exitcode:'. $exitcode ."\n";

// end of script

sleep.php is a simple script that outputs some data:

<?php

ob_implicit_flush();

echo('started'."\n");

for ($i = 1;$i <= 10;$i++) {
	sleep(1);
	echo($i."\n");
}

fwrite(STDERR,'done'."\n");

// end of script

Running the first script from command line or web browser should output:

stdout:started
stdout:1
stdout:2
stdout:3
stdout:4
stdout:5
stdout:6
stdout:7
stdout:8
stdout:9
stdout:10
stderr:done
exitcode:0

On windows I'm seeing:

stdout:started
stderr:done
stdout:1
2
3
4
5
6
7
8
9
10
exitcode:0

I've managed to get the same functionality using popen and redirecting 
stderr to a fifo or tempfile, but proc_open seems like the cleaner 
solution if I can get it to work the way I want.

Any ideas?

Dan



More information about the talk mailing list