¿De qué sirve ob_start () en php?

298

¿Se ob_start()utiliza para output bufferingque los encabezados se guarden en el búfer y no se envíen al navegador? ¿Estoy teniendo sentido aquí? Si no, ¿por qué deberíamos usar ob_start()?

Aditya Shukla
fuente

Respuestas:

481

Piense ob_start()como decir "Comience a recordar todo lo que normalmente se generaría, pero no haga nada con él todavía".

Por ejemplo:

ob_start();
echo("Hello there!"); //would normally get printed to the screen/output to browser
$output = ob_get_contents();
ob_end_clean();

Por lo general, hay otras dos funciones con las que lo empareja: ob_get_contents()que básicamente le da todo lo que se ha "guardado" en el búfer desde que se encendió ob_start(), y luego ob_end_clean()o ob_flush(), que deja de guardar cosas y descarta lo que se guardó, o deja de guardar y lo genera todo a la vez, respectivamente.

Riley Dutton
fuente
55
Gran explicación Iría un paso más allá y reemplazaría ob_get_contents()con ob_get_clean()y eliminaría, ob_end_clean()ya que ob_get_clean()esencialmente realiza ambas funciones. Referencia: php.net/manual/en/function.ob-get-clean.php (PHP 4> = 4.3.0, PHP 5)
Con Antonakos
Supongo que el búfer de salida debe estar habilitado en el orden del archivo .ini para llamar ob_start();¿Es esto correcto? ¿Qué sucede si no está habilitado?
Kevin Wheeler
55
@Riley Dutton No estás diciendo que por qué se usa ob_start ()
Vishnu R Nair
Tuve el mismo problema, después de arreglar mi código ob_end_clean, ¡funciona de maravilla! Gracias @Riley Dutton
Martins
160

Lo uso para poder salir de PHP con mucho HTML pero no representarlo. Me ahorra almacenarlo como una cadena que deshabilita la codificación de color IDE.

<?php
ob_start();
?>
<div>
    <span>text</span>
    <a href="#">link</a>
</div>
<?php
$content = ob_get_clean();
?>

En vez de:

<?php
$content = '<div>
    <span>text</span>
    <a href="#">link</a>
</div>';
?>
JD Isaacks
fuente
1
¿Se puede usar como una forma de tener múltiples páginas html dentro de un PHP y llamarlas a través de GET?
joshkrz
1
Supongo que sí, pero no parece una buena idea. Sería mejor cargarlos desde plantillas separadas.
JD Isaacks
1
Tenga en cuenta que esta técnica utiliza ob_get_clean(), no ob_end_clean()
Blazemonger
11
¡Nunca pensé en esto, esa es una forma increíblemente amigable de desarrollar IDE! Además, elimina mi necesidad de tener Javascript o HTML como una cadena en mi PHP, escapando constantemente ", etc., lo cual es molesto
J-Dizzle
1
Su visual ofrece una imagen clara de los beneficios de usar ob_start.
klewis
86

La respuesta aceptada aquí describe qué ob_start()hace, no por qué se usa (cuál fue la pregunta que se hizo).

Como se indicó en otra parte, ob_start()crea un búfer en el que se escribe la salida.

Pero nadie ha mencionado que es posible apilar múltiples buffers dentro de PHP. Ver ob_get_level ().

En cuanto al por qué ...

  1. Enviar HTML al navegador en fragmentos más grandes brinda un beneficio de rendimiento de una sobrecarga de red reducida.

  2. Pasar los datos fuera de PHP en fragmentos más grandes proporciona un beneficio de rendimiento y capacidad al reducir la cantidad de cambios de contexto requeridos

  3. Pasar grandes cantidades de datos a mod_gzip / mod_deflate brinda un beneficio de rendimiento ya que la compresión puede ser más eficiente.

  4. el almacenamiento en búfer de la salida significa que aún puede manipular los encabezados HTTP más adelante en el código

  5. La descarga explícita del búfer después de generar [head] .... [/ head] puede permitir que el navegador comience a ordenar otros recursos para la página antes de que se complete la secuencia HTML.

  6. La captura de la salida en un búfer significa que puede redirigirse a otras funciones, como el correo electrónico, o copiarse a un archivo como una representación en caché del contenido.

symcbean
fuente
29

Lo tienes al revés. ob_start no almacena los encabezados, almacena el contenido. El uso le ob_startpermite mantener el contenido en un búfer del lado del servidor hasta que esté listo para mostrarlo.

Esto se usa comúnmente para que las páginas puedan enviar encabezados 'después de' que hayan 'enviado' algo de contenido (es decir, decidir redirigir a la mitad del proceso de representación de una página).

Craige
fuente
3
+1 Yo también estaba confundido sobre el uso real de la función. Su respuesta con respecto a su uso durante la "redirección" me recordó todas las veces que tuve el error "Encabezados ya enviados". Gracias
pat
13

Yo prefiero:

ob_start();
echo("Hello there!");
$output = ob_get_clean(); //Get current buffer contents and delete current output buffer
halcón
fuente
8

esto es para aclarar aún más la respuesta de JD Isaaks ...

El problema con el que se encuentra a menudo es que está utilizando php para generar html desde muchas fuentes de php diferentes, y esas fuentes a menudo, por cualquier motivo, se emiten de diferentes maneras.

A veces tiene contenido html literal que desea enviar directamente al navegador; otras veces la salida se crea dinámicamente (del lado del servidor).

El contenido dinámico siempre (?) Será una cadena. Ahora tiene que combinar este html dinámico en cadena con cualquier html literal directo a mostrar ... en una estructura de nodo html significativa.

Esto generalmente obliga al desarrollador a envolver todo ese contenido directo para mostrar en una cadena (como JD Isaak estaba discutiendo) para que pueda entregarse / insertarse correctamente junto con el html dinámico ... aunque realmente no Lo quiero envuelto.

Pero al usar los métodos ob _ ## puede evitar ese desorden de envoltura de cadenas. El contenido literal es, en cambio, salida al búfer. Luego, en un simple paso, todo el contenido del búfer (todo su html literal) se concatena en su cadena dinámica-html.

(Mi ejemplo muestra la salida literal de html al búfer, que luego se agrega a una cadena html ... mire también el ejemplo de JD Isaaks para ver string-wrapping-of-html).

<?php // parent.php

//---------------------------------
$lvs_html  = "" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__without_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

$lvs_html .= "----<br/>" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__with_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

echo $lvs_html ;    
//    02 - component contents
//    html
//    01 - component header
//    03 - component footer
//    more html
//    ----
//    html
//    01 - component header
//    02 - component contents
//    03 - component footer
//    more html 

//---------------------------------
function gf_component_assembler__without_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;
    include( "component_contents.php" ) ;
    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
function gf_component_assembler__with_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;

        ob_start();
        include( "component_contents.php" ) ;
    $lvs_html .= ob_get_clean();

    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
?>

<!-- component_contents.php -->
  <div>
    02 - component contents
  </div>
dsdsdsdsd
fuente
4

Esta función no es solo para encabezados. Puedes hacer muchas cosas interesantes con esto. Ejemplo: podría dividir su página en secciones y usarla así:

$someTemplate->selectSection('header');
echo 'This is the header.';

$someTemplate->selectSection('content');
echo 'This is some content.';

Puede capturar la salida que se genera aquí y agregarla en dos lugares totalmente diferentes en su diseño.

jwueller
fuente
Este tipo de parece a lo que estoy buscando. Necesito procesar cosas en 'secciones' (piense en archivos JS y CSS), pero necesito poder llamarlas dentro de la plantilla (que se carga más tarde que el encabezado) ... Entonces, si llamo "$ this- > addcss ('specificCSStoThisView'); " Quiero que se procese entre las etiquetas <head>. Sin embargo, parece que no puedo googlear esto. ¿Podrías señalarme en la dirección correcta? ¡Gracias!
NoobishPro
2

Las siguientes cosas no se mencionan en las respuestas existentes: Configuración del tamaño del búfer Encabezado HTTP y anidamiento.

Configuración del tamaño del búfer para ob_start:

ob_start(null, 4096); // Once the buffer size exceeds 4096 bytes, PHP automatically executes flush, ie. the buffer is emptied and sent out.

El código anterior mejora el rendimiento del servidor ya que PHP enviará fragmentos de datos más grandes, por ejemplo, 4KB (sin la llamada ob_start, php enviará cada eco al navegador).

Si comienza el almacenamiento en búfer sin el tamaño del fragmento (es decir, un simple ob_start ()), la página se enviará una vez al final del script.

El almacenamiento en búfer de salida no afecta a los encabezados HTTP, se procesan de manera diferente. Sin embargo, debido al almacenamiento en búfer, puede enviar los encabezados incluso después de que se envió la salida, porque todavía está en el búfer.

ob_start();  // turns on output buffering
$foo->bar();  // all output goes only to buffer
ob_clean();  // delete the contents of the buffer, but remains buffering active
$foo->render(); // output goes to buffer
ob_flush(); // send buffer output
$none = ob_get_contents();  // buffer content is now an empty string
ob_end_clean();  // turn off output buffering

Bien explicado aquí: https://phpfashion.com/everything-about-output-buffering-in-php

sudip
fuente
0

No, estás equivocado, pero la dirección encaja;)

El buffer de salida almacena la salida de un script. Eso es (en resumen) todo después echoo print. Lo que pasa con los encabezados es que solo se pueden enviar, si aún no se han enviado. Pero HTTP dice que los encabezados son los primeros de la transmisión. Entonces, si imprime algo por primera vez (en una solicitud), los encabezados se envían y no puede establecer ningún otro encabezado.

KingCrunch
fuente