2010-11-23 88 views
2

我已經編寫了一個Web應用程序,它使用exec()來運行外部程序。程序路徑是可配置的,可以預期其名稱上有空格。衆所周知,Windows命令提示符接受文件名或參數中的空格,你只需要雙引號:exec():在Windows中引用完整命令

C:\>C:\Archivos de programa\GraphicsMagick-1.3.12-Q16\gm.exe 
"C:\Archivos" no se reconoce como un comando interno o externo, 
programa o archivo por lotes ejecutable. 

C:\>"C:\Archivos de programa\GraphicsMagick-1.3.12-Q16\gm.exe" 
GraphicsMagick 1.3.12 2010-03-08 Q16 http://www.GraphicsMagick.org/ 

到目前爲止這麼好。我面臨的問題是使用exec()PHP函數本身。某些Windows服務器要求在雙引號將完整的命令(程序+參數)

exec('""C:\Archivos de programa\GraphicsMagick-1.3.12-Q16\gm.exe" version"'); 

...和其他Windows服務器需要用雙引號:

exec('"C:\Archivos de programa\GraphicsMagick-1.3.12-Q16\gm.exe" version'); 

我可以讀取PHP_OS常量來檢測服務器是否運行Windows,但我不知道引號背後的規則或不引用主題。它如果在PHP手冊中解釋我找不到它。

是可以確定編程是否需要引號,所以我並不需要手動配置應用程序的每個實例?

更新#1:我被誤解了,所以我已經重新編寫了部分問題,使其更加清晰。

更新#2:我發現a comment in the PHP manual,解釋爲什麼需要額外的引號的確切原因(PHP發出內部呼叫cmd /c)。我仍然不知道爲什麼這看起來是真的還是假的取決於系統。

回答

3

我已經寫了這個快速和骯髒的解決方法:

<?php 

class Thumb{ 
    const GM_PATH = 'C:\\Archivos de programa\\GraphicsMagick-1.3.12-Q16\\gm.exe'; 

    /** 
    * Quote full command if required by server (program + arguments) 
    */ 
    private static function quoteFullCommand($command){ 
     // Test only once per script 
     static $extra_quotes_required=NULL; 

     if(is_null($extra_quotes_required)){ 
      if(PHP_OS=='WINNT'){ 
       // This call will be correct (0) if and only if the server requires extra quotes 
       exec('""sort" /?"', $output, $return); 
       $extra_quotes_required = $return==0; 
      }else{ 
       $extra_quotes_required = FALSE; 
      } 
     } 
     if($extra_quotes_required){ 
      $command = '"' . $command . '"'; 
     } 

     return $command; 
    } 


    /** 
    * Return output from "gm version" 
    */ 
    public static function graphicsMagickVersion(){ 
     $command = escapeshellarg(self::GM_PATH) . ' version '; 
     $command = self::quoteFullCommand($command); 
     exec($command, $output, $return); 

     return trim(implode(PHP_EOL, $output)); 
    } 
} 

但是,它會是更好的方式從PHP版本或服務器OS預測它使文檔鏈接或進一步提示是值得歡迎的。

更新:我有一個看片的PHP源代碼,需要在Windows上運行的外部命令的護理:

http://svn.php.net/viewvc/php/php-src/trunk/TSRM/tsrm_win32.c

以下行添加額外的昏迷充分命令:

sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command); 

根據文件歷史記錄,首次加入2008年5月29日(r260429)該行:

MFH:BUG修復當命令被引述 和呼叫 期間參數被引用給exec,結果是cmd.exe的/ C 條的第一和最後報價。

下面的PHP版本是5.3.0和5.2.7,但該行是在5_3分支,而不是在一個5_2。我對PHP開發過程不夠熟悉,所以我無法找到更新日誌或告訴我該修復程序移植到哪個確切的PHP版本,但我敢說這是PHP中的一個錯誤,並且它已在PHP中修復/5.3.0(但它沒有被回溯到5.2,所以他們沒有打破傳統的東西)。

所以我的解決方法可能是矯枉過正。您只需要測試PHP操作系統和版本:

if(PHP_OS=='WINNT' && version_compare(PHP_VERSION, '5.3.0', '<')){ 
    $command = $command = '"' . $command . '"'; 
}