1

I am trying to read input from a file as stdin for the process using proc_open . But this file is actually going to be dynamic i.e. User will enter something in another process into this file. What I want is that proc_open should wait until some new content is added in this file before considering this as STDIN.

Here's what I have tried.

<?php
$desc = array(
    0 => array('file', 'input.txt','r'),
    1 => array('pipe', 'w'), 
    2 => array('pipe', 'w')
);
//$cmd = "java Main";
$cmd="python sample.py";
$proc = proc_open($cmd, $desc, $pipes);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
//stream_set_blocking($pipes[0], 0);
if($proc === FALSE){
    throw new Exception('Cannot execute child process');
}
$status=proc_get_status($proc);
$pid = $status['pid'];
while(true) {
    $status = proc_get_status($proc);
    if($status === FALSE) {
        throw new Exception ("Failed to obtain status information for $pid");
    }
    if($status['running'] === FALSE) {
        $exitcode = $status['exitcode'];
        $pid = -1;
        echo "child exited with code: $exitcode\n";
        exit($exitcode);
    }
    $a=0;
    //fwrite($pipes[0],"10\n");
    foreach(array(1, 2) as $desc) {
        // check stdout for data
        $read = array($pipes[$desc]);
        $write = NULL;
        $except = NULL;
        $tv = 0;
        $utv = 50000;
        $n = stream_select($read, $write, $except, $tv, $utv);
        if($n > 0) {
            do {
                $data = fread($pipes[$desc], 8092);
                //echo "tp".$data;
               //$a=$a+1;
               //echo $a."\n";
                fwrite(STDOUT, $data);
            } while (strlen($data) > 0);
           // echo "Hey". $desc;
        }   
    }
   /* $read = array(STDIN);
    $n = stream_select($read, $write, $except, $tv, $utv);
    if($n > 0) {
        echo "Inside input stream";
        $input=10;
        fwrite($pipes[0], $input);
    }else{
        echo "Not working";
    }*/
}
?>

And when i run a sample program with file input.txt empty the output is this:

Sample python program

print("Hello world")
x=input("Enter a no: ")
print(x)
y=input("Enter any string: ")
print(y)
print(y+str(x))

Output: Output of running python program with php script above

As u can see in the output when input for variable y is expected there's an error because input.txt file does not yet have the value. I want it to wait for some time say 30 secs and then only read newly added content but if it is added before 30 secs then it should immediately resume. Thanks!!!

dc480506
  • 21
  • 1
  • 5
  • Have the other process write the data into a different filename, like `input.temp`, then rename it to `input.txt` when it's done. Then the PHP script can loop, waiting for the file to exist. – Barmar Oct 20 '19 at 17:05
  • @Barmar But this will only solve problem for the first input ... Say if there are 3 inputs expected after every input i need to delete the file.... Also once the script comes out of loop as u mentioned... the process for program execution would have already started and then there's no coming back!! – dc480506 Oct 21 '19 at 06:49
  • You need to delete the files after processing them, so this will work every time. – Barmar Oct 21 '19 at 06:50
  • If there's any other approach you can think of please do share.... I am trying to make an interactive shell for program execution for a website ... So as soon as the output is generated .. user enters input and this is written to a file input.txt which acts as STDIN for proc_open. – dc480506 Oct 21 '19 at 06:51
  • You could use some kind of locking or signalling method. The point is that you need to be sure that the other process is finished writing the file, and there's no automatic way to do that. It requires explicit coordination. – Barmar Oct 21 '19 at 06:53
  • @Barmar Can you share the pseudocode if possible... I don't get it because what I think is once the file is renamed to input.txt the proc_open will completely execute the program – dc480506 Oct 21 '19 at 06:54
  • Yeah i thought of using threads for the signalling and coordination...but i learnt that threads are not supported in web server environment – dc480506 Oct 21 '19 at 06:56

1 Answers1

0

Wait for the file to be created before using it.

while !file_exists("input.txt") {
    sleep(5)
    // code that uses input.txt
}
...
unlink("input.txt") # Remove file to prepare for next iteration

To avoid seeing a partial file, the process that creates the file should write to a temporary name, then rename it to input.txt when it's done.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Consider the first 2 statements of python program which will print `Hello world` and `Enter a no` once this is printed then only i am supposed to take input from user... But for these 2 statements to get outputted ... proc_open should execute... And for proc_open to get executed I need to declare descArray for its stdin i.e. file input.txt needs to be there already which will be initially empty.But once user inputs the value it will be written to it and then only the proc_open should proceed further not before that ..currently it is proceeding even if the file is empty and hence the error. – dc480506 Oct 21 '19 at 07:24
  • Make sure the other program either closes the file or flushes output, otherwise what it's writing will be buffered. – Barmar Oct 21 '19 at 16:42
  • Just realized I wrote a Python answer to a PHP question, I've fixed it. – Barmar Oct 21 '19 at 16:49
  • Thank you so much!!! This did work but on Unix Environment!! Earlier I was trying on Windows OS .. I am marking this as correct – dc480506 Feb 23 '20 at 11:01