2011-02-02 43 views
25

¿Es posible hacer eco cada vez que se ejecuta el ciclo? Por ejemplo:PHP Flush que funciona ... incluso en Nginx

foreach(range(1,9) as $n){ 
    echo $n."\n"; 
    sleep(1); 
} 

En lugar de imprimir todo cuando termina el ciclo, me gustaría verlo imprimiendo cada resultado por vez.

Respuesta

31

SOLUCIÓN FINAL

Así que eso es lo que he encontrado fuera:

La descarga no funcionaría bajo mod_gzip de Apache o gzip de Nginx porque, lógicamente, es gzip el contenido, y para hacerlo debe buf fer contenido para gzip. Cualquier tipo de servidor web gzipping afectaría esto. En resumen, en el lado del servidor, tenemos que desactivar gzip y disminuir el tamaño del búfer fastcgi. Por lo tanto:

  • En php.ini:

    . output_buffering = Off

    . zlib.output_compression = Off

  • En nginx.conf:

    . gzip apagado;

    . proxy_buffering off;

tienen también estas líneas a mano, especialmente si usted no tiene acceso a php.ini:

  • @ini_set ('zlib.output_compression ', 0);

  • @ini_set ('implicit_flush', 1);

  • @ob_end_clean();

  • set_time_limit (0);

pasado, si lo tiene, coment el código de abajo:

  • ob_start ('ob_gzhandler');

  • ob_flush();

código de prueba PHP:

ob_implicit_flush(1); 

for($i=0; $i<10; $i++){ 
    echo $i; 

    //this is for the buffer achieve the minimum size in order to flush data 
    echo str_repeat(' ',1024*64); 

    sleep(1); 
} 

relacionadas:

+0

Impresionante. Gracias. Y si alguien tiene problemas con esto, intente reiniciar su servidor ... (Oye, eso es lo que funcionó para mí. No sé por qué.) – Matt

+0

@Matt php y la configuración del servidor no se aplican hasta que reinicie –

+0

@TimoHuovinen No cambié php.ini en mi caso, sin embargo. – Matt

5

Necesitas vaciar el búfer del php para el navegador

foreach(range(1,9) as $n){ 
    echo $n."\n"; 
    flush(); 
    sleep(1); 
} 

Ver: http://php.net/manual/en/function.flush.php

+0

Es posible que desee llamar @ob_flush() también. –

+0

No está funcionando ... – Roger

+0

@RC: solo curiosidad, ¿por qué necesitas una '@' antes de ob_flush? Yo usaría: 'if (ob_get_level()> 0) ob_flush();' – meze

2

Esto se puede hacer mediante el volcado de memoria intermedia de salida en el medio del bucle.

Ejemplo:

ob_start(); 
foreach(range(1,9) as $n){ 
    echo $n."\n"; 
    ob_flush(); 
    flush(); 
    sleep(1); 
} 

Tenga en cuenta que la configuración de php.ini pueden afectar si esto funcionará o no, si han de compresión zlib encendido

+0

No funciona aquí. Imprime todo al final de la ejecución del ciclo. – Roger

+0

Compruebe su php.ini para lo siguiente: output_buffering = Off zlib.output_compression = Off (Asegúrese de que ambos estén configurados de esta forma) –

+0

Todavía no funciona ... – Roger

22

solución fácil en el servidor nginx:

fastcgi_keep_conn on; # < solution 

proxy_buffering off; 
gzip off; 
+2

Daría +2 si pudiera. Después de probar cualquier otra solución, esta es la que funcionó. – jrhorn424

+2

Igual, la mejor respuesta aquí. – galex

+1

¡increíble! esto realmente funciona – luchaninov

9

yo no quiero tener que apagar gzip para todo el servidor o un directorio completo, sólo por unos guiones, en algunos casos específicos.

Todo lo que necesita es esto antes se echo'ed nada:

header('Content-Encoding: none;'); 

Después, realice el rubor de forma normal:

ob_end_flush(); 
flush(); 

Nginx parece recoger en la codificación de haber sido desactivado y no gzip

+0

+1 para una solución solo PHP (que se puede habilitar fácilmente ad hoc). Tenga en cuenta que para que funcione 'header ('X-Accel-Buffering: no');' también se necesitaba. – cvsguimaraes

+0

Este 'encabezado ('Content-Encoding: none;');' funcionó para mí. No es necesario 'ob_end_flush()' o 'flush()', solo asegúrese de que la salida sea lo suficientemente grande usando 'echo str_repeat ('', 1024 * 64);' – Catalin

1

He encontrado que se puede establecer:

header("Content-Encoding:identity"); 

en el script php para desactivar gzipping nginx sin tener que modificar el nginx.conf

24

La forma más fácil de eliminar el búfer de nginx es mediante la emisión de una cabecera:

header('X-Accel-Buffering: no'); 

Esto elimina tanto proxy_buffering y (si tiene nginx> = 1.5.6), fastcgi_buffering. El bit fastcgi es crucial si estás usando php-fpm. El encabezado también es mucho más conveniente de hacer según sea necesario.

Docs on X-Accel-Buffering Docs on fastcgi_buffering

+0

¡Excelente, funciona bien para mí! – Fernando

+0

Genial, esto funcionó excelente para mí. Usando nginx 1.6.2 en Ubuntu 14.04. Gracias por este comentario. –

+0

¡Muchas gracias! Ojalá lo hubiera descubierto hace una hora. Solución sencilla y elegante de una sola línea :) – digitaltoast

1

que tenía un problema gzip comming de mi motor de PHP-FPM. este código es el único que trabaja para mí:

function myEchoFlush_init() { 
    ini_set('zlib.output_compression', 0); 
    ini_set('output_buffering', 'Off'); 
    ini_set('output_handler', ''); 
    ini_set('implicit_flush', 1); 
    ob_implicit_flush(1); 
    ob_end_clean(); 
    header('Content-Encoding: none;'); 

} 

function myEchoFlush($str) { 
    echo $str . str_repeat(' ', ini_get('output_buffering') * 4) . "<br>\n"; 
} 

Ésta es mi función de prueba: se comprueba max_execution_time:

public function timeOut($time = 1, $max = 0) { 
    myEchoFlush_init(); 
    if ($max) ini_set('max_execution_time', $max); 
    myEchoFlush("Starting infinite loop for $time seconds. It shouldn't exceed : " . (ini_get('max_execution_time'))); 
    $start = microtime(true); 
    $lastTick = 1; 
    while (true) { 
     $tick = ceil(microtime(true) - $start); 
     if ($tick > $lastTick) { 
      myEchoFlush(microtime(true) - $start); 
      $lastTick = $tick; 
     } 
     if ($tick > $time) break; 
    } 
    echo "OK"; 
} 
+0

No use el modo de suspensión, ya que puede no contar en tiempo de ejecución –