Streaming procesos en php

En determinadas ocasiones he necesitado generar una web que me ejecute un proceso del sistema operativo que tarda bastante. Es bastante frustrante tener que esperar a que el proceso termine para saber como se está ejecutando, si eres tan impaciente como yo, este es tu código.

<?php
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-cache');
ini_set('max_execution_time', 600);
echo '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
echo "<style type='text/css'>
 body{
 background:#000;
 color: #7FFF00;
 font-family:'Lucida Console',sans-serif !important;
 font-size: 12px;
 }
 </style></head><body>";
?>

El primer paso es configurar el timeout de la aplicación para que PHP no cierre el proceso, acto seguido indicamos al navegador que esta web no se debe cachear. Y para darle un poco de formato generamos el estilo de una consola de MSDOS.

El siguiente paso es preparar la salida de PHP para que vaya enviando por el socket HTTP la información que se genera sin esperar a que finalice la ejecución del script.

<?php

function disable_ob() {
    // Turn off output buffering
    ini_set('output_buffering', 'off');
    // Turn off PHP output compression
    ini_set('zlib.output_compression', false);
    // Implicitly flush the buffer(s)
    ini_set('implicit_flush', true);
    ob_implicit_flush(true);
	ob_end_flush();
    // Clear, and turn off output buffering
    while (ob_get_level() > 0) {
        // Get the curent level
        $level = ob_get_level();
        // End the buffering
        ob_end_clean();
        // If the current level has not changed, abort
        if (ob_get_level() == $level) break;
    }
    // Disable apache output buffering/compression
    if (function_exists('apache_setenv')) {
        apache_setenv('no-gzip', '1');
        apache_setenv('dont-vary', '1');
    }
}

// tell php to automatically flush after every output
// including lines of output produced by shell commands
disable_ob();
flush();
?>

Para finalizar sólo nos queda ejecutar el comando e ir imprimiendo su salida. En este caso voy a ejecutar un script en python “unbufered” para que el intérprete no se guarde la salida estándar hasta que termina de ejecutar el comando:


$cmd = 'python -u automate.py 2>&1'; 
$pid = popen( $cmd,"r");
 
echo "<body><pre>";
while( !feof( $pid ) )
{
 echo fread($pid, 256);
 flush();
 //ob_flush();
 echo "<script>window.scrollTo(0,99999);</script>";
 usleep(100000);
}
pclose($pid);

Con las líneas:

 echo "<script>window.scrollTo(0,99999);</script>";
 usleep(100000);

Conseguimos el navegador haga scroll hasta la última linea impresa y que PHP no consuma más recursos de los necesarios ya que no es necesario que esté todo el tiempo comprobando la salida estándar del proceso ejecutado.

Resultado:

Console

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.