PHPでは、 Ingrore_user_abort()関数は、ユーザーが切断された後(ブラウザの閉鎖やネットワークの切断など)、スクリプトが実行を継続できるようにするためによく使用されます。ただし、多くの開発者は、使用中に有効になっていないことがわかり、ユーザーが切断されるため、スクリプトはまだ終了します。この記事では、この問題の原因を詳細に分析し、いくつかの一般的なソリューションを要約します。
Ingrore_user_abort()は、ブールパラメーターを受け入れるPHPの組み込み関数です。この関数を呼び出してTrueを渡した後、PHPはユーザーの切断イベントを無視し、完了または積極的に終了するまで現在のスクリプトを実行し続けます。
<?php
ignore_user_abort(true);
echo "スクリプトは実行を開始します\n";
// 時間のかかるタスクが実行されていると仮定します
sleep(30);
echo "スクリプト実行の終了\n";
?>
上記のコードは、ユーザーがブラウザを閉じた場合でも、理論的には実行を継続する必要があります。
PHPの実行モードはさまざまです。
CLIモード:ブラウザー接続の概念がないため、ユーザーが切断されているために終了しません。
CGI/FASTCGIモード:Webサーバーの構成によって制限される場合があり、ユーザーの切断は完全に無視できません。
apache mod_php :一般的に、 Ingore_user_abortはサポートされていますが、構成にも注意を払う必要があります。
スクリプトに出力バッファーがある場合、サーバーはブラウザが切断されたときの時間内にそれを検出しないため、PHPプロセスが切断イベントを正確に把握しないため、設定が無視されます。
解決策:出力バッファーをオフまたは更新します。
<?php
ignore_user_abort(true);
ob_end_flush(); // 出力バッファリングをオフにします
flush(); // ブラウザに出力を送信します
sleep(30);
?>
PHP構成のMAX_EXECUTION_TIMEは、スクリプトの最大実行時間を制限し、スクリプトは到着時間後に終了することを余儀なくされます。
解決策: max_execution_timeを調整するか、呼び出します
<?php
set_time_limit(0); // スクリプトの実行時間制限をキャンセルします
ignore_user_abort(true);
?>
一部のWebサーバーまたはリバースプロキシ(Nginxなど)は、切断要求を積極的に終了し、PHPプロセスが終了信号を受信します。
解決:
サーバーとエージェントのタイムアウト設定を確認します。
非同期タスクキューまたは背景デーモンを使用して、長期のPHPスクリプトを置き換えます。
<?php
ignore_user_abort(true);
echo "タスクの実行を開始します\n";
sleep(30);
echo "ミッションは終了します\n";
?>
ブラウザが切断されている場合、出力がすぐに送信されないため、スクリプトが中断される可能性があり、サーバーが監視できなくなります。
<?php
ignore_user_abort(true);
set_time_limit(0);
echo "タスクの実行を開始します\n";
ob_end_flush();
flush();
sleep(30);
echo "ミッションは終了します\n";
?>
質問 | 解決 |
---|---|
ユーザーの切断によりスクリプトが終了します | Ingrore_user_abort(true) |
スクリプトの実行時間は限られています | set_time_limit(0) |
出力はすぐに送信されず、切断が検出されます | OB_END_FLUSH()をオフにし、 flush()を呼び出します |
サーバーのタイムアウトまたはプロキシ制限 | サーバー構成を調整し、背景タスクメソッドを使用します |
INGRORE_USER_ABORT()は、特に複雑なサーバー環境では全能ではありません。この関数を呼び出すだけで、スクリプトが継続的に実行されることを保証することはできません。合理的な出力制御を組み合わせることによってのみ、実行時間設定とサーバーの構成が理想的な結果を達成できます。同時に、長期的なタスクの場合、メッセージキューまたはバックグラウンドデーモンデザインを使用して、システムの安定性とスケーラビリティを向上させることをお勧めします。
<?php
// 典型的な使用デモンストレーション
ignore_user_abort(true);
set_time_limit(0);
echo "ミッションが始まります\n";
ob_end_flush();
flush();
for ($i = 0; $i < 10; $i++) {
// 長期にわたるタスクをシミュレートします
sleep(3);
echo "スケジュール:$i\n";
flush();
}
echo "タスクの完了\n";
?>