PHP leyendo salida en vivo de shell_exec
Sólo estoy experimentando con PHP yshell_exec
en mi servidor Linux. Es una función realmente interesante de usar y realmente la estoy disfrutando hasta ahora. ¿Hay alguna forma de ver la salida en vivo que se produce mientras se ejecuta el comando?
Por ejemplo, siping stackoverflow.com
se ejecutó, mientras hace ping a la dirección de destino, cada vez que hace ping, ¿muestra los resultados con PHP? ¿Es eso posible?
Me encantaría ver la actualización en vivo del búfer mientras se ejecuta. Quizás no sea posible pero seguro que estaría bien.
Este es el código que estoy probando y de todas las formas que he probado, siempre muestra los resultados una vez finalizado el comando.
<?php
$cmd = 'ping -c 10 127.0.0.1';
$output = shell_exec($cmd);
echo "<pre>$output</pre>";
?>
He intentado poner elecho
pieza en un bucle pero todavía no tuve suerte. ¿Alguien tiene alguna sugerencia para que muestre la salida en vivo en la pantalla en lugar de esperar hasta que se complete el comando?
Lo he probado exec
, shell_exec
, system
y passthru
. Cada uno de ellos muestra el contenido una vez finalizado. A menos que esté usando una sintaxis incorrecta o no esté configurando el bucle correctamente.
Leer el resultado de un proceso popen()
es el camino a seguir. Su script se ejecutará en paralelo con el programa y podrá interactuar con él leyendo y escribiendo su salida/entrada como si fuera un archivo.
Pero si solo desea volcar el resultado directamente al usuario, puede ir al grano y usar passthru()
:
echo '<pre>';
passthru($cmd);
echo '</pre>';
Si desea mostrar el resultado en tiempo de ejecución a medida que avanza el programa, puede hacer esto:
while (@ ob_end_flush()); // end all output buffers if any
$proc = popen($cmd, 'r');
echo '<pre>';
while (!feof($proc))
{
echo fread($proc, 4096);
@ flush();
}
echo '</pre>';
Este código debe ejecutar el comando y enviar la salida directamente al usuario final en tiempo de ejecución.
Más información útil
Tenga en cuenta que si está utilizando sesiones, tener una de ellas ejecutándose evitará que el usuario cargue otras páginas, ya que las sesiones imponen que no se puedan realizar solicitudes simultáneas. Para evitar que esto sea un problema, llame session_write_close()
antes del ciclo.
Si su servidor está detrás de una puerta de enlace nginx, entonces el almacenamiento en búfer de nginx puede alterar el comportamiento deseado. Configure el encabezado header('X-Accel-Buffering: no');
para indicarle a nginx que no debería hacer eso. Como los encabezados se envían primero, esto debe llamarse al comienzo del script, antes de enviar cualquier dato.
En primer lugar, gracias Havenard por tu fragmento: ¡me ayudó mucho!
Una versión ligeramente modificada del código de Havenard que encontré útil.
<?php
/**
* Execute the given command by displaying console output live to the user.
* @param string cmd : command to be executed
* @return array exit_status : exit status of the executed command
* output : console output of the executed command
*/
function liveExecuteCommand($cmd)
{
while (@ ob_end_flush()); // end all output buffers if any
$proc = popen("$cmd 2>&1 ; echo Exit status : $?", 'r');
$live_output = "";
$complete_output = "";
while (!feof($proc))
{
$live_output = fread($proc, 4096);
$complete_output = $complete_output . $live_output;
echo "$live_output";
@ flush();
}
pclose($proc);
// get exit status
preg_match('/[0-9]+$/', $complete_output, $matches);
// return exit status and intended output
return array (
'exit_status' => intval($matches[0]),
'output' => str_replace("Exit status : " . $matches[0], '', $complete_output)
);
}
?>
Uso de muestra:
$result = liveExecuteCommand('ls -la');
if($result['exit_status'] === 0){
// do something if command execution succeeds
} else {
// do something on failure
}