PHP con MySQL: PDO, CRUD y consultas seguras paso a paso
PHP y MySQL permiten construir aplicaciones web capaces de guardar, consultar, modificar y eliminar información de forma persistente. La forma correcta de aprender esta combinación no consiste en concatenar consultas SQL dentro de archivos PHP: necesitas comprender PDO, consultas preparadas, relaciones, transacciones, validación, errores y una estructura de aplicación mantenible.
¿Cómo se conecta PHP con MySQL?
Una forma moderna de conectar PHP con MySQL es mediante PDO.
PDO permite abrir una conexión, preparar consultas SQL, enviar parámetros, ejecutar instrucciones y recuperar resultados.
Para trabajar correctamente deberías aprender al menos: SELECT, INSERT, UPDATE, DELETE, consultas preparadas, transacciones, relaciones e índices.
Y desde PHP necesitas comprender validación, excepciones, separación de responsabilidades y seguridad.
PHP y MySQL implican mucho más que abrir una conexión
PDO
Conexión, consultas y manejo de errores.
CRUD
Crear, consultar, modificar y eliminar datos.
Seguridad
Parámetros, validación y consultas preparadas.
Relaciones
Conectar usuarios, pedidos, productos y otras entidades.
Transacciones
Ejecutar varias operaciones como una unidad.
Rendimiento
Índices, paginación y consultas eficientes.
MySQL permite que los datos sobrevivan después de terminar una solicitud PHP
Una variable PHP existe durante la ejecución de un programa.
Cuando termina esa solicitud, esa variable no se convierte automáticamente en información permanente.
Una base de datos resuelve otro problema
Permite almacenar usuarios, productos, publicaciones, pedidos, mensajes, configuraciones y muchas otras entidades.
PHP puede encargarse de las reglas de la aplicación mientras MySQL mantiene los datos.
PHP ejecuta lógica. MySQL organiza y consulta información persistente.
Aprende SQL además de aprender PHP
Un error habitual es aprender únicamente cómo ejecutar consultas desde PHP.
Eso puede funcionar mientras los ejemplos sean sencillos, pero limita rápidamente tu capacidad para diseñar sistemas.
SELECT
Recupera información.
INSERT
Crea nuevos registros.
UPDATE
Modifica información existente.
DELETE
Elimina registros.
JOIN
Permite combinar información relacionada de varias tablas.
PHP ejecuta estas consultas, pero SQL sigue siendo un lenguaje que necesitas comprender por separado.
Empecemos con una tabla de usuarios
CREATE TABLE usuarios (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(120) NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
activo TINYINT(1) NOT NULL DEFAULT 1,
creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
id identifica cada registro
Una clave primaria proporciona una referencia única para cada usuario.
email tiene una restricción UNIQUE
Eso ayuda a impedir que se almacenen dos usuarios con el mismo email.
No guardamos la contraseña como texto
Guardamos un hash producido desde PHP mediante funciones diseñadas específicamente para contraseñas.
Crear una conexión PDO con MySQL
<?php
$dsn = 'mysql:host=localhost;dbname=ciborg;charset=utf8mb4';
$pdo = new PDO(
$dsn,
$usuarioDb,
$passwordDb,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
utf8mb4
Permite trabajar correctamente con un conjunto amplio de caracteres.
ERRMODE_EXCEPTION
Hace que determinados errores de base de datos generen excepciones, facilitando su manejo.
FETCH_ASSOC
Hace que los resultados se recuperen por defecto como arrays asociativos.
Configuración, secretos y credenciales deberían mantenerse fuera de archivos expuestos públicamente.
La aplicación debe manejar errores sin revelar información sensible
Durante desarrollo, un error detallado puede ayudarte a encontrar el problema.
En producción, mostrar credenciales, rutas internas o consultas completas puede ser peligroso.
<?php
try {
$pdo = new PDO(
$dsn,
$usuarioDb,
$passwordDb,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
);
} catch (PDOException $e) {
error_log($e->getMessage());
exit(
'No fue posible conectar con la base de datos.'
);
}
El usuario recibe un mensaje controlado, mientras el detalle técnico puede registrarse internamente.
INSERT: guardar un registro utilizando una consulta preparada
<?php
$sql = "
INSERT INTO usuarios (
nombre,
email,
password_hash
)
VALUES (
:nombre,
:email,
:password_hash
)
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'nombre' => $nombre,
'email' => $email,
'password_hash' => $passwordHash,
]);
Los parámetros van separados de la consulta
Los valores no se concatenan directamente dentro del SQL.
La contraseña debe convertirse primero en hash
<?php
$passwordHash = password_hash(
$password,
PASSWORD_DEFAULT
);
Nunca necesitas recuperar la contraseña original desde la base de datos.
SELECT: recuperar información
<?php
$sql = "
SELECT
id,
nombre,
email,
activo,
creado_en
FROM usuarios
ORDER BY creado_en DESC
";
$stmt = $pdo->query($sql);
$usuarios = $stmt->fetchAll();
Después puedes recorrer los resultados
<?php foreach ($usuarios as $usuario): ?>
<p>
<?php echo htmlspecialchars(
$usuario['nombre'],
ENT_QUOTES,
'UTF-8'
); ?>
</p>
<?php endforeach; ?>
Son problemas diferentes y ambos deben considerarse.
Buscar un usuario por email
<?php
$sql = "
SELECT
id,
nombre,
email,
password_hash,
activo
FROM usuarios
WHERE email = :email
LIMIT 1
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'email' => $email
]);
$usuario = $stmt->fetch();
Este patrón aparece constantemente en login, perfiles, búsquedas y comprobaciones de existencia.
UPDATE: modificar información existente
<?php
$sql = "
UPDATE usuarios
SET
nombre = :nombre,
email = :email
WHERE id = :id
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'nombre' => $nombre,
'email' => $email,
'id' => $id,
]);
WHERE es fundamental
Una actualización sin una condición adecuada puede afectar muchos registros.
Antes de ejecutar operaciones destructivas, verifica cuidadosamente qué registros deben modificarse.
DELETE: eliminar información de manera controlada
<?php
$sql = "
DELETE FROM usuarios
WHERE id = :id
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'id' => $id
]);
Técnicamente es sencillo; conceptualmente puede no serlo
En una aplicación real debes decidir qué ocurre con información relacionada.
Por ejemplo: ¿qué ocurre con pedidos, comentarios, archivos o auditorías asociados al usuario?
La estructura de la base de datos importa tanto como la consulta PHP.
No construyas SQL concatenando directamente datos del usuario
Este tipo de código debería evitarse:
<?php
$sql = "
SELECT *
FROM usuarios
WHERE email = '" . $_POST['email'] . "'
";
La información recibida está entrando directamente en la estructura de la consulta.
Utiliza parámetros
<?php
$sql = "
SELECT *
FROM usuarios
WHERE email = :email
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'email' => $email
]);
También necesitas validar datos, controlar permisos, proteger formularios y escapar correctamente la salida.
Antes de guardar información, valida que tenga sentido
Una consulta preparada evita mezclar datos con SQL, pero no puede saber qué reglas necesita tu negocio.
Debe tener un formato aceptable.
Precio
Puede necesitar ser mayor o igual a cero.
Estado
Puede pertenecer solamente a un conjunto de valores permitidos.
<?php
$email = filter_input(
INPUT_POST,
'email',
FILTER_VALIDATE_EMAIL
);
if ($email === false || $email === null) {
exit('Email inválido');
}
Las aplicaciones reales suelen tener varias tablas relacionadas
Imagina un ecommerce.
Un usuario puede tener muchos pedidos.
Un pedido puede contener varios productos.
Los productos pueden pertenecer a categorías.
Claves foráneas
CREATE TABLE pedidos (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
usuario_id BIGINT UNSIGNED NOT NULL,
total DECIMAL(12,2) NOT NULL,
estado VARCHAR(50) NOT NULL,
creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_pedidos_usuario
FOREIGN KEY (usuario_id)
REFERENCES usuarios(id)
);
Ahora cada pedido puede relacionarse con un usuario mediante usuario_id.
Combinar información relacionada con JOIN
SELECT
pedidos.id,
pedidos.total,
pedidos.estado,
usuarios.nombre,
usuarios.email
FROM pedidos
INNER JOIN usuarios
ON usuarios.id = pedidos.usuario_id
ORDER BY pedidos.creado_en DESC;
Con una sola consulta podemos obtener información del pedido junto con datos del usuario relacionado.
Aquí SQL empieza a demostrar por qué debe aprenderse de verdad
Las aplicaciones rara vez consisten en una única tabla aislada.
Algunas operaciones deben completarse juntas o no completarse
Imagina una compra.
Necesitas crear un pedido, guardar sus productos y quizás descontar stock.
Si una operación falla en medio, no quieres dejar la base en un estado incoherente.
<?php
try {
$pdo->beginTransaction();
// 1. Crear pedido.
// 2. Insertar productos del pedido.
// 3. Actualizar stock.
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
throw $e;
}
commit confirma
Los cambios se guardan como una unidad.
rollBack revierte
Si algo falla, puedes deshacer los cambios realizados dentro de la transacción.
Pedidos, pagos, inventario y movimientos financieros son ejemplos típicos.
No cargues miles de registros cuando solamente necesitas mostrar veinte
En un proyecto pequeño, fetchAll() puede parecer siempre suficiente.
Pero una tabla puede crecer hasta cientos de miles de registros.
Utiliza paginación
SELECT
id,
nombre,
email
FROM usuarios
ORDER BY id DESC
LIMIT 20
OFFSET 40;
Aquí se solicitan solamente veinte registros, comenzando después de los primeros cuarenta.
Para grandes volúmenes también existen estrategias de paginación basadas en cursores o claves.
Los índices pueden acelerar búsquedas, pero no deberían añadirse al azar
Si constantemente buscas usuarios por email, tener ese campo correctamente indexado puede mejorar las consultas.
PRIMARY KEY ya crea una estructura útil para id
Las claves principales suelen utilizarse constantemente para localizar registros.
UNIQUE también puede servir como índice
En nuestro ejemplo, email necesita ser único.
Más índices no significa automáticamente más velocidad
También tienen coste de almacenamiento y mantenimiento durante escrituras.
Debes diseñarlos según consultas reales.
Evita realizar una consulta adicional por cada fila cuando puedes resolver mejor el problema
Imagina que recuperas cien pedidos.
Después, por cada pedido, haces otra consulta para buscar el usuario.
Terminarías ejecutando una consulta inicial más cien adicionales.
Una combinación bien diseñada puede reducir ese trabajo
JOIN, consultas agrupadas u otras estrategias pueden evitar consultas repetitivas.
Rendimiento backend también exige comprender qué está haciendo la base de datos.
No distribuyas consultas SQL por cada archivo HTML de la aplicación
En un CRUD de aprendizaje puede parecer cómodo escribir consultas directamente donde muestras la interfaz.
Cuando el proyecto crece, esa organización se vuelve difícil de mantener.
Separa acceso a datos
Centraliza las operaciones relacionadas con persistencia.
Separa reglas de negocio
Determinar si un usuario puede cancelar un pedido es una regla, no una consulta SQL.
Separa presentación
Generar HTML debería ser una responsabilidad distinta de actualizar una base de datos.
Una clase puede concentrar las operaciones de usuarios
<?php
final class UsuarioRepository
{
public function __construct(
private PDO $pdo
) {}
public function buscarPorEmail(
string $email
): ?array {
$sql = "
SELECT
id,
nombre,
email,
activo
FROM usuarios
WHERE email = :email
LIMIT 1
";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([
'email' => $email
]);
$usuario = $stmt->fetch();
return $usuario ?: null;
}
}
Esto no significa que todo proyecto necesite exactamente un patrón Repository.
Lo importante es reconocer que acceso a datos constituye una responsabilidad que puede separarse.
Construye un CRUD completo para aprender PHP con MySQL
Crear tabla
Define columnas, tipos y restricciones.
Conectar PDO
Configura conexión y errores.
Crear registro
Formulario, validación e INSERT.
Listar datos
SELECT y paginación.
Editar
Buscar por id y ejecutar UPDATE.
Eliminar
DELETE con autorización y confirmación.
Login
Contraseñas, usuarios y sesiones.
Roles
Añade autorización.
Relaciones
Añade una segunda entidad relacionada.
Refactoriza
Separa datos, lógica y presentación.
PHP y MySQL pueden convertirse en la base de muchos tipos de sistemas
Directorio
Negocios, categorías, búsquedas y usuarios.
Ecommerce
Productos, clientes, pedidos y stock.
Reservas
Clientes, horarios, disponibilidad y estados.
Cotizaciones
Solicitudes, propuestas, profesionales y estados.
SaaS
Usuarios, planes, consumo y suscripciones.
Panel interno
Administración, reportes y procesos.
PHP puede utilizar MySQL como base para sistemas completos
Explora otros proyectos que puedes desarrollar con el lenguaje.
Comprender SQL y bases de datos también mejora tu nivel como desarrollador WordPress
WordPress almacena gran parte de su información en una base de datos relacional.
Sin embargo, cuando desarrollas dentro de WordPress, no deberías saltar automáticamente a consultas SQL personalizadas.
Utiliza primero las APIs disponibles
Posts, usuarios, metadata y opciones disponen de funciones específicas.
Usa $wpdb cuando realmente necesitas acceso SQL
En ese contexto, conceptos como parámetros, índices, relaciones y rendimiento siguen siendo muy importantes.
Lleva tus conocimientos PHP y SQL al desarrollo WordPress
Hooks, plugins, $wpdb, REST API y WooCommerce.
PHP puede convertir información de MySQL en una API
Una aplicación móvil, frontend JavaScript u otro sistema no necesita conectarse directamente a MySQL.
PHP puede actuar como capa intermedia.
<?php
$stmt = $pdo->query(
"SELECT id, nombre FROM productos"
);
$productos = $stmt->fetchAll();
header(
'Content-Type: application/json; charset=utf-8'
);
echo json_encode(
$productos,
JSON_UNESCAPED_UNICODE
);
En una API real también necesitarías routing, autenticación, autorización, validación, errores y códigos HTTP.
Explorar APIs e integraciones →Qué evitar al trabajar con PHP y MySQL
En qué orden aprender PHP con MySQL
PHP básico
Variables, funciones, arrays y errores.
SQL básico
SELECT, INSERT, UPDATE y DELETE.
Diseño de tablas
Tipos, claves y restricciones.
PDO
Conexión y consultas.
Prepared statements
Parámetros y seguridad SQL.
CRUD
Integra PHP, formularios y datos.
Relaciones
Claves foráneas y JOIN.
Transacciones
Operaciones consistentes.
Rendimiento
Índices y paginación.
Arquitectura
Separa datos, negocio e interfaz.
Aprender PHP con MySQL significa aprender a diseñar datos, no solo ejecutar consultas
Aprende SQL por separado.
Conecta PHP mediante PDO.
Utiliza consultas preparadas para datos dinámicos.
Practica INSERT, SELECT, UPDATE y DELETE.
Aprende relaciones y JOIN cuando tu aplicación tenga varias entidades.
Utiliza transacciones cuando varias operaciones deban completarse juntas.
Añade índices y paginación cuando los datos comiencen a crecer.
Y cuando tu proyecto aumente de tamaño, separa la persistencia de la lógica y la presentación.
Continúa avanzando por PHP
Preguntas sobre PHP con MySQL
Puedes utilizar PDO para crear una conexión entre PHP y MySQL. Después puedes preparar y ejecutar consultas SQL, enviar parámetros y recuperar resultados.
PDO es una interfaz de acceso a bases de datos disponible en PHP. Permite crear conexiones, preparar consultas, ejecutar instrucciones y recuperar resultados mediante una API consistente.
CRUD representa Create, Read, Update y Delete: las cuatro operaciones básicas para crear, consultar, modificar y eliminar información almacenada en una base de datos.
Las consultas preparadas permiten separar los datos de la estructura SQL. Son especialmente importantes cuando una consulta utiliza valores provenientes de formularios, URLs u otras fuentes externas.
Sí, es muy recomendable. PDO permite ejecutar consultas, pero necesitas comprender SQL para diseñarlas, trabajar con relaciones, utilizar JOIN, optimizar consultas y modelar correctamente la información.
Una transacción agrupa varias operaciones para que puedan confirmarse conjuntamente o revertirse si alguna falla. Resultan importantes en procesos como pedidos, pagos o movimientos de inventario.
Sí, pueden formar parte de aplicaciones grandes. La capacidad de escalar dependerá también del diseño de base de datos, arquitectura, índices, consultas, infraestructura y necesidades del proyecto.
WordPress utiliza PHP en el servidor y almacena gran parte de su información en una base de datos. Para desarrollo WordPress conviene utilizar primero las APIs de la plataforma y recurrir a consultas personalizadas cuando sea necesario.
Construye un CRUD completo y entenderás por qué PHP y MySQL aparecen juntos en tantas aplicaciones
Diseña una tabla, conecta PDO, utiliza consultas preparadas, crea un CRUD y después añade usuarios, relaciones, transacciones y paginación. Esa base te servirá para construir sistemas mucho mayores.
Continuar con la guía PHP →