Entenda o erro "Cannot modify header information - headers already sent" no PHP

O famoso erro do PHP com o texto "Cannot modify header information - headers already sent" acontece quando tentamos enviar um cabeçalho HTTP após já termos enviado alguma saída no corpo da resposta. Nesse post nós vamos entender o que isso tudo significa e como evitar esse problema em seu código.

HTTP

HTTP (HyperText Transfer Protocol) é o protocolo usado na internet, então sempre que você acessa um site usando seu navegador, por exemplo, HTTP está sendo usado.

HTTP é um protocolo que segue uma arquitetura cliente-servidor, onde há duas partes na comunicação. De forma super simplificada: você, usando seu navegador, é o cliente. O site que você acessa é o servidor.

Esse protocolo define mensagens de requisição (request) e resposta (response). Quando você acessa um site, seu navegador faz uma requisição para o servidor, que processa esse pedido e devolve uma resposta. Essas mensagens são divididas em duas grandes partes: cabeçalhos e corpo.

O corpo de uma resposta, por exemplo, é o conteúdo que você vê na tela, enquanto cabeçalhos possuem informações adicionais como cookies, informações de redirecionamento, etc.

Esse é um resumo bem conciso do protocolo HTTP e de como a internet funciona. Ainda sobre esse assunto, caso você tenha alguma dúvida ou queira entender melhor, eu tenho um vídeo no YouTube. Você pode conferí-lo antes de continuar lendo esse post:

Play Video: Como funciona a Web? - A internet por baixo dos panos | Dias de Dev

Como o PHP funciona

Entendido como a web funciona, é hora de entender o que o PHP faz na web. Aqui no blog há um post sobre como o PHP funciona na Web onde você pode entender como o PHP é executado, mas aqui vou resumir o que você precisa saber para entender o problema de "Cannot modify header information - headers already sent".

Quando você exibe algo em PHP, seja através de funções como echo ou até colocando HTML junto com seu PHP, esse conteúdo é enviado no corpo da resposta HTTP que o PHP gera. Isso tudo é feito de forma transparente para nós desenvolvedores.

Como foi citado no parágrafo anterior, uma resposta HTTP é dividida entre cabeçalhos e corpo, sendo que os cabeçalhos vêm antes do corpo. Sendo assim, para nós adicionarmos algo ao corpo da resposta com PHP, os cabeçalhos precisam ser montados e enviados antes.

Então quando você, em um sistema Web feito em PHP, executa um echo, por exemplo, os cabeçalhos da resposta HTTP são montados e enviados e depois o corpo é enviado com o conteúdo desse echo.

Existem também funções no PHP que podem enviar ou modificar cabeçalhos. Algumas dessas funções são:

  • header
  • header_remove
  • session_start
  • setcookie
  • etc

Entendendo o problema

Como foi dito logo na introdução desse post, o problema "Cannot modify header information - headers already sent" acontece quando tentamos enviar um cabeçalho HTTP após já termos enviado algo no corpo da resposta.

Isso quer dizer que esse erro acontece quando nós tentamos usar alguma função que adiciona ou modifica cabeçalhos HTTP quando algum conteúdo já foi exibido. Se você executar o seguinte código em um contexto web, verá o erro em questão:

<?php

echo 'Corpo da resposta';

header('Location: /url-de-redirecionamento');

O que nós estamos tentando fazer é enviar o cabeçalho Location, mas o corpo da resposta já começou a ser enviado quando nós executamos echo, ou seja, os cabeçalhos já foram montados e enviados para o cliente.

Problema acontecendo mesmo sem echo ou HTML

Você talvez esteja se perguntando o motivo de já ter se deparado com esse erro mesmo sem ter, antes de uma função header, por exemplo, nenhuma exibição de conteúdo. Sendo assim, teoricamente, nenhuma resposta deveria ter sido criada e os cabeçalhos ainda não teriam sido enviados.

O que acontece é que não é incomum que nós geremos uma resposta mesmo sem querer. Se deixarmos espaços em branco antes da tag de abertura do PHP (<?php) ou após a tag de fechamento do PHP (?>), esses espaços serão exibidos e com isso os cabeçalhos serão enviados. Outro caso muito comum é se nossa aplicação gerar algum aviso (os famosos warnings do PHP). Esses avisos sendo exibidos também geram uma resposta e com isso, os cabeçalhos são enviados.

Solução

Para que o erro não ocorra mais, você precisa se certificar que qualquer função que adiciona ou modifica cabeçalhos HTTP (como header ou session_start) seja executada antes que qualquer coisa seja exibida, mesmo que de forma acidental.

Para isso, você pode:

  1. Identificar e corrigir qualquer problema no código que gere algum erro ou aviso;
  2. Mover as funções que adicionam ou modificam cabeçalhos HTTP para o início da execução de sua aplicação, antes de qualquer exibição no corpo da resposta;
  3. Configurar o PHP para não exibir os erros e avisos (Isso só deve ser feito em produção. Em ambiente de desenvolvimento precisamos ver e corrigir os avisos);
  4. Evitar o uso da tag de fechamento do PHP (?>) em arquivos que contenham apenas código PHP;
  5. Garantir que não há espaços antes da tag de abertura (<?php) ou depois da tag de fechamento (?>) do PHP.
  6. Controlar o output buffer do PHP, caso se depare com um caso mais específico.

Conclusão

Um dos erros mais conhecidos do mundo PHP, embora assustador, não é tão difícil de resolver. Com esse post você deve ter as informações necessárias para não se deparar com ele novamente e para resolver o problema caso o encontre.

Caso queira se aprofundar e conhecer ainda mais nos estudos sobre PHP, aqui tem um cupom de desconto para assinar a Alura, plataforma de cursos online onde eu sou o instrutor da maioria dos cursos de PHP.