2010-11-23 44 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 . '"'; 
}