リアルタイムで出力を返すプロセスをWebページで実行しようとしています。たとえば、「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#L4
(Agile Toolkitフレームワークのモジュールとして実装)
すべての回答を確認しましたが、何も機能しません...
見つかった解決策 ここ
Windows上で動作します(この答えは、向こうで検索するユーザーに役立つと思います)
<?php
$a = popen('ping www.google.com', 'r');
while($b = fgets($a, 2048)) {
echo $b."<br>\n";
ob_flush();flush();
}
pclose($a);
?>
コマンドラインで使用する場合:
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マシン+ワンプサーバーでテスト済み)
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
_では機能します) )。最良の(最も簡単な)アプローチは次のとおりです。
header('Content-Type: text/event-stream');
の代わりにheader('Content-Type: text/plain; charset=...');
を使用します。ただし、これはすべてのブラウザー/クライアントで機能するわけではありません!ストリーミングはこれなしでも機能しますが、少なくとも最初の行はブラウザによってバッファリングされます。header('Cache-Control: no-cache');
を無効にすることもできます。ini_set('output_buffering', 'off');
を使用)。これは、Apache/Nginx /前に使用するサーバーでも実行する必要があります。ini_set('zlib.output_compression', false);
を使用)。これは、Apache/Nginx /前に使用するサーバーでも実行する必要があります。C++プログラムでは、次のようなことを行います(ここでも、他のソリューションについては printf flushing problem を参照してください):
_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);
_
PHP look-in、 exec documentation 経由でシステムコマンドを実行する場合。
ただし、トラフィックの多いサイトでこれを行うことはお勧めしません。リクエストごとにプロセスをフォークするのは非常に手間のかかるプロセスです。一部のプログラムでは、プロセスIDをファイルに書き込んで、プロセスを自由に確認して終了できるオプションを提供していますが、pingなどのコマンドについては、マニュアルページを確認してください。
リモートホストでリッスンする予定のポート(IE:HTTPの場合はポート80)でソケットを開くだけで、ユーザーランドおよびネットワーク上ですべてが順調に進んでいることがわかります。
バイナリデータを出力しようとしている場合は、 phpのヘッダー関数 を調べ、適切な content-type および content-disposition を設定してください。 。出力バッファの使用/無効化の詳細については、 ドキュメント を確認してください。
最初に flush() が機能するかどうかを確認します。もしそうなら、もしそうでなければ、おそらくmod_gzipが有効になっているなど、何らかの理由でWebサーバーがバッファリングしていることを意味します。
Pingのようなものの場合、最も簡単な方法はPHP内でループし、「ping -c 1」を複数回実行し、各出力の後にflush()を呼び出すことです。 PHPは、HTTP接続がユーザーによって閉じられたときに中止するように設定されています(通常はデフォルトです。または、ignore_user_abort(false)を呼び出して確認できます))実行中のpingプロセスについても心配する必要があります。
子プロセスonceのみを実行し、その出力を継続的に表示することが本当に必要な場合、それはより困難になる可能性があります-おそらく実行する必要がありますバックグラウンドで、出力をストリームにリダイレクトし、その後、PHPストリームをユーザーにエコーバックし、通常のflush()呼び出しを散在させます。
Php.iniファイルセット「output_buffering = Off」を変更してみてください。ページでリアルタイムの出力を取得できるはずです。execの代わりにシステムコマンドを使用してください。システムコマンドは出力をフラッシュします
出力をログファイルにパイプしてから、そのファイルを使用してコンテンツをクライアントに返すだけではどうでしょうか。かなりリアルタイムではありませんが、おそらく十分でしょうか?