3.1 · MySQL y PDO : conexión y consultas preparadas

Nivel 3 · Bases de datos & POO

3.1MySQL y PDO : conexión y consultas preparadas

Objetivo: persistir datos con MySQL y PDO : conexión, CRUD completo con consultas preparadas, recuperación de resultados — el paso que transforma un sitio en una aplicación real y segura.
Tiempo estimado: 13 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

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.

Error frecuente de interpretación: « Las consultas preparadas solo sirven para formularios, y concatenar saca del apuro en pruebas ». No. Todo dato variable (formulario, URL, cookie, importación) concatenado abre una inyección, y el código « de prueba » siempre termina en producción. Prepare + execute se aplica a cada consulta con datos, sin excepción.
La consulta preparada PDO El código y los datos viajan por separado Conexión PDO Centralizada,ERRMODE_EXCEPTIONprepare() SQL conmarcadores :nombreexecute() Datos pasadospor separadofetch / fetchAll Resultadosleídos con seguridad
El código y los datos viajan por separado
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Conexión : Riad centraliza su PDO con excepciones activadas, credenciales fuera del código. 2) Preparación : su SELECT lleva un marcador :email, sin ningún dato dentro. 3) Ejecución : el email introducido va en execute(), tratado como dato puro aunque contenga SQL tramposo. 4) Lectura : fetch() devuelve la fila. Lección : separar código y datos hace imposible la inyección.

🔎 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

  1. 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).
  2. Realizad un CRUD con CONSULTAS PREPARADAS : INSERT (crear), SELECT (leer, fetch/fetchAll), UPDATE (modificar), DELETE (eliminar).
  3. Usad sistemáticamente marcadores (:nombre o ?) y pasad los datos vía execute() — NUNCA concatenación de datos en el SQL.
  4. Gestionad los errores con try/catch (ERRMODE_EXCEPTION) y verificad que una entrada tramposa ya no rompa nada.
Persistís datos con MySQL y PDO : conexión, CRUD completo con CONSULTAS PREPARADAS (seguridad), recuperación de resultados — el paso que transforma un sitio en una aplicación real y segura.

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.

Lista de salida de la sección
  • Distingo prepare() (código) de execute() (datos).
  • Mi CRUD está totalmente preparado, sin concatenación.
  • Mi conexión está centralizada, errores en excepciones.
Autoevaluación 1-5 : ¿está preparada cada consulta con datos variables?¿están mis credenciales fuera del código versionado?

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.

Comprueba tu comprensión

¿Qué separa una consulta preparada PDO?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 3Preguntas inéditas y más difíciles para validar tus conocimientos