2015-10-16 84 views
4

我想通过exec()运行几个命令,但我不希望任何输出到屏幕。然而,我确实希望坚持输出,以便我可以在脚本运行时控制详细程度。从php exec中捕获/禁止所有输出,包括stderr

这里是我的类:

<?php 
class System 
{ 
    public function exec($command, array &$output = []) 
    { 
     $returnVar = null; 
     exec($command, $output, $returnVar); 
     return $returnVar; 
    } 
} 

的问题是,大多数应用程序把不相干的东西的刺激量为stderr,我似乎不能够阻止。例如,下面是从通过它运行git clone输出:

Cloning into '/tmp/directory'... 
remote: Counting objects: 649, done. 
remote: Compressing objects: 100% (119/119), done. 
remote: Total 649 (delta 64), reused 0 (delta 0), pack-reused 506 
Receiving objects: 100% (649/649), 136.33 KiB | 0 bytes/s, done. 
Resolving deltas: 100% (288/288), done. 
Checking connectivity... done. 

我见过的其他问题,声称使用输出缓冲器可以工作,但它似乎没有工作

<?php 
class System 
{ 
    public function exec($command, array &$output = []) 
    { 
     $returnVar = null; 
     ob_start(); 
     exec($command, $output, $returnVar); 
     ob_end_clean(); 
     return $returnVar; 
    } 
} 

这仍然产生相同的结果。我可以通过在命令中将stderr路由到stdout来解决这个问题,但是,这不仅阻止了我与stdout和stderr的区别,这个应用程序被设计为在Windows和Linux中运行,所以这现在是一个邪恶的混乱。

<?php 
class System 
{ 
    public function exec($command, array &$output = []) 
    { 
     $returnVar = null; 

     // Is Windows 
     if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 
      exec($command, $output, $returnVar); 
      return $returnVar; 
     } 

     // Is not windows 
     exec("({$command}) 2>&1", $output, $returnVar); 
     return $returnVar; 
    } 
} 

有没有办法分别捕获和压制stderr和stdout?

更新/回答样本

在在评论@hexasoft的意见,我更新了我的方法是这样的:

<?php 
class System 
{ 
    public function exec($command, &$stdOutput = '', &$stdError = '') 
    { 
     $process = proc_open(
      $command, 
      [ 
       0 => ['pipe', 'r'], 
       1 => ['pipe', 'w'], 
       2 => ['pipe', 'w'], 
      ], 
      $pipes 
     ); 

     if (!is_resource($process)) { 
      throw new \RuntimeException('Could not create a valid process'); 
     } 

     // This will prevent to program from continuing until the processes is complete 
     // Note: exitcode is created on the final loop here 
     $status = proc_get_status($process); 
     while($status['running']) { 
      $status = proc_get_status($process); 
     } 

     $stdOutput = stream_get_contents($pipes[1]); 
     $stdError = stream_get_contents($pipes[2]); 

     proc_close($process); 

     return $status['exitcode']; 
    } 
} 

这项技术开辟了更高级的选项,包括异步过程。

+1

你*有*使用exec吗?因为'proc_open'可能更适合你的问题。有关详细信息,请参阅http://php.net/manual/fr/function.proc-open.php(允许为stdin/stdout/stderr设置专用管道) – hexasoft

+0

不,我不必使用exec。我会探索这个并回复你。谢谢:) – DanielM

+0

是的,这似乎很好地工作。这当然不是“更简单”,但它绝对是我想要的。我已经更新了我的问题以显示我对该特定方法所做的确切更改,但是我稍后将设置一些更强大的功能。你想弹出一个正确的答案,我会标记它是正确的。 – DanielM

回答

2

命令proc_exec()允许使用管道处理exec-ed命令的文件描述符。

功能是:resource proc_open (string $cmd , array $descriptorspec , array &$pipes […optional parameters])

你给你$ CMD(如exec)命令,你给描述filedescriptors“安装”该命令的数组。该数组通过filedescriptor编号(0 = stdin,1 = stdout ...)进行索引,并包含类型(文件,管道)和模式(r/w ...)以及文件类型的文件名。

然后,您可以在$ pipes中获得一组文件描述符,它们可以用于读取或写入(取决于请求的内容)。

您不应该忘记在使用后关闭这些描述符。

请参考PHP手册(特别是例子):http://php.net/manual/fr/function.proc-open.php

注意,读/写是关系到催生命令,而不是PHP脚本。