Introducción: del pasado al problema actual
\n\nSi alguna vez has programado en PHP y trabajado con bases de datos MySQL, seguro que has visto código como mysql_connect() o mysql_query(). Hace 10 o 15 años, esto era el estándar de facto. Pero los tiempos cambian, y hoy usar las funciones mysql_* es como intentar ejecutar Windows 95 en un MacBook nuevo. Se puede, pero ¿para qué?
En Stack Overflow, la pregunta «Why shouldn't I use mysql_* functions in PHP?» acumula miles de visitas y cientos de votos. No es casualidad: el tema de la seguridad y el enfoque moderno para trabajar con bases de datos es crucial para cualquier desarrollador. En este artículo analizaremos por qué mysql_* no es solo «anticuado», sino francamente peligroso, y mostraremos con qué reemplazarlo.
Problema n.º 1: mysql_* se eliminó por completo en PHP 7
\n\nLa razón más obvia: a partir de PHP 5.5.0, las funciones mysql_* se marcaron como deprecated (obsoletas), y en PHP 7.0 se eliminaron por completo. Si tu servidor se actualiza a PHP 7+, todo el código que use mysql_connect(), mysql_query() y similares simplemente dejará de funcionar. Obtendrás un error fatal:
Fatal error: Call to undefined function mysql_connect()\n\nNo es un «quizá no funcione», es un fallo garantizado del sitio. Por eso, la primera y principal razón es la compatibilidad. Cualquier hosting, tarde o temprano, actualizará PHP y tu proyecto quedará en una zona muerta.
\n\nProblema n.º 2: falta de protección contra inyecciones SQL
\n\nVeamos un código típico con mysql_*:
<?php\n$connection = mysql_connect('localhost', 'usuario', 'contraseña');\nmysql_select_db('mi_base_datos', $connection);\n\n$username = $_POST['username'];\n$password = $_POST['password'];\n\n$query = "SELECT * FROM usuarios WHERE username = '$username' AND password = '$password'";\n$result = mysql_query($query, $connection);\n\nif (mysql_num_rows($result) > 0) {\n echo "¡Bienvenido!";\n} else {\n echo "Usuario o contraseña incorrectos";\n}\n?>\n\n¿Parece inofensivo? Ahora imagina que un atacante introduce en el campo username esta cadena:
admin' OR '1'='1\n\nLa consulta se convierte en:
\n\nSELECT * FROM usuarios WHERE username = 'admin' OR '1'='1' AND password = '...'\n\nY listo: '1'='1' siempre es verdadero, por lo que la consulta devuelve el primer registro de la tabla. El atacante accede al sistema sin contraseña. Esto es una inyección SQL clásica. Las funciones mysql_* no ofrecen ningún mecanismo integrado para escapar datos; tendrías que usar manualmente mysql_real_escape_string(), que también está obsoleto.
Compáralo con los enfoques modernos, donde la protección está integrada en la arquitectura (lo veremos más adelante).
\n\nProblema n.º 3: arquitectura obsoleta y falta de soporte
\n\nmysql_* es una interfaz procedural que no admite:
- \n
- Consultas preparadas (prepared statements) — la principal herramienta contra inyecciones. \n
- Estilo orientado a objetos — en PHP moderno se trabaja con objetos. \n
- Consultas múltiples — no se pueden ejecutar varias sentencias SQL en una sola llamada. \n
- Transacciones — aunque se pueden emular, no hay soporte nativo. \n
- Procedimientos almacenados — trabajar con ellos es muy incómodo. \n
Además, la extensión mysql_* no se actualiza desde 2014. Los desarrolladores de PHP simplemente dejaron de darle soporte. Esto significa que cualquier nueva funcionalidad de bases de datos, mejora de seguridad u optimización te pasa de largo.
¿Qué usar en lugar de mysql_*?
\n\nPHP tiene dos alternativas modernas y con soporte activo: MySQLi y PDO. Ambas ofrecen prepared statements, soporte orientado a objetos y mayor seguridad. En la siguiente sección las compararemos en detalle.