Tutorial 10: Conectando PHP con la Base de Datos MySQL

 

Tutorial 10: Conectando PHP con la Base de Datos MySQL

¡Hola y bienvenido de nuevo!

En esta lección vamos a crear una clase PHP que nos permita conectar con nuestra base de datos MySQL. Esta conexión es fundamental para poder guardar y recuperar la información de los archivos que subamos. ¡Vamos a ello!


📋 Contenido del Tutorial

  1. ¿Qué es PDO y por qué usarlo?

  2. Creando la clase DB

  3. El método connect

  4. Manejando errores con try-catch

  5. El constructor en Whisper

  6. Probando la conexión

  7. Código completo

  8. Explicación detallada

  9. Próximos pasos


🔌 1. ¿Qué es PDO y por qué usarlo?

¿Qué es PDO?

PDO (PHP Data Objects) es una extensión de PHP que proporciona una interfaz consistente para acceder a diferentes bases de datos.

Beneficios de PDO

BeneficioExplicación
SeguridadPreviene inyecciones SQL mediante prepared statements
PortabilidadFunciona con MySQL, PostgreSQL, SQLite, etc.
Orientado a objetosUsa clases y métodos, no funciones sueltas
Manejo de erroresMejor gestión de excepciones
Prepared statementsConsultas más seguras y eficientes

Comparación con otras opciones

OpciónVentajasDesventajas
PDOSeguro, portable, orientado a objetosCurva de aprendizaje
MySQLiSoporte nativo para MySQLSolo funciona con MySQL
mysql_*SimpleObsoleto, inseguro

📁 2. Creando la clase DB

Estructura del archivo

Creamos un nuevo archivo en backend/classes/DB.php:

text
whisper/
├── backend/
│   ├── init.php
│   └── classes/
│       ├── DB.php        # ¡Nuevo archivo!
│       └── Whisper.php
├── files/
├── frontend/
└── index.php

Clase DB básica

php
<?php
class DB {
    public function connect() {
        // Código de conexión
    }
}
?>

🔗 3. El método connect

Sintaxis de conexión PDO

php
new PDO('mysql:host=localhost;dbname=MyWhisper', 'root', '');

Desglose de la conexión

ParteDescripciónEjemplo
mysql:Tipo de base de datosMySQL
host=localhostServidor de la base de datoslocalhost
dbname=MyWhisperNombre de la base de datosMyWhisper
'root'Usuario de la base de datosroot
''Contraseña (vacía por defecto en XAMPP)(sin contraseña)

El método connect completo

php
public function connect() {
    try {
        $db = new PDO('mysql:host=localhost;dbname=MyWhisper', 'root', '');
        return $db;
    } catch(PDOException $error) {
        echo 'Connection Failed: ' . $error;
    }
}

🛡️ 4. Manejando errores con try-catch

¿Qué es try-catch?

try-catch es una estructura de control que nos permite manejar errores de forma elegante:

php
try {
    // Código que puede generar un error
    $db = new PDO(...);
} catch(PDOException $error) {
    // Código que se ejecuta si hay un error
    echo 'Connection Failed: ' . $error;
}

Flujo de try-catch

text
1. Se ejecuta el código dentro de try
   ↓
2. Si ocurre un error → Se salta a catch
   ↓
3. catch captura el error y lo maneja
   ↓
4. El programa continúa (no se detiene)

Posibles errores de conexión

ErrorCausaSolución
Unknown databaseLa base de datos no existeCrear la base de datos
Access deniedUsuario o contraseña incorrectosVerificar credenciales
Can't connectMySQL no está corriendoIniciar MySQL en XAMPP

🏗️ 5. El constructor en Whisper

¿Qué es un constructor?

Un constructor es un método especial que se ejecuta automáticamente cuando se crea un objeto de la clase.

php
class MiClase {
    public function __construct() {
        echo "¡El objeto ha sido creado!";
    }
}

$obj = new MiClase(); // Muestra: "¡El objeto ha sido creado!"

¿Por qué usar un constructor?

  • ✅ Inicializar propiedades

  • ✅ Conectar a la base de datos

  • ✅ Configurar el objeto

  • ✅ Cargar configuraciones

El constructor en Whisper

php
class Whisper {
    private $DB; // Propiedad privada para la conexión
    
    public function __construct() {
        $db = new DB();
        $this->DB = $db->connect();
    }
}

Explicación paso a paso

php
// 1. Crear una instancia de la clase DB
$db = new DB();

// 2. Llamar al método connect()
$connection = $db->connect();

// 3. Almacenar la conexión en la propiedad privada
$this->DB = $connection;

Propiedad privada

php
private $DB;
  • private significa que solo se puede acceder desde dentro de la clase

  • Es una buena práctica para proteger datos sensibles

  • $DB almacena la conexión a la base de datos


🧪 6. Probando la conexión

Prueba 1: Conexión exitosa

Escenario: La base de datos MyWhisper existe

Resultado esperado:

text
Connected

Código de prueba:

php
class Whisper {
    public function __construct() {
        $db = new DB();
        $this->DB = $db->connect();
        echo "Connected"; // Solo para prueba
    }
}

Prueba 2: Error de conexión

Escenario: La base de datos no existe

Resultado esperado:

text
Connection Failed: SQLSTATE[HY000] [1049] Unknown database 'MyWhisper'

Causa: Cambiamos el nombre de la base de datos a uno que no existe

Prueba 3: Error de credenciales

Escenario: Usuario o contraseña incorrectos

Resultado esperado:

text
Connection Failed: SQLSTATE[HY000] [1045] Access denied for user

💻 7. Código completo

Archivo: backend/classes/DB.php

php
<?php
/**
 * Clase DB - Conexión a la base de datos
 * 
 * Esta clase maneja la conexión a MySQL usando PDO
 */
class DB {
    /**
     * Conecta a la base de datos MySQL
     * 
     * @return PDO|false Objeto PDO con la conexión o false en caso de error
     */
    public function connect() {
        try {
            // Configuración de la conexión
            $host = 'localhost';
            $dbname = 'MyWhisper';
            $username = 'root';
            $password = '';
            
            // Crear la conexión PDO
            $db = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
            
            // Configurar el modo de errores
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            
            // Configurar el charset
            $db->exec("SET NAMES utf8mb4");
            
            return $db;
            
        } catch(PDOException $error) {
            // Mostrar el error de conexión
            echo 'Connection Failed: ' . $error->getMessage();
            return false;
        }
    }
}
?>

Archivo: backend/init.php

php
<?php
/**
 * Archivo de inicialización de la aplicación
 * Carga todas las clases necesarias
 */

// Cargar las clases
require 'classes/DB.php';
require 'classes/Whisper.php';

// Crear la instancia de Whisper
$whisperObj = new Whisper();

// La conexión a la base de datos se establece automáticamente
// en el constructor de Whisper
?>

Archivo: backend/classes/Whisper.php

php
<?php
/**
 * Clase Whisper
 * 
 * Maneja la subida y procesamiento de archivos
 */
class Whisper {
    /**
     * @var string Mensajes de error
     */
    public $error;
    
    /**
     * @var PDO Conexión a la base de datos
     */
    private $DB;
    
    /**
     * Constructor - Se ejecuta al crear el objeto
     * Establece la conexión a la base de datos
     */
    public function __construct() {
        // Crear una instancia de la clase DB
        $db = new DB();
        
        // Conectar a la base de datos
        $this->DB = $db->connect();
        
        // (Opcional) Verificar la conexión
        if ($this->DB) {
            // echo "Conexión exitosa a la base de datos";
        }
    }
    
    /**
     * Sube un archivo al servidor
     * 
     * @param array $file Arreglo $_FILES
     * @return string|false Ruta del archivo o false en caso de error
     */
    public function upload($file) {
        // 1. Extraer información del archivo
        $fileTmp  = $file['tmp_name'];
        $filename = basename($file['name']);
        $fileSize = $file['size'];
        $errors   = $file['error'];
        $mime     = $file['type'];
        
        // 2. Obtener la extensión del archivo
        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $ext = strtolower($ext);
        
        // 3. Obtener el directorio raíz del proyecto
        $parentDirectory = dirname(dirname(dirname(__FILE__)));
        
        // 4. Definir los tipos de archivo permitidos
        $allowedMedia = [
            'video/mp4',
            'video/mpeg',
            'audio/mpeg',
            'audio/mpeg3',
            'audio/wav'
        ];
        
        // 5. Validar el tipo de archivo
        if (!in_array($mime, $allowedMedia)) {
            $this->error = "Formato de archivo inválido";
            return false;
        }
        
        // 6. Validar el tamaño del archivo (máximo 20 MB)
        if ($fileSize > 20000000) {
            $this->error = "El archivo es demasiado grande (máximo 20 MB)";
            return false;
        }
        
        // 7. Crear nombre único y subir el archivo
        $folder = 'files/';
        $uniqueName = md5(time() . mt_rand());
        $file = $folder . $uniqueName . '.' . $ext;
        
        // 8. Mover el archivo
        if (move_uploaded_file($fileTmp, $parentDirectory . '/' . $file)) {
            return $file; // Éxito
        } else {
            $this->error = "Error al mover el archivo";
            return false;
        }
    }
    
    /**
     * Guarda la información del archivo en la base de datos
     * 
     * @param string $fileUrl Ruta del archivo
     * @param string $type Tipo de archivo (audio/video)
     * @return int|false ID del registro insertado o false en caso de error
     */
    public function saveFileInfo($fileUrl, $type) {
        try {
            // Preparar la consulta SQL
            $sql = "INSERT INTO files (fileUrl, type) VALUES (:fileUrl, :type)";
            $stmt = $this->DB->prepare($sql);
            
            // Ejecutar la consulta con los parámetros
            $stmt->execute([
                ':fileUrl' => $fileUrl,
                ':type' => $type
            ]);
            
            // Retornar el ID del registro insertado
            return $this->DB->lastInsertId();
            
        } catch(PDOException $error) {
            $this->error = "Error al guardar en la base de datos: " . $error->getMessage();
            return false;
        }
    }
}
?>

Archivo: index.php (sección PHP actualizada)

php
<?php
    // Cargar la configuración inicial
    include 'backend/init.php';
    
    // Variables para mensajes
    $error = null;
    $success = null;
    
    // Verificar si la solicitud es POST
    if ($_SERVER['REQUEST_METHOD'] === "POST") {
        
        // Verificar si el archivo está presente
        if (isset($_FILES['file'])) {
            
            // Verificar que no esté vacío
            if (!empty($_FILES['file']['name'])) {
                
                // Procesar el archivo con la clase Whisper
                $file = $whisperObj->upload($_FILES['file']);
                
                if ($file) {
                    // Determinar el tipo de archivo
                    $mime = $_FILES['file']['type'];
                    $type = strpos($mime, 'video/') === 0 ? 'video' : 'audio';
                    
                    // Guardar en la base de datos
                    $id = $whisperObj->saveFileInfo($file, $type);
                    
                    if ($id) {
                        $success = "¡Archivo subido correctamente! ID: " . $id;
                        // Redirigir a la vista
                        // header("Location: view.php?id=" . $id);
                        // exit;
                    } else {
                        $error = $whisperObj->error;
                    }
                    
                } else {
                    // Error: obtener el mensaje de error
                    $error = $whisperObj->error;
                }
                
            } else {
                $error = "Por favor selecciona un archivo para convertir a texto";
            }
            
        } else {
            $error = "Por favor selecciona un archivo para convertir a texto";
        }
    }
?>

📖 8. Explicación detallada

Flujo de la conexión

text
1. index.php incluye backend/init.php
   ↓
2. init.php requiere DB.php y Whisper.php
   ↓
3. init.php crea $whisperObj = new Whisper()
   ↓
4. El constructor de Whisper se ejecuta automáticamente
   ↓
5. Constructor crea $db = new DB()
   ↓
6. Constructor llama a $db->connect()
   ↓
7. connect() intenta conectar con PDO
   ↓
8. Si funciona → Retorna el objeto PDO
   ↓
9. Si falla → Muestra error y retorna false
   ↓
10. La conexión queda almacenada en $this->DB

Configuración adicional de PDO

php
// Modo de errores: lanzar excepciones
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Configurar charset
$db->exec("SET NAMES utf8mb4");
ConfiguraciónPropósito
ATTR_ERRMODECómo manejar los errores de PDO
ERRMODE_EXCEPTIONLanzar excepciones para cada error
SET NAMES utf8mb4Usar codificación UTF-8 completa

Métodos PDO importantes

MétodoPropósitoEjemplo
prepare()Prepara una consulta SQL$stmt = $db->prepare("SELECT ...")
execute()Ejecuta una consulta preparada$stmt->execute([':id' => 1])
fetch()Obtiene una fila de resultados$row = $stmt->fetch()
fetchAll()Obtiene todas las filas$rows = $stmt->fetchAll()
lastInsertId()Obtiene el último ID insertado$id = $db->lastInsertId()

🧪 9. Probando la conexión

Paso 1: Verificar MySQL en XAMPP

  1. Abre el Panel de Control de XAMPP

  2. Asegúrate de que MySQL esté en verde (corriendo)

  3. Si no está corriendo, haz clic en "Start"

Paso 2: Verificar la base de datos

  1. Ve a http://localhost/phpmyadmin/

  2. Busca MyWhisper en la lista de bases de datos

  3. Verifica que la tabla files exista

Paso 3: Probar la conexión

  1. Abre http://localhost/whisper/

  2. Si todo funciona, no verás mensajes de error

  3. Si hay problemas, verás mensajes de error de conexión

Paso 4: Probar la subida con base de datos

  1. Selecciona un archivo

  2. El archivo se subirá a files/

  3. La información se guardará en la base de datos

  4. Verás un mensaje de éxito con el ID


📊 10. Mensajes de error comunes

Error: "Unknown database 'MyWhisper'"

Causa: La base de datos no existe
Solución: Crear la base de datos en phpMyAdmin

Error: "Access denied for user 'root'@'localhost'"

Causa: Contraseña incorrecta o usuario incorrecto
Solución: Verificar credenciales en la conexión

Error: "Connection Failed: SQLSTATE[HY000] [2002]"

Causa: MySQL no está corriendo
Solución: Iniciar MySQL en XAMPP

Error: "Class 'PDO' not found"

Causa: La extensión PDO no está habilitada
Solución: Habilitar PDO en php.ini


🎯 11. Próximos pasos

Lo que hemos logrado

✅ Clase DB para conectar a MySQL
✅ Uso de PDO para conexiones seguras
✅ Manejo de errores con try-catch
✅ Constructor en Whisper para conexión automática
✅ Guardado de información en la base de datos

Lo que viene en la próxima lección

En la siguiente lección vamos a:

  1. Mostrar la lista de archivos subidos

  2. Crear la página de vista para ver transcripciones

  3. Recuperar datos de la base de datos

  4. Mostrar el reproductor de audio/video

Avance del código de la próxima lección

php
// En Whisper.php
public function getFiles() {
    $sql = "SELECT * FROM files ORDER BY ID DESC";
    $stmt = $this->DB->prepare($sql);
    $stmt->execute();
    return $stmt->fetchAll();
}

// En view.php
$files = $whisperObj->getFiles();
foreach ($files as $file) {
    echo '<li>' . $file['fileUrl'] . '</li>';
}

❓ Preguntas frecuentes

¿Qué es PDO y por qué usarlo en lugar de MySQLi?

  • PDO es una capa de abstracción que funciona con múltiples bases de datos

  • Es más seguro y moderno que las funciones mysql_*

¿Qué significa private $DB;?

  • private significa que la propiedad solo es accesible dentro de la clase

  • $DB almacena el objeto de conexión a la base de datos

¿Por qué usamos try-catch?

  • Para manejar errores de forma elegante

  • Evita que la aplicación se detenga inesperadamente

¿Qué es __construct()?

  • Es un método especial que se ejecuta al crear un objeto

  • Se usa para inicializar propiedades o establecer conexiones

¿Cómo sé si la conexión fue exitosa?

  • Si $db->connect() retorna un objeto PDO, la conexión fue exitosa

  • Si retorna false, hubo un error

¿Puedo cambiar las credenciales de la base de datos?

  • Sí, modifica las variables en DB.php

  • $username y $password según tu configuración


🎓 Ejercicio práctico

Ejercicio 1: Agregar más configuraciones de PDO

Agrega estas configuraciones a la conexión:

php
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Ejercicio 2: Crear un método para obtener archivos

Agrega este método a la clase Whisper:

php
public function getFiles() {
    try {
        $sql = "SELECT * FROM files ORDER BY ID DESC LIMIT 10";
        $stmt = $this->DB->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll();
    } catch(PDOException $error) {
        $this->error = $error->getMessage();
        return false;
    }
}

Ejercicio 3: Usar variables de entorno

Configura las credenciales en variables de entorno:

php
$host = getenv('DB_HOST') ?: 'localhost';
$dbname = getenv('DB_NAME') ?: 'MyWhisper';
$username = getenv('DB_USER') ?: 'root';
$password = getenv('DB_PASS') ?: '';

¡Excelente trabajo! Ahora tenemos una conexión funcional a la base de datos MySQL. En la próxima lección, usaremos esta conexión para mostrar los archivos subidos y sus transcripciones.

Comentarios

Entradas más populares de este blog

Cómo usar Whisper para sacar el texto de un video

Tutorial 18: Creando la Página de Visualización de Archivos Recientes

Tutorial 11: ¿Qué es Whisper AI y Cómo Funciona?