2012-05-14 1 views
19

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

EDIT:

Je ne veux pas utiliser ajax

+0

Après avoir fait le premier ob_flush, voulez-vous que l'autre sortie soit affichée? Ou voulez-vous que la demande soit complètement terminée dans la mesure où le client peut le dire et ensuite un traitement en arrière-plan? – Corbin

+0

continuer en arrière-plan – aWebDeveloper

+0

Ok, j'ai mis à jour ma réponse. – Corbin

Répondre

15

ob_flush écrit le tampon. En d'autres termes, ob_flush dit à PHP de donner à Apache (ou nginx/lighttpd/quelquechose) la sortie et ensuite à PHP de l'oublier. Une fois qu'Apache a la sortie, il fait ce qu'il veut avec. (En d'autres termes, après ob_flush, il est hors de votre contrôle si oui ou non il est immédiatement écrit dans le navigateur).

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

Juste une supposition, vous êtes probablement à la recherche d'AJAX. Chaque fois que les gens essaient de manipuler quand le contenu de la page se charge comme vous le faites, AJAX est presque toujours le bon chemin.

Si vous souhaitez poursuivre une tâche en arrière-plan, vous pouvez utiliser cependant ignore_user_abort, comme here détaillée, qui est souvent la meilleure approche. Vous perdez essentiellement le contrôle de ce thread, et à mon avis, un thread de serveur Web n'est pas là où le traitement lourd appartient. Je voudrais essayer de l'extraire de la toile face à des trucs. Cela pourrait signifier une entrée cron ou juste engendrer un processus d'arrière-plan de l'intérieur de PHP (un processus qui a commencé à partir de l'intérieur du script ne mourra pas avec le script, et le script n'attendra pas qu'il finisse avant de mourir).

Si vous suivez cette route, cela signifie que vous pouvez 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 la progression. (Techniquement, vous pouvez créer un système de statut avec un script ignore_user_abort -ed aussi, mais cela ne me semble pas aussi propre.)

+1

lorsqu'un nouvel utilisateur se connecte je souhaite économiser beaucoup Les données. Ces données devraient être sauvegardées immédiatement mais ne pas interrompre l'utilisateur i.e show charger sur le navigateur – aWebDeveloper

1

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 Hope this helps, acclamations

+7

Il serait utile que vous ajoutiez un petit extrait de comment cela fonctionne ici, donc au cas où votre site tombe en panne, nous avons toujours la réponse ici. Le code que vous avez écrit dans votre blog fonctionne. Cependant, si vous avez dit à apache de gzip votre contenu, il ne fonctionnera plus (puisque la longueur ne sera plus correcte) – Zombaya

-1

utilisation:

header("Content-Length: $len"); 

..where $len est la longueur des données à rincée au client.

Je n'ai pas l'arrière-plan pour savoir quand et où cela va fonctionner, mais j'ai essayé sur quelques navigateurs, et tout retour instantanément:

<?PHP 
    header("Content-length:5"); 
    echo "this is more than 5"; 
    sleep(5); 
?> 

modifier: Chrome, IE, et Opera a montré this, tandis que FireFox a montré this is more than 5. Tous ont fermé la demande après cela cependant.

+0

C'est pourquoi la longueur du contenu doit être égale à la longueur réelle du contenu. Et méfiez-vous de gzip, car cela va modifier la longueur de votre réponse. – Zombaya

+0

@Zombaya, je ne vois pas comment c'est pertinent. Tant qu'il n'essaie pas de couper sa sortie après un certain temps, cela devrait fonctionner pour mettre fin à la demande après avoir envoyé les données nécessaires. – mowwwalker

+0

Eh bien, quand j'ai essayé de le faire et que la longueur ne correspondait pas à la longueur réelle, la connexion ne se fermait pas toujours et continuait à charger. – Zombaya

15

Je l'ai fait dans 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 dit dans quelques commentaires avant, vous devriez regarder pour gzipping votre contenu, car cela modifiera la longueur de votre contenu, mais ne changez pas l'en-tête à ce sujet.Il peut aussi tamponner votre sortie, de sorte qu'il ne sera pas envoyé au client instantanément.
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 rewrite-rules pour aller sur votre page, car cela modifiera aussi ces variables d'environnement. Au moins, il l'a fait pour moi.

Voir plus de mises en garde sur le vidage de votre contenu à l'utilisateur dans le manual.

+0

Juste un FYI la fonction PHP est ob_get_content ** S ** –

+1

Repérer l'erreur délibérée. $ len! = $ taille; –

+1

@LukeOliff, merci pour le heads-up, l'a changé. – Zombaya

4

ceci 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 php fermer la connexion. et bien sûr le navigateur va arrêter la mise 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'); 

premier argument est callable, deuxième argument est un tableau à passer à la fonction 'test' avec un tableau indexé

Note: Je n'utilise pas ob_start() au début du script.

Questions connexes