I've been having issues trying to use a command over ssh2_exec. The command takes input over standard input, waits for it to be closed, then writes back to standard output. Unfortunate, the ssh2 API seems deficient in multiple ways: First, the stream returned by ssh2_exec is for /both/ standard input and error. Closing means theoretically closing them both. This isn't /too/ bad, because I believe my program doesn't use standard error, so I just reassign the FDs at the shell level so that standard output is now on the separate standard error stream. Second, closing the stream doesn't actually seem to close standard input. The program (and cat, for the example below) still seems to think it should read from standard input and thus keeps standard output (well, error) open. This is annoying because it effectively means stream_get_contents is useless for me, because it'll block forever or with non-blocking, spit out a bunch of spurious zeros as it gets nothing constantly. cat will write back after the flush, but not immediately (some spurious zero reads, then a read with data, then more spurious), and my program relies on having standard input closed before it'll write. It appears others have tried to deal with this, but failed: https://stackoverflow.com/questions/19898351/php-close-input-channel-of-bidirectional-stream-from-ssh2-exec As with that person, I would /really/ not want to create a temporary file on the remote server if I can get away with it. I'm using PHP 7.4.8 w/ the PECL SSH2 extension that's shipped by Fedora. -- code -- <?php $server = "redact"; $user = "redact"; $password = "redact"; // no error handling in the sample program (real one does) $conn = ssh2_connect($server, 22); ssh2_auth_password($conn, $user, $password); // redirect stdout to stderr, because closing stdin also closes stdout // use cat as a surrogate (the program I'm calling takes all of stdin // and writes back to stdout on stdin EOF; cat will have to do to show // the broken behaviour) $ssh_stdio = ssh2_exec($conn, "cat 1>&2"); $ssh_stderr = ssh2_fetch_stream($ssh_stdio, SSH2_STREAM_STDERR); stream_set_blocking($ssh_stdio, true); stream_set_blocking($ssh_stderr, true); $written = fwrite($ssh_stdio, "the quick brown fox"); // attempt to close stdin (using stderr afterwards, explained above) fflush($ssh_stdio); fclose($ssh_stdio); // stderr blocking behaviour: // blocking: blocks forever because cat doesn't know it closed? // non-blocking: gets an empty string because cat hasn't written // back in time $out = stream_get_contents($ssh_stderr); var_dump($out);