it-swarm.com.de

Senden Sie eine HTTP-Anfrage von PHP ohne auf Antwort zu warten?

Ich möchte eine HTTP GET-Anfrage von PHP erhalten. Beispiel:

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

Die Idee ist, serverseitige Webanalysen durchzuführen: Anstatt Tracking-Informationen von JavaScript an einen Server zu senden, sendet der Server Tracking-Informationen direkt an einen anderen Server.

Bedarf:

  • Die Anforderung sollte so wenig Zeit wie möglich in Anspruch nehmen, um die Verarbeitung der Seite PHP nicht spürbar zu verzögern.

  • Die Antwort von tracker.example.com muss nicht Geprüft werden. Als Beispiele einige mögliche Antworten von tracker.example.com:

    • 200: Das ist in Ordnung, aber das muss nicht überprüft werden.

    • 404: Pech, aber das muss man auch nicht überprüfen.

    • 301: Eine Umleitung wäre zwar angebracht, würde aber die Verarbeitung der Seite PHP verzögern. Tun Sie dies also nicht.

    Kurz gesagt: Alle Antworten können verworfen werden.

Ideen für Lösungen:

  • In einer nun gelöschten Antwort schlug jemand vor, in einem Shell-Prozess die Befehlszeile aufzurufen curl von PHP. Dies scheint eine gute Idee zu sein. Nur, dass ich nicht weiß, ob das Forkeln vieler Shell-Prozesse unter Schwere Last eine kluge Sache ist.

  • Ich habe php-ga gefunden, ein Paket für das serverseitige GoogleAnalytics von PHP. Auf der Seite des Projekts ist Erwähnt: "Kann so konfiguriert werden, dass [...] nicht blockierende Anforderungen verwendet werden." Bisher habe ich keine Zeit gefunden zu untersuchen, welche Methode php-ga Intern verwendet, aber diese Methode könnte es sein!

In aller Kürze: Was ist die beste Lösung, um generische serverseitige Tracking/Analyse von PHP aus durchzuführen.

38
feklee

Leider ist PHP per Definition blockierend. Während dies für die meisten Funktionen und Operationen gilt, die Sie normalerweise bearbeiten werden, ist das aktuelle Szenario ein anderes.

Der Prozess, den ich HTTP-Ping nennen möchte, erfordert, dass nur touch ein bestimmter URI erforderlich ist, der den Server dazu zwingt, seine interne Logik zu booten. Mit einigen Funktionen können Sie etwas erreichen, das diesem HTTP-Ping sehr ähnlich ist, indem Sie nicht auf eine Antwort warten.

Beachten Sie, dass der Prozess Pinging einer URL in zwei Schritten abläuft:

  1. Lösen Sie das DNS
  2. Die Anfrage stellen

Die Anforderung sollte zwar ziemlich schnell sein, sobald das DNS aufgelöst und die Verbindung hergestellt ist. Es gibt jedoch nicht viele Möglichkeiten, das DNS schneller aufzulösen.

Ein HTTP-Ping kann folgendermaßen ausgeführt werden:

  1. cURL , indem CONNECTION_TIMEOUT auf einen niedrigen Wert gesetzt wird
  2. fsockopen durch Schließen unmittelbar nach dem Schreiben
  3. stream_socket_client (wie fsockopen) und füge auch STREAM_CLIENT_ASYNC_CONNECT hinzu

Während cURL und fsockopen beide blockieren, während der DNS aufgelöst wird. Ich habe festgestellt, dass fsockopen selbst im schlimmsten Fall deutlich schneller ist.

Auf der anderen Seite sollte stream_socket_client das Problem in Bezug auf die DNS-Auflösung beheben und sollte in diesem Szenario die optimale Lösung sein, aber ich habe es nicht geschafft, das Problem zu lösen.

Eine letzte Lösung ist, einen anderen Thread/Prozess zu starten, der dies für Sie erledigt. Ein Systemaufruf dafür sollte funktionieren, aber auch forking der aktuelle Prozess sollte dies auch tun. Leider sind beide nicht wirklich sicher in Anwendungen, in denen Sie nicht die Umgebung steuern können, in der PHP ausgeführt wird.

Systemaufrufe werden meistens blockiert und pcntl ist standardmäßig nicht aktiviert.

29
Khez

Ich würde tracker.example.com so nennen:

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

und im Tracker-Skript:

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;
13
RafaSashi

Ich habe eine Funktion für eine schnelle GET-Anfrage an eine URL implementiert, ohne auf eine Antwort zu warten: 

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);
}
10
CETb

Sie können Shell_exec und Befehlszeilencurl verwenden.

Für ein Beispiel siehe diese Frage

3
Dutow

Kam hierher, während er ein ähnliches Problem erforschte. Wenn Sie über eine praktische Datenbankverbindung verfügen, besteht eine andere Möglichkeit darin, die Anfragedetails schnell in eine Tabelle zu packen und dann einen separaten cron-basierten Prozess zu haben, der diese Tabelle periodisch nach neuen Datensätzen durchsucht, die verarbeitet werden sollen, und die Nachverfolgungsanforderung freigibt Ihre Webanwendung muss nicht die HTTP-Anforderung selbst erstellen.

<?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

Ich musste etwas Ähnliches tun, einfach eine URL anpingen und alle Antworten verwerfen. Ich habe den Befehl proc_open verwendet, mit dem Sie den Prozess sofort mit proc_close beenden können. Ich gehe davon aus, dass Sie Lynx auf Ihrem Server installiert haben:

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