CHAPTER 9 – FILES AND STREAMS – Program Input/Output

Much like UNIX has the paradigm "All IO is a file," PHP has the paradigm "All IO is a stream." Thus, when you want to work with the input and output of a program, you open a stream to that program. Because you need to open two channels to your program--one for reading and one for writing--you use one of two special functions to open the streams: popen() or proc_open().

popen() popen() is the simpler function, providing only unidirec- tional IO to a program; you can only use w or r as the opening mode. When you open a stream to a program, also called a pipe (hence the name popen()), you can use all the normal file functions to read or write from the pipe, and use (for example) feof() to check if there is no more input to read. Here is a small example that reads the output of ls ­l /: <?php $fp = popen('ls ­l /', 'r'); while (!feof($fp)) { echo fgets($fp); } pclose($fp); ?>

proc_open() popen() is seldom useful because you cannot perform any interactive tasks with the opened process. But don't worry--PHP has a function to provide the missing functionality: proc_open(). With proc_open(), you can link all the input and output handlers of a process to either a pipe from which you can read or a pipe to which you can write from your script, or a file. A pipe is treated as a file handle, except that you can never open a file handle for reading and writing at the same time. proc_open() requires three parameters: resource proc_open ( string cmd, array descriptorspec, array pipes) The cmd parameter is the command to execute, such as /usr/local/bin/ php. You don't need to specify the full path to the executable used by popen() if your executable is in the system path. The descriptorspec parameter is more complex. descriptorspec is an array with each element describing a file handler for input or output.

File Descriptors <?php $fin = fopen("readfrom", "r"); $fout = fopen("writeto", "w"); $desc = array (0 => $fin, 1 => $fout); $res = proc_open("php", $desc, $pipes); if ($res) { proc_close($res); } ?> This script starts a PHP interpreter--a child process. It links the input for the child process to the file descriptor $fin (which is a file handler for the file "readfrom") and the output of the child process to $fout (which is a file han- dler for the file "writeto"). The "readfrom" file contains <?php echo 'Hello you!'; ?> After the execution of the script, the file "writeto" contains Hello you!

P|pes Instead of using a file handler for input and output to the PHP child process, as shown in the script in the previous section, you can open pipes to the child process that allow you to control the spawned process from your script. The following script sends the <?php echo 'Hello you!'; ?> script from the script itself to the spawned PHP interpreter. The script writes the output of the echo statement to the standard output of the script, applying urlencode to the output text string "Hello you!". <?php $descs = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w')); $res = proc_open("php", $descs, $pipes); if (is_resource($res)) { fputs($pipes[0], '<?php echo "Hello you!n"; ?>'); fclose($pipes[0]); while (!feof($pipes[1])) { $line = fgets($pipes[1]); echo urlencode($line); } proc_close($res); } ?> The output is Hello+you%21%0A Files You can pass a file as the handler for the file descriptors to your process, as shown in the following example: <?php $descs = array( 0 => array('pipe', 'r'), 1 => array('file', 'output', 'w'), 2 => array('file', 'errors', 'w') ); $res = proc_open("php", $descs, $pipes); if (is_resource($res)) { fputs($pipes[0], '<?php echo "Hello you!n"; ?>'); fclose($pipes[0]); proc_close($res); } ?>

The output file now contains Hello you! and the 'errors' file is empty. In addition to the input pipe[0] and the output pipe[1] shown in the pre- vious examples, you can use other pipes to redirect all file descriptors of the child process. In the preceding example, we redirect all error messages sent to the standard error descriptor (2) to pipe[2], the file errors. The index of the $descs array is not limited to the indices 0-2, so that you can always fiddle with all file descriptors as suits you. However, those additional file descriptors, with an index larger than 2, do not work yet on Windows because PHP doesn't implement a way for the client process to attach to them. Perhaps this will be addressed as PHP develops.

Post Comment
Login to post comments