Index

SSHStream

MMO\core\server · 1 symbol · generated 30 Sep 2026

class

SSHStream

SSHStream.php:12

A Stream wrapping the stdout of a command started via SSH::openExec, with the matching stderr stream and exit code alongside it.

class MMO\core\server\SSHStream extends MMO\core\server\Stream
Namespace
MMO\core\server
Extends
Stream
$stream = $ssh->openExec('ls -la'); $out = $stream->getContents($err); $stream->getExitCode();

Index

exitCode
ssh readonly
stderr
close()Close both the stdout (Stream::close) and, if fetched, the stderr stream.
getContents($errors)Read the output of the ssh command (and its errors) NOTE: when $errors is passed, the two streams are drained TOGETHER (loopContentsAsync), not one after the other.
getExitCode()
getStderr()Get the stderr resource
loopContentsAsync($stdout, $stderr)Read content asynchronously using a Generator.
__construct($ssh, $stream)

Properties3

exitCode

protected ?int $exitCode = null
Type
null | int

ssh

readonly
readonly MMO\core\server\SSH $ssh
Type
SSH

stderr

protected $stderr = null

Methods6

close()

SSHStream.php:36

Close both the stdout (Stream::close) and, if fetched, the stderr stream.

function close(): voidNOTE: relies on `fclose()` invalidating `is_resource()` for every variable referencing that same handle (not just the one it was called through, verified directly) to detect whether [`Stream::close`](https://mmoframework.fr/documentation/mmo.core/php/server/Stream.md#stream-close) actually closed the underlying stdout resource (it won't, e.g., for STDIN/STDOUT/STDERR under the CLI) -- stderr is only closed when stdout was.
returnsvoid

getContents($errors)

SSHStream.php:78

Read the output of the ssh command (and its errors) NOTE: when $errors is passed, the two streams are drained TOGETHER (loopContentsAsync), not one after the other. It used to read stderr to completion first and stdout afterwards, both blocking, which deadlocks as soon as a command fills the buffer of the stream that isn't being read: the remote process blocks writing to stdout while this side waits forever on stderr. Since SSH::execSafe always passes $errors, that was reachable from a plain $ssh->exec() on any chatty command.

function getContents(?string &$errors = null): string
$errors = nullnull | stringfilled with stderr's content -- only read at all if this parameter is actually passed (checked via func_num_args(), so even explicitly passing null triggers it; SSH::execSafe always passes it).
returnsstring

getExitCode()

SSHStream.php:50
function getExitCode(): ?int
returnsnull | intthe command's exit code, or null until it's known -- the ssh2 extension only exposes it (as exit_status stream metadata) once the stream has been fully read (eof), so this always returns null until stdout has been drained (getContents/loopContentsAsync).

getStderr()

SSHStream.php:59

Get the stderr resource

function getStderr()
returnsnull if the underlying stdout stream is already detached/closed.

loopContentsAsync($stdout, $stderr)

SSHStream.php:108

Read content asynchronously using a Generator.

function loopContentsAsync(bool $stdout = true, bool $stderr = false): Generator- Goto next frame with $gen->next() - Read current output source with $gen->key(): stdout|stderr - Read current output with $gen->current()
$stdout = trueboolif true include stdout output
$stderr = falseboolif true include stderr output
returnsGenerator

__construct($ssh, $stream)

SSHStream.php:24
function __construct(MMO\core\server\SSH $ssh, $stream)
$sshSSH
$streamthe command's stdout stream (as returned by ssh2_exec()).
Inherited members (29)
PropertiesDeclared byDescription
streamStream
MethodsDeclared byDescription
debugName()Stream
detach()StreamStreamInterface::detach
Empty()StreamGet an empty stream WARNING: don't write in it as this instance is shared by whomever call this function
eof()StreamStreamInterface::eof
File($filename, $mode)StreamGet a Stream on a file
getContentType($single)StreamNOTE: the return type used to be declared string|array even though this method can return false (when the stream has no usable URI) -- harmless in practice (PHP's weak typing silently coerces t…
getMetadata($key)StreamStreamInterface::getMetadata
getResource()Stream
getSize()StreamStreamInterface::getSize
getUri()Stream
isReadable()StreamStreamInterface::isReadable
isSeekable()StreamStreamInterface::isSeekable
isWritable()StreamStreamInterface::isWritable
read($length)StreamStreamInterface::read
render($opts)Stream
rewind()StreamStreamInterface::rewind Shorthand for seek(0).
seek($offset, $whence)StreamStreamInterface::seek
serialize($path, $serializer)Stream
STDERR()Stream
STDIN()Stream
STDOUT()Stream
tell()StreamStreamInterface::tell
TEMP()StreamGet a new stream backed by php://temp (memory, spilling to a temp file past ~2MB -- unlike Text, which is always pure memory).
Text($text)StreamGet a Stream on a text
unserialize($data, $path, $instances)Stream
write($text)StreamStreamInterface::write Writes the full string, looping over fwrite (which can write fewer bytes than requested in one call, e.g.
__destruct()StreamDestructor. Closes the stream
__toString()StreamStreamInterface::__toString