Headers HTTP en PHP: header(), redirecciones, Content-Type y output buffering

La función header() en PHP envía cabeceras HTTP al navegador antes de que se envíe cualquier contenido. Sirve para redirigir al usuario, indicar el tipo de respuesta, forzar descargas o establecer códigos de estado. Entender cómo y cuándo usarla, junto con el output buffering, es esencial para controlar la comunicación entre el servidor y el cliente.

Redirecciones con header() y exit

La redirección más habitual consiste en enviar la cabecera Location. Es imprescindible llamar a exit o die justo después para que PHP no siga ejecutando código tras la redirección.

<?php
// Redirección permanente (301): la URL ha cambiado definitivamente
http_response_code(301);
header('Location: https://programacion.net/nueva-url');
exit;

// Redirección temporal (302): la URL puede cambiar en el futuro
header('Location: /login', true, 302);
exit;

// Post/Redirect/Get: tras procesar un formulario, redirigir para evitar reenvío
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ... procesar formulario ...
    header('Location: /gracias?ok=1');
    exit; // sin exit, el código posterior se ejecuta igualmente
}
?>

Content-Type para APIs JSON y descargas

La cabecera Content-Type indica al cliente el formato de la respuesta. Para APIs JSON es application/json; para forzar una descarga se usa Content-Disposition junto con el tipo de contenido del fichero.

<?php
// Respuesta JSON para una API REST
header('Content-Type: application/json; charset=utf-8');
http_response_code(200);
echo json_encode(['estado' => 'ok', 'datos' => $resultado]);
exit;

// Forzar descarga de un fichero PDF
$ruta = '/var/datos/informe.pdf';
if (!file_exists($ruta)) {
    http_response_code(404);
    exit;
}

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="informe-2024.pdf"');
header('Content-Length: ' . filesize($ruta));
header('Cache-Control: no-store');
readfile($ruta);
exit;
?>

http_response_code(): códigos de estado HTTP

http_response_code() establece el código de estado de la respuesta. Llamarlo sin argumentos devuelve el código actual. Es más legible que pasar el código como tercer argumento de header().

<?php
// Respuesta 201 Created para una API que crea un recurso
http_response_code(201);
header('Content-Type: application/json; charset=utf-8');
header('Location: /api/usuarios/42');
echo json_encode(['id' => 42, 'nombre' => 'Ana']);
exit;

// 404 con página personalizada
http_response_code(404);
header('Content-Type: text/html; charset=utf-8');
include __DIR__ . '/plantillas/404.php';
exit;

// 422 Unprocessable Entity cuando la validación falla
http_response_code(422);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['errores' => ['El email ya está en uso.']]);
exit;
?>

Output buffering con ob_start()

Por defecto, PHP envía las cabeceras en cuanto aparece la primera salida. El output buffering retiene esa salida en memoria, lo que permite llamar a header() aunque ya haya HTML generado.

<?php
ob_start(); // iniciar buffer

echo '<!-- este HTML queda en el buffer -->';
echo '<p>Contenido generado antes de saber si redirigir.</p>';

$necesitaRedireccion = verificarCondicion();

if ($necesitaRedireccion) {
    ob_end_clean(); // descartar el buffer y las cabeceras no enviadas
    header('Location: /otra-pagina');
    exit;
}

// Modificar el buffer antes de enviarlo
$contenido = ob_get_contents();
ob_end_clean();
$contenidoMinificado = str_replace('  ', ' ', $contenido);
echo $contenidoMinificado;

// ob_start con función de transformación
ob_start('mb_strtolower'); // transforma toda la salida a minúsculas al enviar
echo 'ESTE TEXTO SALDRÁ EN MINÚSCULAS';
ob_end_flush();
?>

headers_sent() para depurar

headers_sent() devuelve true si ya se han enviado cabeceras y por lo tanto ya no es posible modificarlas. Aceptar un segundo y tercer parámetro por referencia permite obtener el fichero y la línea donde ocurrió el primer envío de salida.

<?php
if (headers_sent($fichero, $linea)) {
    echo "No se pueden enviar más cabeceras. ";
    echo "La primera salida fue en $fichero en la línea $linea.";
} else {
    header('X-Mi-Cabecera: valor');
}
?>

La documentación oficial de header() y la de control de salida (output buffering) detallan todas las cabeceras reconocidas por PHP, el manejo de niveles anidados de buffer y las funciones disponibles para manipular el contenido antes de enviarlo al cliente.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP