PHP는 백그라운드 프로세스를 실행
사용자 조치에 따라 디렉토리 사본을 실행해야하지만 디렉토리가 상당히 크기 때문에 사용자가 사본을 완료하는 데 걸리는 시간을 인식하지 않고 그러한 조치를 수행 할 수 있기를 원합니다.
어떤 제안이라도 대단히 감사하겠습니다.
이것이 Linux 컴퓨터에서 실행되고 있다고 가정하면 항상 다음과 같이 처리했습니다.
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
명령을 시작하고 명령 $cmd
출력을로 리디렉션 $outputfile
하고 프로세스 ID를에 기록합니다 $pidfile
.
이를 통해 프로세스가 수행중인 작업과 여전히 실행 중인지를 쉽게 모니터링 할 수 있습니다.
function isRunning($pid){
try{
$result = shell_exec(sprintf("ps %d", $pid));
if( count(preg_split("/\n/", $result)) > 2){
return true;
}
}catch(Exception $e){}
return false;
}
프로세스를 편리한 언어 (php / bash / perl / etc)로 서버 측 스크립트로 작성한 다음 PHP 스크립트의 프로세스 제어 기능에서 호출하십시오.
이 함수는 표준 io가 출력 스트림으로 사용되는지 여부를 감지하고 그렇다면 반환 값을 설정합니다.
Proc_Close (Proc_Open ("./command --foo=1 &", Array (), $foo));
"sleep 25s"를 명령으로 사용하여 명령 줄에서이를 빠르게 테스트했으며 매력처럼 작동했습니다.
( 답변은 여기에 있습니다 )
이것을 명령에 추가하려고 할 수 있습니다
>/dev/null 2>/dev/null &
예.
shell_exec('service named reload >/dev/null 2>/dev/null &');
Windows 에서이 기능을 테스트하기위한 매우 간단한 예를 추가하고 싶습니다.
다음 두 파일을 작성하여 웹 디렉토리에 저장하십시오.
foreground.php :
<?php
ini_set("display_errors",1);
error_reporting(E_ALL);
echo "<pre>loading page</pre>";
function run_background_process()
{
file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
echo "<pre> foreground start time = " . time() . "</pre>";
// output from the command must be redirected to a file or another output stream
// http://ca.php.net/manual/en/function.exec.php
exec("php background.php > testoutput.php 2>&1 & echo $!", $output);
echo "<pre> foreground end time = " . time() . "</pre>";
file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
return $output;
}
echo "<pre>calling run_background_process</pre>";
$output = run_background_process();
echo "<pre>output = "; print_r($output); echo "</pre>";
echo "<pre>end of page</pre>";
?>
background.php :
<?
file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
sleep(10);
file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
?>
위 파일을 작성한 디렉토리에 쓸 수있는 권한을 IUSR에 부여하십시오.
C : \ Windows \ System32 \ cmd.exe를 읽고 실행하려면 IUSR 권한을 부여하십시오.
웹 브라우저에서 foreground.php를 누르십시오
출력 배열의 현재 타임 스탬프 및 로컬 리소스 번호를 사용하여 브라우저에 다음을 렌더링해야합니다.
loading page
calling run_background_process
foreground start time = 1266003600
foreground end time = 1266003600
output = Array
(
[0] => 15010
)
end of page
위의 파일이 저장된 동일한 디렉토리에 testoutput.php가 표시되고 비어 있어야합니다.
위의 파일이 저장된 디렉토리와 동일한 디렉토리에 testprocesses.php가 표시되고 현재 타임 스탬프가 포함 된 다음 텍스트가 포함되어야합니다.
foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610
PHP 페이지가 완료되기를 기다리지 않고 백그라운드에서 무언가를해야하는 경우 wget 명령으로 "호출 된"다른 (백그라운드) PHP 스크립트를 사용할 수 있습니다. 이 배경 PHP 스크립트는 물론 시스템의 다른 PHP 스크립트와 마찬가지로 권한으로 실행됩니다.
다음은 gnuwin32 패키지의 wget을 사용하는 Windows의 예입니다.
훌륭한 배경 코드 (파일 test-proc-bg.php) ...
sleep(5); // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file
포 그라운드 스크립트, 하나는 호출 ...
$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);
이 기능이 제대로 작동하려면 popen / pclose를 사용해야합니다.
wget 옵션 :
-q keeps wget quiet.
-O - outputs to stdout.
-b works on background
다음은 PHP에서 백그라운드 프로세스를 시작하는 함수입니다. 마지막으로 다른 접근 방식과 매개 변수를 많이 읽고 테스트 한 후에 실제로 Windows에서도 작동하는 것을 만들었습니다.
function LaunchBackgroundProcess($command){
// Run command Asynchroniously (in a separate thread)
if(PHP_OS=='WINNT' || PHP_OS=='WIN32' || PHP_OS=='Windows'){
// Windows
$command = 'start "" '. $command;
} else {
// Linux/UNIX
$command = $command .' /dev/null &';
}
$handle = popen($command, 'r');
if($handle!==false){
pclose($handle);
return true;
} else {
return false;
}
}
참고 1 : Windows에서는 /B
다른 곳에서 제안한대로 매개 변수를 사용하지 마십시오 . 프로세스가 start
명령 자체 와 동일한 콘솔 창을 실행하도록 하여 프로세스가 동 기적으로 처리되도록합니다. 별도의 스레드에서 프로세스를 비동기식으로 실행하려면을 사용하지 마십시오 /B
.
참고 2 : start ""
명령이 인용 된 경로 인 경우 뒤에 빈 큰 따옴표 가 필요합니다. start
명령은 처음 인용 된 매개 변수를 창 제목으로 해석합니다.
글쎄, 나는 조금 더 빠르고 사용하기 쉬운 버전을 발견했다.
shell_exec('screen -dmS $name_of_screen $command');
작동합니다.
별도의 프로세스를 분기 한 후 백그라운드에서 사본을 실행할 수 있습니까? PHP를 한 이후로 오래 되었지만 pcntl-fork 함수 는 유망합니다.
Resque 와 같은 큐잉 시스템을 시도 할 수 있습니다 . 그런 다음 정보를 처리하고 "프로세싱"이미지를 사용하여 매우 빠르게 작업을 생성 할 수 있습니다. 이 방법을 사용하면 언제 완료되는지 알 수 없습니다.
이 솔루션은 프론트 머신이 과도한 작업을 수행하지 않기 위해 사용자 요청을 처리 할 수있는 대규모 애플리케이션을위한 것입니다. 따라서 파일 및 폴더와 같은 실제 데이터와 함께 작동하거나 작동하지 않을 수 있지만 더 복잡한 논리 또는 기타 비동기 작업 (예 : 새 등록 메일)을 처리하는 데 유용하고 확장 성이 좋습니다.
백그라운드에서 프로그램을 실행하려면이 기능을 사용하십시오. 크로스 플랫폼이며 완벽하게 사용자 정의 할 수 있습니다.
<?php
function startBackgroundProcess(
$command,
$stdin = null,
$redirectStdout = null,
$redirectStderr = null,
$cwd = null,
$env = null,
$other_options = null
) {
$descriptorspec = array(
1 => is_string($redirectStdout) ? array('file', $redirectStdout, 'w') : array('pipe', 'w'),
2 => is_string($redirectStderr) ? array('file', $redirectStderr, 'w') : array('pipe', 'w'),
);
if (is_string($stdin)) {
$descriptorspec[0] = array('pipe', 'r');
}
$proc = proc_open($command, $descriptorspec, $pipes, $cwd, $env, $other_options);
if (!is_resource($proc)) {
throw new \Exception("Failed to start background process by command: $command");
}
if (is_string($stdin)) {
fwrite($pipes[0], $stdin);
fclose($pipes[0]);
}
if (!is_string($redirectStdout)) {
fclose($pipes[1]);
}
if (!is_string($redirectStderr)) {
fclose($pipes[2]);
}
return $proc;
}
명령이 시작된 후 기본적으로이 기능은 실행중인 프로세스의 stdin 및 stdout을 닫습니다. $ redirectStdout 및 $ redirectStderr 인수를 통해 프로세스 출력을 일부 파일로 리디렉션 할 수 있습니다.
Windows 사용자를위한 참고 사항 : 다음 방법으로
stdout / stderr를 경로 재 지정할 수 없습니다 nul
.
startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');
그러나 다음을 수행 할 수 있습니다.
startBackgroundProcess('ping yandex.com >nul 2>&1');
* nix 사용자를위한 참고 사항 :
1) 실제 PID를 얻으려면 exec shell 명령을 사용하십시오.
$proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
print_r(proc_get_status($proc));
2) 프로그램의 입력에 데이터를 전달하려면 $ stdin 인수를 사용하십시오.
startBackgroundProcess('cat > input.txt', "Hello world!\n");
Windows와 Linux 모두를위한 효과적인 솔루션. 내 github 페이지 에서 자세한 내용을 확인 하십시오 .
function run_process($cmd,$outputFile = '/dev/null', $append = false){
$pid=0;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
$handle = popen("start /B ". $cmd, "r");
$read = fread($handle, 200); //Read the output
$pid=substr($read,strpos($read,'=')+1);
$pid=substr($pid,0,strpos($pid,';') );
$pid = (int)$pid;
pclose($handle); //Close
}else{
$pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
}
return $pid;
}
function is_process_running($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
//tasklist /FI "PID eq 6480"
$result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('ps %d 2>&1', $pid));
if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
return true;
}
}
return false;
}
function stop_process($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$result = shell_exec('taskkill /PID '.$pid );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('kill %d 2>&1', $pid));
if (!preg_match('/No such process/', $result)) {
return true;
}
}
}
백그라운드 프로세스를 시작하는 대신 트리거 파일을 작성하고 cron 또는 autosys와 같은 스케줄러가 주기적으로 트리거 파일을 찾아서 실행하는 스크립트를 실행하는 것은 어떻습니까? 트리거에는 명령이나 원시 명령이 포함될 수 있습니다 (더 나은 방법은 쉘 스크립트입니다).
PHP를 사용하는 경우 pcntl_fork를 사용하여이 작업을 수행하는 훨씬 쉬운 방법이 있습니다.
http://www.php.net/manual/en/function.pcntl-fork.php
나는 많이 사용하고 있습니다 fast_cgi_finish_request()
클로저 및 register_shutdown_function ()과 함께
$message ='job executed';
$backgroundJob = function() use ($message) {
//do some work here
echo $message;
}
그런 다음 종료 전에 실행되도록이 클로저를 등록하십시오.
register_shutdown_function($backgroundJob);
마지막으로 응답이 클라이언트로 전송되면 클라이언트와의 연결을 닫고 PHP 프로세스 작업을 계속할 수 있습니다.
fast_cgi_finish_request();
fast_cgi_finish_request 후에 폐쇄가 실행됩니다.
$ message는 언제든지 표시되지 않습니다. 원하는만큼 클로저를 등록 할 수 있지만 스크립트 실행 시간은주의하십시오. 이것은 PHP가 Fast CGI 모듈로 실행되는 경우에만 작동합니다 (그렇습니까?!)
이 답변 덕분에 : 백그라운드 프로세스를 실행하는 완벽한 도구 는 기능을 기반으로 하지만 사용하기가 훨씬 쉬운 Symfony Process Componentproc_*
입니다. 자세한 내용은 해당 설명서 를 참조하십시오.
PHP 스크립팅은 다른 데스크탑 응용 프로그램 개발 언어와 다릅니다. 데스크톱 응용 프로그램 언어에서는 백그라운드 프로세스를 실행하기 위해 데몬 스레드를 설정할 수 있지만 PHP에서는 사용자가 페이지를 요청할 때 프로세스가 발생합니다. 그러나 PHP 스크립트가 실행하는 서버의 크론 작업 기능을 사용하여 백그라운드 작업을 설정할 수 있습니다.
Windows를 사용하는 사람들은 다음을보십시오.
참조 : http://php.net/manual/en/function.exec.php#43917
스크립트가 계속 실행되는 동안 Windows에서 백그라운드에서 프로그램을 실행하는 데 어려움을 겪었습니다. 이 방법을 다른 솔루션과 달리 최소화하거나 최대화하거나 전혀 창없이 프로그램을 시작할 수 있습니다. llbra @ phpbrasil의 솔루션은 작동하지만 실제로 작업을 숨기고 싶을 때 바탕 화면에 원하지 않는 창이 생성됩니다.
백그라운드에서 최소화 된 Notepad.exe를 시작하십시오.
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("notepad.exe", 7, false);
?>
백그라운드에서 보이지 않는 쉘 명령을 시작하십시오.
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false);
?>
MSPaint 최대화를 시작하고 스크립트를 계속하기 전에 닫을 때까지 기다리십시오.
<?php
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("mspaint.exe", 3, true);
?>
Run () 메서드에 대한 자세한 내용을 보려면 다음 사이트를 방문하십시오 : http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp
수정 된 URL :
위의 링크가 더 이상 존재하지 않으므로 https://technet.microsoft.com/en-us/library/ee156605.aspx로 이동 하십시오 .
나는 그것이 100 살짜리 게시물이라는 것을 알고 있지만 어쨌든 누군가에게 유용 할 것이라고 생각했습니다. 다음과 같이 백그라운드에서 실행해야하는 URL을 가리키는 페이지 어딘가에 보이지 않는 이미지를 넣을 수 있습니다.
<img src="run-in-background.php" border="0" alt="" width="1" height="1" />
참고 URL : https://stackoverflow.com/questions/45953/php-execute-a-background-process
'IT story' 카테고리의 다른 글
스 와이프하여 삭제 및 '추가'버튼 (iOS 7의 Mail 앱에서와 같이) (0) | 2020.04.07 |
---|---|
C ++ 11의 람다가 기본적으로 값별 캡처를 위해 "mutable"키워드를 요구하는 이유는 무엇입니까? (0) | 2020.04.07 |
Erlang은 어디에 사용되며 왜 그런가요? (0) | 2020.04.07 |
Chrome 양식 자동 완성 및 노란색 배경 (0) | 2020.04.07 |
MySQL SELECT 만 null 값이 아닙니다 (0) | 2020.04.07 |