Este ejemplo está diseñado para un nivel básico/intermedio y muestra cómo implementar una conexión segura a bases de datos usando PDO, incluyendo validaciones, manejo de errores y buenas prácticas.
PDO es una capa de abstracción para acceder a bases de datos en PHP que ofrece:
PDO es mejor cuando:
MySQLi es mejor cuando:
Desarrollar una aplicación web que permita:
// Configuración de la conexión PDO <?php // Definimos constantes para la configuración define('DB_HOST', 'localhost'); define('DB_NAME', 'mi_base_datos'); define('DB_USER', 'usuario_seguro'); define('DB_PASS', 'contraseña_compleja'); try { // Creamos la conexión PDO $conn = new PDO( "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ] ); // Verificamos y creamos la tabla si no existe $sql = "CREATE TABLE IF NOT EXISTS usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, fecha_registro DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_email (email) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"; $conn->exec($sql); } catch(PDOException $e) { error_log("Error de conexión: " . $e->getMessage()); die("Ocurrió un error al conectar con la base de datos."); } ?>
<?php if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); exit('Método no permitido'); } header('Content-Type: application/json'); try { require_once 'conexion.php'; $nombre = filter_input(INPUT_POST, 'nombre', FILTER_SANITIZE_STRING); $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); if (empty($nombre) || empty($email)) { throw new Exception('Todos los campos son obligatorios'); } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new Exception('El correo electrónico no es válido'); } $stmt = $conn->prepare("INSERT INTO usuarios (nombre, email) VALUES (:nombre, :email)"); $stmt->bindParam(':nombre', $nombre, PDO::PARAM_STR); $stmt->bindParam(':email', $email, PDO::PARAM_STR); if ($stmt->execute()) { echo json_encode([ 'success' => true, 'message' => 'Usuario registrado correctamente', 'id' => $conn->lastInsertId() ]); } else { throw new Exception('Error al ejecutar la consulta'); } } catch (PDOException $e) { if ($e->getCode() == 23000) { echo json_encode([ 'success' => false, 'message' => 'El correo electrónico ya está registrado' ]); } else { error_log("Error PDO: " . $e->getMessage()); echo json_encode([ 'success' => false, 'message' => 'Error en la base de datos.' ]); } } catch (Exception $e) { echo json_encode([ 'success' => false, 'message' => $e->getMessage() ]); } ?>
document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('registroForm'); const mensajeDiv = document.getElementById('mensaje'); function validarNombre() { const nombre = document.getElementById('nombre').value.trim(); const errorElement = document.getElementById('errorNombre'); if (nombre === '') { errorElement.textContent = 'El nombre es obligatorio'; return false; } else if (nombre.length < 3) { errorElement.textContent = 'El nombre debe tener al menos 3 caracteres'; return false; } else { errorElement.textContent = ''; return true; } } function validarEmail() { const email = document.getElementById('email').value.trim(); const errorElement = document.getElementById('errorEmail'); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (email === '') { errorElement.textContent = 'El correo electrónico es obligatorio'; return false; } else if (!emailRegex.test(email)) { errorElement.textContent = 'Ingresa un correo electrónico válido'; return false; } else { errorElement.textContent = ''; return true; } } form.addEventListener('submit', async function(e) { e.preventDefault(); mensajeDiv.style.display = 'none'; const nombreValido = validarNombre(); const emailValido = validarEmail(); if (!nombreValido || !emailValido) { mostrarMensaje('Por favor, corrige los errores en el formulario', false); return; } const formData = new FormData(form); try { const response = await fetch('registrar_usuario.php', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { mostrarMensaje(data.message, true); form.reset(); } else { mostrarMensaje(data.message, false); } } catch (error) { console.error('Error:', error); mostrarMensaje('Error al conectar con el servidor', false); } }); function mostrarMensaje(texto, esExito) { mensajeDiv.textContent = texto; mensajeDiv.className = 'mensaje ' + (esExito ? 'exito' : 'error-mensaje'); mensajeDiv.style.display = 'block'; mensajeDiv.scrollIntoView({ behavior: 'smooth' }); } });
/** * ARCHIVO COMPLETO DE TUTORIAL PDO PHP * * Este archivo contiene todo el código necesario para el tutorial de conexión a bases de datos * usando PDO en PHP. Incluye la conexión, registro de usuarios y validación. * * Estructura: * 1. Configuración de conexión PDO * 2. Procesamiento del formulario * 3. HTML con formulario * 4. JavaScript para validación */ <?php // ============================================= // SECCIÓN 1: CONFIGURACIÓN DE LA CONEXIÓN PDO // ============================================= define('DB_HOST', 'localhost'); define('DB_NAME', 'mi_base_datos'); define('DB_USER', 'usuario_seguro'); define('DB_PASS', 'contraseña_compleja'); try { // Crear conexión PDO con opciones de configuración $conn = new PDO( "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ] ); // Crear tabla de usuarios si no existe $sql = "CREATE TABLE IF NOT EXISTS usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, fecha_registro DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_email (email) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"; $conn->exec($sql); } catch(PDOException $e) { error_log("Error de conexión: " . $e->getMessage()); die("Ocurrió un error al conectar con la base de datos."); } // ============================================= // SECCIÓN 2: PROCESAMIENTO DEL FORMULARIO // ============================================= if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Content-Type: application/json'); try { // Sanitizar y validar datos de entrada $nombre = filter_input(INPUT_POST, 'nombre', FILTER_SANITIZE_STRING); $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); if (empty($nombre) || empty($email)) { throw new Exception('Todos los campos son obligatorios'); } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new Exception('El correo electrónico no es válido'); } // Insertar usando sentencias preparadas $stmt = $conn->prepare("INSERT INTO usuarios (nombre, email) VALUES (:nombre, :email)"); $stmt->bindParam(':nombre', $nombre, PDO::PARAM_STR); $stmt->bindParam(':email', $email, PDO::PARAM_STR); if ($stmt->execute()) { echo json_encode([ 'success' => true, 'message' => 'Usuario registrado correctamente', 'id' => $conn->lastInsertId() ]); } else { throw new Exception('Error al ejecutar la consulta'); } } catch (PDOException $e) { if ($e->getCode() == 23000) { echo json_encode([ 'success' => false, 'message' => 'El correo electrónico ya está registrado' ]); } else { error_log("Error PDO: " . $e->getMessage()); echo json_encode([ 'success' => false, 'message' => 'Error en la base de datos.' ]); } } catch (Exception $e) { echo json_encode([ 'success' => false, 'message' => $e->getMessage() ]); } exit; } ?> <!-- ============================================= SECCIÓN 3: HTML CON FORMULARIO ============================================= --> <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Registro de Usuarios con PDO</title> <style> /* Estilos CSS para el formulario */ body { font-family: 'Arial', sans-serif; line-height: 1.6; padding: 20px; max-width: 600px; margin: 0 auto; } .form-group { margin-bottom: 15px; } .error { color: red; font-size: 0.9em; } </style> </head> <body> <h1>Registro de Usuarios</h1> <div id="mensaje"></div> <form id="registroForm"> <div class="form-group"> <label for="nombre">Nombre:</label> <input type="text" id="nombre" name="nombre" required> <div id="errorNombre" class="error"></div> </div> <div class="form-group"> <label for="email">Email:</label> <input type="email" id="email" name="email" required> <div id="errorEmail" class="error"></div> </div> <button type="submit">Registrar</button> </form> <!-- ============================================= SECCIÓN 4: JAVASCRIPT PARA VALIDACIÓN ============================================= --> <script> document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('registroForm'); const mensajeDiv = document.getElementById('mensaje'); // Validación en tiempo real document.getElementById('nombre').addEventListener('input', validarNombre); document.getElementById('email').addEventListener('input', validarEmail); function validarNombre() { const nombre = this.value.trim(); const errorElement = document.getElementById('errorNombre'); if (nombre === '') { errorElement.textContent = 'El nombre es obligatorio'; return false; } else if (nombre.length < 3) { errorElement.textContent = 'El nombre debe tener al menos 3 caracteres'; return false; } else { errorElement.textContent = ''; return true; } } function validarEmail() { const email = this.value.trim(); const errorElement = document.getElementById('errorEmail'); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (email === '') { errorElement.textContent = 'El correo electrónico es obligatorio'; return false; } else if (!emailRegex.test(email)) { errorElement.textContent = 'Ingresa un correo electrónico válido'; return false; } else { errorElement.textContent = ''; return true; } } // Envío del formulario con AJAX form.addEventListener('submit', async function(e) { e.preventDefault(); mensajeDiv.style.display = 'none'; const nombreValido = validarNombre.call(document.getElementById('nombre')); const emailValido = validarEmail.call(document.getElementById('email')); if (!nombreValido || !emailValido) { mostrarMensaje('Por favor, corrige los errores en el formulario', false); return; } const formData = new FormData(form); try { const response = await fetch('', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { mostrarMensaje(data.message, true); form.reset(); } else { mostrarMensaje(data.message, false); } } catch (error) { console.error('Error:', error); mostrarMensaje('Error al conectar con el servidor', false); } }); function mostrarMensaje(texto, esExito) { mensajeDiv.textContent = texto; mensajeDiv.className = 'mensaje ' + (esExito ? 'exito' : 'error-mensaje'); mensajeDiv.style.display = 'block'; mensajeDiv.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } }); </script> </body> </html>