I want to know how I can interact with a program that I run in a command line PHP script. The scenario is:
How can I write a PHP script that does this? I'm thinking that I probably want to use proc_open()
but I can't figure out how. I'm thinking it would be something like this but it doesn't work of course:
$descriptorspec = array(
0 => array('pipe', 'r'), //STDIN
1 => array('pipe', 'w'), //STDOUT
2 => array('pipe', 'r'), //STDERR
);
$process = proc_open('mycommand', $descriptorspec, $pipes, null, null);
if (is_resource($process)) {
// Get output until first question is asked
while ($buffer = fgets($pipes[1])) {
echo $buffer;
}
if (strpos($buffer, 'STEP 1:') !== false) {
fwrite($pipes[0], "My first answer\n"); //enter the answer
} else {
die('Unexpected last line before question');
}
// Get output until second question is asked
while ($buffer = fgets($pipes[1])) {
echo $buffer;
}
if (strpos($buffer, 'STEP 2:') !== false) {
fwrite($pipes[0], "My second answer\n"); //enter the answer
} else {
die('Unexpected last line before question');
}
// ...and so we continue...
} else {
echo 'Not a resource';
}
UPDATE: I figured out that the program outputs the questions to STDERR (because it writes STDOUT to a file).
You are certainly on the right track.
It might be best to start with the glaring issue in your code:
while ($buffer = fgets($pipes[1])) {
echo $buffer;
}
This loop will never exit. At some point the program is going to ask you a question, but your code at this point is still executing the (blocking) fgets call.
As to how to write code that works properly....
The most obvious solution is not to bother waiting for the prompt before providing your answer. This will work as long as:
You don't need to adapt your response based on the preceding output of the program
The program is reading from its stdin and does not clear the buffer at any point
In fact, you don't even need a controlling process to this:
program <input.txt >output.txt 2>errors.txt
But assuming 1 and/or 2 do not apply, and given that it is redirecting its stdout already (which kind of suggests there's more to the story than we know about) then,
...
if (is_resource($process)) {
while ($buffer=fgets($pipes[2]) { // returns false at EOF/program termination
if (strpos($buffer, 'STEP 1:') !== false) {
fwrite($pipes[0], "My first answer\n");
} else if (strpos($buffer, 'STEP 2:') !== false) {
fwrite($pipes[0], "My second answer\n"); //enter the answer
}
}
}
Implementing checks for out of sequence questions and branching in the request/response cycle are left as an exercise for the reader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With