exec (): цитирование полной команды в Windows - PullRequest
2 голосов
/ 23 ноября 2010

Я написал веб-приложение, которое использует exec () для запуска внешней программы.Путь к программе настраивается, и в его названии могут быть пробелы.Как мы все знаем, командная строка 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/

Пока все хорошо.Проблема, с которой я сталкиваюсь, заключается в использовании самой функции PHP exec ().Некоторые серверы 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комментарий в руководстве по PHP , объясняющий точную причину, по которой нужны дополнительные кавычки (PHP выполняет внутренний вызов cmd /c).Я до сих пор не знаю, почему это зависит от системы.

1 Ответ

3 голосов
/ 23 ноября 2010

Я написал этот быстрый и грязный обходной путь:

<?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); 

Согласно истории файлов, эта строка была впервые добавлена ​​29 мая 2008 г. ( r260429 ):

MFH: Исправлена ​​ошибка, когда команда заключалась в кавычки, а параметры заключались в кавычки во время вызова exec, в результате cmd.exe / c удаляет первую и последнюю кавычку.

СледующееРелизы 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 . '"';
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...