Saltar al contenido principal

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();
?>
Tipo de dato en bind_param()

La función bind_param() requiere especificar los tipos de las variables:

  • "s" para string
  • "i" para integer
  • "d" para double
  • "b" para blob

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() o stmt->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.