En vous promenant sur Beamreactor, nous stockons votre IP 48h pour des raisons de sécurité.
Beamreactor, WYSIWYG web engines: home
FAQ · TICKETS · CONTACT · CHANGELOG

Having an issue?
We're here.

Browse the FAQ, open a support ticket, or contact us directly. No chatbot, no queue: an operator actually answers.

Before writing, the answer may already be here

Features and architecture

Technical questions about the XDP engine, plugins, security, the frame system and BeamReactor development conventions.

What is frameheader() for?+
frameheader() opens a visual section (frame) on the page. It displays the plugin or section title and creates the HTML container in which content will be rendered. Usage: frameheader('My title', 'h3', false). Title levels follow the HTML hierarchy: h1 for the page title (once only), h2 for main sections, h3 and beyond for frames and widgets. A directly called plugin must start with: if($obj=='my_plugin.php') frameheader($dialplugindisplay); — this condition prevents double header rendering when the plugin is included from another script.
When should I use framefooter()?+
framefooter() closes the frame opened by frameheader(). It is required before opening a new section with frameheader(). Never call framefooter() without a following frameheader(), except at the end of a page. The standard pattern for structuring a page into multiple blocks: frameheader('Section 1'); /* content */ framefooter(); frameheader('Section 2'); /* content */. The engine handles the final closing automatically.
How do I structure a page with multiple sections?+
Use the framefooter() / frameheader() pair to chain sections. Each section creates a distinct visual block with its own title. Example: after displaying a form and receiving an error, close the current frame with framefooter(), open a clean new frame with frameheader(''), include the form again, then return. This keeps the user on a valid, properly framed page without any HTTP redirect.
How does secure() work?+
secure() checks whether the logged-in user's level is sufficient to access a resource. It takes a level constant as parameter (BASE_LEVEL_ADMIN, PLUGIN_LEVEL_MODERATOR, etc.) and returns true or false. The standard pattern: frameheader($dialplugindisplay); if(!secure(PLUGIN_LEVEL_MODERATOR)) { forbids(); return; }. The frame is opened BEFORE the check — forbids() displays inside the frame, otherwise the layout breaks. The trick secure(0) simply checks whether the user is logged in at all.
Which includes should I use in a plugin?+
None for config and libraries — the XDP engine loads them automatically. The only permitted include is for the locale: include(getlocale('plugin_name'));. Files named .conf.inc.php and .lib.inc.php are detected and loaded by the engine. Manual require or include for config or libs will cause a warning and a broken path. Similarly, never include a module (.mod.php) — they are called exclusively via ?obj=name.mod.
How do translations work in a plugin?+
Each plugin has its translation files in /locale/plugin_name.XX.inc.php (XX = ISO language code). Loading is done via include(getlocale('plugin_name'));, which must be called BEFORE frameheader() to avoid missing variable errors. Translations use a $dialpluginname[] array. $dialplugindisplay contains the displayed plugin title, $dialplugincall the name shown in the control centre. getAvailableLanguages() returns the list of available languages.
How do I load plugin-specific CSS or JavaScript?+
Use the global variable $headdata to inject into <head>: $headdata .= '<link rel="stylesheet" type="text/css" href="plugins/my_plugin/css/my_plugin.css">'; For JavaScript, same approach: $headdata .= '<script src="plugins/my_plugin/js/my_plugin.js"></script>'; To execute JS after the DOM, use $footdata with a heredoc. CSS must use variables defined in core.css — never invent colours. If a variable is missing, suggest adding it to core.css.
How do I validate user input?+
Use the Sanitizer: use Beamreactor\Sanitizer\Parser; then Parser::sanitize($input, 'type'). Available types include: bool, date, email, name, html, xml, uuid, url, string, ip, float, int, path and others. sanitize() cleans and validates the data, returning false if invalid. check() verifies the format without cleaning. Always sanitize BEFORE any SQL operation. Never invent a datatype — propose one if needed.
How do I interact with the database?+
Use the SQL class: use Beamreactor\Database\SQL;. Main methods: SQL::query() for multiple rows, SQL::queryFirst() for a single row, SQL::queryValue() for a single value, SQL::insertRow() to insert, SQL::updateRow() to update, SQL::deleteRow() to delete. Always use prepared statements with ? parameters. Direct variable concatenation in SQL is strictly forbidden. Check database availability with isset($cfg['dbtable']) and table existence with SQL::tableExists().
How do I create an AJAX endpoint?+
Modules (.mod.php) are BeamReactor's AJAX endpoints. They respond with JSON, XML, HTML or text. They go in /handlers/plugin_name.mod.php and are called via ?obj=plugin_name.mod (without .php). Never call the full file path. Minimal structure: frameheader check, security via secure(), Content-Type header, action processing via Parser::sanitize(), JSON response with ['success' => !!1] or ['success' => !!0]. On the JavaScript side, calls use $.post(BEAM_BASE_URL + '?obj=plugin_name.mod', {...}).
How does page routing work?+
Everything in BeamReactor goes through index.php. The ?obj= parameter determines what gets loaded. A plugin: ?obj=my_plugin.php. An AJAX module: ?obj=my_plugin.mod. A document: ?obj=my_page.dta. The XDP engine resolves the path, loads config, libs and locale automatically, then executes the script in a secured environment. No PHP script can be called directly — everything goes through the engine.
How do I display notifications to the user?+
BeamReactor has a toast system with 6 levels: debug (0), info (1), success (2), warning (3), error (4), critical (5). Quick usage: Toast::info('Title', 'Message', 5000); or Toast::add(Toast::LEVEL_WARNING, 'Title', 'Message', BASE_LEVEL_USER, 0). The minUserLevel parameter targets notifications by access level. Duration is in milliseconds, 0 for persistent.
What is the structure of a BeamReactor plugin?+
A plugin is a self-contained folder in /plugins/plugin_name/ containing: plugin_name.php (main interface), /conf/ (auto-loaded config), /lib/ (auto-loaded libraries), /locale/ (per-language translations), /handlers/ (AJAX endpoints .mod.php), /css/, /js/, /images/, /sql/ (table installation), /tests/, /doc/ (documentation .md and help .help.json), and /data/cache/ for persistent data. Installation means dropping the folder in. Removal means taking it out.
How do I display JavaScript dialogs in BeamReactor?+
BeamReactor replaces native alert/confirm/prompt with custom dialogs defined in javascript/dialogs.js.php. Four functions: alertWindow('Title', 'message') for alerts, confirmWindow('Title', 'question?', {}, callback) for confirmations, promptWindow('Title', 'Label:', {}, callback) for input, infoWindow('Title', 'info') for information. Never use native alert(), confirm() or prompt().
How do I pass PHP translations to JavaScript?+
In the plugin locale file, define a $js_translations array and call setJavascriptLocale($js_translations). Example: $js_translations = ['my_plugin' => ['error_msg' => $dialmyplugin[5]], 'global' => ['error' => $dial[32]]]; setJavascriptLocale($js_translations);. On the JavaScript side, access translations via PLUGIN_TRANSLATION.my_plugin.error_msg. Translations are injected into the head as a global JavaScript object.
Can I use exit or die in a plugin?+
No. Plugins must never use exit or die. The only permitted die in all plugin code is if(!function_exists('frameheader')) die('forbidden'); on the first line, which verifies the BeamReactor context. To stop execution, use return. To handle an error, display the message inside the frame then return. If a plugin uses exit or die, the engine cannot determine what failed and diagnostics become impossible.
How do security levels work?+
BeamReactor uses a fixed hierarchy: OVERMIND > ADMIN > MODERATOR > HIGHUSER > USER. BASE_LEVEL_* constants are defined in cog.inc.php. Each plugin can define its own levels via PLUGIN_NAME_LEVEL_* in its configuration. $basedisplevel always uses BASE_LEVEL_*, never PLUGIN_LEVEL_*. Custom define() calls come after $basedisplevel. The system automatically fills in missing levels via base_user_levels().
How does automatic class loading work?+
Files named .lib.inc.php and .conf.inc.php are loaded automatically by the engine. For additional classes, register a PSR-4 autoloader in the plugin configuration using spl_autoload_register(). The namespace follows the convention Beamreactor\PluginName\. Class files go in /lib/ and are resolved by the path relative to the namespace. This allows multiple plugins to coexist without name collisions.

Two-factor authentication (2FA)

It adds an essential extra layer of protection by requiring additional identity verification. This ensures that even if your password is stolen, a third party cannot access your data. It is the most effective defense against identity theft and account hacking.

How to set up two-factor authentication?+
To secure your account, two steps are required. Registered users must log in to the main BeamReactor interface. Click the "profile" button at the top left to access your settings. At the bottom, you will find a 2FA QR code to scan with an app like Google Authenticator or Microsoft Authenticator. Backup codes will be provided: make sure to copy them down to recover your account in case of phone loss or theft.
How do I log in with two-factor authentication?+
Log in with your username and password on the BeamReactor website. The system will then ask you for a code, which you will find in the Authenticator app on your phone.
What are the requirements?+
Update your phone's operating system and the Google or Microsoft Authenticator app to their latest versions. If you cannot log in but still have access to your registered email, try changing your password. If you lack email access, contact us via the support form.
What if I forgot my password?+
You can reset it at any time by clicking the "Account inaccessible?" link on the login page.
What if my phone is lost or broken?+
Use one of the backup codes provided during your 2FA registration. On the authentication page, click on "Backup code", enter it, and then update your 2FA settings in your profile once logged in.
What if I change my phone or system?+
New device, new system, reinstall after a format: the procedure is the same as for a lost phone. Use your backup codes to log in, then synchronize your new device via your user profile.
Why is two-factor authentication implemented?+
Two-factor authentication (2FA) adds an essential layer of protection by requiring additional proof of identity. It ensures that even if your password is stolen, your data remains inaccessible to third parties. It is the most effective defense against identity theft and account hacking.

Need personalised help?

Ticketing — For registered users. Open a ticket, track its progress, exchange with the technical support team. Your history is preserved.

Direct contact — For commercial enquiries, partnerships or pre-purchase questions. No account needed.
Contact form →

Recent changelog

- October 3, 2026, 4:27 am: Mise à jour de l'outil MCP read_features, permettant de récuperer jusqu'a 50 tickets features par type, séverité. Correction des calls vers "level(" dans les outils MCP qui n'étaient pas tous en corrélation avec le plugin utilisé ou utilisaient des valeurs numériques (prohibées, patch de flemmasse). Introduction de l'outil MCP dump_schema.lib.inc.php.
- October 3, 2026, 3:34 am: Correction de l'outil MCP write_features (int/string) + ajout des points agile/fibonacci, de la catégorie
- October 1, 2026, 10:14 pm: Chaque lecture de fichier vérifie son résultat : un échec est signalé (trigger_error, message visible), jamais étouffé. is_readable() avant la lecture ne suffit pas (le fichier peut changer entre les deux, et il faut vérifier le retour de toute façon). Lot 1 fait le 30/09/2026 : les 18 @file_get_contents (audit, llm_rag, llmrag_ia, ClassMapScanner, CAPCache, VIES, VisionHelper). Reste : les ~110 autres lectures, plugin par plugin. — Texte d’origine (2004) : Ajouter is_readable() pour chaque fichier en lecture - DONE (features)
- October 1, 2026, 9:36 pm: Mettre la fonction de reconnaissance d'un bot dans la lib de securité. L'installer dans banna. Automatiser la function de reconnaissance de robots, en sql (harmless to harmful, spider, crawler, spam, stealer, etc) - DONE (features)
- October 1, 2026, 9:23 pm: Discard ou replace document si document deja present dans data - DONE (features)
- October 1, 2026, 3:46 pm: Limiter les acces a la BDD au strict minimum avec la fonction connection(); - DONE (features)
- October 1, 2026, 3:42 pm: Etudier la possibilité de faire un cache des plugins. - DONE (features)
- October 1, 2026, 3:26 pm: Multi currency pricing - DONE (features)
- October 1, 2026, 3:23 pm: newsletter/mailer-daemon html. - DONE (features)
- October 1, 2026, 2:51 pm: lib/sanitizer/Datatypes/wip/DatatypeHash.php : erreur de syntaxe (deux php de suite). Le scanner de classes parcourt wip/ (work in progress): Parser::sanitize($x, 'hash') chargerait ce fichier et pourrait potentiellement faire tomber le systeme même si personne ne l'appelle aujourd'hui. - DONE (features, 1 pts)
- October 1, 2026, 2:50 pm: #176 lot C : 19 scandir non vérifiés (liste dans la section 9 de l'audit) - foreach sur false = warning, array_diff(false) / [] + false = fatal en PHP 8 (diskmaster, edito.lib, login_success sont les fatals). - DONE (features, 3 pts)
- October 1, 2026, 1:57 pm: Silent failures hunted down (a 2005 request that was still relevant): every directory or file opening that could white-screen a page under PHP 8 is now checked, from the plugin list itself to the page cache, and settings that could not be read no longer fall back to defaults without a word. Two of them hid real damage: an unreadable database migration was recorded as applied without running, and adding a line to the history could overwrite the whole file. New event log: who banned, anonymized or exported whom, and who installed which plugin, kept one month and readable by site administrators in the Errors and events page. Moderation actions now require a security token: a booby-trapped image could make a moderator ban or anonymize someone, or make any member anonymize their own account. The error detail view no longer runs code hidden in an error message. The GDPR page buttons work again, and the GDPR export includes editorials and notepads again. The audit now finds files that no longer load and unchecked directory openings; its first run repaired the subscribers and quick links plugins.
- September 30, 2026, 6:02 pm: New imagesort plugin: sorts image folders with a local vision model (MiniCPM-V), recursively, from a source to a destination picked at each run under allowed roots. It classifies first and moves nothing, resumes where it stopped, and shows a review page with thumbnails where any category can be corrected; the categories are a base list plus a simple CSV. Moving is journaled and a whole batch can be undone; an identical file already at the destination (same MD5) counts as a duplicate, anything else gets a free name, a copy between drives is checked before the source is deleted, and no metadata is ever written. File reads that fail are no longer silent (first batch of an old 2004 request): the audit reports unreadable files as not audited instead of clean, and its check of the required member files finally reads the right path; the class map, the CAP cache, the VIES VAT check and the vision helper now report their failures. RAG sources given as a URL accept web addresses only (http/https): a local path could be read as a source by an administrator. JSON endpoints no longer get a warning printed into their response.
- September 30, 2026, 5:58 pm: Ajouter is readable a chaque opendir (cf versions.php 0.94 18.09.2005) - DONE (features)
- September 30, 2026, 3:25 pm: Location, for GMT values and hour relative listings and data supplying. - DONE (features)
- September 30, 2026, 3:23 pm: Add avatar - DONE (features)
- September 30, 2026, 3:23 pm: Gallery : target image inclusion within the current theme - DONE (features)
- September 30, 2026, 3:23 pm: base skin detection and creation - DONE (features)
- September 30, 2026, 3:05 pm: BeamReactor 3.0.0-alpha. Member panel diagnostics: each plugin reports from its own dashboard/ folder (counts by severity, "new since your last visit", filtered by level and group) - support tickets, orders, abuse, moderation, scheduler, error logs, calendar, LLM health, bans and reminders, and today the todo list (critical, due within 48 h, open) and the feature requests (blocking, never triaged, in progress). A single version source, core files flagged in the update manifest, and the updater opened to site owners. Foldable frames and title widgets are back without breaking older skins; skin translations move to skinlocale files. RTE 4.3: an emoji button, and a Versions button that reloads any of the last five saved versions of content, blogs, editorials and documents; embedding plugins is reserved to webmasters, with a recursion guard. MCP: the model keeps a notebook of its own (30 notes per user and per model), RAG excerpts name their source, the vector index was repaired, conversations are partitioned per user, the user's request never falls out of the context window, fake turns written by the model are cut and tool loops stop; web_fetch reads the main content in UTF-8, with an offset for long pages, and the sanitizer encodes non-ASCII URLs instead of truncating them. Feature requests gained categories, sortable headers, one-click unfeasible and cancelled states, Fibonacci complexity points with a WSJF sort, a Back link that returns where you were, and list views (blocking, never triaged, in progress) that the member panel opens directly; their write actions are now restricted to moderators (deletion to admins) and carry action tokens - marking a request as done was not checked at all. Cron handlers finally delivered for the defense-log and statistics purges, SQL Operations repairs tables according to their engine, a stored script injection in the oneliner is fixed, and a dozen lookups no longer crash on a missing row.
- September 27, 2026, 9:22 pm: URGENT aegis-ia : routeur user/data/tos.php sur le modèle de user/data/home.php de dev (include de tos_<langue>.html, erreur visible si la langue manque) ; le footer de la skin aegis pointe ensuite sur ?obj=tos.php au lieu de tos_php echo $cfg[22] .html (2 liens), et les og:url des CGU (cgv.html / tos.html, pages mortes) sur la vraie adresse. - DONE (features, 2 pts)
- September 24, 2026, 10:33 pm: Ajouter le niveau de complexité (barres de couleur dans la liste!) - delai necessaire dans features - DONE (features)
- September 24, 2026, 10:32 pm: Regrouper les listes d'ips bannies de chaque site SDP/XDP (export data) - DONE (features)
- September 24, 2026, 10:32 pm: Moteur de recherche HS si page >1 - DONE (features)
- September 24, 2026, 10:28 pm: <!--<a href=spider.php3>.</a>--> - DONE (features)
- September 24, 2026, 10:26 pm: plugin : pense bete - DONE (features)
- September 24, 2026, 10:25 pm: Notice: Undefined index: type in /home/artsonne/public_html/beamreactor.com/plugins/products_editor.php on line 173 Notice: Undefined variable: displaystatus in /home/artsonne/public_html/beamreactor.com/plugins/products_editor.php on line 173 - DONE (features)
- September 24, 2026, 10:23 pm: Laisser le user acceder au documents figés lorsque la base de données est down, mais afficher le 503 en cas d'acces a la BDD - DONE (features)
- September 24, 2026, 10:05 pm: Add repair table in the mysql operqtions plugin - DONE (features)
- September 24, 2026, 9:53 pm: in sponsors, entering a wrong web address ruins any UTF8 text typed in the comment field - DONE (features)
- September 24, 2026, 9:46 pm: feature: edit the request: buttons broken - DONE (features)

Full history →

Didn't find your answer?

Open a ticket or get in touch.

de en es fr pt