jjzjj

php - 执行(): quoting full command in Windows

coder 2024-06-10 原文

我编写了一个使用 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 服务器要求您将完整的命令 (program + arguments) 用双引号引起来:

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 的内部调用)。我仍然不知道为什么这看起来是对还是错取决于系统。

最佳答案

我写了这个快速而肮脏的解决方法:

<?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 版本或服务器操作系统来预测它,因此欢迎提供文档链接或更多提示。

更新:我看过一段 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: Fix bug when command is quoted and parameters are quoted during call to exec, the result is that cmd.exe /c strips the first and last quote.

以下 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 . '"';
}

关于php - 执行(): quoting full command in Windows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4255162/

有关php - 执行(): quoting full command in Windows的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  3. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  4. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  5. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  6. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  7. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  8. ruby-on-rails - Rake 任务仅调用一次时执行两次 - 2

    我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里

  9. ruby-on-rails - 只有当不是 nil 时才执行映射? - 2

    如果names为nil,则以下中断。我怎样才能让这个map只有在它不是nil时才执行?self.topics=names.split(",").mapdo|n|Topic.where(name:n.strip).first_or_create!end 最佳答案 其他几个选项:选项1(在其上执行map时检查split的结果):names_list=names.try(:split,",")self.topics=names_list.mapdo|n|Topic.where(name:n.strip).first_or_create!e

  10. ruby - Capistrano 中的执行、测试和捕获命令有什么区别? - 2

    关于SSHkit-Github它说:Allbackendssupporttheexecute(*args),test(*args)&capture(*args)来自SSHkit-Rubydoc,我明白execute实际上是test的别名?test之间有什么区别?,execute,capture在Capistrano/SSHKit中我应该什么时候使用? 最佳答案 执行只是执行命令。使用非0退出引发错误。测试方法的行为与execute完全相同,但是它返回bool值(true如果命令以0退出,而false否则)。它通常用于控制任务中的流程

随机推荐