目錄:
一、PHP中調用外部指令介紹
二、關于安全問題
三、關于逾時問題
四、關于PHP運作linux環境中指令出現的問題
在PHP中調用外部指令,可以用,1>調用專門函數、2>反引号、3>popen()函數打開程序,三種方法來實作:
方法一:用PHP提供的專門函數(四個):
PHP提供4個專門的執行外部指令的函數:exec(), system(), passthru(), shell_exec()
1)exec()
原型: string exec ( string $command [, array &$output [, int &$return_var ] )
說明: exec執行系統外部指令時不會輸出結果,而是傳回結果的最後一行。如果想得到結果,可以使用第二個參數,讓其輸出到指定的數組。此數組一個記錄代表輸出的一行。即如果輸出結果有20行,則這個數組就有20條記錄,是以如果需要反複輸出調用不同系統外部指令的結果,最好在輸出每一條系統外部指令結果時清空這個數組unset($output),以防混亂。第三個參數用來取得指令執行的狀态碼,通常執行成功都是傳回0。
<?php
exec("dir",$output);
print_r($output);
?>
2)system()
原型: string system ( string $command [, int &$return_var ] )
說明: system和exec的差別在于,system在執行系統外部指令時,它執行給定的指令,輸出和傳回結果。第二個參數是可選的,用來得到指令執行後的狀态碼。
system("pwd",$result);
print $result;//輸出指令的結果狀态碼
關于第二個參數結果狀态碼的簡單介紹:
如果傳回0是運作成功,
在Bash中,當錯誤發生在緻命信号時,bash會傳回128+signal number做為傳回值。
如果找不到指令,将會傳回127。
如果指令找到了,但該指令是不可執行的,将傳回126。
除此以外,Bash本身會傳回最後一個指令的傳回值。
若是執行中發生錯誤,将會傳回一個非零的值。
Fatal Signal : 128 + signo
Can't not find command : 127
Can't not execute : 126
Shell script successfully executed : return the last command exit status
Fatal during execution : return non-zero
3)passthru()
原型: void passthru ( string $command [, int &$return_var ] )
說明: passthru與system的差別,passthru直接将結果輸出到遊覽器,不傳回任何值,且其可以輸出二進制,比如圖像資料。第二個參數可選,是狀态碼。
header("Content-type:image/gif");
passthru("/usr/bin/ppm2tiff /usr/share/tk8.4/demos/images/teapot.ppm");
4)shell_exec()
原型: string shell_exec ( string $cmd )
說明: 直接執行指令$cmd
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
方法二:反撇号
原型: 反撇号`(和~在同一個鍵)執行系統外部指令
說明: 在使用這種方法執行系統外部指令時,要確定shell_exec函數可用,否則是無法使用這種反撇号執行系統外部指令的。
echo `dir`;
方法三:用popen()函數打開程序
原型: resource popen ( string $command , string $mode )
說明: 能夠和指令進行互動。之前介紹的方法隻能簡單地執行指令,卻不能與指令互動。有時須向指令輸入一些東西,如在增加系統使用者時,要調用su來把目前使用者換到root使用者,而su指令必須要在指令行上輸入root的密碼。這種情況下,用之前提到的方法顯然是不行的。
popen( )函數打開一個程序管道來執行給定的指令,傳回一個檔案句柄,可以對它讀和寫。傳回值和fopen()函數一樣,傳回一個檔案指針。除非使用的是單一的模式打開(讀or寫),否則必須使用pclose()函數關閉。該指針可以被fgets(),fgetss(),fwrite()調用。出錯時,傳回FALSE。
error_reporting(E_ALL);
/* Add redirection so we can get stderr. */
$handle = popen('/path/to/executable 2>&1', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);
二、關于安全問題:
由于PHP基本是用于WEB程式開發的,是以安全性成了人們考慮的一個重要方面。
于是PHP的設計者們給PHP加了一個門:安全模式。
在php.ini中的設定safe_mode = On
如果運作在安全模式下,那麼PHP腳本中将受到如下四個方面的限制:
執行外部指令
在打開檔案時有些限制
連接配接MySQL資料庫
基于HTTP的認證
在安全模式下,隻有在特定目錄中的外部程式才可以被執行,對其它程式的調用将被拒絕。這個目錄可以在php.ini檔案中用safe_mode_exec_dir指令,或在編譯PHP 是加上–with-exec-dir選項來指定,預設是/usr/local/php/bin。
當你使用這些函數來執行系統指令時,可以使用escapeshellcmd()和escapeshellarg()函數阻止使用者惡意在系統上執行指令,escapeshellcmd()針對的是執行的系統指令,而escapeshellarg()針對的是執行系統指令的參數。這兩個參數有點類似addslashes()的功能。
當執行指令的傳回結果非常龐大時,可以需要考慮将傳回結果輸出至其他檔案,再另行讀取檔案,這樣可以顯著提高程式執行的效率。
如果要執行的指令要花費很長的時間,那麼應該把這個指令放到系統的背景去運作。但在預設情況下,象system()等函數要等到這個指令運作完才傳回(實際上是在等指令的輸出結果),這肯定會引起PHP腳本的逾時。解決的辦法是把指令的輸出重定向到另外一個檔案或流中,如:
system("/usr/local/bin/order_proc > /tmp/abc ");
但我調用的DOS指令需要幾分鐘的時間,而且為了批處理不能簡單的把結果寫入檔案了事,要順序執行以下的程式
PHP設定了調用系統指令的時間限制,如果調用指令逾時,雖然這個指令還是會被執行完,但PHP沒有得到傳回值,被終止了(最可恨的是,不顯示任何錯誤)
修改php.ini并重新開機Apache以允許系統指令運作更長的時間
max_execution_time = 600
php一般是以apache使用者身份去執行的,也可能是www使用者,把apache加入到存儲你檔案的父檔案夾屬組裡去,然後改該父檔案夾權限為775,這樣屬組成員就有寫的權限,而apache屬于這個組就可以改寫該目錄下所有檔案的權限。
例如:chown www:www dirName
這樣dirName目錄才能被php所控制
注意:改apache/php的運作使用者方法不安全
另外即使檔案或目錄已經是www,php的安全設定也都照顧到,一些自己安裝linux的指令仍然可能無法運作,例如我曾經安裝的ffmpeg軟體,原因就是linux的運作權限問題,即使ffmpeg有www權限設定,但由于ffmpeg所依賴的庫檔案是不允許www使用者運作,是以php運作此程式仍然會報127或126錯誤,通過 ldd 指令可以檢視ffmpeg指令依賴的庫情況。
這個時候就必須對ffmpeg的依賴庫經行設定。具體方法屬于linux管理中的話題,這裡不就讨論了。
本文轉自 陳小龍哈 51CTO部落格,原文連結:
http://blog.51cto.com/chenxiaolong/1898213