5

この質問は、PHPプログラムが無限にループする原因となるバグに遭遇したときに思い浮かびました。状況の例を次に示します。

画像のアップロードを受信するPHPWebページがあるとします(このページは、画像アップロードフォームの応答ページである可能性があります)。サーバーでは、スクリプトは画像を一時ファイルに保存する必要があります。次に、スクリプトはクライアントに確認メッセージを出力し、クライアントが待機しないようにデータの送信を停止する必要があります。その後、スクリプトは実行を継続し、終了する前に画像を処理します(画像のサイズ変更など)。

この「テクニック」は、クライアントが時間のかかるプロセスを待たずにタイムアウトを防ぐのに役立つと思います。

また、これはHTTPメソッドを使用して解決できますか?

4

5 に答える 5

12

はい。

これは、HTTPヘッダーを正しく利用すれば、非同期処理なしで簡単に実行できます。

通常の状態では、PHPは、もう一方の端のクライアントが接続を閉じるとすぐに処理を停止します。このイベントの後で処理を続行する場合は、1つのことを行う必要があります。ユーザーの中止を無視するようにPHPに指示します。どのように?

ignore_user_abort()

これにより、クライアントが回避から抜け出した後でも、スクリプトを実行し続けることができます。しかし、接続を閉じるために、クライアントが行った要求が終了したことをクライアントに通知する方法の問題にも直面しています。通常、PHPは、これらのヘッダーを指定しない場合、これらのヘッダーの送信を透過的に処理します。ただし、ここでは明示的に行う必要があります。そうしないと、クライアントは応答の読み取りをいつ停止するかがわかりません。

これを行うには、適切なHTTPヘッダーを送信して、クライアントにいつ閉じるかを通知する必要があります。

Connection: close
Content-Length: 42

このヘッダーの組み合わせは、42バイトのエンティティ本体応答を読み取ると、メッセージが終了し、接続を閉じる必要があることをクライアントに通知します。この方法にはいくつかの結果があります。

  1. 正しいヘッダーを送信できるようにコンテンツの長さのサイズをバイト単位で決定する必要があるため、出力を送信するに応答を生成する必要があります。
  2. 出力をエコーするに、これらのヘッダーを実際に送信する必要があります。

したがって、スクリプトは次のようになります。

<?php

ignore_user_abort();

// do work to determine the response you want to send ($responseBody)
$contentLength = strlen($responseBody);

header('Connection: close');
header("Content-Length: $contentLength");
flush();

echo $responseBody;

// --- client will now disconnect and you can continue processing here ---

この方法の大きな「Gotchya」は、Web SAPIでPHPを実行しているときに、エンドユーザークライアントが接続を閉じた後に時間のかかる処理を行うと、maxtimelimitディレクティブに簡単にぶつかることができることです。これが問題になる場合は、PHPをCLI環境で実行するときに時間制限がないため、cronを使用した非同期処理オプションを検討する必要があります。set_time_limitまたは、ドキュメントを使用して、Web環境でのスクリプトの制限時間を延長することもできます。

このようなことを行う場合は、応答本文の生成中にconnection_aborted()ドキュメントにチェックを追加して、ユーザーが転送を完了する前に中止した場合に追加の処理を回避できるようにすることもできます。

于 2012-08-25T16:06:54.113 に答える
2

phpのWebサービスを介してiphoneからtwitterとfacebookに画像をアップロードするときに同じ問題に直面しています。

画像のアップロードの処理時間がそれほど長くない場合は、このコメント@Musaが役立つ場合がありますが、処理に時間がかかりすぎる場合は、この手順を試してください。

 1. Image store in folder
 2. Fetch image from folder using cron 
 3. Cron run for every 2 min in backend

これらにより、処理時間が短縮されます。

これがお役に立てば幸いです。

于 2012-08-24T06:57:47.760 に答える
1

使用できますob_implicit_flush(),。暗黙のフラッシュをオンまたはオフにします。暗黙的なフラッシュは、すべての出力呼び出しの後にフラッシュ操作をもたらすため、flush()への明示的な呼び出しは不要になります。

参照する

PHPを使用してこのシナリオを実装するにはどうすればよいですか?

また

特定の時間が経過すると実行されるスタンドアロンのcronを作成し、非同期で実行する必要があります。ユーザーに処理が行われていることを知らせたり、ユーザーを待たせたりすることはありません。このようにして、失敗したケースも検出できるようになります。

また、読み込み時間を最小限に抑えるようにしてください。

于 2012-08-24T06:51:54.630 に答える
1

これらは非同期で行うことをお勧めします。つまり、以前に作成したtmpファイルのみを処理する別のスクリプトを作成し、それをcronで実行します(apacheを使用しないでください)。phpがWebサーバーモジュールとして実行されている場合は、応答をすばやく作成し、次の要求のためにリソースを解放するために使用する必要があります。

あなたはこのように考えることによって正しいことをしています。アーキテクチャの小さな一歩をさらに進めて、実行する必要のある重い作業から要求を完全に切り離します。

于 2012-08-24T06:41:23.993 に答える
1

あなたはそれをいくつかの方法で行うことができます#

1#

ob_start();
//output
header("Content-Length: ".ob_get_length());
header("Connection: close");
ob_end_flush();
//do other stuff

2#

PHPのsystem()またはexec()を使用して、プロセスを閉じます

3#

シェルスクリプトを使用してプロセスを閉じる

于 2012-08-24T06:47:00.793 に答える