Используйте PHP proc_open + bypass_shell для запуска исполняемого файла в фоновом режиме и получения правильного PID?
Итак, в PHP на Windows: возможно ли запустить исполняемый файл в фоновом режиме и получить его PID? Я пришел к выводу, что обе задачи можно выполнять по отдельности, но не вместе.
Фоновый процесс
Для фонового запуска процесса через SHELL, команда 'start /B "bg" myprog.exe'
должен использоваться, и процесс SHELL должен быть закрыт сразу после.
Для этого многие люди используют pclose( popen( ... ) )
вот так pclose( popen( 'start /B "bg" myprog.exe', 'r') );
но, насколько мне известно, невозможно получить pid
при использовании попен.
Потому что невозможно получить pid
с popen мы должны смотреть на proc_open.
Получение PID
С помощью proc_open
мы можем получить PID exe, если и только если bypass_shell
установлен в true.
Если bypass_shell
имеет значение false (по умолчанию), Windows возвращает pid
ОБОЛОЧКИ. Для получения дополнительной информации см.: https://bugs.php.net/bug.php?id=41052
Объясненная проблема
start /B
Сбой команды при передаче в proc_open, когда bypass_shell = true
потому что он пропускает SHELL и отправляет аргументы командной строки непосредственно в myprog.exe, который не знает, что с ними делать.
И наоборот, если bypass_shell = false
(по умолчанию) и proc_close используется для немедленного закрытия SHELL, myprog.exe работает в фоновом режиме, как при использовании pclose( popen( ... ) )
НО неправильный pid
возвращается (мы получаем pid
ОБОЛОЧКИ).
Итак, возможен ли фоновый + правильный поиск pid?
Если нет, какова следующая лучшая вещь? Мне нужно сделать это для сценария PHP, который будет развернут на общем хостинге, чтобы сторонние расширения не могли быть установлены. Лучшее, что я могу придумать, это сделать снимок tasklist
до и после запуска myprog.exe в фоновом режиме, а затем перекрестного анализа результатов. Обратите внимание, что myprog.exe может работать одновременно.
Если это помогает, хотя это не должно иметь никакого значения, myprog.exe на самом деле является ffmpeg (который устанавливается на большинство общих веб-хостов).
Временное решение
// background the process
pclose( popen( 'start /B "bg" ffmpeg.exe', 'r') );
// get the pid using tasklist
exec( 'TASKLIST /NH /FO "CSV" /FI "imagename eq ffmpeg.exe" /FI "cputime eq 00:00:00"', $output );
$output = explode( '","', $output[0] );
$pid = $output[1];
1 ответ
Это не совсем ответ на вопрос OP, так как он не будет работать на сервере Windows, но он будет отлично работать на любом сервере Linux с включенной exec(), так что это может кому-то помочь;)
$pidfile = 'myPidFile'; //coule be done better with tempnam(), but for this example will do like that ;)
$outputfile = '/dev/null'; //can be any text file instead of /dev/null. output from executable will be saved there
$cmd = 'sleep 30'; // this would normaly take 30 seconds
exec(sprintf("%s > %s 2>&1 & echo $! > %s", $cmd, $outputfile, $pidfile));
$pid = file_get_contents($pidfile);
echo $pid;
//delete pid file if you want
//unlink($pidfile);