我编写了一个使用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
的内部调用)。我仍然不知道为什么这似乎是真或假,取决于系统。
答案 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 . '"';
}