Preguntas frecuentes
Funciones y arquitectura
Preguntas técnicas sobre el motor XDP, los plugins, la seguridad, el sistema de frames y las convenciones de desarrollo de BeamReactor.
¿Para qué sirve frameheader()?+
frameheader() abre una sección visual (frame) en la página. Muestra el título del plugin o de la sección y crea el contenedor HTML en el que se renderizará el contenido. Uso: frameheader('Mi título', 'h3', false). Los niveles de título siguen la jerarquía HTML: h1 para el título de la página (una sola vez), h2 para las secciones principales, h3 y siguientes para los frames y widgets. Un plugin llamado directamente debe empezar por: if($obj=='mi_plugin.php') frameheader($dialplugindisplay); — esta condición evita que la cabecera se muestre dos veces cuando el plugin se incluye desde otro script.
¿Cuándo usar framefooter()?+
framefooter() cierra el frame abierto por frameheader(). Es indispensable antes de abrir una nueva sección con frameheader(). No llame nunca a framefooter() sin un frameheader() a continuación, salvo al final de la página. El patrón clásico para estructurar una página en varios bloques: frameheader('Sección 1'); /* contenido */ framefooter(); frameheader('Sección 2'); /* contenido */. El motor se encarga automáticamente del cierre final.
¿Cómo estructurar una página en varias secciones?+
Use el par framefooter() / frameheader() para encadenar las secciones. Cada sección crea un bloque visual distinto con su propio título. Ejemplo: tras mostrar un formulario y recibir un error, cierre el frame actual con framefooter(), abra un frame nuevo y limpio con frameheader(''), vuelva a incluir el formulario y haga return. Así el usuario permanece en una página válida y enmarcada, sin redirección HTTP.
¿Cómo funciona secure()?+
secure() comprueba si el nivel del usuario conectado es suficiente para acceder a un recurso. Recibe como parámetro una constante de nivel (BASE_LEVEL_ADMIN, PLUGIN_LEVEL_MODERATOR, etc.) y devuelve true o false. El patrón habitual: frameheader($dialplugindisplay); if(!secure(PLUGIN_LEVEL_MODERATOR)) { forbids(); return; }. El frame se abre ANTES de la comprobación — forbids() se muestra dentro del frame; si no, el layout se rompe. El truco secure(0) comprueba simplemente si el usuario ha iniciado sesión.
¿Qué includes usar en un plugin?+
Ninguno para la configuración y las bibliotecas — el motor XDP las carga automáticamente. El único include autorizado es el de la locale: include(getlocale('nombre_del_plugin'));. El motor detecta y carga los archivos .conf.inc.php y .lib.inc.php. Hacer un require o include manual de la configuración o de las libs provocará un warning y una ruta rota. Del mismo modo, no incluya nunca un módulo (.mod.php) — se llaman exclusivamente mediante ?obj=nombre.mod.
¿Cómo funcionan las traducciones en un plugin?+
Cada plugin tiene sus archivos de traducción en /locale/nombre_del_plugin.XX.inc.php (XX = código de idioma ISO). La carga se hace mediante include(getlocale('nombre_del_plugin'));, que debe llamarse ANTES de frameheader() para evitar errores de variable ausente. Las traducciones usan un array $dialnombreplugin[]. $dialplugindisplay contiene el título mostrado del plugin, $dialplugincall el nombre en el centro de control. getAvailableLanguages() devuelve la lista de idiomas disponibles.
¿Cómo cargar CSS o JavaScript específico de un plugin?+
Use la variable global $headdata para inyectar en el <head>: $headdata .= '<link rel="stylesheet" type="text/css" href="plugins/mi_plugin/css/mi_plugin.css">'; Para el JavaScript, el principio es el mismo: $headdata .= '<script src="plugins/mi_plugin/js/mi_plugin.js"></script>'; Para ejecutar JS después del DOM, use $footdata con un heredoc. Las CSS deben usar las variables definidas en core.css — no invente nunca colores. Si falta una variable, proponga añadirla a core.css.
¿Cómo validar las entradas del usuario?+
Use el Sanitizer: use Beamreactor\Sanitizer\Parser; y después Parser::sanitize($input, 'type'). Los tipos disponibles incluyen: bool, date, email, name, html, xml, uuid, url, string, ip, float, int, path y otros. sanitize() limpia y valida el dato, y devuelve false si no es válido. check() comprueba el formato sin limpiar. Haga siempre la sanitización ANTES de cualquier operación SQL. No invente nunca un datatype — proponga uno si es necesario.
¿Cómo interactuar con la base de datos?+
Use la clase SQL: use Beamreactor\Database\SQL;. Métodos principales: SQL::query() para varias filas, SQL::queryFirst() para una sola fila, SQL::queryValue() para un valor único, SQL::insertRow() para insertar, SQL::updateRow() para actualizar, SQL::deleteRow() para eliminar. Use siempre consultas preparadas con parámetros ?. La concatenación directa de variables en el SQL está estrictamente prohibida. Compruebe que la BD está disponible con isset($cfg['dbtable']) y que su tabla existe con SQL::tableExists().
¿Cómo crear un endpoint AJAX?+
Los módulos (.mod.php) son los endpoints AJAX de BeamReactor. Responden en JSON, XML, HTML o texto. Se colocan en /handlers/nombre_plugin.mod.php y se llaman mediante ?obj=nombre_plugin.mod (sin el .php). No llame nunca a la ruta completa del archivo. Estructura mínima: comprobación de frameheader, seguridad con secure(), header Content-Type, tratamiento de la acción mediante Parser::sanitize(), respuesta JSON con ['success' => !!1] o ['success' => !!0]. En JavaScript, la llamada se hace con $.post(BEAM_BASE_URL + '?obj=nombre_plugin.mod', {...}).
¿Cómo funciona el enrutamiento de las páginas?+
En BeamReactor todo pasa por index.php. El parámetro ?obj= determina lo que se carga. Un plugin: ?obj=mi_plugin.php. Un módulo AJAX: ?obj=mi_plugin.mod. Un documento: ?obj=mi_pagina.dta. El motor XDP resuelve la ruta, carga automáticamente la configuración, las libs y la locale, y ejecuta el script en un entorno seguro. Ningún script PHP puede llamarse directamente — todo pasa por el motor.
¿Cómo mostrar notificaciones al usuario?+
BeamReactor dispone de un sistema de toasts con 6 niveles: debug (0), info (1), success (2), warning (3), error (4), critical (5). Uso rápido: Toast::info('Título', 'Mensaje', 5000); o Toast::add(Toast::LEVEL_WARNING, 'Título', 'Mensaje', BASE_LEVEL_USER, 0). El parámetro minUserLevel permite dirigir las notificaciones por nivel de acceso. La duración va en milisegundos, 0 para persistente.
¿Cuál es la estructura de un plugin de BeamReactor?+
Un plugin es una carpeta autónoma en /plugins/nombre_del_plugin/ que contiene: nombre_del_plugin.php (interfaz principal), /conf/ (configuración cargada automáticamente), /lib/ (bibliotecas cargadas automáticamente), /locale/ (traducciones por idioma), /handlers/ (endpoints AJAX .mod.php), /css/, /js/, /images/, /sql/ (instalación de las tablas), /tests/, /doc/ (documentación .md y ayuda .help.json) y /data/cache/ para los datos persistentes. La instalación consiste en dejar la carpeta. La eliminación, en retirarla.
¿Cómo mostrar diálogos JavaScript en BeamReactor?+
BeamReactor sustituye los alert/confirm/prompt nativos por diálogos personalizados definidos en javascript/dialogs.js.php. Cuatro funciones: alertWindow('Título', 'mensaje') para una alerta, confirmWindow('Título', '¿pregunta?', {}, callback) para una confirmación, promptWindow('Título', 'Etiqueta:', {}, callback) para una entrada de datos, infoWindow('Título', 'info') para una información. No use nunca alert(), confirm() ni prompt() nativos.
¿Cómo pasar las traducciones PHP al JavaScript?+
En el archivo de locale del plugin, defina un array $js_translations y llame a setJavascriptLocale($js_translations). Ejemplo: $js_translations = ['mi_plugin' => ['error_msg' => $dialmiplugin[5]], 'global' => ['error' => $dial[32]]]; setJavascriptLocale($js_translations);. En JavaScript, acceda a las traducciones mediante PLUGIN_TRANSLATION.mi_plugin.error_msg. Las traducciones se inyectan en el head como un objeto JavaScript global.
¿Puedo usar exit o die en un plugin?+
No. Los plugins no pueden usar nunca exit ni die. El único exit autorizado en todo el código de un plugin es if(!function_exists('frameheader')) die('forbidden'); en la primera línea, que comprueba el contexto BeamReactor. Para interrumpir la ejecución, use return. Para tratar un error, muestre el mensaje dentro del frame y haga return. Si un plugin usa exit o die, el motor no puede saber qué ha fallado y el diagnóstico se vuelve imposible.
¿Cómo funcionan los niveles de seguridad?+
BeamReactor usa una jerarquía fija: OVERMIND > ADMIN > MODERATOR > HIGHUSER > USER. Las constantes BASE_LEVEL_* se definen en cog.inc.php. Cada plugin puede definir sus propios niveles mediante NOMBRE_PLUGIN_LEVEL_* en su configuración. $basedisplevel usa siempre BASE_LEVEL_*, nunca PLUGIN_LEVEL_*. Los define() personalizados se hacen después de $basedisplevel. El sistema completa automáticamente los niveles que faltan mediante base_user_levels().
¿Cómo funciona la carga automática de las clases?+
El motor carga automáticamente los archivos .lib.inc.php y .conf.inc.php. Para clases adicionales, registre un autoloader PSR-4 en la configuración del plugin con spl_autoload_register(). El namespace sigue la convención Beamreactor\NombrePlugin\. Los archivos de clase van en /lib/ y se resuelven por la ruta relativa al namespace. Esto permite que varios plugins convivan sin colisión de nombres.
Autenticación de dos factores (2FA)
Añade una capa de protección indispensable al exigir una prueba de identidad adicional. Garantiza que, aunque le roben la contraseña, un tercero no pueda acceder a sus datos. Es la barrera más eficaz contra los intentos de suplantación de identidad y de pirateo de cuentas.
¿Cómo activar la autenticación de dos factores?+
Para proteger su cuenta, se necesitan dos pasos. Los usuarios registrados deben iniciar sesión en la interfaz principal de BeamReactor. Al hacer clic en el botón «Perfil», arriba a la izquierda, accederá a su perfil. En la parte inferior encontrará un código QR 2FA que debe escanear con una aplicación como Google Authenticator o Microsoft Authenticator. Se le proporcionarán códigos de recuperación: cópielos con cuidado para recuperar su cuenta en caso de pérdida o robo del teléfono.
¿Cómo inicio sesión con la autenticación de dos factores?+
Inicie sesión con su nombre de usuario y contraseña en el sitio BeamReactor. A continuación, el sistema le pedirá un código que encontrará en la aplicación Authenticator de su teléfono.
¿Cuáles son los requisitos?+
Actualice el sistema operativo de su teléfono y la aplicación Google o Microsoft Authenticator a sus últimas versiones. Si no puede iniciar sesión pero aún tiene acceso al correo electrónico de su cuenta, intente cambiar su contraseña. Sin acceso a su correo, contáctenos a través del formulario de soporte.
¿Y si he olvidado mi contraseña?+
Puede restablecerla en cualquier momento haciendo clic en el enlace «¿No puede acceder a su cuenta?» de la página de inicio de sesión.
¿Y si he perdido o roto mi teléfono?+
Utilice uno de los códigos de recuperación proporcionados al activar la 2FA. En la página de autenticación, haga clic en «Código de recuperación», introdúzcalo y, una vez conectado, actualice los ajustes 2FA de su perfil.
¿Y si cambio de teléfono o de sistema?+
Nuevo dispositivo, nuevo sistema, reinstalación tras un formateo: el procedimiento es el mismo que para un teléfono perdido. Utilice sus códigos de recuperación para iniciar sesión y, a continuación, sincronice su nuevo dispositivo desde su perfil de usuario.
¿Por qué se ha implantado la autenticación de dos factores?+
La autenticación de dos factores (2FA) añade una capa de protección indispensable al exigir una prueba de identidad adicional. Garantiza que, aunque le roben la contraseña, un tercero no pueda acceder a sus datos. Es la barrera más eficaz contra los intentos de suplantación de identidad y de pirateo de cuentas.
