Команда 7-Zip не выполняется при асинхронном вызове пакета из php

В моем командном файле у меня есть следующий код

SETLOCAL enabledelayedexpansion
7Z a -r ..\%ZIPNAME%.zip * >> uniqueid8.log
IF !ERRORLEVEL! GEQ 1 (
    CALL :getLineNumber errLine uniqueID8 -2
    PHP ..\..\shell_mailupdate.php ERROR !errLine! "7Z a -r ..\%ZIPNAME%.zip * >> ..\uniqueid8.log"
    ENDLOCAL & EXIT /B
)
ENDLOCAL

:getLineNumber — это функция для получения номера строки:

:::::::::::::::::::::::::::::::::::::::::::::
:GetLineNumber <resultVar> <uniqueID> [LineOffset]
:: Detects the line number of the caller, the uniqueID have to be unique in the batch file
:: The lineno is return in the variable <resultVar> add with the [LineOffset]
SETLOCAL
for /F " usebackq tokens=1 delims=:" %%L IN (`findstr /N "%~2" "%~f0"`) DO set /a lineNr=%~3 + %%L
( 
  ENDLOCAL
  set "%~1=%LineNr%"
  goto :eof
)

Shell_mailupdate.php — это php-скрипт, который отправляет мне информацию об ошибках.

Пакетный файл вызывается асинхронно из моего веб-приложения с помощью этой функции, найденной на исполняемая страница php:

<?php
function execInBackground($path, $exe, $args = "") {
   global $conf;

   if (file_exists($path . $exe)) {
       chdir($path);
       if (substr(php_uname(), 0, 7) == "Windows"){
           pclose(popen("start \"bla\" \"" . $exe . "\" " . escapeshellarg($args), "r"));   
       } else {
           exec("./" . $exe . " " . escapeshellarg($args) . " > /dev/null &");   
       }
   }
}
?>

Когда вызывается пакетный файл (моя серверная ОС — Windows), я получаю сообщение о том, что команда не сработала, и мой пакет прерывается. И когда я захожу посмотреть unique8.log, он пуст. Но когда я пробую эту команду напрямую (путем замены %ZIPNAME% на имя, которое я хочу) на сервере, она работает и создает мой zip-файл. Есть также другие вызовы команды 7-zip для извлечения данных ранее в скрипте, но я подозреваю, что они тоже не сработали, так как данные не были извлечены. Но я знаю, что командный файл работает без сбоев при запуске вручную.

Это не может произойти из переменной, так как я знаю из своей почты, что она была правильно инициализирована. У меня также установлена ​​последняя версия 7-zip.

EDIT: Для тех, кто задается вопросом, почему у меня такая конфигурация, мне нужно создать большой пакет из множества маленьких пакетов. Это включало распаковку маленького пакета и перестановку их содержимого. Поскольку операция занимает много времени, я просто вызываю эту операцию в фоновом режиме и позволяю моему php-скрипту завершиться, не дожидаясь завершения операции, и он сообщает конечному пользователю, что почта будет отправлена, как только операция завершится.

EDIT2: После того, как я последовал совету Wimmel записать stderr в файл журнала, я получил следующее исключение:

Der Befehl "7Z" ist entweder falsch geschrieben oder konnte nicht gefunden werden.

Что грубо переводится в

Команда "7Z" написана неправильно или не найдена

Это странно, потому что, как я упоминал ранее, вызов пакетного сценария вручную проходит гладко без такого исключения.


person Eldros    schedule 19.08.2011    source источник


Ответы (2)


У меня есть несколько предложений, которые вы можете попробовать;

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

7Z a -r ..\%ZIPNAME%.zip * >> uniqueid8.log

с

echo 7Z a -r ..\%ZIPNAME%.zip * >> uniqueid8.log

И посмотрите, может ли он писать в uniqueid8.log, и есть ли правильная командная строка. Следующий шаг — посмотреть, можно ли создать zip-файл:

echo test > ..\%ZIPNAME%.zip

Если проблема может заключаться в правах, вы также можете временно добавить IUSR и IWAM в группу администраторов, просто чтобы проверить, не изменит ли это что-нибудь. Также напишите stderr в тот же файл журнала, как это (также убедитесь, что сам файл журнала не заархивирован):

7Z a -r ..\%ZIPNAME%.zip * >> ..\uniqueid8.log 2>&1

ИЗМЕНИТЬ Что касается вашей ошибки:

Der Befehl "7Z" ist entweder falsch geschrieben oder konnte nicht gefunden werden.

Это, вероятно, означает, что каталог, содержащий 7z, находится в пути вашей собственной учетной записи пользователя, но не в учетной записи пользователя, выполняющего php-скрипт. Самый простой способ решить эту проблему — ввести полный путь к 7z (возможно, вам придется использовать c:\programme вместо c:\program files):

"c:\program files\7-zip\7Z" a -r ..\%ZIPNAME%.zip * >> uniqueid8.log

или добавьте его в путь в начале вашего командного файла:

@echo off
set path="c:\program files\7-zip";%path%
person wimh    schedule 19.08.2011
comment
В настоящее время я не на работе в течение следующих двух недель. Придется подождать до тех пор, чтобы проверить вашу идею, но я вижу, что это имеет смысл. - person Eldros; 21.08.2011
comment
два эха вели себя так, как можно было ожидать, правильно записывая информацию в файл журнала или создавая zip-файл. Теперь я хотел проверить предоставление прав администратора указанному вами пользователю. Однако у меня вопрос: есть ли пользователи IUSR и IWAM под Windows 2000? Потому что я не могу их найти. - person Eldros; 05.09.2011
comment
Я отредактировал свой ответ из-за EDIT2 в вашем исходном вопросе. Если вам все еще нужно знать о IUSR/IWAM на W2k, пожалуйста, дайте мне знать. Я должен копать немного для этого.... ;) - person wimh; 05.09.2011
comment
Добавление его к пути в начале сделало свое дело, но не забило бы переменную повторением пути? - person Eldros; 06.09.2011
comment
Когда вы добавите его таким образом (set path=...;%path%), он не будет запомнен в следующий раз. Таким образом, он будет добавлен только один раз. И даже если он уже находится в вашем пути, например, когда вы запускаете его под своей учетной записью пользователя, не помешает, если он будет включен дважды. - person wimh; 06.09.2011

Я подозреваю, что pclose убивает его. Существует большая разница между перенаправлением на /dev/null (который будет принимать любые данные и молча отбрасывать их) и закрытием его стандартного вывода (что приведет к сбою любой записи).

Я думаю, что вы должны использовать exec также в Windows, просто перенаправить на NUL вместо /dev/null

Также вы должны перенаправлять как stdout, так и stderr на обеих платформах, поэтому >NUL 2>NUL.

person Jan Hudec    schedule 19.08.2011
comment
Жаль, это выглядело многообещающе, но он не только показывает то же поведение, но теперь мой php-скрипт ожидает остановки своего выполнения. - person Eldros; 19.08.2011
comment
@Eldros: попробуйте поставить перед ним команду start в Windows. Это должно делать что-то вроде & в unix. Но я никогда не пробовал это с php (и не запускал php в Windows в этом отношении); просто угадал. - person Jan Hudec; 19.08.2011
comment
Если вы посмотрите на функцию execInBackground, вы увидите, что она уже использует start. Я не изменил этого, когда попробовал предложенное вами решение. - person Eldros; 19.08.2011
comment
@Eldros: Хм, тогда у меня нет идей. - person Jan Hudec; 19.08.2011