Acceso a bases de datos en PHP
PHP permite conectarse a bases de datos relacionales (como MySQL, PostgreSQL o SQLite) para almacenar, consultar y modificar datos de manera estructurada. Esto es fundamental para aplicaciones que necesitan persistencia de datos, múltiples usuarios y operaciones complejas.
Existen varias formas de interactuar con bases de datos en PHP, siendo PDO (PHP Data Objects) y MySQLi las más utilizadas.
Conexión a la base de datos con MySQLi
MySQLi (MySQL Improved) es una extensión de PHP diseñada específicamente para trabajar con bases de datos MySQL. A diferencia de PDO, MySQLi solo funciona con MySQL, pero ofrece soporte para consultas preparadas, transacciones y múltiples funcionalidades avanzadas de MySQL.
MySQLi se puede usar de dos formas: orientada a objetos o procedimental.
Conexión usando MySQLi orientado a objetos
<?php
$host = "localhost";
$usuario = "usuario";
$clave = "clave";
$bd = "miBD";
// Crear conexión
$conexion = new mysqli($host, $usuario, $clave, $bd);
// Comprobar conexión
if ($conexion->connect_error) {
die("Error de conexión: " . $conexion->connect_error);
}
echo "Conexión exitosa usando MySQLi orientado a objetos.";
?>
Ejemplo de consulta SELECT:
<?php
$resultado = $conexion->query("SELECT id, nombre, email FROM usuarios");
if ($resultado->num_rows > 0) {
while ($fila = $resultado->fetch_assoc()) {
echo $fila['id'] . " - " . $fila['nombre'] . " - " . $fila['email'] . "<br>";
}
} else {
echo "No se encontraron registros.";
}
$conexion->close();
?>
Ejemplo de consultas preparadas (seguras):
<?php
$stmt = $conexion->prepare("INSERT INTO usuarios (nombre, email) VALUES (?, ?)");
$stmt->bind_param("ss", $nombre, $email);
$nombre = "Luis";
$email = "luis@example.com";
$stmt->execute();
echo "Usuario insertado correctamente con MySQLi.";
$stmt->close();
$conexion->close();
?>
bind_param()La función bind_param() requiere especificar los tipos de las variables:
"s"parastring"i"parainteger"d"paradouble"b"parablob
Conexión usando MySQLi procedimental
<?php
$conexion = mysqli_connect("localhost", "usuario", "clave", "miBD");
if (!$conexion) {
die("Error de conexión: " . mysqli_connect_error());
}
echo "Conexión exitosa usando MySQLi procedimental.";
mysqli_close($conexion);
?>
Ventajas de MySQLi
- Permite consultas preparadas para mejorar la seguridad.
- Compatible con transacciones y operaciones avanzadas de MySQL.
- Puede usar orientación a objetos o estilo procedimental, según la preferencia del desarrollador.
- Mejor integración con funcionalidades exclusivas de MySQL, como multi-query o store procedures.
Consideraciones
- Solo funciona con MySQL; si se desea compatibilidad con otros motores, PDO es más recomendable.
- Las consultas preparadas son obligatorias para protegerse contra inyección SQL.
- Mantener cerradas las conexiones y liberar recursos (
close()ostmt->close()) para evitar fugas de memoria.
Conexión a la base de datos con PDO
PDO es una interfaz de acceso a bases de datos en PHP que proporciona un conjunto uniforme de funciones para interactuar con distintos motores SQL (MySQL, PostgreSQL, SQLite, entre otros). Su ventaja principal es que permite escribir código independiente del motor de base de datos, facilitando la portabilidad y mejorando la seguridad mediante consultas parametrizadas.
Los problemas del enfoque de conexión usando MySQLi son los siguientes:
- Riesgo de inyección SQL al concatenar variables.
- Código dependiente del motor (aquí MySQL).
- Manejo de errores menos uniforme.
Conexión usando PDO
<?php
$dsn = "mysql:host=localhost;dbname=miBD;charset=utf8mb4";
$usuario = "usuario";
$clave = "clave";
try {
$pdo = new PDO($dsn, $usuario, $clave);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("INSERT INTO usuarios (nombre, email) VALUES (:nombre, :email)");
$stmt->execute([
':nombre' => 'Ana',
':email' => 'ana@example.com'
]);
echo "Usuario insertado correctamente usando PDO.";
} catch (PDOException $e) {
echo "Error de conexión o ejecución: " . $e->getMessage();
}
?>
Ventajas de PDO:
- Consultas parametrizadas que previenen inyección SQL.
- Compatibilidad con múltiples motores de base de datos.
- Manejo de errores uniforme mediante excepciones.
- Mejor legibilidad y mantenibilidad del código.
Consultas básicas
SELECT
Leer datos de una tabla:
<?php
$consulta = $pdo->query("SELECT id, nombre, email FROM usuarios");
while ($fila = $consulta->fetch(PDO::FETCH_ASSOC)) {
echo $fila['id'] . " - " . $fila['nombre'] . " - " . $fila['email'] . "<br>";
}
?>
INSERT
Insertar un nuevo registro usando consultas preparadas para evitar inyección SQL:
<?php
$stmt = $pdo->prepare("INSERT INTO usuarios (nombre, email) VALUES (:nombre, :email)");
$stmt->execute([
':nombre' => 'Carlos',
':email' => 'carlos@example.com'
]);
echo "Usuario insertado correctamente.";
?>
UPDATE
Actualizar datos de manera segura:
<?php
$stmt = $pdo->prepare("UPDATE usuarios SET email = :email WHERE id = :id");
$stmt->execute([
':email' => 'nuevo_email@example.com',
':id' => 2
]);
echo "Usuario actualizado.";
?>
DELETE
Eliminar registros:
<?php
$stmt = $pdo->prepare("DELETE FROM usuarios WHERE id = :id");
$stmt->execute([':id' => 3]);
echo "Usuario eliminado.";
?>
Uso de transacciones
Las transacciones permiten agrupar varias operaciones y asegurar que todas se ejecuten correctamente o ninguna en caso de error.
<?php
try {
// Iniciar transacción
$pdo->beginTransaction();
// Restar saldo
$stmt1 = $pdo->prepare("UPDATE cuentas SET saldo = saldo - :monto WHERE id = :id");
$stmt1->execute([':monto' => 100, ':id' => 1]);
// Sumar saldo
$stmt2 = $pdo->prepare("UPDATE cuentas SET saldo = saldo + :monto WHERE id = :id");
$stmt2->execute([':monto' => 100, ':id' => 2]);
// Confirmar transacción
$pdo->commit();
echo "Transferencia realizada correctamente.";
} catch (Exception $e) {
// Revertir cambios si algo falla
$pdo->rollBack();
echo "Error en la transacción: " . $e->getMessage();
}
?>
Consultas parametrizadas y seguridad
- Evitar concatenar directamente valores de usuario en las consultas.
- Usar prepared statements o bind parameters para prevenir inyección SQL.
- Ejemplo seguro:
<?php
$nombre = $_POST['nombre'];
$email = $_POST['email'];
$stmt = $pdo->prepare("INSERT INTO usuarios (nombre, email) VALUES (?, ?)");
$stmt->execute([$nombre, $email]);
?>
Manejo de errores y buenas prácticas
- Configurar PDO para lanzar excepciones:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - Comprobar siempre los resultados de las consultas.
- Cerrar la conexión explícitamente cuando ya no se necesita (aunque PHP lo hace automáticamente al finalizar el script):
$pdo = null; - Usar transacciones para operaciones críticas que involucren múltiples cambios.
- Mantener las credenciales fuera del código, usando archivos de configuración protegidos o variables de entorno.