4

So I open a process with $process = proc_open("my_process", $descriptors, $pipes);

Then I write to the stdin of the process using fwrite($pipes[0], "some_command");

Then I have to close the pipe using fclose($pipes[0]); before i can read from the pipes stdout using $output = stream_get_contents($pipes[1]);. If I don't close the pipe my php script hangs on this call.

But once I have received the output from stdout what if I want to send another command to the process...the stdin pipe is closed so I have no way to send it. So is it possible to somehow send another command to the process?

Jim_CS
  • 4,082
  • 13
  • 44
  • 80

1 Answers1

2

It sounds like the other process is blocking waiting for EOL or EOF on STDIN. What are you trying to execute?

Regardless, there's a pretty good chance this will sort it out: Just append \n to the command you are sending to the other process.

E.g.

$process = proc_open("my_process", $descriptors, $pipes);

$command = "some_command";
fwrite($pipes[0], $command."\n");

// Fetch the contents of STDOUT

Now, one issue that you may also be running into is to do with the fact that you are using stream_get_get_contents() - which will wait for EOF before it returns. You may have to be a bit more intelligent about how your retrieve the data from $pipes[1], using fgets() and looking for a specific number of lines or a string to indicate the end of the output.

If you tell us what you are executing, I may be able to give you a more specific answer.

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
  • Yes, the other program is an interactive terminal program with its own shell. If I started this other program up 'normally', ie. through the terminal and not through php proc_open it would load up and then display a command prompt like 'my_program >>' that I can run commands against. I have tried appending '\n' to the $command but it doesn't work. It will hang on stream_get_contents(). Using fflush() doesn't work either, it only works when I close $pipes[0]. – Jim_CS Jul 24 '12 at 15:18
  • 1
    @Jim_CS Try the above code, but afterwars just `echo fgetc($pipes[1]);` - just try and fetch 1 character from the other program's STDOUT and echo it in PHP. My guess is that it is your read operation causing the block, rather than the other process waiting for more input/EOF. If that doesn't work, try getting data from the other process' STDERR, it might be outputting the data you want on that. – DaveRandom Jul 24 '12 at 15:23
  • The other program outputs some startup text such as 'Modules loaded: abc, xyz, etc...'. So if I use a while loop with $output[] = fgets[$pipes[1]) it first gets about 8 lines of startup text. If I have used fclose($pipes[0]) it will then give me the output from processing the command I sent. However, if I append an '\n' or use flush() it will get the 8 lines of startup text but then will hang when it is supposed to retrieve the output from my command. This looks to me like my command isn't getting sent to the program's STDIN as if it was getting sent I would be able to retrieve the result. – Jim_CS Jul 24 '12 at 15:32
  • 1
    @Jim_CS AFAIK any `fwrite()` calls in this context send the data to the program immediately, and I have just being playing around executing some interactive programs with `proc_open()` and it does seem to work. I take it this is some custom program that you can't provide me with so I can play with it myself? One possible (albeit very ugly) work around to this would be to telnet/SSH into yourself and execute it that way, because then the PHP stream you are dealing with would be socket based so you can use set timeouts etc, plus you'd only have to deal with one stream for all I/O operations – DaveRandom Jul 24 '12 at 15:41
  • Well the program is called gap, its an open source algebra math program. The latest version doesnt work with proc_open due to some bug but version 4.4.12 does and you can get it here, you need these two packages - ftp://ftp.gap-system.org/pub/gap/gap44/tar.gz/gap4r4p12.tar.gz ftp://ftp.gap-system.org/pub/gap/gap44/tar.gz/packages-2012_01_12-10_47_UTC.tar.gz ... There is a readme with install instructions in the first package, basically you just type 'configure' then './make', its v straightforward. – Jim_CS Jul 24 '12 at 16:08
  • telnetting/ssh is too much, there are simpler workarounds but the best method of all would be if I could just make multiple writes to the STDIN and not have to fclose the pipe. – Jim_CS Jul 24 '12 at 16:16
  • @Jim_CS Alright I'll have a play with it when I get home to a proper Linux machine - I am at work where I only have Windoze and pretend Linux (v. old kernel on MIPS with BusyBox and no gcc). I'll get back to you in ~4 hrs – DaveRandom Jul 24 '12 at 16:24
  • @Jim_CS It's very odd this and not as straightforward as I assumed it would be, it does seem that gap is hanging until EOF appears on STDIN. I think there must be more going on behind the scenes here, because it doesn't do this with a controlling tty, so I'm going to have a dig through the source of gap and see if I can work out what's going on here - I'll get back to you. Let me know if you find a solution yourself. – DaveRandom Jul 24 '12 at 21:57
  • Yes its a strange one alright. It seems using proc_open is not exactly the same as initiating a program through the terminal as opening the latest versions of gap, versions 4.5.5 and 4.5.4, with proc_open doesn't work and throws up errors whereas they open fine in a regular terminal. – Jim_CS Jul 25 '12 at 10:17
  • @Jim_CS That is because they will be checking [`isatty()`](http://linux.die.net/man/3/isatty) which you could work around with the aforementioned telnet/SSH approach. I'm still trying to come up with a nicer solution though... – DaveRandom Jul 25 '12 at 10:26
  • Interestingly [this](http://www.gap-system.org/Faq/Programming/programming1.html) seems to suggest that what you are doing should be possible: `What you can do is to run GAP in a child process and communicate with it using pipes, pseudo-ttys, UNIX FIFOs or some similar device` – DaveRandom Jul 25 '12 at 10:36