2015-10-16 87 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腳本。