【问题标题】:PHP exec() with double quote argumentPHP exec() 带双引号参数
【发布时间】:2017-03-04 21:06:14
【问题描述】:

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

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

我的命令如下:

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

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

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

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

【问题讨论】:

  • 经过多次尝试,这适用于我在 PHP 5.3.8 上:exec('"c:\Program Files (x86)\wget.exe" -c "http://localhost/tmp/test 1.php"');,您的示例可能应该是:exec('"path\to\program.exe" -flag1 attribute1 -flag2 attribute2 -flag3 "attribute3 attribute4"');
  • 那个命令对我也不起作用......我不知道为什么。 :/ 不过我找到了一个非常临时的解决方案,稍后我会发布。
  • Windows 在这种情况下有点tricky,就像php,所以你解决它很好,Derek。玩得开心!

标签: php command-line-arguments


【解决方案1】:

我自己想出了答案……

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

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

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

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

一个相关问题:How do I deal with quote characters when using cmd.exe 但并不完全相关,因为 PHP 不允许您通过在其调用上放置 /S 标志来修改其 exec() 命令(这肯定会容易得多)。

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

【讨论】:

    【解决方案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()。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 我忘了提到我尝试双引号来逃避,但无济于事。至于escapeshellarg的说明,我将直接从服务器端执行这个命令,但感谢您的建议!我会记住的。
      • 也许其他形式,如\"?对不起,正如我所说,我在 Windows 上不熟悉这个。我主要发布了一个答案来指出 escapeshellarg 和/或 escapeshellcmd :-)
      【解决方案4】:
      猜你喜欢
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 1970-01-01
      • 2012-01-14
      • 2011-06-02
      相关资源
      最近更新 更多