PHP執行外部程序的方法

在一些特殊狀況下,會使用PHP調用外部程序執行,好比:調用shell命令、shell腳本、可執行程序等等,今天在源碼中瞭解了一下PHP執行外部程序的方法,藉此機會順便整理一下。php

在源碼中 exec.h文件中,列出了可調用外部程序的幾個函數,藍色框裏的兩個函數只是輔助做用,本文只對其餘幾個函數作介紹。shell

clipboard.png

前提編程

1 PHP沒有運行在安全模式,關掉安全模式,即:safe_mode = off

2 禁用函數列表 disable_functions =  exec, system, shell_exec,proc_open, popen, 若是禁用了,就關掉。
注意:執行外部程序是存在風險的,因此使用這些函數要在確保安全的狀況下使用。

exec() 函數segmentfault

原型:string exec ( string command [, array &output [, int &return_var]] )
描述:返回值保存最後的輸出結果,而全部輸出結果將會保存到$output數組,$return_var用來保存命令執行的狀態碼(用來檢測成功或失敗)。
例子:數組

<?php
exec('whoami',$output, $status);
var_dump($output);
exit;

// 輸出結果:

array(1) {
  [0]=>
  string(7) "hedong"
}

注意:
① 輸出結果會逐行追加到$output中,所以在調用exec以前須要unset($output),特別是循環調用的時候。
② 若是想經過exec調用外部程序後立刻繼續執行後續代碼,僅僅在命令里加"&"是不夠的,此時exec依然會等待命令執行完畢;須要再將標準輸出作重定向才能夠,例如:exec("ls -al >/dev/null &", $output, $var);瀏覽器

shell_exec() 函數安全

原型:string shell_exec( string command)函數

描述:經過 shell 環境執行命令,而且將完整的輸出以字符串的方式返回。
例子:spa

<?php
$output = shell_exec('whoami');
echo "$output"; // hedong
exit;

注意:指針

當進程執行過程當中發生錯誤,或者進程不產生輸出的狀況下,都會返回 NULL, 因此,使用本函數沒法經過返回值檢測進程是否成功執行。 若是須要檢查進程執行的退出碼,請使用 exec() 函數。

system() 函數
原型:string system ( string command [, int &return_var] )
描述:執行給定的命令,返回最後的輸出結果;第二個參數是可選的,用來獲得命令執行後的狀態碼。
例子:

<?php
system("whoami", $status); // 直接輸出
var_dump($status); // 成功時狀態碼是 0
exit;

// 輸出結果:hedong

passthru() 函數
原型:void passthru (string command [, int return_var])
描述:執行給定的命令,但不返回任何輸出結果,而是直接輸出到顯示設備上;第二個參數可選,用來獲得命令執行後的狀態碼。

用途:當所執行的 Unix 命令輸出二進制數據, 而且須要直接傳送到瀏覽器的時候, 須要用此函數來替代 exec() 或 system() 函數

例子:

<?php
passthru("whoami", $status); // 直接輸出
var_dump($status); // 成功時狀態碼是 0
exit;

輸出結果:hedong

popen() 函數
原型:resource popen ( string command, string mode )
描述:打開一個指向進程的管道,該進程由派生給定的 command 命令執行而產生。 返回一個和 fopen() 所返回的相同的文件指針,只不過它是單向的(只能用於讀或寫)而且必須用 pclose() 來關閉。此指針能夠用於 fgets(),fgetss() 和 fwrite()。
例子:

$fd = popen("command", 'r'); $ret = fgets($fd);

注意:只能打開單向管道,不是'r'就是'w';而且須要使用pclose()來關閉。

proc_open() 函數

原型:resource proc_open ( string cmd, array descriptorspec, array &pipes [, string cwd [, array env [, array other_options]]] )
描述:與popen相似,可是能夠提供雙向管道。
例子:

<?php
/**
 * @author: hedong
 * @date 2017-04-04
 */

// 管道配置
$descriptors = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w")
);

$process = proc_open("php", $descriptors, $pipes);

if (is_resource($process)) {
    fwrite($pipes[0], "<?php\n");
    fwrite($pipes[0], "  \$rand = rand(1,2);\n");
    fwrite($pipes[0], "  if (\$rand == 1) {\n");
    fwrite($pipes[0], "    echo \"Hello, World!\n\";\n");
    fwrite($pipes[0], "  } else {");
    fwrite($pipes[0], "    echo \"Goodbye, World!\n\";\n");
    fwrite($pipes[0], "  }");
    fwrite($pipes[0], "?>");
    fclose($pipes[0]);

    $output = "";
    while (!feof($pipes[1])) {
        $output .= fgets($pipes[1]);
    }

    $output = strtoupper($output);
    echo $output; fclose($pipes[1]);

    proc_close($process);
}

// 輸出結果:

GOODBYE, WORLD!

注意:
① 後面須要使用proc_close()關閉資源,而且若是是pipe類型,須要用pclose()關閉句柄。
② proc_open打開的程序做爲php的子進程,php退出後該子進程也會退出。

總結:

exec函數將輸出結果保存在第二個參數上;

shell_exec函數沒有參數中接收返回值,並且沒有執行成功的狀態碼;

system函數將執行的結果直接輸出;passthru函數同system函數,不一樣之處是適合處理輸出二進制數據;

popen函數會fork一個子進程,返回文件指針

proc_open函數同popen,但可提供雙向通道

clipboard.png

關注個人公衆號,一塊兒成長

推薦閱讀:PHP多進程編程

相關文章
相關標籤/搜索