it-source

PHP에서 실시간 출력으로 프로세스 실행

criticalcode 2022. 10. 20. 21:17
반응형

PHP에서 실시간 출력으로 프로세스 실행

웹 페이지에서 실시간으로 출력을 반환하는 프로세스를 실행하려고 합니다.예를 들어 'ping' 프로세스를 실행하면 새로운 행이 반환될 때마다 페이지가 갱신됩니다(현재는 exec(명령어, 출력)을 사용할 때 -c 옵션을 사용해야 하며 프로세스가 완료될 때까지 웹 페이지에서 출력을 볼 수 있습니다).이것을 php로 할 수 있습니까?

또한 누군가가 페이지를 떠날 때 이러한 과정을 멈추는 올바른 방법이 무엇인지 궁금합니다.'ping' 프로세스의 경우 시스템 모니터에서 실행 중인 프로세스를 확인할 수 있습니다(무엇이 말이 되는지).

이 방법은 효과가 있었습니다.

$cmd = "ping 127.0.0.1";

$descriptorspec = array(
   0 => array("pipe", "r"),   // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),   // stdout is a pipe that the child will write to
   2 => array("pipe", "w")    // stderr is a pipe that the child will write to
);
flush();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
    while ($s = fgets($pipes[1])) {
        print $s;
        flush();
    }
}
echo "</pre>";

셸 명령어의 실시간 출력을 표시하는 좋은 방법은 다음과 같습니다.

<?php
header("Content-type: text/plain");

// tell php to automatically flush after every output
// including lines of output produced by shell commands
disable_ob();

$command = 'rsync -avz /your/directory1 /your/directory2';
system($command);

출력 버퍼링을 방지하려면 다음 기능이 필요합니다.

function disable_ob() {
    // Turn off output buffering
    ini_set('output_buffering', 'off');
    // Turn off PHP output compression
    ini_set('zlib.output_compression', false);
    // Implicitly flush the buffer(s)
    ini_set('implicit_flush', true);
    ob_implicit_flush(true);
    // Clear, and turn off output buffering
    while (ob_get_level() > 0) {
        // Get the curent level
        $level = ob_get_level();
        // End the buffering
        ob_end_clean();
        // If the current level has not changed, abort
        if (ob_get_level() == $level) break;
    }
    // Disable apache output buffering/compression
    if (function_exists('apache_setenv')) {
        apache_setenv('no-gzip', '1');
        apache_setenv('dont-vary', '1');
    }
}

제가 사용해 본 모든 서버에서 동작하는 것은 아니지만, php 설정에서 무엇을 찾아야 하는지 조언하고 싶습니다.이러한 동작이 서버에서 동작하도록 하기 위해 머리를 뽑아야 하는지 판단하기 위해서입니다.또 아는 사람?

다음은 플레인 PHP의 더미 예시입니다.

<?php
header("Content-type: text/plain");

disable_ob();

for($i=0;$i<10;$i++) 
{
    echo $i . "\n";
    usleep(300000);
}

나는 이것이 검색으로 여기까지 온 다른 사람들에게 도움이 되기를 바란다.

모든 답을 확인했지만 아무 것도 작동하지 않았습니다...

솔루션 검색은 이쪽

윈도우에서 동작합니다(저쪽에서 검색하는 사용자에게 도움이 될 것 같습니다).

<?php
    $a = popen('ping www.google.com', 'r'); 
    
    while($b = fgets($a, 2048)) { 
        echo $b."<br>\n"; 
        ob_flush();flush(); 
    }

    pclose($a); 
?>

최신 HTML5 Server Side Events를 사용한 이 오래된 문제에 대한 보다 나은 해결책은 다음과 같습니다.

http://www.w3schools.com/html/html5_serversentevents.asp


예:

http://sink.agiletoolkit.org/realtime/console

코드: https://github.com/atk4/sink/blob/master/admin/page/realtime/console.php#L40

(Agile Toolkit 프레임워크의 모듈로 구현)

명령줄 사용:

function execute($cmd) {
    $proc = proc_open($cmd, [['pipe','r'],['pipe','w'],['pipe','w']], $pipes);
    while(($line = fgets($pipes[1])) !== false) {
        fwrite(STDOUT,$line);
    }
    while(($line = fgets($pipes[2])) !== false) {
        fwrite(STDERR,$line);
    }
    fclose($pipes[0]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    return proc_close($proc);
}

파일을 실행하려는 경우 먼저 실행 권한을 부여해야 할 수 있습니다.

chmod('/path/to/script',0755);

이것을 사용해 보세요(Windows 머신과 wamp 서버에서 테스트 완료).

        header('Content-Encoding: none;');

        set_time_limit(0);

        $handle = popen("<<< Your Shell Command >>>", "r");

        if (ob_get_level() == 0) 
            ob_start();

        while(!feof($handle)) {

            $buffer = fgets($handle);
            $buffer = trim(htmlspecialchars($buffer));

            echo $buffer . "<br />";
            echo str_pad('', 4096);    

            ob_flush();
            flush();
            sleep(1);
        }

        pclose($handle);
        ob_end_flush();

Windows에서 다양한 PHP 실행 명령어를 사용해 본 결과, 많은 차이가 있었습니다.

  • 하지 않음:shell_exec,exec,passthru
  • 종류 : 업업종종 :proc_open,popen 「는, 할 수 없기 때문에 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------my.exe --something 와 같이 할 수 있습니다._my_something.bat를 참조해 주세요.

최적의 (간단한) 접근법은 다음과 같습니다.

  1. exe가 명령어를 플러시하고 있는지 확인해야 합니다(프린트 플러시 문제 참조).이것이 없으면, 대부분의 경우, 약 4096 바이트의 텍스트 배지를 받게 됩니다.
  2. 경우, 「」를 사용해 .header('Content-Type: text/event-stream');)header('Content-Type: text/plain; charset=...');일부 브라우저/클라이언트에서는 동작하지 않습니다.스트리밍은 이 기능이 없어도 작동하지만 적어도 첫 번째 행은 브라우저에 의해 버퍼링됩니다.
  3. , 캐시 「」를 디세블로 할 수도 .header('Cache-Control: no-cache');.
  4. hpp. "hpp.ini" 중 ).ini_set('output_buffering', 'off');이 작업은 Apache/Nginx 또는 앞에서 사용하는 서버에서도 수행해야 합니다.
  5. 전환(hpp "hpp.ini" 중 )ini_set('zlib.output_compression', false);이 작업은 Apache/Nginx 또는 앞에서 사용하는 서버에서도 수행해야 합니다.

따라서 C++ 프로그램에서는 다음과 같은 작업을 수행합니다(다른 솔루션에 대해서는 printflush 문제 참조).

Logger::log(...) {
  printf (text);
  fflush(stdout);
}

PHP에서는 다음과 같은 작업을 수행합니다.

function setupStreaming() {
    // Turn off output buffering
    ini_set('output_buffering', 'off');
    // Turn off PHP output compression
    ini_set('zlib.output_compression', false);
    // Disable Apache output buffering/compression
    if (function_exists('apache_setenv')) {
        apache_setenv('no-gzip', '1');
        apache_setenv('dont-vary', '1');
    }
}
function runStreamingCommand($cmd){
    echo "\nrunning $cmd\n";
    system($cmd);
}
...

setupStreaming();
runStreamingCommand($cmd);

먼저 flush()가 자신에게 적합한지 확인합니다.정상적으로 동작하고 있는 경우는, 예를 들면 mod_gzip이 유효하게 되어 있는 경우 등, 어떠한 이유로 Web 서버가 버퍼링 되고 있는 것을 의미합니다.

ping 등의 경우 가장 쉬운 방법은 PHP 내에서 루프를 실행하여 "ping -c 1"을 여러 번 실행하고 각 출력 후에 flush()를 호출하는 것입니다.사용자가 HTTP 연결을 닫았을 때 PHP를 중단하도록 설정했다고 가정하면(일반적으로 기본값이거나 확인을 위해 ignore_user_abort(false)를 호출할 수 있습니다), 실행 ping 프로세스에 대해서도 걱정할 필요가 없습니다.

자프로세스를 1회만 실행하여 출력을 연속적으로 표시해야 하는 경우, 백그라운드에서 실행하고 출력을 스트림으로 리다이렉트한 후 일반 flush() 호출을 사용하여 사용자에게 스트림백하는 PHP 에코가 필요할 수 있습니다.

PHP를 통해 시스템 명령을 실행하는 경우 exec 문서를 참조하십시오.

그러나 트래픽량이 많은 사이트에서는 이 작업을 권장하지 않습니다.요청마다 프로세스를 포킹하는 것은 매우 큰 작업입니다.일부 프로그램에서는 프로세스 ID를 파일에 쓰는 옵션을 제공하여 사용자가 원하는 대로 프로세스를 확인하고 종료할 수 있도록 하지만 ping과 같은 명령어는 man 페이지를 확인하십시오.

리모트 호스트상에서 리슨 하고 있는 포토(HTTP 의 경우는 포토 80)의 소켓을 여는 것만으로, 유저랜드나 네트워크상에서 모든 것이 정상적으로 동작하고 있는 것을 알 수 있기 때문에, 보다 나은 서비스를 제공할 수 있습니다.

바이너리 데이터를 출력하려고 하면 php의 헤더 함수를 살펴보고 적절한 content-typecontent-disposition을 설정했는지 확인합니다.출력 버퍼의 사용/비활성화에 대한 자세한 내용은 설명서를 참조하십시오.

php.ini 파일 세트 "output_dispering = Off"를 변경해 보십시오.exec 대신 시스템명령어 사용 페이지에서 실시간 출력을 얻을 수 있습니다.system 명령어는 출력을 플러시합니다.

출력을 로그 파일로 파이핑한 다음 해당 파일을 사용하여 클라이언트에 내용을 반환하는 것이 좋습니다.꽤 실시간은 아니지만 충분히 좋을까?

Symfony Process Components(https://symfony.com/doc/current/components/process.html)를 사용해야만 동일한 문제가 발생하였습니다.

간단한 예:

<?php 

use Symfony\Component\Process\Process;

$process = new Process(['ls', '-lsa']);
$process->run(function ($type, $buffer) {
    if (Process::ERR === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

?>

언급URL : https://stackoverflow.com/questions/1281140/run-process-with-realtime-output-in-php

반응형