que - Cómo deshabilitar el almacenamiento en búfer de salida en PHP
session_start(); ob_start(); (5)
Escribí una secuencia de comandos de retransmisión simple que se conecta a una cámara web y lee desde el socket, y emite estos datos usando la función de impresión. Los datos son datos MJPG con límites ya configurados. Acabo de mostrar los datos que se leen.
El problema es que PHP parece almacenar en búfer estos datos. Cuando configuro la cámara a 1 FPS, la alimentación se congela durante 7-8 segundos, luego muestra rápidamente 8 cuadros. Si configuro la resolución a un tamaño enorme, la cámara se mueve a más o menos 1 fotograma por segundo. Supongo que está ocurriendo algo de almacenamiento en búfer (ya que los tamaños grandes llenan el búfer rápidamente, y los tamaños bajos no), y no puedo encontrar la manera de desactivar este almacenamiento en búfer. ¿Alguien sabe cómo?
Código:
ignore_user_abort(false);
$boundary = "myboundary";
//Set this so PHP doesn''t timeout during a long stream
set_time_limit(0);
$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0/r/n/r/n");
//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");
@ini_set(''implicit_flush'', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);
stream_set_blocking($f2, false);
//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
$chunk = fread($socketConn, 128);
print $chunk;
}
fclose($socketConn);
tl; versión dr
Haz dos cosas:
Inhabilita el búfer de salida del espacio de usuario, ya sea ...
A nivel mundial, ya sea por ...
- Desactivando
output_buffering
en tu php.ini, o Desactivando
output_buffering
en tu configuración de Apache usandophp_flag "output_buffering" Off
- Desactivando
o solo por el guión que te importa, ya sea por ...
- llamando a
ob_end_flush()
, o - llamando a
ob_end_clean()
- llamando a
Además, deshabilite el búfer de salida de nivel de servidor tanto como sea posible, ya sea por:
- llamando a
ob_implicit_flush()
al comienzo de su script, o - invocando
flush()
después de cada declaración deecho
u otra instrucción que agrega salida al cuerpo de respuesta
- llamando a
Versión más larga
Confusamente, hay dos capas de almacenamiento intermedio que pueden ser relevantes y la documentación de PHP hace un trabajo pobre de distinguir entre los dos.
El buffer de salida
La primera capa suele ser referida por los documentos PHP como el ''buffer de salida''. Esta capa de almacenamiento en búfer solo afecta la salida al cuerpo de la respuesta HTTP, no a los encabezados. Puede activar el almacenamiento en búfer de salida con ob_start()
y desactivarlo con ob_end_flush()
o ob_end_clean()
. También puede hacer que todos los scripts comiencen automáticamente con el búfer de salida utilizando la opción output_buffering
en php.ini.
El valor predeterminado de esta opción para las versiones de producción de php.ini es 4096, lo que significa que los primeros 4096 bytes de salida se almacenarán en el búfer de salida, en ese punto se vacían y el búfer de salida se desactiva.
Puede desactivar esta capa de almacenamiento en búfer de forma global estableciendo output_buffering
en Off
en su archivo php.ini (o usando
php_flag "output_buffering" Off
en tu configuración de Apache, si estás usando Apache). Alternativamente, puede desactivarlo para un solo script llamando a ob_end_clean()
o ob_end_flush()
al comienzo del script.
El búfer de escritura y el búfer del servidor web
Más allá del búfer de salida, el manual de PHP se refiere al "búfer de escritura", más cualquier sistema de búfer que tenga su servidor web. Si está utilizando PHP con Apache a través de mod_php
, y no está usando mod_gzip
, puede llamar a flush()
para vaciarlos; con otros backends, podría funcionar también, aunque el manual es cauteloso para dar garantías:
Descripción
void flush ( void )
Vacía los búferes de escritura de PHP y cualquier backend que PHP esté usando (CGI, un servidor web, etc.). Esto intenta llevar la salida actual al navegador con algunas advertencias.
flush () puede no ser capaz de anular el esquema de almacenamiento en búfer de su servidor web y no tiene ningún efecto sobre el almacenamiento en búfer del lado del cliente en el navegador. Tampoco afecta el mecanismo de búfer de salida del espacio de usuario de PHP. Esto significa que tendrá que llamar tanto a ob_flush() como a flush () para purgar los búferes de salida ob si los está utilizando.
También hay un par de maneras en que puede hacer que PHP llame automáticamente a flush()
cada vez que haga echo
algo (o haga cualquier otra cosa que emita eco en el cuerpo de la respuesta).
El primero es llamar a ob_implicit_flush()
. Tenga en cuenta que esta función es engañosamente nombrada; dado su prefijo ob_
, cualquier persona razonable esperaría que afectaría al ''buffer de salida'', como hacen ob_start
, ob_flush
, etc. Sin embargo, este no es el caso; ob_implicit_flush()
, como flush()
, afecta al búfer de salida del nivel del servidor y no interactúa de ninguna manera con el búfer de salida controlado por las otras funciones ob_
.
El segundo es habilitar globalmente el enjuague implícito configurando el indicador implicit_flush
en On
en su php.ini. Esto es equivalente a invocar ob_implicit_flush()
al inicio de cada script. Tenga en cuenta que el manual desaconseja esto, citando crípticamente "implicaciones graves de rendimiento" , algunas de las cuales exploro en esta respuesta tangencialmente relacionada .
El almacenamiento en búfer de salida se puede aplicar en capas y he tenido casos en los que el código anterior había alcanzado varios niveles. Esto los limpiará a todos.
while (ob_get_level()) ob_end_clean();
// or ob_end_flush() if you want the contents of the buffer.
En lugar de deshabilitar el almacenamiento en búfer de salida, puede simplemente llamar a flush()
después de cada operación de lectura. Esto evita tener que meterse con la configuración del servidor y hace que su script sea más portátil.
Podemos dar el siguiente código en el archivo .htaccess para deshabilitar el almacenamiento en búfer de salida en PHP
php_flag "output_buffering" off
Sé que esta pregunta es un poco antigua, pero volviendo a esta pregunta, puede desactivar el almacenamiento en búfer de salida en un script a script, como este:
if (ob_get_level())
ob_end_clean();
Esto debería desactivar todos los búferes de salida para cualquier script que lo siga.