3

I'm using proc_open with pdftk to pre-fill some forms with data, this works pretty well, but rather than save the result to a file and then read the file back, I'd like to print the file directly out. I've got this working so I'm not having any problems. But I'd like to direct the output of proc_open directly to the stream returned to the user so that I don't have to hold the value in memory in php. So far I have the following:

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
  fwrite($pipes[0], $fdf);
  fclose($pipes[0]);
  echo stream_get_contents($pipes[1]));
  fclose($pipes[1]);
  proc_close($process);
}

I'd like to direct the result directly out to the use as you would get in the above code, without actually saving the value in a variable and then printing it out. Is there a way to direct a stream in php's output directly to the output. I'd like to do this to save memory and reduce the time it takes for the code to run.

Does anyone know of a function for a stream in php that prints the stream result directly out. Or is there a setting for proc_open that does this. Either way I fear this may not work at all, as I may need to add a content-length header to the output to display the PDF directly. If anyone knows of the function to print the stream directly out, is there also a way to get the byte length of the stream without actually reading it in.

kyall
  • 403
  • 1
  • 3
  • 11
  • http://php.net/manual/en/function.stream-copy-to-stream.php – kyall Feb 18 '13 at 04:56
  • http://php.net/manual/en/function.stream-copy-to-stream.php stream_copy_to_stream seems to serve, where the destination stream is created with fopen("php://output","w") Trying to find a way to get the stream length, may not be necessary however, have to test to see if it can display in the browser without the content-length set. Sorry for the comment span, first comment posted accidentally, I got interrupted by RL events, was unable to finish edit until the 5 minute edit epoch was expired. – kyall Feb 18 '13 at 05:05

2 Answers2

3

Since no one has posted an answer this I may as well post the answer I've found.

Open a stream to php://output with fopen mode w, and use stream_copy_to_stream to send the data from the proc_open process to the user directly. There does not appear to be an easy method to get the length or size of the data in the stream however.

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
  fwrite($pipes[0], $fdf);
  fclose($pipes[0]);

  /* New Code */  
  if( $fout = fopen("php://output","w") ) {
    stream_copy_to_stream($pipes[1],$fout);
    fclose($fout);
  }  

  fclose($pipes[1]);
  $result = proc_close($process);
}
kyall
  • 403
  • 1
  • 3
  • 11
0

The doc says:

descriptor_spec:

...

Each element can be:

  • An array describing the pipe to pass to the process. The first element is the descriptor type and the second element is an option for the given type. Valid types are pipe (the second element is either r to pass the read end of the pipe to the process, or w to pass the write end) and file (the second element is a filename). Note that anything else than w is treated like r.
  • A stream resource representing a real file descriptor (e.g. opened file, a socket, STDIN).

So you can use:

$descriptors = [
    1 => \fopen('php://stdout', 'w'),
    2 => ['pipe', 'w'],
];
JoniJnm
  • 720
  • 2
  • 10
  • 19