yazrkisvs3vvvsv33svrhetrjsvyvsvvyjsvsvs
tavsuysvssvvjvvyjyjkvsvqd
qfogsvvsvsegjdgdfgdskhgdksvqsvshdqsd
<?php
// verify-email.php — FASE 8.6: confirma cambio de email vía token enviado al nuevo email
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/db.php';

$token = trim((string)($_GET['t'] ?? ''));

function _ve_render(string $title, string $body, string $color = '#dc2626'): void {
    echo "<!DOCTYPE html><html lang='es'><head><meta charset='utf-8'>
        <title>{$title} · Brain</title>
        <style>body{font-family:system-ui,sans-serif;background:#0a0a0a;color:#e5e5e5;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:20px}
        .box{max-width:480px;background:#1a1a1a;border:1px solid #2a2a2a;border-radius:14px;padding:32px;text-align:center}
        h1{color:{$color};margin:0 0 14px;font-size:22px}
        p{color:#a1a1aa;line-height:1.6;margin:0 0 18px}
        a.btn{display:inline-block;padding:10px 24px;background:#dc2626;color:#fff;text-decoration:none;border-radius:8px;font-weight:700}</style>
        </head><body><div class='box'><h1>{$title}</h1><div>{$body}</div></div></body></html>";
    exit;
}

if (!$token || !preg_match('/^[a-f0-9]{64}$/', $token)) {
    _ve_render('Token inválido', '<p>El link de confirmación no tiene un formato válido.</p><p><a class="btn" href="index.php">Volver al inicio</a></p>');
}

if (!$pdo) _ve_render('Error temporal', '<p>No hay conexión a la base de datos. Intenta de nuevo más tarde.</p>');

try {
    $st = $pdo->prepare('SELECT user_id, new_email, expires_at FROM dm_email_change_tokens WHERE token=? LIMIT 1');
    $st->execute([$token]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
} catch (\Throwable $e) {
    _ve_render('Error temporal', '<p>Algo salió mal verificando el token.</p>');
}

if (!$row) {
    _ve_render('Link inválido o ya usado', '<p>Este link no existe o ya fue consumido. Si quieres cambiar tu email, vuelve a Mi Perfil y solicita un nuevo cambio.</p><p><a class="btn" href="index.php">Ir a Brain</a></p>');
}

if (strtotime($row['expires_at']) < time()) {
    $pdo->prepare('DELETE FROM dm_email_change_tokens WHERE token=?')->execute([$token]);
    _ve_render('Link expirado', '<p>Este link tenía validez de 1 hora y ya expiró. Solicita un nuevo cambio desde Mi Perfil.</p><p><a class="btn" href="index.php">Ir a Brain</a></p>');
}

// Aplicar cambio + consumir token + log
try {
    $pdo->beginTransaction();
    // Verificar otra vez que el email no esté tomado (race condition window)
    $du = $pdo->prepare('SELECT id FROM dm_users WHERE email=? AND id<>? LIMIT 1');
    $du->execute([$row['new_email'], (int)$row['user_id']]);
    if ($du->fetchColumn()) {
        $pdo->rollBack();
        $pdo->prepare('DELETE FROM dm_email_change_tokens WHERE token=?')->execute([$token]);
        _ve_render('Email ya en uso', '<p>El email ' . htmlspecialchars($row['new_email']) . ' fue registrado por otro usuario mientras tu link estaba pendiente. Solicita un nuevo cambio con un email diferente.</p>');
    }
    $pdo->prepare('UPDATE dm_users SET email=? WHERE id=?')->execute([$row['new_email'], (int)$row['user_id']]);
    $pdo->prepare('DELETE FROM dm_email_change_tokens WHERE token=?')->execute([$token]);
    $pdo->commit();
    if (function_exists('dm_log')) {
        dm_log((int)$row['user_id'], null, 'email_changed', "Email confirmado: {$row['new_email']}");
    }
    // Si la sesión activa es la del usuario, actualizar memoria
    if (session_status() === PHP_SESSION_ACTIVE && (int)($_SESSION['dm_user_id'] ?? 0) === (int)$row['user_id']) {
        $_SESSION['dm_email'] = $row['new_email'];
    }
    _ve_render('✓ Email actualizado', '<p>Tu nuevo email <b style="color:#10b981">' . htmlspecialchars($row['new_email']) . '</b> está activo. Inicia sesión con él la próxima vez.</p><p><a class="btn" href="index.php">Ir a Brain</a></p>', '#10b981');
} catch (\Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    _ve_render('Error aplicando cambio', '<p>Algo falló al actualizar tu email. Intenta de nuevo o contacta soporte.</p>');
}
