ob_get_contents - php clean output buffer
Cómo vaciar los datos al navegador pero continuar ejecutando (7)
Lo he hecho en el pasado y así lo resolví:
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();
}
Como dije en un par de comentarios antes, debes tener cuidado con tu contenido, ya que eso alterará la longitud de tu contenido, pero no cambiará el encabezado al respecto. También puede amortiguar su salida, por lo que no se enviará al cliente al instante.
Puede intentar que Apache sepa que no debe descomprimir su contenido usando apache_setenv(''no-gzip'', ''1'');
. Pero esto no funcionará si usa reglas de reescritura para ir a su página, ya que también modificará esas variables de entorno. Al menos, lo hizo por mí.
Vea más advertencias sobre la descarga de su contenido al usuario en el manual .
Tengo un ob_start()
y un ob_flush()
correspondiente. Me gustaría vaciar una parte de los datos y continuar ejecutando el resto. Usar ob_flush()
no ayudó. Además, si es posible, el descanso debe ocurrir sin mostrar la carga en el navegador.
EDITAR:
No quiero usar ajax
Si está utilizando PHP-FPM:
ignore_user_abort(true);
fastcgi_finish_request();
Sobre dos funciones están los factores clave que ignore_user_abort
evita el error y fastcgi_finish_request
cierra la conexión del cliente.
Tengo un artículo que explica cómo se puede lograr esto usando apache / mod_php en mi blog aquí: http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.html Espero que esto ayude, aclamaciones
Utilizar:
header("Content-Length: $len");
..where $len
es la longitud de los datos que se deben vaciar al cliente.
No tengo el fondo para saber cuándo y dónde va a funcionar esto, pero probé en algunos navegadores, y todos regresaron al instante con:
<?PHP
header("Content-length:5");
echo "this is more than 5";
sleep(5);
?>
edición: Chrome, IE y Opera mostraron this
, mientras que FireFox mostró que this is more than 5
. Sin embargo, todos ellos cerraron la solicitud después de eso.
esta es mi funcion
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);
}
Envuelva la función que se ejecutará al final, después de que PHP cierre la conexión. y por supuesto el navegador detendrá el almacenamiento en búfer.
function test() {
while (true) {
echo ''this text will never seen by user'';
}
}
Así es como se llama a la función.
bg_process(''test'');
el primer argumento es callable
, el segundo argumento es una matriz que se pasa a la función de "prueba" con una matriz indexada
Nota: no uso ob_start()
al principio de la secuencia de comandos.
fastcgi_finish_request
Esta función vacía todos los datos de respuesta al cliente y finaliza la solicitud. Esto permite realizar tareas que consumen mucho tiempo sin dejar abierta la conexión con el cliente.
no funciona en Apache. (PHP 5> = 5.3.3, PHP 7)
ob_flush
escribe el búfer. En otras palabras, ob_flush
le dice a PHP que le dé a Apache (o nginx / lighttpd / lo que sea) la salida y luego a PHP para que se olvide de ello. Una vez que Apache tiene la salida, hace lo que quiere con ella. (En otras palabras, después de ob_flush
queda fuera de su control si se escribe inmediatamente o no en el navegador).
Entonces, respuesta corta: no hay una forma garantizada de hacerlo.
Sólo una conjetura, es probable que estés buscando AJAX. Cuando las personas intentan manipular cuando el contenido de la página se carga como lo está haciendo, AJAX es casi siempre la ruta correcta.
Si desea continuar una tarea en segundo plano, puede usar ignore_user_abort
, como se detalla here , sin embargo, a menudo este no es el enfoque óptimo. Básicamente, se pierde el control sobre ese hilo, y en mi opinión, un hilo del servidor web no es a donde pertenece el procesamiento pesado.
Intentaría extraerlo de las cosas de la web. Esto podría significar una entrada cron o simplemente generar un proceso en segundo plano desde PHP (un proceso que aunque comenzó desde adentro de la ejecución del script no morirá con el script, y el script no esperará a que termine antes de morir).
Si va por esa ruta, significará que incluso puede hacer algún tipo de sistema de estado si es necesario. Luego, puede supervisar la ejecución y proporcionar al usuario actualizaciones periódicas sobre el progreso. (Técnicamente, también podría crear un sistema de estado con un script ignore_user_abort
-ed, pero no me parece tan limpio).