2013-02-22 8 views
6

Ho uno script PHP che invia un numero elevato di record e voglio svuotare ogni record non appena è disponibile: il client è in grado di elaborare ogni 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'intero trasferimento perché deve essere inviato in più pacchetti, ma consente comunque al client di iniziare a lavorare prima.Previene il buffering dell'output con PHP e Apache

Ho provato tutte le diverse funzioni flush() e ob_flush() ma nulla sembra aiutare a ottenere 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.

risposta

4

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

Bene, se si utilizza Apache, è possibile impostare alcune direttive php ini (incluso output_buffering) dalla configurazione del server, incluso un file .htaccess. Così ho usato il seguente in un file .htaccess per disattivare l'output_buffering solo per questo unico file:

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

E poi nella mia configurazione server statico, ho solo bisogno di AllowOverride Options=php_value (o un martello più grande, come AllowOverride All) al fine perché ciò sia permesso in un file .htaccess.

+1

Non sono sicuro se questo fosse sempre sbagliato o qualcosa fosse cambiato in PHP5.6, ma dovevo usare 'php_flag output_buffering Off' per far funzionare' Off'. – RiggsFolly

+0

Ho impostato "output_buffering" da php.ini da 4096 a Off, e ho riavviato l'intero server, verificato con phpinfo(); ma devo ancora affrontare lo stesso problema, il server è in attesa di caricamento della pagina prima di inviare dati al browser. C'è un'altra impostazione in Apache2 o Ubuntu 16.04? Sto usando PHP7. – Tarik

3

Non si parla di quale server Web si sta utilizzando, ma ho intenzione di uscire su un ramo qui e indovinare Apache2. Colpisco quasi la stessa identica cosa che descrivi. Stavo cercando di ottenere 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 almeno esasperante. Ho seguito esattamente i passi che descrivi. La risoluzione nel mio caso è stato quello di modificare il file di configurazione nella sites-enabled/terrifico.com Apache2 (la linea in questione inizia con

SetEnvIfNoCase

(È possibile ignorare la roba sopra e sotto quella linea, sto solo mostrando per riferimenti di dove ho messo.)

<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 

Da fissare il traffico di rete che va avanti e indietro, finalmente mi resi conto che il browser è stato pubblicità che ha accettato la deflazione per qualsiasi cosa (che era il testo). Ad esempio, questa era la differenza tra browser e arricciatura. Il bit saliente era

Accept-Encoding: gzip, sgonfiare, SDCH

C'era un po 'di chunking, ma questo non ha impatto questo particolare problema. Quindi, il browser chiedeva mod_deflate per dare il via, 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.

2

Per disattivare il buffering di uscita in fase di esecuzione in PHP senza cambiare php.ini o avere un file .htaccess, basta usare ob_end_flush() o ob_end_clean() all'inizio dello script. Ad esempio:

Questo stamperà senza buffering:

<?php 
ob_end_clean(); 

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

Questo uscite con buffer (tutto alla volta) se output_buffering inizia, indipendentemente dal flush() chiamata:

<?php 

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

Nonostante la sua nome, ob_implicit_flush chiamate flush(), non ob_flush(), implicitamente dopo ogni uscita. 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 corregge 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 almeno 1024 byte prima di iniziare a produrre qualcosa.

+0

Questo codice fa lo stesso 3 -.- –