Categoría: Desarrollo backend

  • Guía rápida de attributes en PHP 8+: uso y ejemplos

    Guía rápida de attributes en PHP 8+: uso y ejemplos

    Los attributes en PHP 8+ permiten adjuntar metadatos nativos a clases, métodos, propiedades y parámetros. Esta guía muestra cómo definirlos, aplicarlos y leerlos con Reflection, incluyendo ejemplos prácticos.

    Introducción

    Antes de PHP 8 se usaban docblocks y parsing de comentarios para añadir metadatos (por ejemplo, rutas). Los attributes son nativos: son clases usadas como metadatos mediante sintaxis literal, p. ej. #[Route('/users')].

    Prerrequisitos

    Necesitas PHP 8.0+ (los attributes son una característica introducida con PHP 8). También conviene familiaridad básica con clases y la API de Reflection para leer atributos en tiempo de ejecución.

    Desarrollo

    Procedimiento

    1. Crear la clase que representará el attribute y marcarla con #[Attribute].
    2. Aplicar el attribute sobre clases, métodos, propiedades o parámetros según correspondan.
    3. Leer los atributos en tiempo de ejecución usando Reflection y, si hace falta, instanciarlos.

    A continuación hay snippets que ilustran cada paso: definición, uso y lectura por Reflection.

    <?php
    #[Attribute(Attribute::TARGET_METHOD)]
    class Route
    {
        public function __construct(
            public string $path,
            public array $methods = ['GET']
        ) {}
    }
    Lenguaje del código: PHP (php)
    <?php
    class UserController
    {
        #[Route('/users', methods: ['GET'])]
        public function index() {}
    }
    Lenguaje del código: PHP (php)
    <?php
    $method = new ReflectionMethod(UserController::class, 'index');
    $attributes = $method->getAttributes();
    
    foreach ($attributes as $attribute) {
        $instance = $attribute->newInstance();
        var_dump($instance->path); // '/users'
    }
    Lenguaje del código: PHP (php)

    Atributos nativos

    PHP incluye varios attributes útiles. Aquí hay ejemplos prácticos tomados de la sintaxis nativa que aparecen en el lenguaje.

    Ejemplo: #[ReturnTypeWillChange] — se usa para compatibilidad de firmas en bibliotecas.

    <?php
    class MyIterator implements Iterator
    {
        #[ReturnTypeWillChange]
        public function current() {
            return 'foo';
        }
    }
    Lenguaje del código: PHP (php)

    Ejemplo: #[Deprecated] — marca elementos en desuso y puede incluir un motivo.

    <?php
    #[Deprecated(reason: 'Use newFunction() instead.')]
    function oldFunction() {
        return 'legacy';
    }
    Lenguaje del código: PHP (php)

    Ejemplo: #[AllowDynamicProperties] — re-habilita propiedades dinámicas en clases legadas.

    <?php
    #[AllowDynamicProperties]
    class User {}
    
    $user = new User();
    $user->name = 'Lukasz'; // funciona
    Lenguaje del código: PHP (php)

    Ejemplo: #[SensitiveParameter] — oculta valores en trazas y dumps para parámetros sensibles.

    <?php
    function login(#[SensitiveParameter] string $password) {
        throw new Exception('Oops!');
    }
    
    login('super-secret-password');
    Lenguaje del código: PHP (php)

    Ejemplo: #[Override] — asegura que un método realmente sobrescribe uno del padre.

    <?php
    class Base {
        public function greet() {}
    }
    
    class Child extends Base {
        #[Override]
        public function greet() {
            echo "Hello!";
        }
    }
    Lenguaje del código: PHP (php)

    Ejemplos

    Combinar atributos con frameworks o bibliotecas propias suele reducir la necesidad de parsear docblocks y simplifica extractores de metadatos. Un patrón común: definir attributes para rutas, validar parámetros sensibles y marcar API obsoletas.

    Ejemplo práctico rápido: definir una ruta y extraerla desde un bootstrap de aplicación para registrar endpoints.

    <?php
    // Definición ya mostrada arriba: Route
    // En bootstrap de la app:
    $rc = new ReflectionClass(UserController::class);
    foreach ($rc->getMethods() as $method) {
        foreach ($method->getAttributes() as $attr) {
            $route = $attr->newInstance();
            // registrar $route->path y $route->methods en el router
        }
    }
    Lenguaje del código: PHP (php)

    Checklist

    1. Reemplazar parsing de docblocks por classes-attribute cuando sea posible.
    2. Marcar las classes de attribute con #[Attribute] y ajustar TARGET_* según uso.
    3. Actualizar extractores para usar Reflection::getAttributes().
    4. Probar casos de compatibilidad: #[ReturnTypeWillChange] y #[AllowDynamicProperties] si persisten dependencias legadas.
    5. Marcar parámetros sensibles con #[SensitiveParameter] para proteger trazas.

    Conclusión

    Los attributes son una mejora clara frente a los docblocks: son nativos, más seguros y fáciles de consumir por código. Migrar a attributes reduce parsing ad hoc y coloca la metadata junto al código que la usa.

    Si estás manteniendo una librería o framework en PHP, prueba a implementar un pequeño atributo y su extractor: la reducción de complejidad suele notarse rápido.

  • Seguridad de sesiones y cookies en PHP: guía práctica

    Seguridad de sesiones y cookies en PHP: guía práctica

    Resumen: Esta guía práctica resume las medidas esenciales para gestionar sesiones y cookies en PHP de forma segura: inicio de sesión, regeneración de ID, cookies seguras, timeouts, almacenamiento eficiente y limpieza al cerrar sesión.

    Introducción

    Sesiones y cookies permiten mantener estado en aplicaciones web PHP: autenticación, preferencias y datos temporales. Usadas correctamente mejoran la experiencia; mal configuradas, introducen riesgos de seguridad.

    Prerrequisitos

    Antes de aplicar las prácticas descritas asegúrate de servir las páginas sensibles por HTTPS y de tener control sobre el código que inicia y destruye sesiones. No afirmaré compatibilidades concretas; valida esto según tu entorno.

    Conocimiento mínimo necesario: saber dónde llamar a session_start() y cómo enviar cookies desde PHP. Evita exponer identificadores de sesión en URLs o registros.

    Desarrollo

    Procedimiento

    Pasos prácticos y concisos para asegurar sesiones y cookies en PHP. Aplique cada paso según el riesgo y la arquitectura de su aplicación.

    1. Iniciar sesiones de forma controlada y consistente.
    2. Regenerar el identificador de sesión tras la autenticación.
    3. Enviar cookies con flags Secure, HttpOnly y SameSite cuando corresponda.
    4. Implementar timeouts por inactividad y limpieza al logout.
    5. Almacenar solo identificadores en la sesión; datos pesados en base de datos o cache.
    6. Opcional: usar un session handler personalizado para almacenamiento centralizado.

    Detalles clave: regenerar el ID reduce el riesgo de session fixation; Secure y HttpOnly protegen el cookie en tránsito y frente a JavaScript; SameSite mitiga ciertas CSRF.

    Pro tip: Usa sesiones para identificar entidades (IDs) y no para persistir grandes objetos o datos sensibles sin cifrado.

    Ejemplos

    A continuación se incluyen ejemplos prácticos adaptados desde patrones comunes. Escapa los marcadores de apertura PHP en tu código según la plantilla del bloque.

    <?php
    // Start the session
    session_start();
    
    // Store some data in the session
    $_SESSION['username'] = 'JohnDoe';
    
    // Retrieve data from the session
    echo 'Hello, ' . $_SESSION['username']; // Outputs: Hello, JohnDoe
    Lenguaje del código: PHP (php)

    Regenerar el ID de sesión inmediatamente después de un login exitoso:

    <?php
    session_start();
    
    // After a successful login
    if ($_POST['username'] == 'user' && $_POST['password'] == 'password') {
        session_regenerate_id(true);  // Regenerate the session ID for added security
        
        $_SESSION['username'] = 'user';
        echo "Login successful, and your session ID has been regenerated!";
    }
    Lenguaje del código: PHP (php)

    Ejemplo de cookie segura con atributos recomendados (transmisión segura y protección contra acceso por JS):

    <?php
    // Set a cookie that only works on secure connections (HTTPS)
    setcookie('user_preference', 'dark_mode', [
        'expires' => time() + 3600, // 1 hour expiration
        'path' => '/',
        'domain' => 'yourdomain.com',
        'secure' => true,  // Send cookie only over HTTPS
        'httponly' => true,  // Prevent JavaScript access to cookie
        'samesite' => 'Strict' // Helps prevent CSRF attacks
    ]);
    
    echo 'Your preference cookie is set securely.';
    Lenguaje del código: PHP (php)

    Timeout de sesión por inactividad (mecanismo simple basado en marcas temporales):

    <?php
    session_start();
    
    // Set timeout period (10 minutes)
    $timeout = 600;
    
    if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $timeout)) {
        // If the session has expired, destroy it
        session_unset();
        session_destroy();
        echo 'Session expired. Please log in again.';
    } else {
        $_SESSION['LAST_ACTIVITY'] = time(); // Update last activity time
        echo 'Your session is still active.';
    }
    Lenguaje del código: PHP (php)

    Esqueleto de un session handler personalizado para almacenar sesiones en base de datos o cache centralizada:

    <?php
    class CustomSessionHandler extends SessionHandler {
        public function read($session_id) {
            // Read session data from the database
        }
    
        public function write($session_id, $data) {
            // Write session data to the database
        }
    }
    
    // Register custom session handler
    $handler = new CustomSessionHandler();
    session_set_save_handler($handler, true);
    session_start();
    Lenguaje del código: PHP (php)

    Al cerrar sesión, destruye la sesión y expira las cookies relevantes para evitar reutilización:

    <?php
    session_start();
    
    // Destroy the session and clear all session data
    session_unset();
    session_destroy();
    
    // Expire session and preference cookies
    setcookie(session_name(), '', time() - 3600, '/');
    setcookie('user_preference', '', time() - 3600, '/');
    
    echo 'Session and cookies have been cleared.';
    Lenguaje del código: PHP (php)

    Checklist

    1. Servir páginas sensibles por HTTPS.
    2. Iniciar sesión con session_start() solo donde sea necesario.
    3. Regenerar ID de sesión tras autenticación (session_regenerate_id).
    4. Enviar cookies con Secure, HttpOnly y SameSite adecuados.
    5. Implementar timeout por inactividad y actualizar LAST_ACTIVITY.
    6. Almacenar solo identificadores en la sesión; consultar DB para datos grandes.
    7. Destruir sesión y expirar cookies en logout.

    Conclusión

    La seguridad de sesiones y cookies es una combinación de buenas prácticas: transporte seguro (HTTPS), configuración correcta de cookies, rotación de identificadores, timeouts y limpieza al logout. Estas medidas reducen riesgos comunes como hijacking y XSS.

    Empieza aplicando los pasos del checklist y adapta las implementaciones (por ejemplo, handlers personalizados) según la escala y arquitectura de tu aplicación.

  • PHP vs Node.js: cómo elegir el backend en 2025

    PHP vs Node.js: cómo elegir el backend en 2025

    Resumen: Comparativa técnica entre PHP y Node.js para elegir backend según requisitos de rendimiento, ecosistema y experiencia del equipo.

    Este artículo sintetiza ventajas, limitaciones y ejemplos mínimos para ayudar a arquitectos y desarrolladores a decidir qué tecnología usar.

    Introducción

    PHP y Node.js son tecnologías maduras para backend con enfoques distintos: PHP tradicionalmente síncrono y orientado a request-response; Node.js basado en I/O asíncrono y event-driven.

    Prerrequisitos

    Antes de elegir, evalúa: cargas concurrentes previstas, necesidad de tiempo real, experiencia del equipo y requisitos de despliegue.

    1. Definir el patrón de tráfico (p. ej. muchas conexiones concurrentes vs pocas por usuario).
    2. Identificar dependencias y ecosistema (CMS, bibliotecas, integraciones).
    3. Revisar capacidades de hosting y costos operativos.

    Desarrollo

    Comparar en cuatro ejes: rendimiento, ecosistema, curva de aprendizaje y despliegue.

    Procedimiento

    1) Analiza el caso de uso. 2) Mide concurrencia y latencia objetivo. 3) Selecciona la pila que minimice riesgos técnicos y de operación.

    Resumen de diferencias clave:

    • PHP: buen soporte para sitios de contenido, despliegue sencillo en hosting compartido, amplio ecosistema (WordPress, Composer, Laravel).
    • Node.js: mejor para I/O intensivo y tiempo real; ecosistema moderno con npm y frameworks como Express o Fastify.

    Ejemplos

    Ejemplos mínimos que ilustran el modelo de ejecución en cada plataforma.

    <?php
    // Ejemplo PHP: manejador básico en entorno tradicional (request-response)
    header('Content-Type: application/json');
    $response = ['time' => date('c'), 'message' => 'Hola desde PHP'];
    echo json_encode($response);
    Lenguaje del código: PHP (php)

    En PHP el ciclo típico abre, procesa y cierra la petición; es sencillo y efectivo para sitios de contenido.

    const http = require('http');
    
    const server = http.createServer((req, res) => {
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ time: new Date().toISOString(), message: 'Hola desde Node.js' }));
    });
    
    server.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    Lenguaje del código: JavaScript (javascript)

    Node.js mantiene un loop de eventos que permite gestionar muchas conexiones concurrentes con eficiencia en I/O.

    Checklist

    Lista rápida para decidir tecnología según el proyecto.

    1. ¿El proyecto requiere tiempo real o muchas conexiones concurrentes? → Considerar Node.js.
    2. ¿Priman CMS o contenidos estáticos y despliegue rápido? → PHP/WordPress puede ser suficiente.
    3. ¿El equipo domina JavaScript o PHP/Laravel? → Elegir según experiencia para reducir riesgos.
    4. ¿Necesitas microservicios o arquitectura basada en eventos? → Node.js suele facilitarlo.

    Conclusión

    No existe una respuesta universal: PHP sigue siendo válido para sitios de contenido y despliegues rápidos; Node.js destaca en aplicaciones en tiempo real y arquitecturas orientadas a I/O.

    La recomendación práctica: prioriza requisitos técnicos, experiencia del equipo y costos operativos al seleccionar entre PHP y Node.js.