【问题标题】:shell_exec() timeout management & exec()shell_exec() 超时管理 & exec()
【发布时间】:2010-08-04 17:07:04
【问题描述】:

我正在使用我编写的包装类运行第三方脚本,该类调用shell_exec() 并将管道导入我稍后使用php 代码解析的文件。我应该提到这是有效的,但我正在尝试增强功能,遇到了一个我没有想到的用例。

如何最好地管理 shell_exec() 的超时?我正在考虑将其包装在 try() catch() 中,但我不确定如何最好地处理时间组件。

我在这里阅读了一些与shell_exec()exec() 相关的问题,似乎通过将输出参数传递给exec() 您可以获得回报,但这确实取决于脚本以返回状态。另外,在我的迷你测试页面中,我似乎无法让它返回任何输出!

我想到的另一个选项是使用模态对话框,在脚本工作时使用 ajax 样式微调器,并在 javascript 中设置手动超时。然后给用户一个关于它失败/超时和结束的模型对话框消息。

此用例是否有任何可接受的方法?

我的小测试,包括以下内容,

public $e_return = array();
public $e_status = '';
// Paths are absolute from /
public function execCheck($domain){
    exec($this->ssl_check_path." -s ".$domain." -p 443 > ".$this->folder.$this->filename." 2>&1 &", &$this->e_return, &$this->e_status);
}

// Returns
Array
(
)

0

使用这个问题作为参考, Can't execute PHP script using PHP exec

http://www.php.net/manual/en/function.exec.php

【问题讨论】:

    标签: php shellexecute


    【解决方案1】:

    我为这样的任务编写了一些工作代码。函数返回退出代码(0 - OK,>0 - 错误)并将 stdout、stderr 写入引用变量。

    /*execute program and write all output to $out
    terminate program if it runs more than 30 seconds */
    execute("program --option", null, $out, $out, 30);
    echo $out;
    
    function execute($cmd, $stdin=null, &$stdout, &$stderr, $timeout=false)
    {
        $pipes = array();
        $process = proc_open(
            $cmd,
            array(array('pipe','r'),array('pipe','w'),array('pipe','w')),
            $pipes
        );
        $start = time();
        $stdout = '';
        $stderr = '';
    
        if(is_resource($process))
        {
            stream_set_blocking($pipes[0], 0);
            stream_set_blocking($pipes[1], 0);
            stream_set_blocking($pipes[2], 0);
            fwrite($pipes[0], $stdin);
            fclose($pipes[0]);
        }
    
        while(is_resource($process))
        {
            //echo ".";
            $stdout .= stream_get_contents($pipes[1]);
            $stderr .= stream_get_contents($pipes[2]);
    
            if($timeout !== false && time() - $start > $timeout)
            {
                proc_terminate($process, 9);
                return 1;
            }
    
            $status = proc_get_status($process);
            if(!$status['running'])
            {
                fclose($pipes[1]);
                fclose($pipes[2]);
                proc_close($process);
                return $status['exitcode'];
            }
    
            usleep(100000);
        }
    
        return 1;
    }
    

    【讨论】:

      【解决方案2】:

      我建议您考虑使用proc_open。您可以将其配置为返回流资源,手动保留一个计时器,如果计时器在进程完成之前到期,您可以使用proc_terminate 终止它。如果它在计时器到期之前完成,那么您可以使用proc_close 然后stream_get_contents 来获取本来会写入标准输出的数据。

      http://www.php.net/manual/en/function.proc-open.php

      【讨论】:

      【解决方案3】:

      我尝试使用popen(),但之后无法终止进程。 此外,即使在 Windows 上使用 stream_set_blocking 时,stream_get_contents() 也会阻止流,所以我不得不改用 fread。此外,proc_terminate 在 Windows 上不能正常工作,所以我不得不使用替代的 kill 函数。

      我想出了这个,它现在应该可以在 Windows 和 Linux 上运行:

      function execute($command, $timeout = 5) {
          $handle = proc_open($command, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipe);
      
          $startTime = microtime(true);
      
          /* Read the command output and kill it if the proccess surpassed the timeout */
          while(!feof($pipe[1])) {
              $read .= fread($pipe[1], 8192);
              if($startTime + $timeout < microtime(true)) break;
          }
      
          kill(proc_get_status($handle)['pid']);
          proc_close($handle);
      
          return $read;
      }
      
      /* The proc_terminate() function doesn't end proccess properly on Windows */
      function kill($pid) {
          return strstr(PHP_OS, 'WIN') ? exec("taskkill /F /T /PID $pid") : exec("kill -9 $pid");
      }
      

      【讨论】:

        【解决方案4】:

        如果您使用的是 Linux(或 Windows 10 中的 WSL),那么使用 timeout 命令似乎是最简单的方法。 看到这个答案: exec() with timeout

        【讨论】:

          猜你喜欢
          • 2011-10-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-14
          • 2010-11-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多