web-dev-qa-db-ja.com

PHPから応答を待たずにHTTPリクエストを送信しますか?

PHPからHTTP GETリクエストを送信したい。例:

http://tracker.example.com?product_number=5230&price=123.52

アイデアは、サーバー側のWeb分析を行うことです。トラッキング情報をJavaScriptからサーバーに送信する代わりに、サーバーはトラッキング情報を別のサーバーに直接送信します。

要件:

  • PHPページの処理を著しく遅延させないために、リクエストの時間はできるだけ短くする必要があります。

  • tracker.example.comからの応答を確認する必要はありません。例として、tracker.example.comからのいくつかの可能な応答:

    • 200:それで問題ありませんが、確認する必要はありません。

    • 404:運が悪いが、-もう一度-確認する必要はない。

    • 301:リダイレクトは適切ですが、PHPページの処理を遅らせるため、しないでくださいそれ。

    要するに:All応答は破棄できます。

ソリューションのアイデア:

  • 削除された回答では、誰かがコマンドラインを呼び出すことを提案しました curl from PHP Shellプロセスで。これは良いアイデアのように思えますが、重い負荷の下で多くのシェルプロセスをフォークするのは賢明なことです。

  • php-ga を見つけました。これは、PHPからサーバー側のGoogle Analyticsを実行するためのパッケージです。プロジェクトのページには、次のように記載されています: "非ブロッキング要求を使用するように構成できます。"これまでのところ、 php-gaが内部的に使用しているメソッドを調査する時間を見つけましたが、このメソッドはそれである可能性があります!

簡単に言うと、PHPからサーバー側の一般的な追跡/分析を行うための最良のソリューションは何ですか。

40
feklee

残念ながらPHP定義によりblockingです。これは大部分の機能と操作に当てはまりますが、通常は処理します、現在のシナリオは異なります。

HTTP-Ping を呼び出すプロセスでは、特定のURIのみをtouchする必要があり、特定のサーバーに内部ロジックを強制的にブートストラップさせます。一部の関数では、応答を待たずに、このHTTP-pingと非常によく似たものを実現できます。

URLのpingingのプロセスは2段階のプロセスであることに注意してください。

  1. DNSを解決する
  2. リクエストをする

DNSが解決されて接続が確立されると、要求の作成はかなり高速になりますが、DNSをより速く解決する方法は多くありません。

Http-pingを実行するいくつかの方法は次のとおりです。

  1. cURL 、CONNECTION_TIMEOUTを低い値に設定することにより
  2. fsockopen 書き込み後すぐに閉じる
  3. stream_socket_client (fsockopenと同じ)およびSTREAM_CLIENT_ASYNC_CONNECT

DNSの解決中は、cURLfsockopenの両方がブロックされます。 fsockopenは、最悪の場合でもかなり高速であることに気付きました。

stream_socket_client一方、DNS解決に関する問題を修正する必要があり、このシナリオでの最適なソリューションになるはずですが、私はそれを機能させることができませんでした。

最後の解決策の1つは、これを行う別のスレッド/プロセスを開始することです。これのためのシステムコールを行うことは機能するはずですが、 forking も現在のプロセスがそれを行うべきです。残念ながら、PHPが実行されている環境を制御できないアプリケーションでは、両方とも本当に安全ではありません。

システムコールはブロックされないことが多く、pcntlはデフォルトでは有効になっていません。

29
Khez

次のようにtracker.example.comを呼び出します。

get_headers('http://tracker.example.com?product_number=5230&price=123.52');

トラッカースクリプトでは:

ob_end_clean();
ignore_user_abort(true);
ob_start();
header("Connection: close");
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();

// from here the response has been sent. you can now wait as long as you want and do some tracking stuff 

sleep(5); //wait 5 seconds
do_some_stuff();
exit;
14
RafaSashi

応答を待たずにurlへの高速GETリクエストの関数を実装しました:

function fast_request($url)
{
    $parts=parse_url($url);
    $fp = fsockopen($parts['Host'],isset($parts['port'])?$parts['port']:80,$errno, $errstr, 30);
    $out = "GET ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['Host']."\r\n";
    $out.= "Content-Length: 0"."\r\n";
    $out.= "Connection: Close\r\n\r\n";

    fwrite($fp, $out);
    fclose($fp);
}
11
CETb

Shell_execとコマンドラインcurlを使用できます。

例については、「 この質問 」を参照してください

3
Dutow

同様の問題を調査している間にここに来ました。便利なデータベース接続がある場合、もう1つの可能性は、リクエストの詳細をテーブルにすばやく詰め込んでから、処理する新しいレコードを定期的にスキャンして追跡リクエストを作成するcronベースのプロセスを個別に用意することです。 Webアプリケーション自体がHTTP要求を作成する必要がないようにします。

<?php
// Create a stream
$opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: en" 
  )
);

 $context = stream_context_create($opts);

// Open the file using the HTTP headers set above
$file = file_get_contents('http://tracker.example.com?product_number=5230&price=123.52', false, $context);
?>
0
Ali

URLをpingして、すべての応答を破棄するだけで、似たようなことをする必要がありました。 proc_closeコマンドを使用してプロセスをすぐに終了できるproc_openコマンドを使用しました。私はあなたのサーバーにlynxがインストールされていると仮定しています:

<?php    
function ping($url) {
      $proc = proc_open("lynx $url",[],$pipes);
      proc_close($proc);
    }
?>
0
Gerald Melendez