feof会生成无限循环

5

因此,我会执行一个简单的步骤,首先通过ssh2_exec(在成功验证后)执行命令,然后将答案读取到变量中。我的代码如下(没有身份验证)

try {
        $stdout_stream = ssh2_exec($this->connection, $_cmd);
        $stderr_stream = ssh2_fetch_stream($stdout_stream, \SSH2_STREAM_STDERR);
    } catch (Exception $e) {
        $std_output = $e->getMessage();
        return false;
    }

    $output = "";

    while (!feof($stdout_stream)) {
        $output .= fgets($stdout_stream, 4096);
    }

    while (!feof($stderr_stream)) {
        $output .= fgets($stderr_stream, 4096);
    }

    fclose($stdout_stream);
    fclose($stderr_stream);     

    return $output;

例如,我尝试执行这样的命令:
sudo service httpd stop && sudo service httpd start

当命令正确执行时,一切正常,响应为:

关闭 httpd: [ OK ]启动 httpd: [ OK ]

但是当我尝试在没有使用 sudo 的情况下执行此类命令时:

service httpd stop && service httpd start

我知道服务器可能会提示类似于“命令未找到”的错误,但是我却收不到这个错误,这个脚本一直在执行。

我尝试以以下方式重写我的代码(或者类似于以下的方式)

    $dataString = fgets($stdout_stream);
        if($dataString == "\n" || $dataString == "\r\n" || $dataString == "") {
            //var_dump("Empty line found.");
        }

        if($dataString === false && !feof($stdout_stream)) {
            //var_dump("not string");
        } elseif($dataString === false && feof($stdout_stream)) {
            //var_dump("We are at the end of the file.\n");
            break;
        } else {
            //else all is good, process line read in
            $output .= $dataString;
        }
    }

但是结果是相同的。

所以问题在于我们无法预先确定是$stdout_stream还是$stderr_stream引起了无限循环。

我正在使用PHP 5.3。


在您重写代码的版本中,您是否总是进入“$output .=”情况或其他情况发生?如果是sudo造成了差异,您可以进行权限检查吗?一般来说,无限循环可能是由于错误的“停止条件”(“停止情况”,“cas d'arrêt”)或错误的递增/下一次迭代步骤引起的。也许回答这些问题会对您有所帮助。祝你好运。 - Answers_Seeker
感谢您的回复。有时候,即使命令最终成功执行,fgets($stdout_stream)也会返回false,因此当我知道命令不会执行良好时,我不能依赖它。Auth_User拥有重启httpd服务的权限。 - Alexandr Suleymanov
“www-data” 是否属于 “Auth_User” 组?如果不是,也许赋予 www-data 执行 httpd 的权限(chown)可以解决问题。 - Answers_Seeker
能否在你的流中加入一个 var_dump()?在循环之前,是否有任何方法可以将 EOF(chr(26))字符连接到流的末尾? - Answers_Seeker
var_dump 非常大。我真的不知道如何将 EOF 字符串连接到流的末尾,你知道任何方法吗? - Alexandr Suleymanov
显示剩余2条评论
2个回答

0

我决定相信服务器检查错误是否存在只需要大约2秒钟的时间。为了以防万一,我设置了第二个循环的最大时间。所以我的代码如下。它执行的时间比我想象的要长...

    try {
        $stdout_stream = ssh2_exec($this->connection, $_cmd);
        $stderr_stream = ssh2_fetch_stream($stdout_stream, \SSH2_STREAM_STDERR);
    } catch (Exception $e) {
        $std_output = $e->getMessage();
        return false;
    }

    $output = "";

    $start_time = time();
    $max_time = 2; //time in seconds

    while(((time()-$start_time) < $max_time)) {
        $output .= fgets($stderr_stream, 4096);
    }

    if(empty($output)) {
        $start_time = time();
        $max_time = 10; //time in seconds

        while (!feof($stdout_stream)) {
            $output .= fgets($stdout_stream, 4096);
            if((time()-$start_time) > $max_time) break;
        }
    }

    fclose($stdout_stream);
    fclose($stderr_stream);     

    return $output;

0

天啊,我真高兴找到了这个!我也遇到了同样的问题。最终我是用这种方法解决的。

不要使用:

while (!feof($stdout_stream)) {
    $output .= fgets($stdout_stream, 4096);
}

while (!feof($stderr_stream)) {
    $output .= fgets($stderr_stream, 4096);
}

做这个:
while (!feof($stdout_stream) || !feof($stderr_stream)) {
    $output_stdout .= fgets($stdout_stream, 4096);
    $output_stderr .= fgets($stderr_stream, 4096);
}

技术细节超出了我的理解范围,但似乎这两个描述符是同时关闭的,而不是一个接一个地关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接