3.1MySQL y PDO : conexión y consultas preparadas
Lo esencial en 30 segundos
- PDO es la interfaz moderna : conexión unificada por objetos (new PDO), multibase, errores como excepciones con ERRMODE_EXCEPTION.
- La consulta preparada no es negociable : marcadores :nombre o ?, datos pasados a execute() — la base los trata como datos puros, nunca como código.
- El CRUD se lee en cuatro verbos : INSERT / SELECT / UPDATE / DELETE, resultados vía fetch() (una fila) o fetchAll() (todas).
Mini-caso hilado — Riad salva su tienda de una inyección
Riad, desarrollador web en Constantine, gestiona los pedidos de una tienda concatenando el email introducido en su SELECT — una prueba con una comilla tramposa le devuelve toda la tabla de clientes. Lo reescribe todo en PDO : conexión centralizada en un archivo config.php con ERRMODE_EXCEPTION, consultas prepare() + execute() con marcadores nombrados, fetch/fetchAll para leer. Misma tienda, base ahora impenetrable por ese vector.
Este mismo caso vuelve en el curso, el esquema, el guion y el reto 48h.
1. MySQL, PDO y conexión centralizada
Una aplicación real almacena de forma duradera sus datos : MySQL (o MariaDB), base relacional, organiza los datos en tablas (columnas tipadas), filas (registros), consultadas en SQL : SELECT (leer), INSERT (crear), UPDATE (modificar), DELETE (eliminar) — las cuatro operaciones del CRUD.
El enfoque moderno es PDO (PHP Data Objects) : interfaz unificada y orientada a objetos que funciona con varias bases (portabilidad), consultas preparadas elegantes con marcadores nombrados, y gestión de errores por excepciones en modo PDO::ERRMODE_EXCEPTION (try/catch limpio). Reflejos de Riad : centralizar la conexión (un solo archivo config/conexión reutilizado, nunca una conexión por página) y nunca versionar las credenciales — viven fuera del código (variables de entorno), nunca en duro.
2. Consultas preparadas : prepare + execute, siempre
El peligro : construir SQL concatenando datos de usuario ('SELECT … WHERE email = ' . $email) crea una falla crítica de inyección SQL — el atacante inyecta SQL ejecutado por la base (lectura, modificación, destrucción). La solución es la consulta preparada : se prepara con marcadores (? o nombrados :email) — $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email') — luego se ejecuta pasando los datos por separado — $stmt->execute(['email' => $email]) — y se recupera con fetch() o fetchAll().
La regla es absoluta : toda consulta con datos variables DEBE prepararse ; NUNCA concatenar datos en el SQL. Riad la aplica a todo el CRUD : INSERT de un pedido, SELECT de clientes, UPDATE del estado, DELETE de un borrador — cada execute() recibe sus valores, el SQL solo contiene marcadores.
🔎 Ejemplo concreto — Conexión PDO y SELECT preparado
Riad busca un cliente por email, con total seguridad.
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->prepare('SELECT id, nom, email FROM clients WHERE email = :email');
$stmt->execute(['email' => $emailSaisi]);
$client = $stmt->fetch();
Lectura : conexión con excepciones, marcador :email, datos en execute(), una fila vía fetch().
Lección : incluso con un email tramposo, la base solo ve dato — ningún código ejecutado.
Vocabulario de la sección
- Base de datos / MySQL
- Sistema que almacena datos de forma duradera ; MySQL/MariaDB : base relacional (tablas, filas, columnas) consultada en SQL (SELECT/INSERT/UPDATE/DELETE = CRUD).
Ejemplo sencillo: La tabla de pedidos de la tienda de Riad.
Lo que no es: un array PHP vaciado al final de cada petición.
Reflejo: almacenar en base en cuanto el dato deba perdurar.
- PDO
- PHP Data Objects : interfaz moderna, unificada y orientada a objetos para conectarse a las bases y ejecutar consultas ; multibase, excepciones, marcadores nombrados.
Ejemplo sencillo: La conexión centralizada de Riad con ERRMODE_EXCEPTION.
Lo que no es: las funciones mysql_* obsoletas y eliminadas.
Reflejo: siempre PDO con ERRMODE_EXCEPTION.
- Inyección SQL
- Falla crítica : datos concatenados en el SQL se interpretan como código ejecutado (lectura, modificación, destrucción de la base).
Ejemplo sencillo: La comilla tramposa que vaciaba la tabla de clientes de Riad.
Lo que no es: una simple errata de visualización sin gravedad.
Reflejo: nunca concatenar un dato en SQL.
- Consulta preparada
- Consulta con marcadores (? o :nombre) : prepare() envía el código, execute() envía los datos por separado — la base los trata como datos puros.
Ejemplo sencillo: prepare('… WHERE email = :email') luego execute(['email' => $emailSaisi]).
Lo que no es: una concatenación '…' . $email en la cadena SQL.
Reflejo: prepare + execute para cada consulta con datos variables.
- CRUD / fetch
- Create (INSERT), Read (SELECT), Update (UPDATE), Delete (DELETE) ; lectura vía fetch() (una fila) o fetchAll() (todas).
Ejemplo sencillo: Riad crea, lee, modifica y luego elimina un pedido de prueba.
Lo que no es: un solo SELECT copiado-pegado sin escritura.
Reflejo: dominar los cuatro verbos antes de cualquier framework.
En la práctica — Persistir datos con MySQL y PDO
- Cread una base y una tabla en MySQL (vía phpMyAdmin) ; conectaos desde PHP con PDO (host, base, usuario, contraseña fuera del código).
- Realizad un CRUD con CONSULTAS PREPARADAS : INSERT (crear), SELECT (leer, fetch/fetchAll), UPDATE (modificar), DELETE (eliminar).
- Usad sistemáticamente marcadores (:nombre o ?) y pasad los datos vía execute() — NUNCA concatenación de datos en el SQL.
- Gestionad los errores con try/catch (ERRMODE_EXCEPTION) y verificad que una entrada tramposa ya no rompa nada.
Guion listo para decir — presentar su acceso a base PDO (30 s)
« Los pedidos están en MySQL vía PDO : conexión centralizada con excepciones, CRUD completo en consultas preparadas con marcadores nombrados, lectura en fetch y fetchAll. Probado con una entrada tramposa : la base la trata como un simple dato, la inyección es imposible. »
Para decir en revisión ; mostrar un prepare/execute y la prueba tramposa.
Modelo copiar-pegar — PDO + CRUD preparado
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// CREATE
$stmt = $pdo->prepare('INSERT INTO clients (nom, email) VALUES (:nom, :email)');
$stmt->execute(['nom' => $nom, 'email' => $email]);
// READ
$stmt = $pdo->prepare('SELECT id, nom, email FROM clients WHERE email = :email');
$stmt->execute(['email' => $email]);
$client = $stmt->fetch();
$tous = $pdo->query('SELECT id, nom FROM clients')->fetchAll();
// UPDATE + DELETE
$stmt = $pdo->prepare('UPDATE clients SET nom = :nom WHERE id = :id');
$stmt->execute(['nom' => $nom, 'id' => $id]);
$stmt = $pdo->prepare('DELETE FROM clients WHERE id = :id');
$stmt->execute(['id' => $id]);
Independiente
Un CRUD de clientes en PDO preparado basta para fiabilizar los presupuestos almacenados.
PYME en Constantine
Riad centraliza la conexión de la tienda y prepara cada consulta del back-office.
Equipo de producto
Imponer un archivo de conexión único para consultas coherentes entre módulos.
Principiante
Esta semana : una tabla, una conexión PDO y un SELECT preparado leído en fetch().
✓ Buenas prácticas
- Centralizar la conexión PDO (un solo lugar, reutilizado en todas partes).
- Preparar sistemáticamente : marcadores + execute(), nunca concatenación.
- Activar ERRMODE_EXCEPTION y leer con fetch/fetchAll según la necesidad.
✗ Errores frecuentes
- Concatenar datos en el SQL, aunque sea « solo para probar » (inyección crítica).
- Crear una conexión PDO en cada archivo (duplicación, credenciales dispersas).
- Usar las funciones mysql_* obsoletas en lugar de PDO.
Puntos clave
- Una aplicación real ALMACENA sus datos en una BASE. MySQL/MariaDB (relacional : tablas, filas) consultada en SQL (SELECT/INSERT/UPDATE/DELETE = CRUD).
- PDO = la interfaz MODERNA y segura para conectarse y ejecutar consultas (multibase, excepciones, marcadores nombrados).
- CENTRAL : las CONSULTAS PREPARADAS. Concatenar datos = falla CRÍTICA de INYECCIÓN SQL. Marcadores (:nombre / ?) + datos en execute().
- REGLA ABSOLUTA : toda consulta con datos variables DEBE prepararse ; fetch/fetchAll para leer — competencia central del PHP con base.
Reto 48h — aplica mañana
Conectad 1 PDO con excepciones y haced un CRUD INSERT + SELECT preparados probado con una entrada tramposa.
- Distingo prepare() (código) de execute() (datos).
- Mi CRUD está totalmente preparado, sin concatenación.
- Mi conexión está centralizada, errores en excepciones.
Preguntas frecuentes
¿Qué es la inyección SQL y por qué las consultas preparadas son la solución?
La inyección SQL es un ataque donde datos enviados por el atacante (campo, parámetro de URL) terminan ejecutados como SQL porque los habéis concatenado en la consulta : bypass de login, lectura o destrucción de tablas. La causa : mezclar código y datos en una misma cadena. La consulta preparada separa ambos : prepare() envía el código con marcadores, execute() envía los datos aparte — la base los trata como datos puros, aunque sean tramposos. Es LA protección, para aplicar siempre, sin excepción.
¿Por qué usar PDO y cómo estructurar el acceso a la base?
PDO es el enfoque moderno : abstracción multibase (misma API para MySQL, PostgreSQL…), consultas preparadas elegantes con marcadores nombrados, API orientada a objetos coherente, errores en excepciones (try/catch). Para estructurar : centralizad la conexión (un archivo config/conexión o una clase, reutilizado en todas partes), credenciales fuera del repositorio (entorno), y reutilizad el mismo PDO en todo el código — fin de la conexión recreada por página.
¿Qué separa una consulta preparada PDO?