Impedisci il buffering dell'output con PHP e Apache

Ho uno script PHP che invia un numero elevato di record e voglio svuotare each record non appena è disponibile: il client è in grado di elaborare each record non appena arriva, non ha bisogno di aspettare l'intera risposta. Mi rendo conto che ci vuole un po 'più a lungo per l'integer trasferimento perché deve essere inviato in più pacchetti, ma consente comunque al client di iniziare a lavorare prima.

Ho provato tutte le diverse funzioni flush() e ob_flush() ma nulla sembra aiutare a get i dati effettivamente inviati sulla linea prima che la pagina sia finita. Ho confermato che non è il browser web perché l'ho provato usando telnet.

L'unica soluzione che ha funzionato per me era impostare la direttiva output_buffering in php.ini su "Off". Non volevo farlo per l'integer server, solo questa una risorsa specifica. Normalmente è ansible utilizzare ini_set dallo script PHP, ma per qualsiasi ragione php non consente di impostare output_buffering in questo modo (consultare il manuale php ).

Bene, se si utilizza Apache, è ansible impostare alcune direttive php ini (incluso output_buffering ) dalla configuration del server, incluso un file .htaccess. Quindi ho usato quanto segue in un file .htaccess per disabilitare l'output_buffering solo per quel file:

 <Files "q.php"> php_value output_buffering Off </Files> 

E poi nella mia configuration statica del server, avevo solo bisogno di AllowOverride Options=php_value (o di un hammer più grande, come AllowOverride All ) in modo che fosse permesso in un file .htaccess.

Non si parla di quale server Web si sta utilizzando, ma ho intenzione di uscire su un arto qui e indovinare Apache2. Colpisco quasi la stessa identica cosa che descrivi. Stavo cercando di get il mio script cgi per passare informazioni indietro come era pronto, invece di buffering l'intera cosa. Ha funzionato come un ricciolo, ecc., Ma è stato memorizzato in un browser (praticamente qualsiasi browser), il che è stato alless esasperante. Ho seguito esattamente i passi che descrivi. Nel mio caso, la risoluzione era di modificare il file di configuration di sites-enabled/terrifico.com in Apache2 (la row in questione inizia con

SetEnvIfNoCase

(Puoi ignorare la roba sopra e sotto quella linea, la sto solo mostrando come riferimento di where l'ho posizionata.)

 <VirtualHost *:80> ServerAdmin [email protected] ServerName test.terrifico.com ServerAlias test.terrifico.com SetEnvIfNoCase Request_URI \.cgi$ no-gzip dont-vary DocumentRoot /var/www/test.terrifico.com 

Dall'osservare il traffico di networking che andava avanti e indietro, alla fine mi resi conto che il browser stava pubblicizzando che accettava la deflazione per qualsiasi cosa (era il text). Ad esempio, questa era la differenza tra browser e arricciatura. Il pezzo saliente era

Accept-Encoding: gzip, deflate, SDCH

C'era un po 'di chunking , ma questo non ha avuto alcun impatto su questo particolare problema. Quindi, il browser chiedeva mod_deflate per dare il via, il che ha sconfitto i miei byte con attenzione mentre li ho estratti nel mio script cgi. Potresti cambiarlo nel browser, ma è sembrato più sensato cambiarlo sul server una volta per i lavori.

Forse questo aiuta.

Per distriggersre il buffering dell'output in fase di esecuzione in PHP senza modificare php.ini o con un file .htaccess , basta usare ob_end_flush() o ob_end_clean() all'inizio dello script. Per esempio:

Questo dovrebbe uscire senza buffering:

 <?php ob_end_clean(); for ($i = 0; $i < 5; $i++) { echo "$i\n"; flush(); usleep(0.5e6); } 

Questo output viene output_buffering con il buffering (tutto alla volta) se output_buffering è output_buffering , indipendentemente dalla chiamata a flush() :

 <?php for ($i = 0; $i < 5; $i++) { echo "$i\n"; flush(); usleep(0.5e6); } 

Nonostante il suo nome, ob_implicit_flush chiama flush() , non ob_flush() , implicitamente dopo each output. Questo può essere utile in questa istanza dopo aver chiuso il buffer di output all'inizio:

 <?php ob_end_clean(); // disable output buffer ob_implicit_flush(); // call flush() automatically after every output for ($i = 0; $i < 5; $i++) { echo "$i\n"; usleep(0.5e6); } 

Questo risolve il lato PHP. Potrebbe esserci qualcos'altro in corso con mod_deflate o simile (vedi la risposta di Ted Collins), e ho notato che Firefox ha bisogno di alless 1024 byte prima che inizi a produrre qualcosa.