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.
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:
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:
STREAM_CLIENT_ASYNC_CONNECT
hinzuWä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.
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;
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);
}
Sie können Shell_exec
und Befehlszeilencurl verwenden.
Für ein Beispiel siehe diese Frage
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);
?>
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);
}
?>