web-dev-qa-db-fra.com

Envoyer une requête HTTP à partir de PHP sans attendre de réponse?

Je souhaite qu'une requête HTTP GET soit envoyée à partir de PHP. Exemple:

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

L’idée est d’effectuer une analyse Web côté serveur: au lieu d’envoyer des informations de suivi De JavaScript à un serveur, le serveur envoie les informations de suivi Directement à un autre serveur.

Exigences:

  • La requête devrait prendre le moins de temps possible, afin de ne pas retarder sensiblement le traitement de la page PHP.

  • La réponse du tracker.example.com n'a pas besoin d'être vérifiée A titre d’exemples, quelques réponses possibles de tracker.example.com:

    • 200: C'est bien, mais inutile de vérifier cela.

    • 404: Pas de chance, mais - encore une fois - inutile de vérifier cela.

    • 301: Bien qu'une redirection serait appropriée, elle retarderait le traitement de la page PHP par __, donc ne le faites pas.

    En bref: Toutes les réponses peuvent être ignorées.

Idées de solutions:

  • Dans une réponse maintenant supprimée, quelqu'un a suggéré d'appeler la ligne de commande curl depuis PHP dans un processus Shell. Cela semble être une bonne idée, mais je ne sais pas si je ne sais pas si il est judicieux de passer à travers beaucoup de processus Shell.

  • J'ai trouvé php-ga , un paquet permettant de faire du Google côté serveurAnalytics à partir de PHP. Il est mentionné sur la page du projet : "Peut être configuré pour utiliser [...] des requêtes non bloquantes." Jusqu'à présent, je n'ai pas trouvé le temps d'enquêter sur la méthode utilisée en interne par php-ga , Mais cette méthode pourrait bien l'être!

En bref: Quelle est la meilleure solution pour effectuer un suivi/analyse générique côté serveur à partir de PHP.

38
feklee

Malheureusement PHP par définition est bloquant. Bien que cela soit vrai pour la majorité des fonctions et des opérations que vous allez normalement gérer, le scénario actuel est différent.

Le processus que j'aime appeler HTTP-Ping nécessite que vous n'ayez que tactile un URI spécifique, forçant le serveur spécifique à initialiser sa logique interne. Certaines fonctions vous permettent d’obtenir quelque chose de très similaire à ce HTTP-ping en n’attendant pas de réponse.

Notez que le processus de ping} une URL est un processus en deux étapes:

  1. Résoudre le DNS
  2. Faire la demande

Bien que la demande doive être assez rapide une fois que le DNS est résolu et que la connexion est établie, il n'y a pas beaucoup de moyens de rendre la résolution DNS plus rapide.

Quelques façons de faire un http-ping sont:

  1. cURL , en définissant CONNECTION_TIMEOUT sur une valeur faible
  2. fsockopen en fermant immédiatement après avoir écrit
  3. stream_socket_client (identique à fsockopen) et ajout de STREAM_CLIENT_ASYNC_CONNECT

Alors que cURL et fsockopen sont tous deux bloquants pendant la résolution du DNS. J'ai remarqué que (fsockopen} _ est nettement plus rapide, même dans les cas les plus défavorables.

stream_socket_client devrait en revanche résoudre le problème de la résolution DNS et devrait constituer la solution optimale dans ce scénario, mais je n'ai pas réussi à le faire fonctionner.

Une dernière solution consiste à démarrer un autre thread/processus qui le fait pour vous. Faire un appel système pour cela devrait fonctionner, mais aussi falsifier le processus actuel devrait le faire aussi. Malheureusement, les deux ne sont pas vraiment sûrs dans les applications où vous ne pouvez pas contrôler l'environnement sur lequel PHP est en cours d'exécution.

Les appels système sont le plus souvent bloqués et pcntl n'est pas activé par défaut.

29
Khez

J'appellerais tracker.example.com de cette façon:

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

et dans le script de suivi:

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

J'ai implémenté la fonction de requête rapide GET en url sans attendre la réponse 

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

Vous pouvez utiliser Shell_exec et curl à la ligne de commande.

Pour un exemple, voir cette question

3
Dutow

Je suis venu ici tout en recherchant un problème similaire. Si vous avez une connexion de base de données à portée de main, une autre possibilité est de ranger rapidement les détails de la demande dans une table, puis d’avoir un processus séparé basé sur cron qui analyse périodiquement cette table afin de rechercher de nouveaux enregistrements à traiter, puis effectue la demande de suivi, ce qui libère votre application Web d’avoir à faire la demande HTTP elle-même.

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

J'avais besoin de faire quelque chose de similaire, juste un ping une url et jeter toutes les réponses. J'ai utilisé la commande proc_open qui vous permet de terminer le processus immédiatement avec proc_close. Je suppose que Lynx est installé sur votre serveur:

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