128 votes

continuer à traiter php après avoir envoyé la réponse http

Mon script est appelé par le serveur. Du serveur, je recevrai ID_OF_MESSAGE y TEXT_OF_MESSAGE .

Dans mon script, je vais gérer le texte entrant et générer la réponse avec les paramètres : ANSWER_TO_ID y RESPONSE_MESSAGE .

Le problème est que j'envoie une réponse à une demande incommensurable. "ID_OF_MESSAGE" Mais le serveur qui m'a envoyé un message à gérer va considérer que son message m'a été remis (ce qui signifie que je peux lui envoyer une réponse à cet ID), après avoir reçu la réponse http 200.

L'une des solutions consiste à enregistrer le message dans la base de données et à créer un cron qui s'exécutera toutes les minutes, mais j'ai besoin de générer un message de réponse immédiatement.

Existe-t-il une solution pour envoyer au serveur une réponse http 200 et continuer à exécuter le script php script ?

Merci beaucoup.

5voto

Matthew Slyman Points 166

J'ai posé cette question à Rasmus Lerdorf en avril 2012, en citant ces articles :

J'ai suggéré le développement d'une nouvelle fonction PHP intégrée pour notifier à la plateforme qu'aucune autre sortie (sur stdout ?) ne sera générée (une telle fonction pourrait se charger de fermer la connexion). Rasmus Lerdorf a répondu :

Voir Gearman . Vous ne voulez vraiment pas que vos serveurs Web frontaux effectuent des traitements backend de cette manière.

Je peux comprendre son point de vue, et soutenir son opinion pour certaines applications/ scénarios de chargement ! Cependant, pour d'autres scénarios, les solutions de vcampitelli et al, sont bonnes.

4voto

martti Points 1140

J'utilise la fonction php register_shutdown_function pour cela.

void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )

http://php.net/manual/en/function.register-shutdown-function.php

Modifier : Ce qui précède ne fonctionne pas. Il semble que j'ai été induit en erreur par une ancienne documentation. Le comportement de la fonction register_shutdown_function a changé depuis PHP 4.1. lien lien

4voto

Fil Points 164

Je n'arrive pas à installer pthread et aucune des solutions précédentes ne fonctionne pour moi. Je n'ai trouvé que la solution suivante pour fonctionner (réf : https://stackoverflow.com/a/14469376/1315873 ):

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(); // optional
ob_start();
echo ('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush();            // Unless both are called !
session_write_close(); // Added a line suggested in the comment
// Do processing here 
sleep(30);
echo('Text user will never see');
?>

3voto

Mayur S Points 701

J'ai quelque chose qui peut compresser et envoyer la réponse et laisser un autre code php s'exécuter.

function sendResponse($response){
    $contentencoding = 'none';
    if(ob_get_contents()){
        ob_end_clean();
        if(ob_get_contents()){
            ob_clean();
        }
    }
    header('Connection: close');
    header("cache-control: must-revalidate");
    header('Vary: Accept-Encoding');
    header('content-type: application/json; charset=utf-8');
    ob_start();
    if(phpversion()>='4.0.4pl1' && extension_loaded('zlib') && GZIP_ENABLED==1 && !empty($_SERVER["HTTP_ACCEPT_ENCODING"]) && (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) && (strstr($GLOBALS['useragent'],'compatible') || strstr($GLOBALS['useragent'],'Gecko'))){
        $contentencoding = 'gzip';
        ob_start('ob_gzhandler');
    }
    header('Content-Encoding: '.$contentencoding);
    if (!empty($_GET['callback'])){
        echo $_GET['callback'].'('.$response.')';
    } else {
        echo $response;
    }
    if($contentencoding == 'gzip') {
        if(ob_get_contents()){
            ob_end_flush(); // Flush the output from ob_gzhandler
        }
    }
    header('Content-Length: '.ob_get_length());
    // flush all output
    if (ob_get_contents()){
        ob_end_flush(); // Flush the outer ob_start()
        if(ob_get_contents()){
            ob_flush();
        }
        flush();
    }
    if (session_id()) session_write_close();
}

2voto

Jérome S. Points 121

En cas d'utilisation de php file_get_contents, la fermeture de la connexion n'est pas suffisante. php attend toujours l'envoi de l'eof par le serveur.

ma solution consiste à lire "Content-Length :".

Voici un échantillon :

response.php :

 <?php

ignore_user_abort(true);
set_time_limit(500);

ob_start();
echo 'ok'."\n";
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();
sleep(30);

Notez le " \n " en réponse à la fermeture de la ligne, sinon le fget read while wait eof.

read.php :

<?php
$vars = array(
    'hello' => 'world'
);
$content = http_build_query($vars);

fwrite($fp, "POST /response.php HTTP/1.1\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: " . strlen($content) . "\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");

fwrite($fp, $content);

$iSize = null;
$bHeaderEnd = false;
$sResponse = '';
do {
    $sTmp = fgets($fp, 1024);
    $iPos = strpos($sTmp, 'Content-Length: ');
    if ($iPos !== false) {
        $iSize = (int) substr($sTmp, strlen('Content-Length: '));
    }
    if ($bHeaderEnd) {
        $sResponse.= $sTmp;
    }
    if (strlen(trim($sTmp)) == 0) {
        $bHeaderEnd = true;
    }
} while (!feof($fp) && (is_null($iSize) || !is_null($iSize) && strlen($sResponse) < $iSize));
$result = trim($sResponse);

Comme vous pouvez le voir, ce script n'attend pas la fin de la procédure si la longueur du contenu est atteinte.

J'espère que cela vous aidera

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X