Llevo toda la tarde con un cabreo monumental. Entro por FTP al servidor gratuito donde tengo alojado mi proyecto final, subo los archivos de PHP que funcionaban perfectamente en mi casa, voy al navegador y... nada. Los formularios no envían datos, las sesiones han desaparecido y las variables están vacías. Tras horas tirándome de los pelos y revisando el código línea a línea, entro al foro de PHP y me entero de la broma: el proveedor ha actualizado a PHP 4.2.0 y la directiva register_globals viene ahora apagada por defecto.

Si has estado programando en PHP los últimos años, esto es un jarro de agua fría. Han cambiado las reglas del juego a mitad de partido y todos los que aprendimos a hacer webs dinámicas leyendo tutoriales por internet tenemos ahora un montón de código roto.

El fin de la magia en PHP

Hasta ahora, PHP tenía una característica que lo hacía increíblemente fácil para los que empezábamos a trastear con la web. Si un usuario rellenaba un formulario HTML con un campo llamado nombre, cuando ese formulario llegaba a tu script PHP, mágicamente tenías una variable $nombre lista para usar. Lo mismo pasaba con los parámetros de la URL (?id=5 creaba la variable $id) y con las sesiones.

Era rápido, era cómodo y, como acabamos de descubrir todos a base de palos, era un agujero de seguridad colosal.

Piensa en esto: si tenías un script que comprobaba una contraseña y luego ponía $autorizado = true;, cualquiera podía saltarse tu seguridad simplemente añadiendo ?autorizado=1 en la barra de direcciones de su navegador. Como register_globals estaba activado, PHP cogía ese parámetro de la URL y sobreescribía tu variable interna. Un desastre.

Al final, te das cuenta de que dejarle tanto control a la máquina o al usuario siempre acaba mal.

El nuevo paradigma: Bienvenidos a los arrays superglobales

Con la llegada de PHP 4.1.0 nos introdujeron los arrays "superglobales", y desde la versión 4.2.0 (que es la que me acaba de arruinar el sábado), dependemos de ellos por obligación.

El código que antes escribíamos así de alegremente:

<?php
// Código vulnerable de la vieja escuela
if ($usuario == "admin" && $password == "1234") {
    $logueado = true;
}

if ($logueado) {
    echo "Bienvenido a la zona secreta, " . $nombre;
}
?>

Ahora falla porque $usuario, $password y $nombre simplemente no existen si no las declaras tú. Tenemos que ir a buscar explícitamente de dónde vienen esos datos usando $_POST, $_GET, $_SESSION o $_COOKIE.

El código correcto y seguro ahora mismo tiene esta pinta:

<?php
// La nueva forma de trabajar
$usuario = $_POST['usuario'];
$password = $_POST['password'];
$logueado = false; // Siempre inicializar variables

if ($usuario == "admin" && $password == "1234") {
    $logueado = true;
}

if ($logueado) {
    // Escapando siempre el HTML por si acaso
    echo "Bienvenido a la zona secreta, " . htmlentities($_POST['nombre']);
}
?>

Toca remangarse y reescribir

La transición duele, no lo voy a negar. He tenido que abrir el UltraEdit y repasar decenas de archivos buscando variables sueltas para envolverlas en $_POST[].

Algunos en los foros recomiendan meterse en el php.ini o usar un archivo .htaccess y poner php_flag register_globals on para que todo vuelva a funcionar como antes y olvidarse del problema. Te aconsejo que no lo hagas. Si los desarrolladores de PHP han tomado una decisión tan radical que rompe miles de webs en todo el mundo, es porque el problema de seguridad era insostenible.

Tarde o temprano, todos los servidores de alojamiento compartido van a tener esta directiva apagada por motivos de seguridad. Cuanto antes nos acostumbremos a escribir código un poco más verboso pero mucho más seguro, menos disgustos nos llevaremos cuando publiquemos nuestros proyectos en internet. Toca picar código y hacer las cosas bien desde el principio.