2

I'd say it's quite a simple question but I'm stuck with it:

I need to communicate with external program (specifically, Exim) run with some debug options. As I run it from linux shell, it goes like this: run exim -bh 11.22.33.44, then read its output (both STDOUT and STDERR), the type in some line from SMTP dialog, then read Exim output again, type another SMTP line and so on. And it's nicely works while I'm on bash shell, but as I run it from PHP script it stuck in STDIN read loop.

I use proc-open:

$descriptorspec = array(
    0 => array("pipe", "r"), 
    1 => array("pipe", 'w'), 
    2 => array("pipe", 'w')
);
$process=proc_open('/usr/sbin/exim -bh 11.22.33.44', $descriptorspec, $pipes, NULL, NULL);
if (is_resource($process)) {
    stream_set_blocking($pipes[1], 1);
    stream_set_blocking($pipes[2], 1);
    while(!feof($pipes[2])) {
        $txt2 = fgets($pipes[2]);
    }
    while(!feof($pipes[1])) {
        $txt2 = fgets($pipes[1]);
    }
    fwrite($pipes[0], 'HELO testhost');
...
}

Looks simple, but as it goes to the end of first STDERR, it stuck.

Tried both blocking and unblocking mode, tried to swap reading from STDERR and STDIN - no luck so far.

Please point me the right way to do that!

suspectus
  • 16,548
  • 8
  • 49
  • 57
Alexander
  • 464
  • 1
  • 5
  • 17

1 Answers1

0

I double check to make sure that exim isn't doing anything funky with STDIN, STDOUT, and STDERR. In addition, I know that you can use swaks to pipe to STDIN and from STDOUT (STDERR is debug output, so you can ignore that). With swaks, it's common to test debug builds with commands such as:

swaks --pipe './build-Linux-i386/exim -bh 205.201.128.129 
              -C/work/home/exim-build/tmp/etc/exim/exim.conf'
  --ehlo twitter4.us4.mcsv.net 
  --from bounce-mc.us3_23284199.312009-user=example.com@twitter4.us4.mcsv.net
  --to localuser@example.net --data $HOME/12.eml

Your script is checking for EOF, which is only sent when the pipe is closed. Instead you need to construct a function which an outer loop checks for() checks for !eof() from one of the pipes. Inside the loop, check for output from STDERR and STDOUT, and display it if found. When it gets to a point where it's expecting input, then send your SMTP commands.

There is still an issue though. If you use print $txt2 in order to see what it's doing, somehow that output seems to be the same as fprintf($pipes[0]...). I'm not sure why, and I'm not a php programmer to know why it would be doing this.

Todd Lyons
  • 998
  • 12
  • 19
  • The problem is that when I use blocking pipe mode my script hangs on last iteration of `fgets()` (that is, it'll wait for more data to come), when I set mode to unblocking, I can't get (all the) text at all as I returns pretty fast. BTW, thank you for `swaks`, anyway, it's never too late to know something new! – Alexander Jun 04 '14 at 17:53