Program Tip

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

programtip 2020. 11. 13. 23:58
반응형

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


실시간으로 출력을 반환하는 웹 페이지에서 프로세스를 실행하려고합니다. 예를 들어 'ping'프로세스를 실행하면 새 줄을 반환 할 때마다 내 페이지를 업데이트해야합니다 (지금 당장은 exec (command, output)을 사용할 때 -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);
}

나는 이것이 여기에서 그들의 길을 검색 한 다른 사람들에게 도움이되기를 바랍니다.


최신 HTML5 서버 측 이벤트를 사용하여이 오래된 문제에 대한 더 나은 솔루션이 여기에 설명되어 있습니다.

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);

Checked all answers, nothing works...

Found solution Here

It works on windows (i think this answer is helpful for users searching over there)

<?php
$a = popen('ping www.google.com', 'r'); 

while($b = fgets($a, 2048)) { 
echo $b."<br>\n"; 
ob_flush();flush(); 
} 
pclose($a); 

?>

try this (tested on Windows machine + wamp server)

        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();

I've tried various PHP execution commands on Windows and found that they differ quite a lot.

  • Don't work for streaming: shell_exec, exec, passthru
  • Kind of works: proc_open, popen -- "kind of" because you cannot pass arguments to your command (i.e. wont' work with my.exe --something, will work with _my_something.bat).

The best (easiest) approach is:

  1. You must make sure your exe is flushing commands (see printf flushing problem). Without this you will most likely receive batches of about 4096 bytes of text whatever you do.
  2. If you can, use header('Content-Type: text/event-stream'); (instead of header('Content-Type: text/plain; charset=...');). This will not work in all browsers/clients though! Streaming will work without this, but at least first lines will be buffered by the browser.
  3. You also might want to disable cache header('Cache-Control: no-cache');.
  4. Turn off output buffering (either in php.ini or with ini_set('output_buffering', 'off');). This might also have to be done in Apache/Nginx/whatever server you use in front.
  5. Turn of compression (either in php.ini or with ini_set('zlib.output_compression', false);). This might also have to be done in Apache/Nginx/whatever server you use in front.

So in your C++ program you do something like (again, for other solutions see printf flushing problem):

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

In PHP you do something like:

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);

First check whether flush() works for you. If it does, good, if it doesn't it probably means the web server is buffering for some reason, for example mod_gzip is enabled.

For something like ping, the easiest technique is to loop within PHP, running "ping -c 1" multiple times, and calling flush() after each output. Assuming PHP is configured to abort when the HTTP connection is closed by the user (which is usually the default, or you can call ignore_user_abort(false) to make sure), then you don't need to worry about run-away ping processes either.

If it's really necessary that you only run the child process once and display its output continuously, that may be more difficult -- you'd probably have to run it in the background, redirect output to a stream, and then have PHP echo that stream back to the user, interspersed with regular flush() calls.


If you're looking to run system commands via PHP look into, the exec documentation.

I wouldn't recommend doing this on a high traffic site though, forking a process for each request is quite a hefty process. Some programs provide the option of writing their process id to a file such that you could check for, and terminate the process at will, but for commands like ping, I'm not sure that's possible, check the man pages.

You may be better served by simply opening a socket on the port you expect to be listening (IE: port 80 for HTTP) on the remote host, that way you know everything is going well in userland, as well as on the network.

If you're attempting to output binary data look into php's header function, and ensure you set the proper content-type, and content-disposition. Review the documentation, for more information on using/disabling the output buffer.


Try changing the php.ini file set "output_buffering = Off". You should be able to get the real time output on the page Use system command instead of exec.. system command will flush the output


why not just pipe the output into a log file and then use that file to return content to the client. not quite real time but perhaps good enough?

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

반응형