Обновлено: см. мой ответ на этот пост для решения этой конкретной проблемы; Я также удалил части вопроса, которые больше не имеют отношения к решению.
Я новичок в PHP и разработке в целом, и я спрашиваю, потому что еще не нашел рабочего решения для своей проблемы.
В рамках проекта я пытаюсь запустить пакетный скрипт. Пакетный скрипт создает несколько файлов анализа и, что особенно важно, компилирует и запускает 2 исполняемых файла, которые мне нужно запустить на потом.
Чтобы запустить скрипт, я составляю вызов $cmd, в котором устанавливаю 2 переменные среды и рабочий каталог, а также добавляю некоторые необходимые параметры, необходимые скрипту для запуска.
затем я бегу
exec($cmd);
Этот вызов создает все файлы в рабочем каталоге и запускает процессы, однако теперь пакетный сценарий ожидает завершения исполняемых процессов, поскольку он очищает некоторые временные файлы после завершения программ. В этот момент программа PHP прекращает выполнение и ожидает завершения пакетного сценария, чего она не делает.
В течение последних 2 дней я пробовал несколько решений, предложенных здесь
или
exec($cmd.' > NUL 2>&1 &')
и
pclose(popen("start /B " . $cmd . " 1> ".$scrptDir." 2>&1 &", "r"));
где $scrptDir — рабочий каталог, описанный ранее.
Я не нашел рабочего решения, в лучшем случае скрипт вообще не запускается, а в худшем выдает синтаксическую ошибку при выполнении AJAX-вызова, что, правда, я пока не понял, почему именно так, ведь AJAX был реализован предшественник и остался довольно недокументированным.
Обновлено: синтаксические ошибки были вызваны мной, потому что я забыл точку с запятой.
Это PHP-код:
public function runScript() {
//-- compose the command line to start script
$cmd = $this->getCall();
//-- execute the script
exec($cmd);
}
}
Обновления: Запуск скрипта через
pclose(popen("start /B " . $cmd . " 1> NUL 2>&1 &", "r"));
или
popen("start /B " . $cmd . " 1> NUL 2>&1 &", "r");
или
exec('nohup ' . $cmd . ' 2>&1 &');
имеет тот же результат: сценарий запускается, но исполняемые файлы закрываются, и сценарий выполняет очистку.
С использованием
exec($cmd.' > NUL 2>&1 &');
поведение не отличается от
exec($cmd);
При работе над этим я бы рекомендовал сначала протестировать фиктивный скрипт, чтобы увидеть, как работают эти параметры. Для получения дополнительной помощи вы можете обновить свой пост с точными результатами, которые вы получаете с каждым вариантом.
Чтобы помочь вам исправить конкретную проблему с вашим программным кодом, мы ожидаем, что вы отправите все, что нам нужно, чтобы воспроизвести эту проблему в среде того же типа.
@Compo Извините, я добавил код, который сейчас использую для выполнения скрипта. Возможно ли запустить функцию runScript() асинхронно?






Это один из способов сделать это. Имейте в виду, что это не лучший способ сделать это, особенно если вам нужно что-то сделать с результатами вызова AJAX.
Допустим, вы инициируете запрос AJAX следующим образом:
$(document).ready(function() {
$.ajax({
type: 'POST',
url: 'myscript.php',
data: {'val1':val1,'val2':val2,....},
timeout: 100,
success: function(data) {
// whatever it is you need to do on success, although you could leave it empty
},
error: function (xmlhttprequest, textstatus, message, desc, err) {
if (textstatus === "timeout") {
// do something else
} else {
// cover the case of an error which is not a timeout
}
}
});
});
Ключевой частью здесь является timeout. Это прервет ожидающий AJAX, а это означает, что JS не будет ждать ответа, но скрипт на стороне сервера, вызванный с ним, все равно будет выполняться.
Если вы не используете jQuery, вы можете сделать то же самое в ванильном Javascript, например.
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", "myscript.php", true);
// Post the request with your data
xmlHttp.send(
JSON.stringify({
val1 : val1,
val2 : val2,
... etc
})
);
xmlHttp.onload = function(e) {
// Check if the request was a success
if (this.readyState === XMLHttpRequest.DONE && (this.status === 201 || this.staus === 200)) {
clearTimeout(xmlHttpTimeout);
// do whatever it is you do on successful response
}
}
// Timeout to abort in 100 miliseconds
var xmlHttpTimeout = setTimeout(ajaxTimeout,100);
function ajaxTimeout(){
xmlHttp.abort();
// do what you would normally do once initiating the AJAX
}
Если вы не уверены, достигает ли запрос AJAX серверной части, и нет ли ошибок консоли или сетевых ошибок, вы можете сделать следующее.
Сначала создайте скрипт с именем test.php (или дайте ему другое имя, если у вас уже есть скрипт с таким названием). Затем внутри этого скрипта поместите следующее.
<?php
sleep(15);
$filename = "zztest.txt";
$file = fopen($filename,'a+');
fwrite($file, date("Y-m-d H:i:s"));
sleep(5);
fwrite($file, PHP_EOL.date("Y-m-d H:i:s").PHP_EOL."********".PHP_EOL);
fclose($file);
?>
Что это будет делать:
sleep(15))fclose(...). Как правило, это не очень хорошая практика, потому что что-то может нарушить выполнение скрипта, и файл останется заблокированным, но в данном случае это нормально, потому что он предназначен для тестирования.sleep(5)), а затем запишите в него текущую дату и время. PHP_EOL — символ новой строкиСледующий шаг — заменить вызов myscript.php внутри вашего AJAX, чтобы он вызывал test.php. Остальная часть вашей настройки AJAX может остаться прежней.
Затем выполните AJAX, как обычно. Подождите около 20 секунд и проверьте, был ли создан файл с именем zztest.txt, и если да, то каково его содержимое.
Если нет, то проблема во внешнем интерфейсе (вызов AJAX).
Я попытался использовать опубликованный вами ванильный javascript, и запрос проходит и запускает скрипт, затем срабатывает тайм-аут. Однако я все еще не могу выполнить какой-либо PHP-код, он все еще ждет завершения сценария.
Пожалуйста, смотрите обновленный ответ. Я добавил для вас способ проверить, работает ли AJAX. Если это так (то, что я объяснил в обновлении, действительно происходит), то проблема может быть в вашем исходном PHP-скрипте. Если код исходного PHP-скрипта необходимо продолжить после вызова пакетного скрипта, вы можете рассмотреть возможность разделения PHP-кода на два отдельных файла. Это, однако, может не сработать для вас, если код PHP под exec($cmd) полагается на его результаты.
Скрипт создал текстовый файл и записал в него: " 2023-01-02 11:26:15 2023-01-02 11:26:20 ******** ", поэтому я думаю, что проблема заключается в PHP-код.
Вот кое-что еще, что можно попробовать: в верхней части исходного PHP-скрипта добавьте эти две строки кода: error_reporting(E_ALL); ini_set("display_errors",1); Они включат ведение журнала ошибок. Если вы включаете или требуете какие-либо дополнительные файлы в своем PHP-скрипте (в самом верху), поместите две строки под ними. Кроме того, в целях тестирования временно закомментируйте строку кода, которая вызывает пакетный скрипт. Это делается для того, чтобы он не запустился, так как сейчас вы просто ищете ошибки. Если проблема не устранена, я предлагаю открыть еще один вопрос на SO.
Где будут отображаться эти ошибки? Я использую XAMPP.
Они должны отображаться в ответе AJAX — вы можете открыть раздел «Сеть» инструментов разработчика, нажав CTRL + SHIFT + P (Chrome) или CTRL + SHIFT + E (Firefox). После открытия раздела «Сеть» активируйте AJAX и дождитесь его появления. Когда вы нажмете на нее, справа откроется боковая панель. Найдите в нем вкладку Response и проверьте содержимое.
Хорошо, я нашел обходной путь.
Вместо
exec($cmd)
я использовал
$filename = "help.bat";
$file = fopen($filename,'a+');
fwrite($file, $cmd);
fclose($file);
pclose(popen("start /B ". $filename, "r"));
Я записал составленную команду $cmd в пакетный файл, а затем вместо этого выполнил этот пакетный файл. Я думаю, что причина, по которой это работает сейчас, заключается в том, что мой составленный вызов был слишком сложным для меня, поэтому я попытался сделать его проще.
Привет, пожалуйста, исправьте форматирование в вашем вопросе.