PHP @exec не работает тихо - PullRequest
       36

PHP @exec не работает тихо

4 голосов
/ 03 апреля 2009

Это сводит меня с ума. Я пытаюсь выполнить оператор командной строки в окне Windows для моего веб-приложения PHP. Он работает на Windows XP, IIS5.1. Веб-приложение работает нормально, но я не могу заставить @exec () работать с определенной контактной переменной. Моя командная конструкция выглядит так:

$cmd = ($config->svn." cat ".$this->repConfig->svnParams().quote($path).' -r '.$rev.' > '.quote($filename));

Эта команда не работает, как указано выше, когда генерирует следующую строку:

svn --non-interactive --config-dir /tmp cat "file:///c:/temp/test/acccount/dbo_sproctest.sql" -r 1 > "C:\Inetpub\sites\websvn\temp\wsv5B45.tmp"

Если я скопирую / вставлю это в свою командную строку, все будет работать нормально.

Если я жестко закодирую тот же самый путь вместо добавления его с переменной, это сработает! Я пробовал с и без кавычек вокруг имени файла. Я пробовал с и без кавычек вокруг всей команды. Я пробовал другие каталоги. Я попытался передать выходной параметр в exec (), и он возвращается пустым (Array ()). Я попытался перенаправить вывод потока ошибок команды в файл, и этот файл вывода ошибок никогда не создается.

Единственное, в чем я могу заключить, это то, что exec () молча завершается сбоем. Что, черт возьми, я здесь делаю не так? Если я жестко закодирую путь к файлу, используя ту же структуру dir и имя файла, он работает нормально. Если я этого не сделаю, это не так.

Возможно, косые черты () в пути к файлу не экранируются должным образом, но когда я делаю это вручную с одинарными кавычками, они не считаются escape-последовательностями ??

UPDATE:

Я снял @ с exec и до сих пор не вижу никаких ошибок.

Я дал полный путь к SVN, все еще не повезло. Следует отметить, что команда работала раньше с SVN с неполным путем, пока я вручную определяю назначение файла для cat.

Обновление 2: RE: Kieth

Я звоню exec, пробуя оба:

exec($cmd);

или

exec($cmd, $out);

Мой php.ini уже имел safe_mode = 0.

Я добавил error_reporting (E_ALL); и ничего нового не увидел

Если я повторяю (или print_r) мой вызов exec, я фактически не вижу что-либо

Если я повторяю (или print_r) мой вызов exec, когда включаю выходную переменную, я получаю пустое значение

Обновление 3

Я пробовал и escapeshellcmd, и escapeshellarg безрезультатно (хотя хорошая идея).

Я должен добавить, что файл создается путем вызова

tempnam("temp", "wbsn");

Тот факт, что все работает нормально, если я вручную указываю строку вместо того, чтобы дать ей сгенерировать временное имя, похоже, указывает на источник проблемы, но я не могу понять как. Я сравнил ручную строку с сгенерированной, и она вернулась как совпадение.

Ответы [ 9 ]

23 голосов
/ 03 апреля 2009

@exec всегда будет молчать, потому что @ - это оператор подавления ошибок PHP.

5 голосов
/ 16 февраля 2010

Не уверен, поможет ли это вам, поскольку вы работаете в Windows, а я в Linux, но я столкнулся с той же проблемой скрытых ошибок в PHP exec (). Я понял, что команда, которую я пытался выполнить (nconvert), отправляет свои сообщения об ошибках в стандартный поток ошибок, а не в стандартный вывод. Поэтому я добавил

2>&1

в конце командной строки, чтобы перенаправить мою ошибку обратно в стандартный поток. Затем я увидел, что nconvert выдает ошибку «Отказано в разрешении».

2 голосов
/ 03 апреля 2009

Возможно, что PATH не совпадает с вашим php-скриптом и вашей учетной записью. Попробуйте удалить символ @ и посмотреть, не выдает ли он ошибку.

Кроме того, вы можете попробовать указать полный путь файловой системы к исполняемому файлу SVN.

1 голос
/ 01 августа 2009

Очень полезная хитрость при отладке проблем с shell-командой заключается в том, чтобы поместить "echo" в начале команды. Убедитесь, что вы можете просмотреть стандартный вывод где-то.

Это позволит вам проверить команду на наличие очевидных проблем. Возможно, он имеет подстановочный знак, который неожиданно расширяется, или, возможно, цитирование оболочки не совсем верно. Эхо позволит вам увидеть это, и вы можете вырезать и вставить команду echoed в другую оболочку, чтобы проверить, работает ли она правильно.

1 голос
/ 03 апреля 2009

Я не знаю, что происходит, но у меня по крайней мере есть обходной путь.

Это работает:

$tmp = tempnam("./", "wbsn");
$filename = dirname($tmp).'\\temp\\'.basename($tmp);

Это, однако, не так, но я бы ожидал, что он сгенерирует тот же путь (имя файла сравнения, так как это новый tempnam ()).

$tmp = tempnam("temp", "wbsn");

Кроме того, это не работает, что я также ожидал бы генерировать то же самое:

$tmp = tempnam("temp", "wbsn");
$filename = dirname($tmp).'\\'.basename($tmp);

Все 3 из этих решений появляются , чтобы генерировать одинаковые пути к файлам, но только первый действительно работает при использовании в моем exec. У меня нет понятия, почему это не так.

Визуальный осмотр (эхо) всех трех из них, по-видимому, генерирует одинаковые пути (за исключением, конечно, имен файлов, отличающихся). Сравнение строк dirname () каждого из этих 3-х показывается как совпадение. Я понятия не имею, в чем дело, но первый - это обходной путь.

1 голос
/ 03 апреля 2009

Вы пробовали echo exec ("dir") или что-то простое, чтобы увидеть, работает ли exec () вообще?

1 голос
/ 03 апреля 2009

Я не большой поклонник добавления другого ответа, но если я просто отредактирую свой предыдущий ответ, вы можете его не увидеть.

В PHP есть несколько специальных экранирующих команд для сценариев оболочки: escapeshellcmd и escapeshellarg .

Я думаю вы можете использовать escapeshellcmd для всего вашего $ cmd, но я не уверен.

1 голос
/ 03 апреля 2009

Что ж, если удаление @ не работает, попробуйте включить это в начале кода, который вы выполняете:

error_reporting(E_ALL);

Это включит полный отчет об ошибках, на случай, если он будет отключен или отключен в вашем файле php.ini.

Не думаю, что вы могли бы показать нам, как именно вы звоните exec()? Не могли бы вы также убедиться, что вы случайно не запускаете скрипт в безопасном режиме? Вы повторяете, что exec() возвращает, и если да, то что он возвращает?

0 голосов
/ 26 марта 2013

Мой совет будет перейти с WIN, IIS на Linux, но в качестве альтернативы вы можете попробовать это:

function exec_alt($cmd) {
    exec($cmd, $output);
    if (!$output) {
        /**
         * FIXME: for some reason exec() returns empty output array @mine,'s machine.
         *        Somehow proc_open() approach (below) works, but doesn't work at
         *        test machines - same empty output with both pipes and temporary
         *        files (not we bypass shell wrapper). So use it as a fallback.
         */
        $output = array();
        $handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
        if (is_resource($handle)) {
            $output = explode("\n", stream_get_contents($pipes[1]));
            fclose($pipes[1]);
            proc_close($handle);
        }
    }
    return $output; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...