Cómo corregir el error "Encabezados ya enviados" en PHP

Resuelto Moses89 asked hace 54 años • 16 respuestas

Al ejecutar mi script, recibo varios errores como este:

Advertencia: No se puede modificar la información del encabezado: los encabezados ya fueron enviados por ( la salida comenzó en /some/file.php:12 ) en /some/file.php en la línea 23

Las líneas mencionadas en los mensajes de error contienen header()ysetcookie() .

¿Cuál podría ser la razón de ésto? ¿Y como arreglarlo?

Moses89 avatar Jan 01 '70 08:01 Moses89
Aceptado

¡No hay salida antes de enviar encabezados!

Las funciones que envían/modifican encabezados HTTP deben invocarse antes de realizar cualquier salida . summary ⇊ De lo contrario, la llamada falla:

Advertencia: No se puede modificar la información del encabezado: los encabezados ya se enviaron (la salida comenzó en script:line )

Algunas funciones que modifican el encabezado HTTP son:

  • header/header_remove
  • session_start/session_regenerate_id
  • setcookie/setrawcookie

La salida puede ser:

  • Involuntario:

    • Espacio en blanco antes <?phpo después?>
    • La marca de orden de bytes UTF-8 específicamente
    • Mensajes o avisos de error anteriores
  • Intencional:

    • printy echootras funciones que producen resultados
    • <html>Código previo de secciones sin procesar <?php.

¿Por que sucede?

Para comprender por qué los encabezados deben enviarse antes de la salida, es necesario observar una respuesta HTTP típica. Los scripts PHP generan principalmente contenido HTML, pero también pasan un conjunto de encabezados HTTP/CGI al servidor web:

HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>

La página/salida siempre sigue a los encabezados. PHP primero debe pasar los encabezados al servidor web. Sólo puede hacerlo una vez. Después del doble salto de línea ya no podrá modificarlos.

Cuando PHP recibe el primer resultado ( print,, ) echo, <html>eliminará todos los encabezados recopilados. Luego puede enviar todos los resultados que desee. Pero entonces es imposible enviar más encabezados HTTP.

¿Cómo puede saber dónde ocurrió la salida prematura?

La header()advertencia contiene toda la información relevante para localizar la causa del problema:

Advertencia: No se puede modificar la información del encabezado : los encabezados ya se enviaron (la salida comenzó en /www/usr2345/htdocs/auth.php:52 ) en /www/usr2345/htdocs/index.php en la línea 100

Aquí, "línea 100" se refiere al script donde falló la header() invocación .

La nota " la salida comenzó en " entre paréntesis es más significativa. Denomina la fuente de producción anterior. En este ejemplo, es auth.php y la línea52 . Ahí es donde había que buscar resultados prematuros.

Causas típicas:

  1. Imprimir, eco

    La salida intencional de declaraciones printy echocancelará la oportunidad de enviar encabezados HTTP. El flujo de aplicaciones debe reestructurarse para evitarlo. Utilice funciones y esquemas de plantillas. Asegúrese de header()que las llamadas se realicen antes de que se escriban los mensajes.

    Las funciones que producen resultados incluyen

    • print, echo, printf,vprintf
    • trigger_error, ob_flush, ob_end_flush, var_dump,print_r
    • readfile, passthru, flush, imagepng,imagejpeg


    entre otros y funciones definidas por el usuario.

  2. Áreas HTML sin formato

    Las secciones HTML no analizadas de un .phparchivo también son salida directa. Las condiciones del script que desencadenarán una header()llamada deben anotarse antes de cualquier bloque sin formato <html>.

    <!DOCTYPE html>
    <?php
        // Too late for headers already.
    

    Utilice un esquema de plantillas para separar el procesamiento de la lógica de salida.

    • Coloque el código de procesamiento de formularios encima de los scripts.
    • Utilice variables de cadena temporales para aplazar mensajes.
    • La lógica de salida real y la salida HTML entremezclada deben seguir al final.

  3. Espacio en blanco antes <?phppara las advertencias de "script.php línea 1 "

    Si la advertencia se refiere a la salida en línea 1, entonces se trata principalmente de espacios en blanco , texto o HTML antes del <?phptoken de apertura.

     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.
    

    De manera similar, puede ocurrir con scripts o secciones de script adjuntos:

    ?>
    
    <?php
    

    PHP en realidad consume un solo salto de línea después de cerrar etiquetas. Pero no compensará múltiples líneas nuevas, tabulaciones o espacios desplazados en esos espacios.

  4. Lista de materiales UTF-8

    Los saltos de línea y los espacios por sí solos pueden ser un problema. Pero también hay secuencias de caracteres "invisibles" que pueden causar esto. El más famoso es el UTF-8 BOM (Byte-Order-Mark) , que no se muestra en la mayoría de los editores de texto. Es la secuencia de bytes EF BB BF, que es opcional y redundante para documentos codificados en UTF-8. Sin embargo, PHP tiene que tratarlo como una salida sin procesar. Puede aparecer como caracteres en la salida (si el cliente interpreta el documento como Latin-1) o "basura" similar.

    En particular, los editores gráficos y los IDE basados ​​en Java no se dan cuenta de su presencia. No lo visualizan (obligado por el estándar Unicode). Sin embargo, la mayoría de los programadores y editores de consola hacen:

    El editor Joes muestra el marcador de posición BOM UTF-8 y el editor MC un punto.

    Allí es fácil reconocer el problema desde el principio. Otros editores pueden identificar su presencia en un menú de archivo/configuración (Notepad++ en Windows puede identificar y solucionar el problema ). Otra opción para inspeccionar la presencia de BOM es recurrir a un editor hexadecimal . En los sistemas *nix hexdumpsuele estar disponible, si no una variante gráfica, que simplifica la auditoría de estos y otros problemas:

    beav hexeditor mostrando utf-8 bom

    Una solución fácil es configurar el editor de texto para guardar archivos como "UTF-8 (sin BOM)" o una nomenclatura similar. A menudo, los recién llegados recurren a crear nuevos archivos y simplemente copiar y pegar el código anterior.

    Utilidades de corrección

    También existen herramientas automatizadas para examinar y reescribir archivos de texto ( sed/awk o recode). Para PHP específicamente existe la phptagsetiqueta tidier . Reescribe etiquetas de cierre y apertura en formatos largos y cortos, pero también soluciona fácilmente problemas de espacios en blanco iniciales y finales, Unicode y UTF-x BOM:

    phptags  --whitespace  *.php
    

    Es seguro usarlo en un directorio de proyecto o de inclusión completo.

  5. Espacio en blanco después?>

    Si se menciona la fuente del error detrás del cierre?> , entonces aquí es donde se escribieron algunos espacios en blanco o el texto sin formato. El marcador de fin de PHP no finaliza la ejecución del script en este punto. Cualquier carácter de texto/espacio posterior se escribirá aún como contenido de la página.

    Comúnmente se recomienda, en particular a los recién llegados, que ?>se omitan las etiquetas finales de cierre de PHP. Esto evita una pequeña porción de estos casos. (Muy comúnmente include()dlos guiones son los culpables).

  6. El origen del error se menciona como "Desconocido en la línea 0"

    Normalmente es una extensión de PHP o una configuración de php.ini si no se concreta ninguna fuente de error.

    • En ocasiones es la gzipconfiguración de codificación de transmisión o el archivoob_gzhandler .
    • Pero también podría ser cualquier extension=módulo doblemente cargado que genere un mensaje de advertencia/inicio de PHP implícito.

  7. Mensajes de error anteriores

    Si otra declaración o expresión PHP provoca que se imprima un mensaje de advertencia o aviso, eso también cuenta como salida prematura.

    En este caso, debe evitar el error, retrasar la ejecución de la declaración o suprimir el mensaje con, por ejemplo, isset()o @()- cuando ninguno de los dos obstruya la depuración posterior.

Ningún mensaje de error

Si tiene error_reportingo display_errorsdeshabilitó per php.ini, no aparecerá ninguna advertencia. Pero ignorar los errores no hará que el problema desaparezca. Los encabezados aún no se pueden enviar después de una salida prematura.

Por lo tanto, cuando header("Location: ...")las redirecciones fallan silenciosamente, es muy recomendable buscar advertencias. Vuelva a habilitarlos con dos comandos simples encima del script de invocación:

error_reporting(E_ALL);
ini_set("display_errors", 1);

O set_error_handler("var_dump");si todo lo demás falla.

Hablando de encabezados de redireccionamiento, a menudo deberías usar un modismo como este para las rutas de código finales:

exit(header("Location: /finished.html"));

Preferiblemente incluso una función de utilidad, que imprime un mensaje de usuario en caso de header()fallas.

Almacenamiento en búfer de salida como solución alternativa

El almacenamiento en búfer de salida de PHP es una solución alternativa para aliviar este problema. A menudo funciona de manera confiable, pero no debería sustituir la estructuración adecuada de la aplicación y la separación de la salida de la lógica de control. Su propósito real es minimizar las transferencias fragmentadas al servidor web.

  1. Sin embargo, el output_buffering= entorno puede ayudar. Configúrelo en php.ini o mediante .htaccess o incluso .user.ini en configuraciones modernas de FPM/FastCGI.
    Habilitarlo permitirá que PHP almacene en buffer la salida en lugar de pasarla al servidor web instantáneamente. Por lo tanto, PHP puede agregar encabezados HTTP.

  2. También se puede activar con una llamada ob_start(); encima del script de invocación. Lo cual sin embargo es menos confiable por múltiples razones:

    • Incluso si <?php ob_start(); ?>se inicia el primer script, es posible que los espacios en blanco o una lista de materiales se mezclen antes, lo que los vuelve ineficaces .

    • Puede ocultar espacios en blanco para la salida HTML. Pero tan pronto como la lógica de la aplicación intenta enviar contenido binario (una imagen generada, por ejemplo), la salida extraña almacenada en el buffer se convierte en un problema. (Es necesario ob_clean() como solución alternativa adicional).

    • El búfer tiene un tamaño limitado y puede desbordarse fácilmente si se deja con los valores predeterminados. Y eso tampoco es algo raro, difícil de rastrear cuando sucede.

Por lo tanto, ambos enfoques pueden volverse poco fiables, en particular al cambiar entre configuraciones de desarrollo y/o servidores de producción. Esta es la razón por la que el almacenamiento en búfer de salida se considera en general solo una muleta o estrictamente una solución alternativa.

Consulte también el ejemplo de uso básico en el manual y para conocer más ventajas y desventajas:

  • ¿Qué es el almacenamiento en búfer de salida en PHP?
  • ¿Por qué utilizar el buffer de salida en PHP?
  • ¿Se considera una mala práctica el uso del almacenamiento en búfer de salida?
  • Caso de uso para el almacenamiento en búfer de salida como solución correcta para "encabezados ya enviados"

¿Pero funcionó en el otro servidor?

Si no recibió la advertencia de los encabezados antes, entonces la configuración del buffer de salida de php.ini ha cambiado. Es probable que esté desconfigurado en el servidor nuevo/actual.

Comprobando conheaders_sent()

Siempre puedes usar headers_sent()para probar si todavía es posible... enviar encabezados. Lo cual es útil para imprimir información condicionalmente o aplicar otra lógica alternativa.

if (headers_sent()) {
    die("Redirect failed. Please click on this link: <a href=...>");
}
else{
    exit(header("Location: /user.php"));
}

Las soluciones alternativas útiles son:

  • <meta>etiqueta HTML

    Si su aplicación es estructuralmente difícil de arreglar, entonces una forma fácil (pero algo poco profesional) de permitir redireccionamientos es inyectar una <meta>etiqueta HTML. Se puede lograr una redirección con:

     <meta http-equiv="Location" content="http://example.com/">
    

    O con un breve retraso:

     <meta http-equiv="Refresh" content="2; url=../target.html">
    

    Esto genera HTML no válido cuando se utiliza más allá de la <head>sección. La mayoría de los navegadores todavía lo aceptan.

  • Redirección de JavaScript

    Como alternativa, se puede utilizar una redirección de JavaScript para redirecciones de páginas:

     <script> location.replace("target.html"); </script>
    

    Si bien esto suele ser más compatible con HTML que la <meta>solución alternativa, implica una dependencia de clientes compatibles con JavaScript.

Sin embargo, ambos enfoques suponen alternativas aceptables cuando fallan las llamadas genuinas de encabezado HTTP(). Lo ideal sería siempre combinar esto con un mensaje fácil de usar y un enlace en el que se pueda hacer clic como último recurso. (Que, por ejemplo, es lo que hace la extensión PECL http_redirect() ).

Por qué setcookie()y session_start()también se ven afectados

Ambos setcookie()y session_start()necesitan enviar un Set-Cookie:encabezado HTTP. Por lo tanto, se aplican las mismas condiciones y se generarán mensajes de error similares en situaciones de salida prematura.

(Por supuesto, además se ven afectados por las cookies deshabilitadas en el navegador o incluso por problemas de proxy. La funcionalidad de la sesión obviamente también depende del espacio libre en el disco y otras configuraciones de php.ini, etc.)

Otros enlaces

  • Google proporciona una larga lista de discusiones similares .
  • Y, por supuesto, también se han cubierto muchos casos específicos en Stack Overflow.
  • Las preguntas frecuentes de WordPress explican ¿Cómo soluciono el problema de advertencia de encabezados ya enviados? de manera genérica.
  • Comunidad Adobe: Desarrollo PHP: por qué las redirecciones no funcionan (encabezados ya enviados)
  • Preguntas frecuentes de Nucleus: ¿Qué significa "encabezados de página ya enviados"?
  • Una de las explicaciones más completas son los encabezados HTTP y la función PHP header(): un tutorial de NicholasSolutions (enlace de Internet Archive). Cubre HTTP en detalle y brinda algunas pautas para reescribir scripts.
mario avatar Nov 06 '2011 17:11 mario

Este mensaje de error se activa cuando se envía algosetcookie antes de enviar los encabezados HTTP (con o header). Las razones comunes para mostrar algo antes de los encabezados HTTP son:

  • Espacios en blanco accidentales, a menudo al principio o al final de los archivos, como este:

       <?php
      // Note the space before "<?php"
      ?>
    

       Para evitar esto, simplemente omita el cierre ?>; de ​​todos modos, no es necesario.

  • Marcas de orden de bytes al comienzo de un archivo php. Examine sus archivos php con un editor hexadecimal para descubrir si ese es el caso. Deberían comenzar con los bytes 3F 3C. Puede eliminar de forma segura la lista de materiales EF BB BFdesde el inicio de los archivos.
  • Salida explícita, como llamadas a echo, printf, , código antes readfile, etc.passthru<?
  • Una advertencia generada por php, si la display_errorspropiedad php.ini está configurada. En lugar de fallar por un error del programador, php corrige el error silenciosamente y emite una advertencia. Si bien puede modificar las display_errorsconfiguraciones de error_reporting , debería solucionar el problema.
    Las razones comunes son el acceso a elementos no definidos de una matriz (como $_POST['input']sin usar emptyo issetpara probar si la entrada está configurada), o el uso de una constante indefinida en lugar de una cadena literal (como en $_POST[input], tenga en cuenta las comillas que faltan).

Activar el almacenamiento en búfer de salida debería hacer que el problema desaparezca; toda la salida después de la llamada a ob_startse almacena en la memoria hasta que libera el búfer, por ejemplo, con ob_end_flush.

Sin embargo, si bien el almacenamiento en búfer de salida evita estos problemas, realmente deberías determinar por qué tu aplicación genera un cuerpo HTTP antes del encabezado HTTP. Sería como atender una llamada telefónica y hablar sobre su día y el clima antes de decirle a la persona que llama que se equivocó de número.

phihag avatar Nov 06 '2011 17:11 phihag

Recibí este error muchas veces antes y estoy seguro de que todos los programadores de PHP recibieron este error al menos una vez antes.

Posible solución 1

Este error puede haber sido causado por los espacios en blanco antes del inicio del archivo o después del final del archivo. Estos espacios en blanco no deberían estar aquí.

ex)

<!-- THERE SHOULD BE NO BLANK SPACES HERE -->
<?php  

   echo "your code here";

?>
<!-- THERE SHOULD BE NO BLANK SPACES HERE -->

Verifique todos los archivos asociados con el archivo que causa este error.

Nota: A veces, como EDITOR (IDE) gedit(un editor predeterminado de Linux), agrega una línea en blanco al guardar el archivo. Esto no debería suceder. Si estás usando Linux. Puede utilizar el editor VI para eliminar espacios/líneas al ?>final de la página.

Posible solución 2: si este no es su caso, utilice ob_start para generar el almacenamiento en búfer:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

Esto activará el almacenamiento en búfer de salida y sus encabezados se crearán después de que la página esté almacenada en el búfer.

Manish Shrivastava avatar Aug 01 '2012 06:08 Manish Shrivastava

En lugar de la línea de abajo

//header("Location:".ADMIN_URL."/index.php");

escribir

echo "<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>";

o

?><script><?php echo "location.href = '".ADMIN_URL."/index.php?msg=$msg';";?></script><?php

Definitivamente resolverá tu problema. Me enfrenté al mismo problema, pero lo resolví escribiendo la ubicación del encabezado de la manera anterior.

Ipsita Rout avatar Mar 24 '2013 12:03 Ipsita Rout