2012-05-14 14 views
19

Ho un ob_start() e un corrispondente ob_flush(). Vorrei svuotare una porzione di dati e continuare a eseguire il resto. L'utilizzo di ob_flush() non ha aiutato. Inoltre, se possibile, il resto deve avvenire senza mostrare il caricamento nel browser.Come svuotare i dati nel browser, ma continuare a eseguire

EDIT:

Non voglio usare ajax

+0

Dopo aver eseguito il primo ob_flush, vuoi visualizzare altri output? O vuoi che la richiesta sia completamente finita per quanto il cliente possa dirlo e poi qualche tipo di elaborazione continua in background? – Corbin

+0

continua in background – aWebDeveloper

+0

Ok, ho aggiornato la mia risposta. – Corbin

risposta

15

ob_flush scrive il buffer. In altre parole, ob_flush indica a PHP di fornire ad Apache (o nginx/lighttpd/qualunque) l'output e quindi a PHP di dimenticarsene. Una volta che Apache ha l'output, fa quello che vuole con esso. (In altre parole, dopo ob_flush è fuori dal tuo controllo se viene o meno scritto immediatamente nel browser).

Quindi, risposta breve: non esiste un modo garantito per farlo.

Solo un'ipotesi, probabilmente stai cercando AJAX. Ogni volta che le persone cercano di manipolare quando il contenuto della pagina viene caricato come si sta facendo, AJAX è quasi sempre il percorso corretto.

Se si desidera continuare un'attività in background, è possibile utilizzare ignore_user_abort, come dettagliato here, tuttavia, che spesso non è l'approccio ottimale. In pratica, si perde il controllo su quel thread e, a mio parere, un thread del server Web non è il luogo in cui l'elaborazione pesante appartiene.

Proverei a estrarlo dal web. Questo potrebbe significare una voce di cron o semplicemente generare un processo in background dall'interno di PHP (un processo che sebbene avviato dall'esecuzione dello script non morirà con lo script, e lo script non aspetterà che finisca prima di morire).

Se si va su quella rotta, ciò significa che è anche possibile creare una sorta di sistema di stato se necessario. Quindi è possibile monitorare l'esecuzione e fornire all'utente aggiornamenti periodici sullo stato di avanzamento. (Tecnicamente potresti creare un sistema di stato con uno script ignore_user_abort, ma non mi sembra così pulito.)

+1

quando un nuovo utente si collega voglio salvare molto un dati. Questi dati dovrebbero essere salvati immediatamente ma non interrompere l'utente che mostra il caricamento sul browser – aWebDeveloper

1

Ho un articolo che spiega come questo può essere ottenuto usando apache/mod_php sul mio blog qui : http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.html Spero che questo aiuti, applausi

+7

Sarebbe utile se tu aggiungessi un piccolo frammento di come funziona qui, quindi nel caso in cui il tuo sito dovesse mai andare giù, abbiamo ancora la risposta qui. Il codice che hai scritto nel tuo blogpost funziona. Tuttavia, se hai detto apache prima di gzip il tuo contenuto, non funzionerà più (poiché la lunghezza non sarà più corretta) – Zombaya

-1

Usa:

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

..dove $len è la lunghezza dei dati da lavare al cliente.

non ho lo sfondo per sapere quando e dove questo sta andando a lavorare, ma ho provato su alcuni browser, e tutto tornato istantaneamente con:

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

edit: Chrome, IE, e Opera ha mostrato this, mentre FireFox ha mostrato this is more than 5. Comunque, tutti hanno chiuso la richiesta.

+0

Ecco perché la lunghezza del contenuto deve essere della stessa lunghezza del contenuto attuale. E fai attenzione a gzip, poiché ciò modificherà la lunghezza della tua risposta. – Zombaya

+0

@Zombaya, non vedo come sia rilevante. Finché non sta cercando di tagliare la sua produzione dopo una certa quantità, questo dovrebbe funzionare per terminare la richiesta dopo aver inviato i dati necessari. – mowwwalker

+0

Bene, quando ho provato a farlo e la lunghezza non corrispondeva alla lunghezza effettiva, la connessione non si chiudeva sempre e continua a caricare. – Zombaya

15

ho fatto in passato, e questo è come ho risolto:

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(); 
} 

Come ho detto in un paio di osservazioni prima, si dovrebbe guardare fuori per gzipping suo sito web, dal momento che cambierà la lunghezza del tuo contenuto, ma non modificare l'intestazione su di esso.Può anche bufferizzare l'output, quindi non verrà inviato al client all'istante.
Puoi provare a far sapere a apache di non gzipare i tuoi contenuti usando apache_setenv('no-gzip', '1');. Ma questo non funzionerà se usi le regole di riscrittura per andare alla tua pagina, poiché modificherà anche quelle variabili d'ambiente. Almeno, lo ha fatto per me.

Vedere ulteriori avvertenze sull'eliminazione dei contenuti per l'utente nel manual.

+0

Solo una FYI la funzione PHP è ob_get_content ** S ** –

+1

Trova l'errore intenzionale. $ len! = $ dimensione; –

+1

@LukeOliff, grazie per l'heads-up, cambiato. – Zombaya

4

questa è la mia funzione di

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); 
    } 

avvolgere la funzione da eseguire alla fine, dopo php chiudere la connessione. e ovviamente il browser smetterà di buffering.

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

questo è come chiamare la funzione

bg_process('test'); 

primo parametro è callable, secondo argomento è un array da passare alla funzione 'test' con un array indicizzato

Nota: Non uso ob_start() all'inizio dello script.

Problemi correlati