exec():在Windows中引用完整命令

时间:2010-11-23 10:39:16

标签: php windows

我编写了一个使用exec()来运行外部程序的Web应用程序。程序路径是可配置的,并且可以预期其名称上有空格。众所周知,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的内部调用)。我仍然不知道为什么这似乎是真或假,取决于系统。

1 个答案:

答案 0 :(得分: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版本或服务器操作系统预测它会更好,所以欢迎链接到文档或进一步提示。

更新:我已经了解了在Windows中运行外部命令的PHP源代码:

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:修复引用命令时的错误   和呼叫期间引用参数   执行,结果是cmd.exe / c   剥去第一个和最后一个引用。

以下PHP版本是5.3.0和5.2.7,但该行位于5_3分支而不是5_2分支。我对PHP开发过程不太熟悉,所以我找不到更改日志或告诉修复程序移植到哪个确切的PHP版本但是我敢说它是PHP中的一个错误并且它已在PHP中修复/5.3.0(但它没有向后移植到5.2因此它们没有破坏遗留的东西)。

所以我的解决方法可能有些过分。您只需要测试PHP OS和版本:

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