Files
guias_informatica/Guia_prepare_statements_cruds.md
T
2026-08-04 19:24:21 +02:00

1107 lines
19 KiB
Markdown

CRUD con MySQL usando Prepared Statements (recomendado)
<?php
$host = "localhost";
$user = "tu\_usuario";
$pass = "tu\_contraseña";
$db = "nombre\_bd";
// Crear conexión
$conn = new mysqli($host, $user, $pass, $db);
// Verificar conexión
if ($conn->connect\_error) {
die("Error de conexión: " . $conn->connect\_error);
}
// ========== CREATE (INSERT) ==========
function createUser($nombre, $email) {
global $conn;
$stmt = $conn->prepare("INSERT INTO usuarios (nombre, email) VALUES (?, ?)");
$stmt->bind\_param("ss", $nombre, $email);
if ($stmt->execute()) {
echo "Usuario creado con ID: " . $stmt->insert\_id . "\n";
} else {
echo "Error al crear usuario: " . $stmt->error . "\n";
}
$stmt->close();
}
// ========== READ (SELECT) ==========
function getUsers() {
global $conn;
$stmt = $conn->prepare("SELECT id, nombre, email FROM usuarios");
$stmt->execute();
$result = $stmt->get\_result();
$users = [];
while ($row = $result->fetch\_assoc()) {
$users[] = $row;
}
$stmt->close();
return $users;
}
// ========== UPDATE ==========
function updateUser($id, $nombre, $email) {
global $conn;
$stmt = $conn->prepare("UPDATE usuarios SET nombre = ?, email = ? WHERE id = ?");
$stmt->bind\_param("ssi", $nombre, $email, $id);
if ($stmt->execute()) {
echo "Usuario actualizado. Filas afectadas: " . $stmt->affected\_rows . "\n";
} else {
echo "Error al actualizar: " . $stmt->error . "\n";
}
$stmt->close();
}
// ========== DELETE ==========
function deleteUser($id) {
global $conn;
$stmt = $conn->prepare("DELETE FROM usuarios WHERE id = ?");
$stmt->bind\_param("i", $id);
if ($stmt->execute()) {
echo "Usuario eliminado. Filas afectadas: " . $stmt->affected\_rows . "\n";
} else {
echo "Error al eliminar: " . $stmt->error . "\n";
}
$stmt->close();
}
// ========== EJEMPLOS DE USO ==========
// Crear usuario
createUser("Juan Pérez", "juan@example.com");
// Obtener todos los usuarios
$usuarios = getUsers();
print\_r($usuarios);
// Actualizar usuario (asumiendo que existe el ID 1)
updateUser(1, "Juan García", "juan.garcia@example.com");
// Eliminar usuario (asumiendo que existe el ID 2)
deleteUser(2);
// Cerrar conexión
$conn->close();
?>
Ejemplo de SELECT con Prepared Statements en MySQLi
Aquí tienes un ejemplo completo de cómo realizar consultas SELECT usando prepared statements con MySQLi:
1. Ejemplo básico (obtener múltiples registros)
<?php
// Configuración de la base de datos
$host = "localhost";
$user = "tu\_usuario";
$pass = "tu\_contraseña";
$db = "nombre\_bd";
// Crear conexión
$conn = new mysqli($host, $user, $pass, $db);
// Verificar conexión
if ($conn->connect\_error) {
die("Error de conexión: " . $conn->connect\_error);
}
// Preparar la consulta SELECT
$stmt = $conn->prepare("SELECT id, nombre, email FROM usuarios WHERE activo = ?");
$activo = 1; // Valor para el parámetro
$stmt->bind\_param("i", $activo); // "i" indica que es un entero
// Ejecutar la consulta
$stmt->execute();
// Obtener resultados
$result = $stmt->get\_result();
// Procesar resultados
echo "Usuarios activos:\n";
while ($row = $result->fetch\_assoc()) {
echo "ID: " . $row['id'] . ", Nombre: " . $row['nombre'] . ", Email: " . $row['email'] . "\n";
}
// Cerrar statement y conexión
$stmt->close();
$conn->close();
?>
1. Ejemplo con parámetros dinámicos
<?php
// ... (configuración de conexión igual que arriba)
// Función para buscar usuarios por nombre
function buscarUsuariosPorNombre($nombre) {
global $conn;
$stmt = $conn->prepare("SELECT id, nombre, email FROM usuarios WHERE nombre LIKE ?");
$param = "%" . $nombre . "%"; // Búsqueda parcial
$stmt->bind\_param("s", $param); // "s" indica string
$stmt->execute();
$result = $stmt->get\_result();
$usuarios = [];
while ($row = $result->fetch\_assoc()) {
$usuarios[] = $row;
}
$stmt->close();
return $usuarios;
}
// Ejemplo de uso
$resultados = buscarUsuariosPorNombre("Juan");
print\_r($resultados);
$conn->close();
?>
1. Ejemplo con múltiples parámetros
<?php
// ... (configuración de conexión igual que arriba)
// Consulta con múltiples condiciones
$stmt = $conn->prepare("SELECT \* FROM usuarios WHERE edad > ? AND pais = ?");
$edad\_minima = 18;
$pais = "España";
$stmt->bind\_param("is", $edad\_minima, $pais); // "is" = integer + string
$stmt->execute();
$result = $stmt->get\_result();
while ($row = $result->fetch\_assoc()) {
echo "Usuario: " . $row['nombre'] . " (" . $row['edad'] . " años)\n";
}
$stmt->close();
$conn->close();
?>
1. Ejemplo con ORDER BY y LIMIT
<?php
// ... (configuración de conexión igual que arriba)
// Consulta con ordenación y límite
$stmt = $conn->prepare("SELECT nombre, email FROM usuarios ORDER BY fecha\_registro DESC LIMIT ?");
$limite = 10;
$stmt->bind\_param("i", $limite);
$stmt->execute();
$result = $stmt->get\_result();
echo "Últimos 10 usuarios registrados:\n";
while ($row = $result->fetch\_assoc()) {
echo "- " . $row['nombre'] . ": " . $row['email'] . "\n";
}
$stmt->close();
$conn->close();
?>
Ventajas de usar prepared statements para SELECT:
Seguridad: Previene inyección SQL al separar claramente los datos de la consulta
Rendimiento: Mejor performance en consultas repetidas (el motor prepara la consulta una vez)
Claridad: Código más organizado y mantenible
Tipado seguro: Los parámetros se vinculan con su tipo correcto (entero, string, etc.)
Tipos de parámetros en bind\_param():
"i" - integer (entero)
"d" - double (decimal)
"s" - string (cadena)
"b" - blob (datos binarios)
Puedes combinar tipos cuando tienes múltiples parámetros: $stmt->bind\_param("iss", $id, $nombre, $email);
Recomendación:
Usa new mysqli() porque:
Es más moderno y consistente con PHP actual
Mejor para mantenimiento de código
Permite encadenamiento de métodos
Más intuitivo en frameworks modernos
CRUD con MySQL sin Prepared Statements (no recomendado)
Aquí tienes el mismo CRUD pero sin utilizar prepared statements. Importante: Este método es menos seguro y no se recomienda para producción, ya que es vulnerable a inyección SQL.
<?php
// Configuración de la base de datos
$host = "localhost";
$user = "tu\_usuario";
$pass = "tu\_contraseña";
$db = "nombre\_bd";
// Crear conexión
$conn = new mysqli($host, $user, $pass, $db);
// Verificar conexión
if ($conn->connect\_error) {
die("Error de conexión: " . $conn->connect\_error);
}
// ========== CREATE (INSERT) ==========
function createUser($nombre, $email) {
global $conn;
// Escapar valores para prevenir inyección SQL (no es tan seguro como prepared statements)
$nombre = $conn->real\_escape\_string($nombre);
$email = $conn->real\_escape\_string($email);
$sql = "INSERT INTO usuarios (nombre, email) VALUES ('$nombre', '$email')";
if ($conn->query($sql)) {
echo "Usuario creado con ID: " . $conn->insert\_id . "\n";
} else {
echo "Error al crear usuario: " . $conn->error . "\n";
}
}
// ========== READ (SELECT) ==========
function getUsers() {
global $conn;
$sql = "SELECT id, nombre, email FROM usuarios";
$result = $conn->query($sql);
$users = [];
if ($result->num\_rows > 0) {
while ($row = $result->fetch\_assoc()) {
$users[] = $row;
}
}
return $users;
}
// ========== UPDATE ==========
function updateUser($id, $nombre, $email) {
global $conn;
// Escapar valores
$id = (int)$id; // Forzar tipo entero
$nombre = $conn->real\_escape\_string($nombre);
$email = $conn->real\_escape\_string($email);
$sql = "UPDATE usuarios SET nombre = '$nombre', email = '$email' WHERE id = $id";
if ($conn->query($sql)) {
echo "Usuario actualizado. Filas afectadas: " . $conn->affected\_rows . "\n";
} else {
echo "Error al actualizar: " . $conn->error . "\n";
}
}
// ========== DELETE ==========
function deleteUser($id) {
global $conn;
$id = (int)$id; // Forzar tipo entero
$sql = "DELETE FROM usuarios WHERE id = $id";
if ($conn->query($sql)) {
echo "Usuario eliminado. Filas afectadas: " . $conn->affected\_rows . "\n";
} else {
echo "Error al eliminar: " . $conn->error . "\n";
}
}
// ========== EJEMPLOS DE USO ==========
// Crear usuario
createUser("Juan Pérez", "juan@example.com");
// Obtener todos los usuarios
$usuarios = getUsers();
print\_r($usuarios);
// Actualizar usuario (asumiendo que existe el ID 1)
updateUser(1, "Juan García", "juan.garcia@example.com");
// Eliminar usuario (asumiendo que existe el ID 2)
deleteUser(2);
// Cerrar conexión
$conn->close();
?>
Diferencias clave con la versión con prepared statements:
Seguridad:
Se usa real\_escape\_string() en lugar de parámetros enlazados
Se fuerza el tipo de datos con (int) para IDs
Aún así es menos seguro que los prepared statements
Sintaxis:
Consultas directas con concatenación de strings
No hay bind\_param() ni execute()
Se usa $conn->query() directamente
Manejo de resultados:
Se accede a conn->insert\_id en lugar de stmt->insert\_id
Se usa conn->affected\_rows en lugar de stmt->affected\_rows
Advertencia importante:
Este método no es recomendable para aplicaciones reales porque:
real\_escape\_string() no protege completamente contra inyección SQL
La conversión de tipos manual es propensa a errores
Es más difícil mantener el código
No aprovecha las optimizaciones del servidor SQL
Los prepared statements son el método recomendado para interactuar con bases de datos en PHP por su seguridad y eficiencia.
\------------------------------------------------------------------------------------------------------------------------------
CRUD con SQLite usando Prepared Statements (recomendado)
<?php
// Configuración de la base de datos SQLite
$dbFile = 'mi\_base\_datos.db';
try {
// Crear/conectar a la base de datos
$db = new PDO("sqlite:$dbFile");
$db->setAttribute(PDO::ATTR\_ERRMODE, PDO::ERRMODE\_EXCEPTION);
// Crear tabla si no existe
$db->exec("CREATE TABLE IF NOT EXISTS productos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
precio REAL NOT NULL,
stock INTEGER NOT NULL
)");
// ========== CREATE (INSERT) ==========
function crearProducto($nombre, $precio, $stock) {
global $db;
$stmt = $db->prepare("INSERT INTO productos (nombre, precio, stock) VALUES (?, ?, ?)");
$stmt->execute([$nombre, $precio, $stock]);
return $db->lastInsertId();
}
// ========== READ (SELECT) ==========
function obtenerProductos() {
global $db;
$stmt = $db->prepare("SELECT \* FROM productos");
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH\_ASSOC);
}
function obtenerProductoPorId($id) {
global $db;
$stmt = $db->prepare("SELECT \* FROM productos WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH\_ASSOC);
}
// ========== UPDATE ==========
function actualizarProducto($id, $nombre, $precio, $stock) {
global $db;
$stmt = $db->prepare("UPDATE productos SET nombre = ?, precio = ?, stock = ? WHERE id = ?");
$stmt->execute([$nombre, $precio, $stock, $id]);
return $stmt->rowCount();
}
// ========== DELETE ==========
function eliminarProducto($id) {
global $db;
$stmt = $db->prepare("DELETE FROM productos WHERE id = ?");
$stmt->execute([$id]);
return $stmt->rowCount();
}
// ===== Ejemplos de uso =====
// Crear
$idNuevo = crearProducto("Laptop", 1200.50, 10);
echo "Producto creado con ID: $idNuevo\n";
// Leer todos
$productos = obtenerProductos();
print\_r($productos);
// Leer uno
$producto = obtenerProductoPorId(1);
print\_r($producto);
// Actualizar
$filasActualizadas = actualizarProducto(1, "Laptop Pro", 1350.75, 8);
echo "Filas actualizadas: $filasActualizadas\n";
// Eliminar
$filasEliminadas = eliminarProducto(2);
echo "Filas eliminadas: $filasEliminadas\n";
} catch (PDOException $e) {
die("Error con SQLite: " . $e->getMessage());
}
?>
CRUD con SQLite usando Prepared Statements (sin PDO)
<?php
// Configuración de la base de datos SQLite
$dbFile = 'mi\_base\_datos.db';
try {
// Crear/conectar a la base de datos
$db = new SQLite3($dbFile);
// Habilitar excepciones para manejo de errores
$db->enableExceptions(true);
// Crear tabla si no existe
$db->exec("CREATE TABLE IF NOT EXISTS productos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
precio REAL NOT NULL,
stock INTEGER NOT NULL
)");
// ========== CREATE (INSERT) con prepared statement ==========
function crearProducto($nombre, $precio, $stock) {
global $db;
$stmt = $db->prepare("INSERT INTO productos (nombre, precio, stock) VALUES (:nombre, :precio, :stock)");
$stmt->bindValue(':nombre', $nombre, SQLITE3\_TEXT);
$stmt->bindValue(':precio', $precio, SQLITE3\_FLOAT);
$stmt->bindValue(':stock', $stock, SQLITE3\_INTEGER);
$result = $stmt->execute();
return $db->lastInsertRowID();
}
// ========== READ (SELECT) con prepared statement ==========
function obtenerProductos() {
global $db;
$stmt = $db->prepare("SELECT \* FROM productos");
$result = $stmt->execute();
$productos = [];
while ($row = $result->fetchArray(SQLITE3\_ASSOC)) {
$productos[] = $row;
}
return $productos;
}
function obtenerProductoPorId($id) {
global $db;
$stmt = $db->prepare("SELECT \* FROM productos WHERE id = :id");
$stmt->bindValue(':id', $id, SQLITE3\_INTEGER);
$result = $stmt->execute();
return $result->fetchArray(SQLITE3\_ASSOC);
}
// ========== UPDATE con prepared statement ==========
function actualizarProducto($id, $nombre, $precio, $stock) {
global $db;
$stmt = $db->prepare("UPDATE productos SET nombre = :nombre, precio = :precio, stock = :stock WHERE id = :id");
$stmt->bindValue(':nombre', $nombre, SQLITE3\_TEXT);
$stmt->bindValue(':precio', $precio, SQLITE3\_FLOAT);
$stmt->bindValue(':stock', $stock, SQLITE3\_INTEGER);
$stmt->bindValue(':id', $id, SQLITE3\_INTEGER);
$stmt->execute();
return $db->changes();
}
// ========== DELETE con prepared statement ==========
function eliminarProducto($id) {
global $db;
$stmt = $db->prepare("DELETE FROM productos WHERE id = :id");
$stmt->bindValue(':id', $id, SQLITE3\_INTEGER);
$stmt->execute();
return $db->changes();
}
// ===== Ejemplos de uso =====
// Crear producto
$idNuevo = crearProducto("Monitor", 199.99, 15);
echo "Producto creado con ID: $idNuevo\n";
// Leer todos los productos
$productos = obtenerProductos();
print\_r($productos);
// Leer un producto específico
$producto = obtenerProductoPorId(1);
print\_r($producto);
// Actualizar producto
$filasActualizadas = actualizarProducto(1, "Monitor HD", 179.99, 10);
echo "Filas actualizadas: $filasActualizadas\n";
// Eliminar producto
$filasEliminadas = eliminarProducto(2);
echo "Filas eliminadas: $filasEliminadas\n";
} catch (Exception $e) {
die("Error con SQLite: " . $e->getMessage());
} finally {
if (isset($db)) {
$db->close();
}
}
?>
Características clave:
Prepared Statements nativos de SQLite3:
Uso de prepare() para crear statements
bindValue() para vincular parámetros
Tipos de datos definidos (SQLITE3\_TEXT, SQLITE3\_INTEGER, etc.)
Métodos importantes:
execute() para ejecutar el statement preparado
fetchArray(SQLITE3\_ASSOC) para obtener resultados
lastInsertRowID() para obtener el último ID insertado
changes() para obtener filas afectadas
Tipos de datos para bindValue():
SQLITE3\_INTEGER
SQLITE3\_FLOAT
SQLITE3\_TEXT
SQLITE3\_BLOB
SQLITE3\_NULL
Ventajas:
Seguridad contra inyección SQL
Manejo adecuado de tipos de datos
No requiere PDO
Sintaxis específica para SQLite
Diferencia con la versión PDO:
Sintaxis:
PDO usa ? o :nombre para placeholders
SQLite3 nativo usa :nombre principalmente
Métodos:
PDO tiene bindParam() y bindValue()
SQLite3 nativo solo tiene bindValue()
Tipos de resultados:
PDO ofrece fetchAll() y varios estilos de fetch
SQLite3 nativo usa fetchArray() con constantes para el estilo
En SQLite3 usando la extensión nativa de PHP (no PDO), no se usa el sistema de tipos combinados como en MySQLi ("iss").
En su lugar, debes especificar el tipo para cada parámetro individualmente usando bindValue().
CRUD con SQLite sin Prepared Statements (no recomendado)
<?php
// Configuración de la base de datos SQLite
$dbFile = 'mi\_base\_datos.db';
try {
// Crear/conectar a la base de datos
$db = new SQLite3($dbFile);
// Crear tabla si no existe
$db->exec("CREATE TABLE IF NOT EXISTS productos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
precio REAL NOT NULL,
stock INTEGER NOT NULL
)");
// ========== CREATE (INSERT) ==========
function crearProducto($nombre, $precio, $stock) {
global $db;
$nombre = SQLite3::escapeString($nombre);
$precio = floatval($precio);
$stock = intval($stock);
$sql = "INSERT INTO productos (nombre, precio, stock)
VALUES ('$nombre', $precio, $stock)";
if ($db->exec($sql)) {
return $db->lastInsertRowID();
}
return false;
}
// ========== READ (SELECT) ==========
function obtenerProductos() {
global $db;
$result = $db->query("SELECT \* FROM productos");
$productos = [];
while ($row = $result->fetchArray(SQLITE3\_ASSOC)) {
$productos[] = $row;
}
return $productos;
}
function obtenerProductoPorId($id) {
global $db;
$id = intval($id);
$result = $db->querySingle("SELECT \* FROM productos WHERE id = $id", true);
return $result;
}
// ========== UPDATE ==========
function actualizarProducto($id, $nombre, $precio, $stock) {
global $db;
$id = intval($id);
$nombre = SQLite3::escapeString($nombre);
$precio = floatval($precio);
$stock = intval($stock);
$sql = "UPDATE productos SET
nombre = '$nombre',
precio = $precio,
stock = $stock
WHERE id = $id";
return $db->exec($sql);
}
// ========== DELETE ==========
function eliminarProducto($id) {
global $db;
$id = intval($id);
$sql = "DELETE FROM productos WHERE id = $id";
return $db->exec($sql);
}
// ===== Ejemplos de uso =====
// Crear
$idNuevo = crearProducto("Teclado", 45.99, 25);
echo "Producto creado con ID: $idNuevo\n";
// Leer todos
$productos = obtenerProductos();
print\_r($productos);
// Leer uno
$producto = obtenerProductoPorId(1);
print\_r($producto);
// Actualizar
$actualizado = actualizarProducto(1, "Teclado Mecánico", 59.99, 15);
echo "Actualizado: " . ($actualizado ? "Sí" : "No") . "\n";
// Eliminar
$eliminado = eliminarProducto(3);
echo "Eliminado: " . ($eliminado ? "Sí" : "No") . "\n";
} catch (Exception $e) {
die("Error con SQLite: " . $e->getMessage());
}
?>