【问题标题】:PHP ssh2_exec no feof on empty stdoutPHP ssh2_exec 在空标准输出上没有 feof
【发布时间】:2019-01-08 17:11:08
【问题描述】:

这个 PHP sn-p 应该通过 SSH 执行一个简单的命令(精简到最小的工作示例):

$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);
}

只要有任何输出到标准输出,就可以很好地工作。但是,如果 stdout 保持为空,则循环将变为无限循环。

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

如果

  • stdout 可能为空
  • 但 stdout 也可能非常大(几千兆字节,不可能通过一次调用 stream_get_contents 或类似的方法将变量放入变量中)。

附录:我挂起的真实世界代码使用未知参数执行 mysqldump。显然,echo -n >&2 按预期工作,尽管它的标准输出也是空的。

【问题讨论】:

    标签: php ssh stream


    【解决方案1】:

    如果有人也偶然发现这一点:也必须阅读 stderr。

    $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);
    }
    

    这样做的缺点是之后 SSH 连接不再可用(无法执行进一步的ssh2_exec)。

    一种可能的解决方案是保持两个流阻塞并以非交错方式读取 stdout 和 stderr:

    $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);
    

    我邀请任何知道如何将流交错并保持 SSH 连接可用的人发布另一个答案。

    【讨论】:

      猜你喜欢
      • 2022-11-30
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      相关资源
      最近更新 更多