有些時後在 PHP 裡難免會碰到需要外部程式的狀況;使用 system / exec 與重導 (<, >, |) 雖然很方便,不過又會有增加 I/O 的問題。在系統繁忙,要考慮 I/O 的情況下,使用 pipe function (popen, pclose, proc_open, …) 會比較恰當。這些函式能夠以 pipe 直接與其它程式溝通,避過了在 shell 處理重導的問題 (file lock & dead lock, I/O)。其中 popen 有著只能 r 或 w 的限制,proc_open 則可以同時取代 in, out, err。

resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] )

  • $cmd : 執行的程式名稱,可以帶參數,例如 /bin/ls –color
  • $descriptorspec : 指定 in, out, err 三個 pipe 如何處理
  • &$pipes : 傳回對應至 $descriptorspec 所指定的幾個 pipe, 成員都是 resource, 兩者的 key 會相等

取自 PHP 官網,的 proc_open 範例如下:

<?php
 array("pipe", "r"),  // stdin 為 pipe
    1 => array("pipe", "w"),  // stdout 為 pipe
    2 => array("file", "/tmp/error-output.txt", "a") // 將 stderr 導到 /tmp/error-output.txt, append
  );

  $cwd = '/tmp';
  $env = array('some_option' => 'aeiou');

  $process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

  if (is_resource($process)) {
    // $pipes 的元素是
    // $pipes[0] : 可寫入的 stream, 對應到子行程的 stdin
    // $pipes[1] : 可讀取的 stream, 對應到子行程的 stdout

    fwrite($pipes[0], '');
    fclose($pipes[0]);

    // stdout 要透過 stream_get_contents 讀取, 因為 $pipes[1] 是 stream, 不是 file resource
    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // 要先 fclose($pipes) 才能 proce_close($process)
    $return_value = proc_close($process);

    echo "command returned $return_valuen";
  }
?>