web-dev-qa-db-fra.com

Comment vider les données dans le navigateur mais continuer à exécuter

J'ai un ob_start() et un ob_flush() correspondant. Je voudrais vider une partie des données et continuer à exécuter le reste. Utiliser ob_flush() n'a pas aidé. Aussi, si le repos possible doit se produire sans montrer le chargement dans le navigateur. 

MODIFIER:

Je ne veux pas utiliser ajax

19
aWebDeveloper

ob_flush écrit le tampon. En d'autres termes, ob_flush indique à PHP de donner à Apache (ou nginx/lighttpd/what) la sortie, puis à PHP de l'oublier. Une fois qu'Apache a la sortie, il fait tout ce qu'il veut avec. (En d’autres termes, après ob_flush, vous ne pouvez pas contrôler immédiatement si elle est écrite immédiatement dans le navigateur).

Donc, réponse courte: il n'y a pas de moyen garanti de le faire.

Juste une supposition, vous êtes probablement à la recherche d'AJAX. Chaque fois que des personnes tentent de manipuler le contenu de la page lorsque vous le chargez, AJAX est presque toujours le bon chemin.

Si vous souhaitez continuer une tâche en arrière-plan, vous pouvez utiliser ignore_user_abort, comme indiqué en détail ici . Cependant, ce n'est souvent pas l'approche optimale. Vous perdez essentiellement le contrôle de ce fil, et à mon avis, un fil de serveur Web n’appartient pas à un traitement lourd. 

J'essaierais de l'extraire du Web. Cela pourrait signifier une entrée cron ou tout simplement générer un processus d'arrière-plan à partir de l'intérieur de PHP (un processus lancé à partir de l'exécution du script ne mourra pas avec le script, et le script n'attendra pas qu'il se termine avant de mourir. ).

Si vous choisissez cette voie, vous pourrez même créer un système de statut si nécessaire. Ensuite, vous pouvez surveiller l'exécution et donner à l'utilisateur des mises à jour périodiques sur l'avancement. (Techniquement, vous pouvez également créer un système de statut avec un script ignore_user_abort-, mais cela ne me semble pas aussi clair.)

16
Corbin

Je l'ai fait par le passé et voici comment je l'ai résolu:

ob_start();

/*
 * Generate your output here
 */ 

// Ignore connection-closing by the client/user
ignore_user_abort(true);

// Set your timelimit to a length long enough for your script to run, 
// but not so long it will bog down your server in case multiple versions run 
// or this script get's in an endless loop.
if ( 
     !ini_get('safe_mode') 
     && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE 
){
    set_time_limit(60);
}

// Get your output and send it to the client
$content = ob_get_contents();         // Get the content of the output buffer
ob_end_clean();                      // Close current output buffer
$len = strlen($content);             // Get the length
header('Connection: close');         // Tell the client to close connection
header("Content-Length: $len");     // Close connection after $len characters
echo $content;                       // Output content
flush();                             // Force php-output-cache to flush to browser.
                                     // See caveats below.

// Optional: kill all other output buffering
while (ob_get_level() > 0) {
    ob_end_clean();
}

Comme je l'ai déjà dit dans quelques commentaires, vous devez surveiller votre contenu, car cela modifiera la longueur de votre contenu, mais pas l'en-tête. Il peut également mettre votre sortie en mémoire tampon afin qu’elle ne soit pas envoyée instantanément au client.
Vous pouvez essayer de faire savoir à Apache de ne pas gzip votre contenu en utilisant Apache_setenv('no-gzip', '1');. Mais cela ne fonctionnera pas si vous utilisez des règles de réécriture pour accéder à votre page, car cela modifiera également ces variables d'environnement. Au moins, il l'a fait pour moi.

Reportez-vous aux mises en garde relatives à l'envoi de votre contenu à l'utilisateur dans le manuel manuel .

16
Zombaya

c'est ma fonction

function bg_process($fn, $arr) {
    $call = function($fn, $arr){
        header('Connection: close');
        header('Content-length: '.ob_get_length());
        ob_flush();
        flush();
        call_user_func_array($fn, $arr);
        };
    register_shutdown_function($call, $fn, $arr);
    }

envelopper la fonction à exécuter à la fin, après la fermeture de php la connexion. et bien sûr, le navigateur arrêtera de mettre en mémoire tampon.

function test() {
    while (true) {
        echo 'this text will never seen by user';
        }
    }

c'est comment appeler la fonction

bg_process('test'); 

le premier argument est callable , Le second argument est un tableau à transmettre à la fonction 'test' avec un tableau indexé.

Remarque: je n'utilise pas ob_start() au début du script.

4
Afrig Aminuddin

J'ai un article expliquant comment cela peut être réalisé en utilisant Apache/mod_php sur mon blog ici: http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.html J'espère que ça aide, à la vôtre

2
smassey

fastcgi_finish_request

Cette fonction vide toutes les données de réponse du client et termine la demande. Cela permet d'effectuer des tâches fastidieuses sans laisser la connexion au client ouverte.

ne fonctionne pas sur Apache (PHP 5> = 5.3.3, PHP 7)

0
sun

Si vous utilisez PHP-FPM:

ignore_user_abort(true);
fastcgi_finish_request();

Au-dessus de deux fonctions sont les facteurs clés pour lesquels ignore_user_abort empêche les erreurs et fastcgi_finish_request ferme la connexion client.

0
Nick Tsai