Detalles del protocolo HTTP que todo desarrollador PHP debe conocer

Algo que siempre me llamó la atención es cómo en los cursos de PHP (o de programación web en general para el caso), suele pasarse por alto hablar de HTTP.

Es cierto que esto puede sonar demasiado teórico y, lo admito, aburrido, sin embargo, es un conocimiento que va a aclararte muchas cosas.

Un claro ejemplo de esto es cuando te encontrás con un error como este:

PHP Warning: session_start(): Cannot start session when headers already sent

Cuando tu código dice algo como:

Hola!
<?php
session_start();

O también:

PHP Warning: Cannot modify header information - headers already sent

Al entrar a una página con un código como:

Hola!
<?php
setcookie('MyCookie','MyValue');

O

Hola!
<?php
header('Location: pagina2.php');

Seguramente sabrás (tal vez por experiencia o porque «así es como se hace») que las funciones session_start, setcookie y header deben invocarse antes de enviar contenido al cliente, es decir:

<?php
header('Location: pagina2.php');
?>
Hola!

Y así las cosas funcionan.

Pero, por supuesto que existe una razón para esto (No es que haya sido un capricho de Rasmus :)).

Para comprender qué tienen de especial estas funciones es necesario entender un poquito qué es lo que sucede cuando visitas una página web.

Más específicamente, debes saber lo básico sobre la forma en que se comunica el cliente (Tu navegador) y el servidor.

Esa comunicación se realiza siguiendo las reglas que establece el protocolo HTTP.

Cómo funciona HTTP

Lo primero que debes saber es que HTTP es un protocolo de transferencia de texto (De ahí su nombre HyperText Transfer Protocol).

La noción de hypertexto es algo anticuada pero no olvides que HTTP se diseñó a principios de la década de 1990!

Se trata de un texto que puede contener referencias a otros textos (Es decir, links).

Cuando comenzó la web, realmente era algo bastante simple.

Una vez establecida la conexión física no había mucho que pudiera hacer el cliente más que solicitar algún archivo de texto que, esperablemente, estaría presente en el disco del servidor.

Si este era efectivamente el caso, la tarea del servidor era enviar el contenido de ese archivo de vuelta al cliente.

Corría por cuenta del cliente interpretar ese texto y mostrarlo al usuario de una forma humanamente agradable (Esto sigue siendo así hasta hoy).

El flujo es algo similar a:

Pero, además del contenido del archivo (El HTML en este caso), el servidor envía algo de información adicional al cliente.

Esta información (o meta-información si se quiere) viaja al cliente a través de lo que se conoce como encabezados HTTP.

Cómo se ve un encabezdo HTTP

Los encabezados, como todo lo demás en HTTP, son cadenas de texto.

En particular, los encabezados son cadenas con un formato especial:

NOMBRE: VALOR

Si nunca viste estos encabezados te invito a que abras una nueva ventana de tu navegador (esta por ejemplo) y busques la consola del desarrollador (Si usás Chrome la vas a ver al apretar F12):

Te vas a encontrar con algo como:

Y en particular, si vas a la pestaña Network:

Vas a encontrarte con un detalle de todas las peticiones que tu browser hizo para poder mostrarte el sitio que estás viendo.

¿Me acompañás un pasito más?

Hacé click en una petición cualquiera:

Y ahí estás viendo los encabezados (Headers).

Si bajás un poquito por el panel derecho te encontrás con:

Los encabezados que el servidor le envió a tu navegador.

A partir de esta información el navegador toma ciertas decisiones, por ejemplo, acá vez que hay un encabezado que dice content-encoding: gzip.

Ese encabezado le está diciendo al navegador que el texto que va a recibir (cuando finalicen los encabezados) corresponde al resultado de comprimir el contenido buscado, de modo que, para poder interpretarlo, primero tendrá que descomprimirlo.

Y aquí llegamos al fondo de la cuestión, la clave del misterio es que los encabezados siempre se envían antes del contenido propiamente dicho.

Qué tienen en común session_start(), setcookie() y header()

Lo que estas tres funciones tienen en común es que todas envían encabezados al cliente.

La función header lo hace de forma explícita… de eso se trata precisamente, de enviar un encabezado arbitrario al cliente.

La función setcookie en realidad es una especie de atajo para no escribir una expresión más compleja como:

header('Set-Cookie: MyCookie=Value');

Y la función session_start()… bueno, es algo más complicado explicar qué hace pero internamente hace uso de setcookie (es decir, de header()).

La lista de encabezados HTTP (y sus funciones) son muchas, si estás con ganas de investigar podés seguir por acá.

Algo que te recomiendo conocer (al menos básicamente) son los códigos de error HTTP, algo que te va a venir muy bien si te toca desarrollar WebServices REST por ejemplo.

Y ahora sí, espero haberte aclarado algunos conceptos y que no te vuelva a sorprender un error de encabezados ya enviados 😉

mchojrin
Publicada el
Categorizado como Conceptos Etiquetado como

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

2 comentarios

  1. Hola Mauro. Qué tal!! Te sigo desde hace casi 2 años y tu trabajo me parece de los mejores que he visto y tus aportaciones a quienes estamos en el camino de PHP. ¿Has publicado algo o podrías recomendar respecto a cifrado de información? Me refiero a la pasarela de variables (get) y rutas del proyecto que se podrían observar en el código. Espero haberme explicado. Saludos y gracias.

    1. Hola Eduardo!

      Gracias por tu mensaje 🙂 No estoy seguro de haber comprendido tu pregunta.

      Lo que publiqué por aquí es sobre cifrado de contraseñas (https://academy.leewayweb.com/cual-es-el-modo-mas-seguro-de-almacenar-passwords-en-php/), si se trata de pasar valores cifrados a través de URLs existen varios métodos.

      Lo primero sería cifrar el dato y mandar el resultado del cifrado a través del método GET.

      Dependiendo de qué tanta seguridad necesites se decidirá el mecanismo específico. Los mejores son aquellos de clave pública/clave privada, para ello te puede venir bien usar este paquete: https://github.com/defuse/php-encryption

      Espero haberte ayudado 🙂

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.