dongzhi9192 2018-08-01 07:50
浏览 71

PHP ssh2_exec在空stdout上没有feof

This PHP snippet should execute a simple command via SSH (stripped down to minimal working example):

$sshconn = ssh2_connect($HostAddr, 22);
ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
$stdout = ssh2_exec($sshconn, 'echo hello');
if ($stdout !== false)
{
    stream_set_blocking($stdout, true);
    while (!feof($stdout))
    {
        $proc_stdout = fgets($stdout, 3E6);
        if ($proc_stdout !== false) echo $proc_stdout;
    }
    fclose($stdout);
}

Works great as long as there is any output to stdout. However, if stdout remains empty, the loop turns into an endless loop.

$stdout = ssh2_exec($sshconn, 'echo hello >&2');

How do I read the stdout properly if

  • stdout may be empty
  • but stdout may also very large (several Gigabytes, impossible to slurp into a variable by a single call to stream_get_contents or the like).

Addendum: My real world code that hangs executes mysqldump with an unknown parameter. Obviously, echo -n >&2 works as expected, although its stdout is also empty.

  • 写回答

1条回答 默认 最新

  • doudiemei2013 2018-08-01 08:21
    关注

    If anyone stumbles upon this too: stderr has to be read too.

    $sshconn = ssh2_connect($HostAddr, 22);
    ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
    
    $stdout = ssh2_exec($sshconn, 'echo Hello >&2');
    if ($stdout !== false)
    {
        $stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
        stream_set_blocking($stdout, false);
        stream_set_blocking($stderr, false);
        while (!feof($stdout))
        {
                $proc_stdout = fgets($stdout, 3E6);
                if ($proc_stdout !== false) echo $proc_stdout;
                $proc_stderr = fgets($stderr, 3E6);
                if ($proc_stderr !== false) fwrite(STDERR, $stderr);
        }
        fclose($stdout); fclose($stderr);
    }
    

    The disadvantage of this is that the SSH connection is no longer usable afterwards (a further ssh2_exec cannot be executed).

    A possible solution is to keep both streams blocking and read stdout and stderr non-interleaved:

    $stdout = ssh2_exec($sshconn, 'echo Hello >&2');
    $stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
    stream_set_blocking($stdout, true);
    stream_set_blocking($stderr, true);
    while ($content = fread($stdout, 3E6)) echo $content;
    while ($content = fread($stderr, 3E6)) fwrite(STDERR, $content);
    

    I invite anyone who knows how to have the streams interleaved and keep the SSH connection usable to post another answer.

    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?