proc_open
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
proc_open — 執行一個命令,並且打開用來輸入/輸出的檔案指針。
說明
mixed
$cmd
,array
$descriptorspec
,array
&$pipes
,string
$cwd
= null
,array
$env
= null
,array
$other_options
= null
): resource
類似 popen() 函式, 但是 proc_open() 提供了更加強大的控制程式執行的能力。
參數
-
cmd
-
以 string 形式執行的命令列。特殊字元必須經過轉義,並且使用正確的引號。
注意: 在 Windows 上, 除非在
other_options
中 把bypass_shell
設定為true
,否則cmd
會被傳遞給 cmd.exe (實際上是%ComSpec%
) 其中的/c
標誌是 未加引號的 字串 (也就是和 proc_open() 一樣)。 這可能會導致 cmd.exe 刪除cmd
中的引號 (詳見 cmd.exe 文件), 從而導致意外的,甚至是潛在的危險行為,因為 cmd.exe 錯誤訊息可能包含 (部分) 傳遞的cmd
(見下面的例子)。從 PHP 7.4.0 開始,
cmd
參數可以使用 array 型別傳遞。 在這種情況下,程序將直接打開(不通過 shell )。 而 PHP 會處理任何必要的參數轉義。注意:
在 Windows 上, array 元素的參數轉義假定 執行命令的命令列解析與 VC 執行時進行的命令列參數解析相容。
-
descriptorspec
-
一個索引陣列。 陣列的鍵表示描述符,陣列元素值表示 PHP 如何將這些描述符傳送至子程序。 0 表示標準輸入(stdin),1 表示標準輸出(stdout),2 表示標準錯誤(stderr)。
陣列中的元素可以是:
-
包含了要傳送至程序的管道的描述資訊的陣列。
第一個元素為描述符型別,
第二個元素是針對該描述符的選項。
有效的型別有:
pipe
(第二個元素可以是:r
向程序傳送該管道的讀取端,w
向程序傳送該管道的寫入端), 以及file
(第二個元素為檔名)。 -
表達一個真實檔案描述符的流資源型別
(例如:已打開的檔案,一個 socket 埠,
STDIN
)。
檔案描述符的值不限於 0,1 和 2,你可以使用任何有效的檔案描述符 並將其傳送至子程序。 這使得你的指令碼可以和其他指令碼互動操作。 例如,可以通過指定檔案描述符將密碼以更加安全的方式 傳送至諸如 PGP,GPG 和 openssl 程式, 同時也可以很方便的獲取這些程式的狀態資訊。
-
包含了要傳送至程序的管道的描述資訊的陣列。
第一個元素為描述符型別,
第二個元素是針對該描述符的選項。
有效的型別有:
-
pipes
-
將被置為索引陣列, 其中的元素是被執行程式建立的管道對應到 PHP 這一端的檔案指針。
-
cwd
-
要執行命令的初始工作目錄。 必須是 絕對 路徑, 設定此參數為
null
表示使用預設值(目前 PHP 程序的工作目錄)。 -
env
-
要執行的命令所使用的環境變數。 設定此參數為
null
表示使用和目前 PHP 程序相同的環境變數。 -
other_options
-
你還可以指定一些附加選項。 目前支援的選項包括:
-
suppress_errors
(僅用於 Windows 平臺): 設定為true
表示抑制本函式產生的錯誤。 -
bypass_shell
(僅用於 Windows 平臺): 設定為true
表示繞過cmd.exe
shell。 -
blocking_pipes
(僅用於 Windows 平臺): 設定為true
表示強制堵塞管道。 -
create_process_group
(僅用於 Windows 平臺): 設定為true
表示允許子程序處理CTRL
事件。 -
create_new_console
(僅用於 Windows 平臺): 表示新程序有一個新的控制檯,用於代替父程序的控制檯。
-
返回值
返回表示程序的資源型別,
當使用完畢之後,請呼叫 proc_close() 函式來關閉此資源。
如果失敗,返回 false
。
更新日誌
版本 | 說明 |
---|---|
7.4.4 |
為 other_options 參數增加 create_new_console 選項。
|
7.4.0 |
proc_open() 的 cmd 參數現在也允許陣列型別。
|
7.4.0 |
為 other_options 參數增加 create_process_group 選項。
|
範例
示例 #1 proc_open() 例程
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // 標準輸入,子程序從此管道中讀取數據
1 => array("pipe", "w"), // 標準輸出,子程序向此管道中寫入數據
2 => array("file", "/tmp/error-output.txt", "a") // 標準錯誤,寫入到一個檔案
);
$cwd = '/tmp';
$env = array('some_option' => 'aeiou');
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
// $pipes 現在看起來是這樣的:
// 0 => 可以向子程序標準輸入寫入的控制代碼
// 1 => 可以從子程序標準輸出讀取的控制代碼
// 錯誤輸出將被追加到檔案 /tmp/error-output.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// 切記:在呼叫 proc_close 之前關閉所有的管道以避免死鎖。
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
?>
以上例程的輸出類似於:
Array ( [some_option] => aeiou [PWD] => /tmp [SHLVL] => 1 [_] => /usr/local/bin/php ) command returned 0
示例 #2 proc_open() 在 Windows 上的怪異行為
雖然人們可能期望下面的程式能夠搜索檔案 filename.txt 進行文字搜索, 並列印結果,但它的行為相當不同。
<?php
$descriptorspec = [STDIN, STDOUT, STDOUT];
$cmd = '"findstr" "search" "filename.txt"';
$proc = proc_open($cmd, $descriptorspec, $pipes);
proc_close($proc);
?>
以上例程會輸出:
'findstr" "search" "filename.txt' is not recognized as an internal or external command, operable program or batch file.
要解決該行為,通常只需將 cmd
加上引號:
$cmd = '""findstr" "search" "filename.txt""';
註釋
注意:
Windows 相容性:超過 2 的描述符也可以作為可繼承的控制代碼傳送到子程序。 但是,由於 Windows 的架構並不將檔案描述符和底層控制代碼進行關聯, 所以,子程序無法訪問這樣的控制代碼。 標準輸入,標準輸出和標註錯誤會按照預期工作。
注意:
如果你只需要單向的程序管道, 使用 popen() 函式會更加簡單。
參見
- popen() - 打開程序檔案指針
- exec() - 執行一個外部程式
- system() - 執行外部程式,並且顯示輸出
- passthru() - 執行外部程式並且顯示原始輸出
- stream_select() - Runs the equivalent of the select() system call on the given arrays of streams with a timeout specified by seconds and microseconds
- The 執行運算子