1

我在 Windows 上使用 PHP 的 exec() 函数运行命令时遇到问题。根据 PHP 网站上关于exec()的评论:

在 Windows 中,exec() 发出对“cmd /c your_command”的内部调用。

我的命令看起来像:

"path\to\program.exe" -flag1 attribute1 -flag2 attribute2 -flag3 "attribute3 attribute4"

在我的本地命令提示符下定期执行此命令,没有 /c 标志,该命令运行良好。但是,随着 /c 标志的引入,命令提示符告诉我“系统找不到指定的路径”。

我认为命令提示符将双引号参数解释为另一个文件的路径,但这是我遇到的最远的问题。

有人对如何克服这个有任何想法吗?谢谢!

4

4 回答 4

2

我已经自己想出了答案...

仔细阅读 cmd.exe 的 /? 并试图破译这一点,我注意到一个重要的部分:

  1. 如果满足以下所有条件,则保留命令行中的引号字符:

    • 无 /S 开关(带引号)
    • 正好两个引号字符
    • 两个引号字符之间没有特殊字符,其中 special 是以下之一: & < >( ) @ ^ |
    • 两个引号字符之间有一个或多个空格字符
    • 两个引号字符之间的字符串是可执行文件的名称。
  2. 否则,旧的行为是查看第一个字符是否是引号字符,如果是,则去除前导字符并删除命令行上的最后一个引号字符,保留最后一个引号字符之后的任何文本。要否定此行为,请在命令行的开头和结尾使用双引号 ""。

似乎在任何时候都有一对以上的引号,引号将从第二对引号中删除,然后继续。

一个相关的问题:如何在使用 cmd.exe但不完全相关时处理引号字符,因为 PHP 不允许您通过在其调用上放置 /S 标志来修改其 exec() 命令(这肯定会很多更轻松)。

我已经设法通过使用 chdir() 直接将目录更改为 .exe 所在的文件夹,然后 chdir()'ing 回到我原来的工作目录来解决这个问题。这是一个非常 hacky 的解决方案,因为我很幸运我只有一组使用双引号的参数。如果有人要使用双引号有多个参数,我不知道如何解决...

于 2012-07-20T17:49:29.103 回答
2

我也遇到了这个问题,其原因确实是您自己的答案中描述的“cmd /c”的内部使用。

我做了一些调查,发现这在 PHP 5.3 中得到了解决,这就是为什么一些评​​论者无法重现它的原因。

它在以下提交中得到修复:

https://github.com/php/php-src/commit/19322fc782af429938da8d3b421c0807cf1b848a#diff-15f2d3ef68f383a87cce668765721041R221

对于仍然需要支持 PHP 5.2 的任何人来说,在您自己的代码中复制修复是相当容易的。代替:

$cmd = "...any shell command, maybe with multiple quotes...";
exec($cmd);

采用

$cmd = "...any shell command, maybe with multiple quotes...";

if (strtoupper(substr(php_uname('s'), 0, 3)) == "WIN"
    && version_compare(PHP_VERSION, "5.3", "<")) 
{
    $cmd = '"' . $cmd . '"';
}

exec($cmd);

这复制了 PHP 5.3 及更高版本的行为,与上面链接的提交中的方式相同。

请注意,这适用于所有 shell 命令,而不仅仅是我的示例中使用的 exec()。

于 2017-03-04T12:44:59.353 回答
0

只是一个猜测(我不熟悉 Windows 上的 PHP):也许将引号转义为"become ""

"path\to\program.exe" -flag1 attribute1 -flag2 attribute2 -flag3 ""attribute3 attribute4""

无论解决方案是什么,请确保当有某种形式的用户输入作为参数传递给此命令时,您使用escapeshellarg和/或escapeshellcmd

于 2012-07-19T21:26:25.783 回答
0

我希望它会有所帮助

escapeshellarg() — 转义要用作 shell 参数的字符串
escapeshellcmd() — 转义 shell 元字符

于 2012-07-19T21:47:40.083 回答