【问题标题】:feof generates infinite loopfeof 生成无限循环
【发布时间】:2015-07-01 16:26:16
【问题描述】:

所以我做了一件简单的事情,首先我通过 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;

比如我尝试执行这样的cmd:

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 有区别,您可以进行权限检查吗?一般来说,无限循环可能是由错误的“停止标准”(“stop case”、“cas d'arrêt”)或下一次迭代的错误增量/步骤引起的。也许回答这些问题会对你有所帮助。祝你好运
  • 感谢您的回复。有时fgets($stdout_stream) 返回 false,即使命令最终成功执行,这就是为什么当我知道命令无法正常执行时我不能指望它。 Auth_User 具有重启 httpd 服务的权限。
  • “www-data”是“Auth_User”组的一部分吗?如果没有,也许赋予 www-data 执行 httpd 的权限就可以了。(chown)
  • 谢谢,我会检查这个选项,但是我将 sudo 添加到我的命令中没有问题,兴趣是为什么 ssh2_exec 返回,看起来,良好的响应(类型流的资源),但脚本不能用它做任何可以接受的事情。我猜它无法到达文件末尾,但实际上不知道是什么问题。
  • 你能加入你的流的 var_dump() 吗?有什么方法可以在循环之前将 EOF (chr(26)) 字符连接到流的末尾?

标签: php feof ssh2-exec


【解决方案1】:

我决定相信我的服务器只需 ~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;

【讨论】:

    【解决方案2】:

    男孩,我很高兴我找到了这个!我遇到了同样的问题。我最终以这种方式解决了它。

    代替:

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

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

    【讨论】:

      猜你喜欢
      • 2014-11-21
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 2023-03-28
      • 2018-10-04
      • 2018-09-09
      • 2012-06-18
      相关资源
      最近更新 更多