Trabajo con archivos y persistencia de datos

Avanzado
PHP
PHP
Actualizado: 29/08/2025

Lectura y escritura de archivos

La capacidad de interactuar con archivos es fundamental en cualquier aplicación web. PHP ofrece múltiples formas de leer y escribir archivos, desde métodos simples para operaciones básicas hasta funciones más avanzadas para un control granular del proceso.

Funciones básicas para trabajar con archivos

PHP proporciona dos enfoques principales para el manejo de archivos: funciones simples para operaciones directas y funciones de bajo nivel para un control más detallado.

Lectura completa de archivos

La función file_get_contents() es la forma más directa de leer el contenido completo de un archivo:

<?php
// Leer todo el contenido de un archivo
$contenido = file_get_contents('datos.txt');

if ($contenido !== false) {
    echo "Contenido del archivo: " . $contenido;
} else {
    echo "Error al leer el archivo";
}
?>

Escritura completa de archivos

Para escribir contenido completo en un archivo, utilizamos file_put_contents():

<?php
// Escribir contenido en un archivo
$texto = "Hola mundo desde PHP\nEsta es una segunda línea";
$resultado = file_put_contents('salida.txt', $texto);

if ($resultado !== false) {
    echo "Se escribieron $resultado bytes";
} else {
    echo "Error al escribir el archivo";
}
?>

Manejo de archivos con control granular

Para situaciones que requieren mayor control, PHP ofrece funciones de bajo nivel que permiten abrir, leer, escribir y cerrar archivos paso a paso.

Apertura y cierre de archivos

La función fopen() abre un archivo y devuelve un recurso que podemos usar para operaciones posteriores:

<?php
// Abrir archivo para lectura
$archivo = fopen('datos.txt', 'r');

if ($archivo) {
    // Realizar operaciones con el archivo
    // ...
    
    // Siempre cerrar el archivo
    fclose($archivo);
} else {
    echo "No se pudo abrir el archivo";
}
?>

Modos de apertura más utilizados:

  • 'r' - Solo lectura. El puntero se sitúa al inicio del archivo
  • 'w' - Solo escritura. Trunca el archivo a longitud cero o crea uno nuevo
  • 'a' - Solo escritura. El puntero se sitúa al final del archivo
  • 'r+' - Lectura y escritura. El puntero se sitúa al inicio
  • 'w+' - Lectura y escritura. Trunca el archivo o crea uno nuevo
  • 'a+' - Lectura y escritura. El puntero de escritura se sitúa al final

Lectura línea por línea

Para archivos grandes o cuando necesitamos procesar el contenido línea por línea, podemos usar fgets():

<?php
$archivo = fopen('datos.txt', 'r');

if ($archivo) {
    $numeroLinea = 1;
    
    // Leer línea por línea
    while (($linea = fgets($archivo)) !== false) {
        echo "Línea $numeroLinea: " . trim($linea) . "<br>";
        $numeroLinea++;
    }
    
    fclose($archivo);
}
?>

Escritura incremental

Para añadir contenido a un archivo existente o escribir datos de forma incremental:

<?php
// Abrir archivo en modo append (añadir al final)
$archivo = fopen('log.txt', 'a');

if ($archivo) {
    $timestamp = date('Y-m-d H:i:s');
    $mensaje = "[$timestamp] Usuario conectado\n";
    
    // Escribir al final del archivo
    fwrite($archivo, $mensaje);
    
    fclose($archivo);
    echo "Log registrado correctamente";
}
?>

Verificación y manejo de errores

Es fundamental verificar la existencia y permisos de archivos antes de intentar operaciones:

<?php
$nombreArchivo = 'configuracion.txt';

// Verificar si el archivo existe
if (file_exists($nombreArchivo)) {
    // Verificar si es legible
    if (is_readable($nombreArchivo)) {
        $contenido = file_get_contents($nombreArchivo);
        echo "Archivo leído correctamente";
    } else {
        echo "El archivo no tiene permisos de lectura";
    }
} else {
    echo "El archivo no existe";
}

// Verificar si se puede escribir
if (is_writable($nombreArchivo)) {
    file_put_contents($nombreArchivo, "Nuevo contenido");
} else {
    echo "No se puede escribir en el archivo";
}
?>

Trabajo con rutas y directorios

PHP incluye funciones útiles para manipular rutas y trabajar con directorios:

<?php
// Obtener información sobre un archivo
$archivo = 'documentos/reporte.txt';

echo "Ruta completa: " . realpath($archivo) . "<br>";
echo "Directorio padre: " . dirname($archivo) . "<br>";
echo "Nombre del archivo: " . basename($archivo) . "<br>";
echo "Extensión: " . pathinfo($archivo, PATHINFO_EXTENSION) . "<br>";

// Crear un directorio si no existe
$directorio = 'uploads';
if (!is_dir($directorio)) {
    mkdir($directorio, 0755, true);
    echo "Directorio creado: $directorio";
}
?>

Ejemplo práctico: Sistema de logs

Un caso de uso común es implementar un sistema básico de logs:

<?php
function escribirLog($mensaje, $nivel = 'INFO') {
    $archivoLog = 'logs/aplicacion.log';
    
    // Crear directorio si no existe
    $directorio = dirname($archivoLog);
    if (!is_dir($directorio)) {
        mkdir($directorio, 0755, true);
    }
    
    // Preparar el mensaje con timestamp
    $timestamp = date('Y-m-d H:i:s');
    $entradaLog = "[$timestamp] [$nivel] $mensaje" . PHP_EOL;
    
    // Escribir al archivo de log
    if (file_put_contents($archivoLog, $entradaLog, FILE_APPEND | LOCK_EX) === false) {
        error_log("Error al escribir en el archivo de log");
    }
}

// Uso del sistema de logs
escribirLog("Aplicación iniciada");
escribirLog("Usuario 'admin' inició sesión", 'INFO');
escribirLog("Intento de acceso no autorizado", 'WARNING');
?>

Lectura de archivos CSV

Un formato muy utilizado en aplicaciones web es CSV (Comma Separated Values). PHP proporciona funciones específicas para trabajar con este formato:

<?php
// Leer archivo CSV
$archivo = fopen('usuarios.csv', 'r');

if ($archivo) {
    echo "<table border='1'>";
    
    // Leer línea por línea como array
    while (($datos = fgetcsv($archivo)) !== false) {
        echo "<tr>";
        foreach ($datos as $campo) {
            echo "<td>" . htmlspecialchars($campo) . "</td>";
        }
        echo "</tr>";
    }
    
    echo "</table>";
    fclose($archivo);
}

// Escribir archivo CSV
$usuarios = [
    ['Juan', 'Pérez', 'juan@email.com'],
    ['María', 'García', 'maria@email.com'],
    ['Carlos', 'López', 'carlos@email.com']
];

$archivo = fopen('nuevo_usuarios.csv', 'w');
if ($archivo) {
    foreach ($usuarios as $usuario) {
        fputcsv($archivo, $usuario);
    }
    fclose($archivo);
    echo "Archivo CSV creado correctamente";
}
?>

Introducción básica a bases de datos (MySQL con PHP)

Aunque el manejo de archivos resulta útil para muchos escenarios, cuando necesitamos almacenar y gestionar grandes cantidades de datos de forma estructurada, las bases de datos se convierten en la solución más eficiente y robusta.

¿Por qué utilizar bases de datos?

Las bases de datos relacionales ofrecen ventajas significativas frente al almacenamiento en archivos planos:

  • Estructura organizada: Los datos se almacenan en tablas con relaciones definidas
  • Consultas eficientes: Permiten búsquedas y filtrados complejos de forma rápida
  • Integridad de datos: Garantizan la consistencia mediante restricciones y validaciones
  • Acceso concurrente: Múltiples usuarios pueden acceder simultáneamente sin conflictos
  • Escalabilidad: Manejan eficientemente desde pequeños hasta grandes volúmenes de datos

MySQL como sistema de gestión de bases de datos

MySQL es uno de los sistemas de gestión de bases de datos más utilizados en el desarrollo web. Se integra perfectamente con PHP y ofrece un rendimiento excelente para aplicaciones web de cualquier tamaño.

Las principales características de MySQL incluyen:

  • Código abierto y gratuito para la mayoría de usos
  • Alto rendimiento y optimización para aplicaciones web
  • Compatibilidad con estándares SQL
  • Facilidad de uso y administración
  • Amplio soporte de la comunidad y documentación extensa

Conexión de PHP con MySQL usando PDO

PDO (PHP Data Objects) es la forma moderna y recomendada de conectar PHP con bases de datos. Proporciona una interfaz consistente para trabajar con diferentes sistemas de bases de datos y ofrece características de seguridad avanzadas.

Establecer una conexión básica

<?php
// Configuración de la conexión
$host = 'localhost';
$dbname = 'mi_aplicacion';
$username = 'usuario';
$password = 'contraseña';

try {
    // Crear conexión PDO
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", 
                   $username, $password);
    
    // Configurar modo de errores
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    echo "Conexión establecida correctamente";
    
} catch (PDOException $e) {
    die("Error de conexión: " . $e->getMessage());
}
?>

Configuración óptima de PDO

Para un desarrollo profesional, es importante configurar PDO con las opciones adecuadas desde el momento de la conexión:

<?php
function conectarBaseDatos() {
    $host = 'localhost';
    $dbname = 'mi_aplicacion';
    $username = 'usuario';
    $password = 'contraseña';
    
    $opciones = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
    ];
    
    try {
        $pdo = new PDO(
            "mysql:host=$host;dbname=$dbname;charset=utf8mb4", 
            $username, 
            $password, 
            $opciones
        );
        
        return $pdo;
        
    } catch (PDOException $e) {
        throw new Exception("Error de conexión: " . $e->getMessage());
    }
}

// Uso de la función
try {
    $conexion = conectarBaseDatos();
    echo "Base de datos conectada correctamente";
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

Verificación del estado de la conexión

Es fundamental verificar que la conexión funciona correctamente y que podemos comunicarnos con la base de datos:

<?php
function verificarConexion($pdo) {
    try {
        // Ejecutar una consulta simple para verificar la conexión
        $stmt = $pdo->query("SELECT VERSION() as version");
        $resultado = $stmt->fetch();
        
        echo "Conexión activa. Versión MySQL: " . $resultado['version'];
        return true;
        
    } catch (PDOException $e) {
        echo "Error al verificar conexión: " . $e->getMessage();
        return false;
    }
}

// Verificar después de conectar
$conexion = conectarBaseDatos();
verificarConexion($conexion);
?>

Estructura básica de una base de datos

Antes de trabajar con datos, es importante comprender la estructura básica que utilizaremos. Una base de datos típica para una aplicación web podría tener tablas como esta:

-- Ejemplo de estructura de tabla para usuarios
CREATE TABLE usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL,
    fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Ejemplo de tabla para productos
CREATE TABLE productos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(200) NOT NULL,
    precio DECIMAL(10,2) NOT NULL,
    descripcion TEXT,
    stock INT DEFAULT 0
);

Gestión de configuración y seguridad

Para aplicaciones profesionales, es crucial separar la configuración de conexión del código principal:

<?php
// archivo: config/database.php
class DatabaseConfig {
    private const HOST = 'localhost';
    private const DB_NAME = 'mi_aplicacion';
    private const USERNAME = 'usuario';
    private const PASSWORD = 'contraseña';
    
    public static function getConnection() {
        $opciones = [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false
        ];
        
        try {
            return new PDO(
                "mysql:host=" . self::HOST . ";dbname=" . self::DB_NAME . ";charset=utf8mb4",
                self::USERNAME,
                self::PASSWORD,
                $opciones
            );
        } catch (PDOException $e) {
            error_log("Error de conexión a la base de datos: " . $e->getMessage());
            throw new Exception("Error interno del servidor");
        }
    }
}

// Uso en la aplicación
try {
    $pdo = DatabaseConfig::getConnection();
    echo "Aplicación conectada a la base de datos";
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

Preparación para consultas

Con la conexión establecida, el siguiente paso es preparar el entorno para ejecutar consultas de forma segura. PDO utiliza consultas preparadas que previenen inyecciones SQL:

<?php
function prepararConsulta($pdo, $sql) {
    try {
        $stmt = $pdo->prepare($sql);
        return $stmt;
    } catch (PDOException $e) {
        throw new Exception("Error al preparar consulta: " . $e->getMessage());
    }
}

// Ejemplo de preparación de consulta
$conexion = DatabaseConfig::getConnection();

// Preparar una consulta para buscar usuarios
$sqlBuscar = "SELECT id, nombre, email FROM usuarios WHERE email = ?";
$stmtBuscar = prepararConsulta($conexion, $sqlBuscar);

echo "Consulta preparada correctamente";
?>

Manejo de errores y logging

Un sistema robusto debe manejar adecuadamente los errores de base de datos:

<?php
class DatabaseLogger {
    public static function logError($mensaje, $contexto = []) {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[$timestamp] DATABASE ERROR: $mensaje";
        
        if (!empty($contexto)) {
            $logEntry .= " | Contexto: " . json_encode($contexto);
        }
        
        error_log($logEntry);
    }
}

function ejecutarConConsultaSegura($pdo, $sql, $parametros = []) {
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute($parametros);
        return $stmt;
        
    } catch (PDOException $e) {
        DatabaseLogger::logError($e->getMessage(), [
            'sql' => $sql,
            'parametros' => $parametros
        ]);
        
        throw new Exception("Error en la operación de base de datos");
    }
}
?>

Pool de conexiones y optimización

Para aplicaciones con mayor carga, es importante considerar la gestión eficiente de conexiones:

<?php
class ConnectionManager {
    private static $instance = null;
    private $connection = null;
    
    private function __construct() {
        // Conexión singleton para evitar múltiples conexiones innecesarias
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function getConnection() {
        if ($this->connection === null) {
            $this->connection = DatabaseConfig::getConnection();
        }
        return $this->connection;
    }
    
    public function closeConnection() {
        $this->connection = null;
    }
}

// Uso del gestor de conexiones
$manager = ConnectionManager::getInstance();
$pdo = $manager->getConnection();
?>

Esta base sólida de conexión con MySQL mediante PDO nos proporciona los fundamentos necesarios para implementar operaciones de base de datos seguras y eficientes. La configuración mostrada sigue las mejores prácticas actuales y prepara el terreno para realizar operaciones CRUD completas de forma profesional.

Operaciones CRUD básicas

Con la conexión establecida y las consultas preparadas, podemos implementar las cuatro operaciones fundamentales para gestionar datos: Create (crear), Read (leer), Update (actualizar) y Delete (eliminar). Estas operaciones forman la base de cualquier sistema de gestión de datos.

Create - Insertar datos

La inserción de datos nos permite agregar nuevos registros a nuestras tablas. Utilizamos consultas preparadas para garantizar la seguridad y evitar inyecciones SQL:

<?php
function crearUsuario($pdo, $nombre, $email) {
    $sql = "INSERT INTO usuarios (nombre, email) VALUES (?, ?)";
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$nombre, $email]);
        
        // Obtener el ID del registro insertado
        $nuevoId = $pdo->lastInsertId();
        
        return [
            'success' => true,
            'id' => $nuevoId,
            'mensaje' => "Usuario creado con ID: $nuevoId"
        ];
        
    } catch (PDOException $e) {
        return [
            'success' => false,
            'mensaje' => "Error al crear usuario: " . $e->getMessage()
        ];
    }
}

// Uso de la función
$conexion = DatabaseConfig::getConnection();
$resultado = crearUsuario($conexion, "Ana García", "ana@email.com");

if ($resultado['success']) {
    echo $resultado['mensaje'];
} else {
    echo $resultado['mensaje'];
}
?>

Inserción de múltiples registros

Para optimizar el rendimiento cuando necesitamos insertar varios registros, podemos usar transacciones:

<?php
function crearMultiplesUsuarios($pdo, $usuarios) {
    $sql = "INSERT INTO usuarios (nombre, email) VALUES (?, ?)";
    
    try {
        // Iniciar transacción
        $pdo->beginTransaction();
        
        $stmt = $pdo->prepare($sql);
        $insertados = 0;
        
        foreach ($usuarios as $usuario) {
            $stmt->execute([$usuario['nombre'], $usuario['email']]);
            $insertados++;
        }
        
        // Confirmar transacción
        $pdo->commit();
        
        return [
            'success' => true,
            'insertados' => $insertados,
            'mensaje' => "Se insertaron $insertados usuarios correctamente"
        ];
        
    } catch (PDOException $e) {
        // Revertir cambios en caso de error
        $pdo->rollback();
        
        return [
            'success' => false,
            'mensaje' => "Error al insertar usuarios: " . $e->getMessage()
        ];
    }
}

// Ejemplo de uso
$nuevosUsuarios = [
    ['nombre' => 'Carlos López', 'email' => 'carlos@email.com'],
    ['nombre' => 'María Rodríguez', 'email' => 'maria@email.com'],
    ['nombre' => 'Pedro Martín', 'email' => 'pedro@email.com']
];

$resultado = crearMultiplesUsuarios($conexion, $nuevosUsuarios);
echo $resultado['mensaje'];
?>

Read - Consultar datos

Las consultas de lectura nos permiten obtener información de la base de datos. Podemos realizar desde consultas simples hasta búsquedas complejas con filtros:

<?php
// Obtener todos los usuarios
function obtenerTodosLosUsuarios($pdo) {
    $sql = "SELECT id, nombre, email, fecha_registro FROM usuarios ORDER BY fecha_registro DESC";
    
    try {
        $stmt = $pdo->query($sql);
        return $stmt->fetchAll();
        
    } catch (PDOException $e) {
        error_log("Error al obtener usuarios: " . $e->getMessage());
        return [];
    }
}

// Obtener un usuario específico por ID
function obtenerUsuarioPorId($pdo, $id) {
    $sql = "SELECT id, nombre, email, fecha_registro FROM usuarios WHERE id = ?";
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$id]);
        
        $usuario = $stmt->fetch();
        
        return $usuario ? $usuario : null;
        
    } catch (PDOException $e) {
        error_log("Error al obtener usuario: " . $e->getMessage());
        return null;
    }
}

// Uso de las funciones
$todosUsuarios = obtenerTodosLosUsuarios($conexion);

foreach ($todosUsuarios as $usuario) {
    echo "ID: {$usuario['id']}, Nombre: {$usuario['nombre']}, Email: {$usuario['email']}<br>";
}

// Obtener usuario específico
$usuarioEspecifico = obtenerUsuarioPorId($conexion, 1);
if ($usuarioEspecifico) {
    echo "Usuario encontrado: " . $usuarioEspecifico['nombre'];
} else {
    echo "Usuario no encontrado";
}
?>

Consultas con filtros y búsquedas

Para búsquedas más específicas, podemos implementar funciones que permitan filtrar por diferentes criterios:

<?php
function buscarUsuarios($pdo, $criterio = [], $limite = 10, $offset = 0) {
    $condiciones = [];
    $parametros = [];
    
    // Construir condiciones dinámicamente
    if (!empty($criterio['nombre'])) {
        $condiciones[] = "nombre LIKE ?";
        $parametros[] = "%" . $criterio['nombre'] . "%";
    }
    
    if (!empty($criterio['email'])) {
        $condiciones[] = "email LIKE ?";
        $parametros[] = "%" . $criterio['email'] . "%";
    }
    
    if (!empty($criterio['fecha_desde'])) {
        $condiciones[] = "fecha_registro >= ?";
        $parametros[] = $criterio['fecha_desde'];
    }
    
    // Construir la consulta SQL
    $sql = "SELECT id, nombre, email, fecha_registro FROM usuarios";
    
    if (!empty($condiciones)) {
        $sql .= " WHERE " . implode(" AND ", $condiciones);
    }
    
    $sql .= " ORDER BY fecha_registro DESC LIMIT ? OFFSET ?";
    $parametros[] = $limite;
    $parametros[] = $offset;
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute($parametros);
        
        return [
            'usuarios' => $stmt->fetchAll(),
            'total' => count($stmt->fetchAll())
        ];
        
    } catch (PDOException $e) {
        error_log("Error en búsqueda: " . $e->getMessage());
        return ['usuarios' => [], 'total' => 0];
    }
}

// Ejemplo de búsqueda
$criterios = [
    'nombre' => 'Ana',
    'fecha_desde' => '2024-01-01'
];

$resultado = buscarUsuarios($conexion, $criterios, 5, 0);
echo "Usuarios encontrados: " . count($resultado['usuarios']);
?>

Update - Actualizar datos

La actualización de registros nos permite modificar datos existentes de forma selectiva:

<?php
function actualizarUsuario($pdo, $id, $datosNuevos) {
    // Construir campos a actualizar dinámicamente
    $campos = [];
    $parametros = [];
    
    if (isset($datosNuevos['nombre'])) {
        $campos[] = "nombre = ?";
        $parametros[] = $datosNuevos['nombre'];
    }
    
    if (isset($datosNuevos['email'])) {
        $campos[] = "email = ?";
        $parametros[] = $datosNuevos['email'];
    }
    
    if (empty($campos)) {
        return [
            'success' => false,
            'mensaje' => 'No hay datos para actualizar'
        ];
    }
    
    // Añadir el ID al final de los parámetros
    $parametros[] = $id;
    
    $sql = "UPDATE usuarios SET " . implode(", ", $campos) . " WHERE id = ?";
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute($parametros);
        
        $filasAfectadas = $stmt->rowCount();
        
        if ($filasAfectadas > 0) {
            return [
                'success' => true,
                'mensaje' => "Usuario actualizado correctamente"
            ];
        } else {
            return [
                'success' => false,
                'mensaje' => "No se encontró el usuario o no hubo cambios"
            ];
        }
        
    } catch (PDOException $e) {
        return [
            'success' => false,
            'mensaje' => "Error al actualizar: " . $e->getMessage()
        ];
    }
}

// Actualizar datos específicos
$datosActualizar = [
    'nombre' => 'Ana García López',
    'email' => 'ana.garcia@nuevoemail.com'
];

$resultado = actualizarUsuario($conexion, 1, $datosActualizar);
echo $resultado['mensaje'];
?>

Actualización condicional con verificaciones

Para mayor robustez, podemos implementar actualizaciones que verifiquen condiciones adicionales:

<?php
function actualizarUsuarioConVerificacion($pdo, $id, $datosNuevos) {
    // Primero verificar que el usuario existe
    $usuarioExistente = obtenerUsuarioPorId($pdo, $id);
    
    if (!$usuarioExistente) {
        return [
            'success' => false,
            'mensaje' => 'Usuario no encontrado'
        ];
    }
    
    // Verificar email único si se va a actualizar
    if (isset($datosNuevos['email']) && $datosNuevos['email'] !== $usuarioExistente['email']) {
        $sqlVerificar = "SELECT id FROM usuarios WHERE email = ? AND id != ?";
        $stmt = $pdo->prepare($sqlVerificar);
        $stmt->execute([$datosNuevos['email'], $id]);
        
        if ($stmt->fetch()) {
            return [
                'success' => false,
                'mensaje' => 'El email ya está en uso por otro usuario'
            ];
        }
    }
    
    // Proceder con la actualización
    return actualizarUsuario($pdo, $id, $datosNuevos);
}
?>

Delete - Eliminar datos

La eliminación de registros debe implementarse con cuidado, considerando la integridad de los datos:

<?php
function eliminarUsuario($pdo, $id) {
    // Primero verificar que el usuario existe
    $usuario = obtenerUsuarioPorId($pdo, $id);
    
    if (!$usuario) {
        return [
            'success' => false,
            'mensaje' => 'Usuario no encontrado'
        ];
    }
    
    $sql = "DELETE FROM usuarios WHERE id = ?";
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$id]);
        
        $filasEliminadas = $stmt->rowCount();
        
        if ($filasEliminadas > 0) {
            return [
                'success' => true,
                'mensaje' => "Usuario '{$usuario['nombre']}' eliminado correctamente"
            ];
        } else {
            return [
                'success' => false,
                'mensaje' => 'No se pudo eliminar el usuario'
            ];
        }
        
    } catch (PDOException $e) {
        return [
            'success' => false,
            'mensaje' => "Error al eliminar: " . $e->getMessage()
        ];
    }
}

// Uso de la función
$resultado = eliminarUsuario($conexion, 3);
echo $resultado['mensaje'];
?>

Eliminación lógica (soft delete)

En muchas aplicaciones profesionales, es preferible implementar eliminación lógica para mantener un historial:

<?php
function eliminarUsuarioLogico($pdo, $id) {
    $sql = "UPDATE usuarios SET activo = 0, fecha_eliminacion = NOW() WHERE id = ? AND activo = 1";
    
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$id]);
        
        $filasAfectadas = $stmt->rowCount();
        
        if ($filasAfectadas > 0) {
            return [
                'success' => true,
                'mensaje' => 'Usuario desactivado correctamente'
            ];
        } else {
            return [
                'success' => false,
                'mensaje' => 'Usuario no encontrado o ya está desactivado'
            ];
        }
        
    } catch (PDOException $e) {
        return [
            'success' => false,
            'mensaje' => "Error al desactivar usuario: " . $e->getMessage()
        ];
    }
}

// Función para obtener solo usuarios activos
function obtenerUsuariosActivos($pdo) {
    $sql = "SELECT id, nombre, email, fecha_registro FROM usuarios WHERE activo = 1 ORDER BY fecha_registro DESC";
    
    try {
        $stmt = $pdo->query($sql);
        return $stmt->fetchAll();
        
    } catch (PDOException $e) {
        error_log("Error al obtener usuarios activos: " . $e->getMessage());
        return [];
    }
}
?>

Ejemplo completo de gestión CRUD

Para consolidar los conceptos, aquí tienes una clase que encapsula todas las operaciones CRUD:

<?php
class UsuarioManager {
    private $pdo;
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
    }
    
    public function crear($nombre, $email) {
        $sql = "INSERT INTO usuarios (nombre, email) VALUES (?, ?)";
        
        try {
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([$nombre, $email]);
            
            return [
                'success' => true,
                'id' => $this->pdo->lastInsertId()
            ];
            
        } catch (PDOException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    public function obtenerPorId($id) {
        $sql = "SELECT * FROM usuarios WHERE id = ?";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([$id]);
        
        return $stmt->fetch();
    }
    
    public function obtenerTodos() {
        $sql = "SELECT * FROM usuarios ORDER BY fecha_registro DESC";
        $stmt = $this->pdo->query($sql);
        
        return $stmt->fetchAll();
    }
    
    public function actualizar($id, $datos) {
        $campos = [];
        $parametros = [];
        
        foreach ($datos as $campo => $valor) {
            if (in_array($campo, ['nombre', 'email'])) {
                $campos[] = "$campo = ?";
                $parametros[] = $valor;
            }
        }
        
        if (empty($campos)) return ['success' => false, 'error' => 'No hay datos válidos'];
        
        $parametros[] = $id;
        $sql = "UPDATE usuarios SET " . implode(", ", $campos) . " WHERE id = ?";
        
        try {
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($parametros);
            
            return ['success' => true, 'filas_afectadas' => $stmt->rowCount()];
            
        } catch (PDOException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    public function eliminar($id) {
        $sql = "DELETE FROM usuarios WHERE id = ?";
        
        try {
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([$id]);
            
            return ['success' => true, 'filas_eliminadas' => $stmt->rowCount()];
            
        } catch (PDOException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}

// Uso de la clase
$userManager = new UsuarioManager($conexion);

// Crear usuario
$nuevoUsuario = $userManager->crear("Luis Fernández", "luis@email.com");
if ($nuevoUsuario['success']) {
    echo "Usuario creado con ID: " . $nuevoUsuario['id'] . "<br>";
}

// Leer usuarios
$usuarios = $userManager->obtenerTodos();
echo "Total de usuarios: " . count($usuarios) . "<br>";

// Actualizar usuario
$actualizacion = $userManager->actualizar(1, ['nombre' => 'Luis Fernández García']);
if ($actualizacion['success']) {
    echo "Usuario actualizado<br>";
}
?>

Las operaciones CRUD forman la base de cualquier aplicación que maneje datos persistentes. La implementación mostrada utiliza consultas preparadas para garantizar la seguridad, manejo de errores robusto para la fiabilidad, y patrones de diseño que facilitan el mantenimiento y escalabilidad del código.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en PHP

Documentación oficial de PHP
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, PHP es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de PHP

Explora más contenido relacionado con PHP y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender cómo leer y escribir archivos en PHP usando funciones básicas y de bajo nivel.
  • Aprender a manejar rutas, directorios y seguridad en el acceso a archivos.
  • Conectar PHP con bases de datos MySQL mediante PDO y configurar conexiones seguras.
  • Implementar operaciones CRUD básicas (crear, leer, actualizar, eliminar) con consultas preparadas.
  • Gestionar errores y optimizar la interacción con bases de datos para aplicaciones web robustas.