2012-08-30 108 views
11

exec命令在我的服務器上不起作用,它什麼都不做,我已經關閉了safe_mode,並且驗證了所有的控制檯命令正在工作,我嘗試過使用絕對路徑。我已經檢查了應用程序的權限以及我需要的所有應用程序的執行權限。我不知道還有什麼可以做的,這裏是我試過的代碼的簡要介紹。如何調試exec()問題?

echo exec('/usr/bin/whoami'); 

echo exec('whoami'); 

exec('whoami 2>&1',$output,$return_val); 
if($return_val !== 0) { 
    echo 'Error<br>'; 
    print_r($output); 
} 

exec('/usr/bin/whoami 2>&1',$output,$return_val); 
if($return_val !== 0) { 
    echo 'Error<br>'; 
    print_r($output); 
} 

最後兩個代碼顯示:

Error 
Array () 

我已經聯繫了服務器服務,他們不能幫助我,他們不知道爲什麼exec命令不能正常工作。 原諒我英語不好。

+0

你是什麼意思「不工作」?任何錯誤輸出? – Touki

+0

您是否嘗試過error.log? – Rolice

+0

錯誤設置'display_errors = 1'和'error_report = E_ALL'? (請注意,您不應該在實時系統上顯示錯誤,如果完成,請將其禁用) – KingCrunch

回答

10

看看/etc/php.ini,有下:

; This directive allows you to disable certain functions for security reasons. 
; It receives a comma-delimited list of function names. This directive is 
; *NOT* affected by whether Safe Mode is turned On or Off. 
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-functions 
disable_functions = 

請確保exec沒有像這樣列出:

disable_functions=exec 

如果是這樣,請將其刪除並重新啓動apache。

爲了便於調試,我通常喜歡手動執行php文件(可以在主ini中不要設置它的情況下請求更多的錯誤)。這樣做頭添加:

#!/usr/bin/php 
ini_set("display_errors", 1); 
ini_set("track_errors", 1); 
ini_set("html_errors", 1); 
error_reporting(E_ALL); 

到文件的開頭,給它的權限使用chmod +x myscript.php並執行它./myscript.php。特別是在一個忙碌的服務器上寫了很多日誌文件,這非常值得注意。

編輯

聽起來像一個權限問題。創建一個簡單的bash腳本,如echo "helo world"並嘗試運行它。確保您擁有文件的權限以及包含文件的文件夾的權限。你只需做chmod 755只是爲了測試。

+0

'disable_functions'在我的'php.ini'中是空的,我按照你的建議運行腳本,控制檯不顯示任何東西。 – carcargi

+0

@Necroside答案已更新。 – Kuf

+0

非常感謝,這是一個竅門,問題在於某種程度上(因爲我的客戶可以訪問服務器,他認爲他是專家XD),他複製並更改了應用程序的權限。我已經將它們移回原始文件夾並重新配置路徑,現在一切正常,我在測試應用程序的權限時發現了這一點。 謝謝。 – carcargi

4

可以retreive輸出和返回exec命令的代碼,放入系統的威力包含可以解釋這個問題的信息...

exec('my command', $output, $return); 
+0

剛剛將代碼添加到問題中,沒有注意到這個答案,它只是顯示了這一點。 '錯誤 Array()' – carcargi

+0

什麼包含$ return_val變量? – YohannP

5

由於您正在將PHP上下文退出到本機shell中,因此您將遇到很多調試問題。

我過去使用的最好也是最簡單的方法是將腳本的輸出寫入日誌文件並在PHP執行過程中將其拖尾。

<?php 
shell_exec("filename > ~/debug.log 2>&1"); 

然後,在一個單獨的shell:

tail -200f ~/debug.log 

當你執行你的PHP腳本,你的錯誤,並從你的shell調用輸出會在你debug.log文件中顯示。

0

還有一些筆記。

  • 對於調試,總是將您的exec/shell_exec函數包裝在var_dump()中。

  • error_reporting(-1);應該是,因爲要display_errors,作爲最後的手段,即使set_error_handler("var_dump"); - 如果只看到如果PHP本身沒有援引execvp否則後果不堪設想。

  • 使用2>&1(合併外殼STDERR到STDOUT流)以查看調用失敗的原因。
    在某些情況下,你可能需要額外的shell調用來包裝你的命令:

    // capture STDERR stream via standard shell 
    shell_exec("/bin/sh -c 'ffmpeg -opts 2>&1' "); 
    

    否則日誌文件重定向通過@Mike作爲建議是最值得推薦的做法。

  • 在各種可執行函數之間進行交替以發現錯誤消息。雖然他們大多是做同樣的事情,輸出返回路徑各不相同:

    1. exec()→要麼返回輸出函數的結果,或通過可選的$output paramater。
      還提供了一個$return_var參數,其中包含運行應用程序或shell的errno/exit代碼。你可能會得到:

      • ENOENT(2) - 沒有這樣的文件
      • EIO(127) - IO錯誤:文件未找到
    2. shell_exec()→是要大多運行殼什麼式表達式。
      一定要用例如分配/打印返回值。 var_dump(shell_exec("..."));

    3. ``反引號→是相同的shell_exec

    4. system()→與exec類似,但總是返回輸出作爲函數結果(打印出來!)。此外允許捕獲結果代碼。

    5. passthru()→是另一個exec替代方法,但總是將任何STDOUT結果發送到PHP輸出緩衝區。它經常使它成爲最適合的EXE包裝器。

    6. popen()或更好proc_open()→允許單獨捕獲STDOUT和STDERR。

  • 大多數殼中的錯誤PHP的或阿帕奇error.log拉閘不重定向時。如果沒有提供有用的錯誤消息,請檢查您的系統日誌或Apache日誌。

困擾PHP/LAMP新人最常見的問題是:由於@Kuf提到

  • :過時的虛擬主機方案,你仍然可以找到safe_mode或啓用disable_functions。沒有一個PHP exec函數可以工作。 (最好找一個更好的供應商,否則調查 「CGI」 - 但而unversed不自己安裝PHP解釋器)

  • 同樣可以的AppArmor/SELinux的/ Firejail有時到位。這些限制了每個應用程序產生新進程的能力。

  • 預期的二進制不存在。幾乎沒有網絡主機預裝了類似ffmpeg的工具。沒有準備,你不能只運行任意的shell命令。 有些東西需要安裝!

    // Check if `ffmpeg` is actually there: 
    var_dump(shell_exec("which ffmpeg")); 
    
  • PATH是關閉的。如果您安裝了自定義工具,則需要確保它們可以訪問。使用var_dump(shell_exec("ffmpeg -opts"))將搜索所有常見路徑 - 或者Apache已被告知/限制(通常只是/bin:/usr/bin)。

    請使用print_r($_SERVER);進行檢查您的PATH包含的內容是否包含您想要運行的工具。否則,你可能需要調整服務器設置(在/ etc/apache2的/ envvars中),或者使用完整路徑:

    // run with absolute paths to binary 
    var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'")); 
    

    這在一定程度上顛覆了殼的概念。我個人並不認爲這是可取的。儘管如此,它對安全的目的確實有意義;此外用於使用當然的定製安裝。

  • 權限

    1. 爲了運行BSD/Linux系統上的二進制,它需要進行 「可執行」。這是chmod a+x ffmpeg所做的。

    2. 進一步模擬此類自定義二進制文件的路徑需要可供您的PHP腳本運行的Apache用戶讀取。

    3. 更多現代設置使用PHP內置FPM模式(suexec + FastCGI),其中您的虛擬主機帳戶等於PHP運行的內容。

  • 測試與SSH。它應該不用說,但在通過PHP運行命令之前,在真實shell中測試它將非常明智。用例如探針ldd ffmpeg如果所有的lib依賴關係都存在,並且它否則可以工作。

  • 的輸入值(GET,POST,文件名,用戶數據)獲得在EXEC串命令參數傳遞需要與escapeshellarg()進行轉義。

    $q = "escapeshellarg"; 
    var_dump(shell_exec("echo {$q($_GET['text'])} | wc")); 
    

    否則你會很容易地得到shell語法錯誤;並可能利用稍後安裝的代碼...