2012-02-02 32 views
9

我有這樣的問題: 在一個ISS Web服務器中,Windows 7 64位專業,安裝Zend服務器。在PHP運行此命令:PHP高管:不返回輸出

exec('dir',$output, $err); 

$output is empty, $err=1.所以EXEC不returing輸出,似乎有一些錯誤。 Php disable_functions爲空,php不在安全模式下,是標準的,我檢查了所有選項。 這似乎是一個普遍的錯誤,即使搜索谷歌不給結果。

請寫出每個人他的遭遇和最終的解決方案或解決方法。

+0

也許是因爲有錯誤? :)檢查什麼錯誤1代碼的意思... – Catalin 2012-02-02 15:05:49

+0

如果我啓動相同的命令CMD shell與PHP script.php它的作品,當我從瀏覽器(所以網絡服務器)啓動它不起作用,我真的不明白其中錯誤是 – albanx 2012-02-02 15:10:24

+0

@albanx:這會讓我相信權限,如果它運行時,而不是當IIS運行時。 – 2012-02-02 15:19:08

回答

13

有幾個職位,以PHP手冊等的相關章節爲this one

我用的是有麻煩PHP執行命令執行任何批次 文件。執行其他命令(即「dir」)工作正常)。但是,如果我 執行了一個批處理文件,我沒有收到exec命令的輸出。

服務器設置我有包含在Windows Server 2003上運行 IIS6和PHP 5.2.3服務器。在此服務器上,我有:

  1. 授予對c:\ windows \ system32 \ cmd.exe上的Internet用戶的執行權限。
  2. 授予Everyone->完全控制寫入批處理文件的目錄。
  3. 授予Everyone->完全控制整個c:\ cygwin \ bin目錄及其內容。
  4. 授予Internet用戶「作爲批處理登錄」權限。
  5. 指定每個正在執行的文件的完整路徑。
  6. 測試這些腳本從服務器上的命令行運行,他們工作得很好。
  7. 確保%systemroot%\ system32位於系統路徑中。

事實證明,即使上述所有的服務器上的地方,我 必須指定在exec調用的完整路徑CMD.EXE。

當我使用的電話:$output = exec("c:\\windows\\system32\\cmd.exe /c $batchFileToRun");

則一切正常。在我的情況,$batchFileToRun是 實際的系統路徑批處理文件(即, 真實路徑調用的結果())。

在手冊頁execshell_exec上還有一些內容。也許通過他們後會得到它併爲你工作。

+0

我會盡量按照這個步驟操作,但它不是批處理執行。 – albanx 2012-02-11 13:46:50

-1

看看阿帕奇的error_log,也許你會發現錯誤消息。

此外,您可以嘗試使用EXEC的POPEN代替。它提供了更多的控制,因爲從輸出讀取你可以單獨進程啓動:

$p = popen("dir", "r"); 
if (!$p) 
    exit("Cannot run command.\n"); 
while (!feof($p)) 
    echo fgets($p); 
pclose($p); 
+0

他在Windows上使用IIS服務器。 – Treffynnon 2012-02-06 14:36:35

+0

我試圖找到IIS日誌,但我無法理解他們在win7上的位置 – albanx 2012-02-07 16:27:16

0

出於安全考慮,您的服務器可能對「exec」命令的訪問權限受限制。在這種情況下,也許你應該聯繫託管公司來取消這個限制(如果有的話)。

+0

我有本地服務器,exec沒有限制,因爲我知道 – albanx 2012-02-10 13:07:56

9

您從命令(如dir)獲得零輸出的主要原因是因爲dir不存在。它是命令提示符的一部分,這個特定問題的解決方案很好,在這個頁面的某處。

您可以通過按WIN + R,然後輸入dirstart來解決這個問題 - 出現錯誤信息!

不過這可能聽起來很不錯,我發現在Windows中執行任何與進程相關的最可靠的方法是使用組件對象模型。你說我們要分享我們的經驗,對吧?

$我聽到讓人忍俊不禁

失而復得你冷靜了嗎?

所以,首先我們將創建COM對象:

$pCOM = new COM("WScript.Shell"); 

然後,我們就永遠運行需要運行什麼。

$pShell = $pCom->Exec("C:\Random Folder\Whatever.exe"); 

很酷!現在,這將掛起,直到一切完成在二進制文件。所以,我們現在需要做的是抓取輸出。

$sStdOut = $pShell->StdOut->ReadAll; # Standard output 
$sStdErr = $pShell->StdErr->ReadAll; # Error 

還有一些其他的事情可以做 - 發現什麼是進程ID,錯誤代碼等。雖然this example是爲Visual Basic,它是基於相同的方案。

4

編輯:幾期試驗研究,我看到執行DIR命令的唯一方法之後是這樣的:

cmd.exe /c dir c:\ 

所以,你可以使用try我的解決方案:

$command = 'cmd.exe /c dir c:\\'; 

您可以使用proc_open函數,它可以讓你訪問stderr,返回狀態碼和stdout。

$stdout = $stderr = $status = null; 
    $descriptorspec = array(
     1 => array('pipe', 'w'), // stdout is a pipe that the child will write to 
     2 => array('pipe', 'w') // stderr is a pipe that the child will write to 
    ); 

    $process = proc_open($command, $descriptorspec, $pipes); 

    if (is_resource($process)) { 
     // $pipes now looks like this: 
     // 0 => writeable handle connected to child stdin 
     // 1 => readable handle connected to child stdout 
     // 2 => readable handle connected to child stderr 

     $stdout = stream_get_contents($pipes[1]); 
     fclose($pipes[1]); 

     $stderr = stream_get_contents($pipes[2]); 
     fclose($pipes[2]); 

     // It is important that you close any pipes before calling 
     // proc_close in order to avoid a deadlock 
     $status = proc_close($process); 
    } 

    return array($status, $stdout, $stderr); 

有趣的部分與proc_open,比起像POPEN或者exec等功能,是它提供了具體的選項,Windows平臺,如:

suppress_errors (windows only): suppresses errors generated by this function when it's set to TRUE 
bypass_shell (windows only): bypass cmd.exe shell when set to TRUE 
0

您可以檢查IIS用戶的permisssions到CMD。 EXE

cacls C:\WINDOWS\system32\cmd.exe 

如果輸出類似(COMPUTERNAME =你的計算機名)線:

C:\WINDOWS\system32\cmd.exe COMPUTERNAME\IUSR_COMPUTERNAME:N 

這意味着用戶無權執行cmd。

您可以添加使用命令執行權限:

cacls C:\WINDOWS\system32\cmd.exe /E /G COMPUTERNAME\IUSR_COMPUTERNAME:R 
1

我知道我已經選擇一個答案,我必須這樣做,但我還是不明白爲什麼它不會對我的MACCHINE工作,但我發現了一個回退(使用其他方法proc_open)解決方案:

public static function exec_alt($cmd) 
{ 
    exec($cmd, $output); 
    if (!$output) { 
     /** 
     * FIXME: for some reason exec() returns empty output array @mine,'s machine. 
     *  Somehow proc_open() approach (below) works, but doesn't work at 
     *  test machines - same empty output with both pipes and temporary 
     *  files (not we bypass shell wrapper). So use it as a fallback. 
     */ 
     $output = array(); 
     $handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true)); 
     if (is_resource($handle)) { 
      $output = explode("\n", stream_get_contents($pipes[1])); 
      fclose($pipes[1]); 
      proc_close($handle); 
     } 
    } 
    return $output; 
} 

希望這可以幫助別人。

+1

我認爲這個關鍵是'bypass_shell'參數。根據我的理解,'exec()'在你傳遞的命令上調用'cmd/c'。無論出於什麼原因,它都不能找到這個最初的'cmd.exe'文件(可能是因爲本地環境變量或其他原因)。通過繞過PHP提供的隱式shell,並明確地告訴命令在這個特定的目錄中運行「這個特定的'cmd' shell」,PHP成功地做了你告訴它的事情。 – cartbeforehorse 2013-04-23 06:21:32

1

我同樣的問題,花費了大量的時間和一杯咖啡

之後就在Windows 7 短路徑禁用用戶帳戶控制(UAC):P C:\ WINDOWS \ SYSTEM32 \ UserAccountControlSettings。 exe 並選擇「從不通知」

和php exec()工作正常!

我用: Apache的版本:2.2.11
PHP版本:5.2.8
的Windows 7 SP1 32位

最好的問候! :d

+0

現在我不記得了,但即使我應該已經禁用了UAC,但是即使這樣也應該記住。好的+1。 – albanx 2013-06-16 07:01:58

0

試試這個:

shell_exec('dir 2>&1'); 

它在Windows罰款啓用8.1 64位與UAC。

0

如果您在Windows機器上,並試圖像這樣運行的可執行文件:

shell_exec("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile\YourFile.exe"); 

並沒有輸出或文件沒有啓動,那麼你應該試試這個:

chdir("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile"); 
shell_exec("YourFile.exe"); 

它應該工作。

這是特別方便,如果是使用從文件夾中的腳本目前正在位於相對路徑,例如:

$dir = dirname(__FILE__).'\\..\\..\\..\\web\\'; 

而且不要忘了CHDIR()返回到原始文件夾,如果你需要運行其他程序。