Technische Referenz

Widget Storm v4.0.0 — Systemdokumentation

1. Systemübersicht

Widget Storm ist eine modulare Widget-Plattform für das Web, aktiv seit 2008. Widgets sind eigenständige Webkomponenten aus drei Schichten (PHP, CSS, JavaScript), die verschlüsselt auf dem Server gespeichert und über HTTP-Endpunkte ausgeliefert werden.

EigenschaftWert
Version4.0.0
SprachePHP 8.3
DatenbankMySQL / MariaDB
VerschlüsselungRIJNDAEL-256 (Legacy), AES-256-CBC (Modern)
Standard-AutorWidgetStormSystem
AusführungskontexteLokal (wgclient.php), Remote (wgcall.php), Client-seitig (wghandler.php)
Für eine geführte Einführung mit interaktiven Beispielen siehe das Tutorial.

2. Widget-Struktur

Jedes Widget besteht aus exakt drei Dateien. Alle drei Schichten haben Zugriff auf die gleichen Parameter ($wgparams) und die Instanz-ID ($wgguid).

SchichtDateiContent-TypeBeschreibung
PHPwidget_name.phptext/htmlServerseitige Logik und HTML-Ausgabe
CSSwidget_name.csstext/cssStyling mit optionaler PHP-Bridge
JSwidget_name.jstext/javascriptClient-seitige Interaktion

Verfügbare Variablen im Widget-Code

VariableTypBeschreibung
$wgparamsobject|array|stringWidget-Parameter (geparst aus JSON, Semikolon-Liste oder String)
$widgetparamsobject|array|stringAlias für $wgparams
$wgguidstringInstanz-ID für CSS/JS-Scoping — beim Script-Tag gesetzt, im PHP-Include das 5. Argument

PHP-Schicht — Beispiel

<?php
if(isset($widgetparams->uid)) $wgguid = $widgetparams->uid;
else $wgguid = "";
if(isset($wgparams)){
    $text = isset($wgparams->text) ? $wgparams->text : "Standard-Text";
    ?>
    <div id="mein_widget<?= $wgguid;?>" class="mein-widget">
        <p><?= $text;?></p>
    </div>
    <?php
}
?>

Ausgabemodi

ModusAusgabe
phpNur HTML (evalBei Widget-Storm führt eval() ausschließlich Widget-Code aus, der von authentifizierten Autoren in der Datenbank hinterlegt wurde — nicht von Benutzereingaben. Es ist die technische Grundlage der PHP-in-CSS Bridge und der dynamischen Widget-Komposition. Kein User-Input erreicht eval().-Ergebnis)
cssNur CSS (evalDie CSS-Schicht wird durch eval() gerendert, um die PHP-in-CSS Bridge zu aktivieren. Der Code stammt ausschließlich aus der Datenbank — erstellt von authentifizierten Widget-Autoren. Dynamische Selektoren und instanzspezifisches Styling wären ohne diesen Mechanismus nicht möglich.-Ergebnis)
jsNur JavaScript (evalAuch die JS-Schicht nutzt eval() für eingebettete PHP-Variablen (UID-Scoping, Parameter). Wie bei allen Widget-Schichten: der ausgeführte Code ist autorengeprüft und datenbankgespeichert, nicht nutzergeneriert.-Ergebnis)
(leer)<style>CSS</style> PHP <script>JS</script>

3. Parameter-System

Parameter werden über wgparams an Widgets übergeben. Das System unterstützt drei Formate:

JSON (empfohlen)

{"text":"Hallo Welt","color":"#ff0000","items":[1,2,3]}

Wird zu einem stdClass-Objekt geparst. Zugriff via $wgparams->text.

Semikolon-getrennt

Wert1;Wert2;Wert3

Wird zu einem Array geparst. Zugriff via $wgparams[0], $wgparams[1], etc.

Einfacher String

Ein beliebiger Text

Wird unverändert als String durchgereicht.

URL-Encoding für HTTP-Requests

wgparams={"text":"Hallo","uid":"abc123"}

// In PHP für URL-Parameter:
$packurl = http_build_query(['wgparams' => $paramsArray]);

4. PHP-in-CSS/JS Bridge

CSS- und JS-Dateien können eingebetteten PHP-Code enthalten. Da PHP-Tags in CSS/JS syntaktisch ungültig sind, werden sie in Kommentare verpackt. Das System konvertiert diese automatisch vor der Ausführung.

Konvertierungsregeln

Im QuellcodeWird zu
/*<?php<?php
/*<?=<?=
?>*/?>

CSS-Beispiel

/*<?php
if(isset($wgparams->uid)) $wgguid = $wgparams->uid;
else $wgguid = "";
?>*/
div#mein_widget/*<?= $wgguid;?>*/ {
    background: rgba(170,210,210,0.08);
    border: 1px solid rgba(170,210,210,0.2);
    padding: 1em;
    border-radius: 0.4em;
}

JS-Beispiel

/*<?php
if(isset($wgparams->uid)) $wgguid = $wgparams->uid;
else $wgguid = "";
?>*/
jQuery(document).ready(function(){
    jQuery("#mein_widget/*<?= $wgguid;?>*/").on("click", function(){
        jQuery(this).toggleClass("active");
    });
});
Die PHP-Bridge ermöglicht instanzspezifische CSS-Selektoren und JS-Handler, sodass mehrere Instanzen desselben Widgets auf einer Seite koexistieren können.

5. Verschachtelung & Marker

Widgets können andere Widgets laden. Dies geschieht über Marker im PHP-Code, die vom Server rekursiv aufgelöst werden.

Marker-Syntax

##wgstart##widgetname::autor::parameter##wgend##
SegmentBeschreibung
widgetnameName des einzubettenden Widgets
autorAutor des Widgets
parameterParameter als JSON oder Semikolon-Liste

Auflösungsprozess

  1. Server findet alle ##wgstart##...##wgend## Marker im PHP-Code
  2. Extrahiert Name, Autor und Parameter aus dem Marker
  3. Löst das verschachtelte Widget rekursiv auf
  4. CSS und JS des verschachtelten Widgets werden an das Eltern-Widget angehängt
  5. PHP wird Base64-kodiert und über intern_script_wall() ausgeführt

UID-Scoping & Platzhalter

PlatzhalterErsetzungVerwendung
##self##widgetname + md5($wgguid)Selektor dieser Instanz (Widgetname + md5 von $wgguid). Script-Tag: jede Einbettung auf einer Seite erhält einen eigenen. PHP-Include: jeder Wiederholung desselben Widgets ein eigenes $wgguid (5. Argument) übergeben.
##wgself##widgetname + md5($wgguid)Alias für ##self##
##selfreplace####self##Escape: literales ##self## im Output

6. Verfügbarkeitsstufen

StufeZugriffBilling
openAlle registrierten NutzerKostenlos
authenticatedAutor + Nutzer mit expliziter BerechtigungOptional
paymentAutor + Nutzer mit aktivem BillingErforderlich

Entwickler legen die Verfügbarkeit beim Upload fest (Parameter wgrmode). Die Stufe bestimmt, wer das Widget über seinen wgclient abrufen kann — und ob eine Abrechnung erforderlich ist.

Zugriffskontrolle

1. Widget.availability == 'open'       → Zugriff gewährt
2. Widget.author == RequestUser        → Zugriff gewährt (Autor)
3. Berechtigungsprüfung              → Prüfung in interner Berechtigungstabelle
   - Globale Berechtigung              → Gilt für alle Nutzer
   - Spezifische Berechtigung          → Gilt für einzelne Nutzer

Sicherheit auf Widget-Ebene

Widgets können eigene Sicherheitsmechanismen mitbringen — unabhängig vom Hostsystem. Das Widget wg_demo_todo demonstriert dieses Prinzip: AES-256-verschlüsselte Persistenz, schlüsselbasierte Authentifizierung mit Brute-Force-Schutz und automatische Preflight-Checks für Abhängigkeiten und Berechtigungen. Weitere Details finden Sie auf der Widget-Übersicht.

7. HTTP-Endpunkte

wgclient.php — Widget-Auslieferung (lokal)

Dient als HTTP-Endpunkt und als PHP-Include für serverseitige Einbindung.

ParameterPflichtBeschreibung
wgnameJaWidget-Name
wgauthorNeinWidget-Autor (Standard: WidgetStormSystem)
wgmodeNeinAusgabemodus: php, css, js oder leer (alle)
wgparamsNeinWidget-Parameter (JSON, Semikolon-Liste oder String)
wgguidNeinInstanz-ID für Scoping

Composer — wgclient & wghandler als Pakete

Beide Client-Dateien lassen sich alternativ über ein privates Composer-Repository installieren. Die Authentifizierung erfolgt mit Ihrem Station-Login (HTTP Basic — Composer fragt beim ersten Zugriff danach und speichert die Zugangsdaten in der auth.json).

composer config repositories.widget-storm composer https://widget-storm.de/composer
composer require widget-storm/wgclient:^4.1
vendor/bin/wg-deploy public/

Schlüssel-Semantik: Wiederholte Installationen und composer update liefern denselben Schlüssel erneut aus — Ihr installierter wgclient bleibt gültig. Nur die allererste Composer-Installation eines Kontos erzeugt einmalig einen neuen Schlüssel (ein zuvor über die Station geladener wgclient wird dabei ungültig). Eine bewusste Rotation ist jederzeit möglich (wgclientcreator.php?rotate=1); danach composer clear-cache && composer reinstall widget-storm/wgclient ausführen und neu deployen — ohne clear-cache würde Composers lokaler Paket-Cache den alten Client wiederherstellen.

wgcall.php — Remote Widget-Auslieferung

Endpunkt für externe Server. Erfordert Authentifizierung und verschlüsselt die Antwort.

ParameterPflichtBeschreibung
wgnameJaWidget-Name (alphanumerisch + Unterstrich + Bindestrich)
wgauthorJaWidget-Autor
wgmodeJaErlaubte Werte: php, css, js, go, c, md
requestuserJaBenutzername
requestkeyJaAuthentifizierungsschlüssel (MD5-Hash)
wgparamsNeinWidget-Parameter
wgguidNeinInstanz-ID
wgfirstNeintrue = keine Verschachtelungsauflösung

wgregistration.php — Widget-Upload

Endpunkt zum Hochladen neuer oder aktualisierter Widgets.

ParameterBeschreibung
wgrnameWidget-Name
wgrparamSchicht: php, css, js
wgrcodeVerschlüsselter Widget-Code
wgrmodeVerfügbarkeit: authenticated, open, payment
wgrrequestuserBenutzername
wgrrequestkeyAuthentifizierungsschlüssel
Autoren-Isolation: Uploads sind an den authentifizierten Nutzer gebunden. Es können nur eigene Widgets erstellt oder aktualisiert werden — Widgets anderer Autoren sind vor Überschreibung geschützt. Beim Upload aus wgbuilds/ (Batch-Modus) werden entsprechend nur Widgets verarbeitet, die dem eigenen Autoren-Konto zugeordnet sind.

wgclientcreator.php — Client-Download

Generiert eine personalisierte wgclient.php mit eingebetteten Zugangsdaten. Erfordert aktive Session (Login über Station). Ihr requestkey bleibt bei wiederholtem Download erhalten; ein neuer wird nur beim allerersten Download erzeugt — oder auf Wunsch per ?rotate=1 (Key-Rotation, der alte Schlüssel wird ungültig).

wghandlercreator.php — Handler-Download

Generiert eine portable wghandler.php Klasse mit eingebetteter RIJNDAEL-256 Implementierung (pure PHP via phpseclib3, kompatibel mit PHP 8+), lokalem Widget-Caching und Unterstützung für verschachtelte Widgets.

8. Widget-Einbindung

Lokale Einbindung (gleicher Server)

<!-- CSS im <head> -->
<link rel="stylesheet"
    href="wgclient.php?wgname=basic&wgauthor=WidgetStormSystem&wgmode=css&wgparams=..."
    type="text/css">

<!-- JavaScript vor </body> -->
<script src="wgclient.php?wgname=basic&wgauthor=WidgetStormSystem&wgmode=js&wgparams=..."></script>

<!-- PHP im <body> -->
<?php
require_once 'wgclient.php';
$wg->get('basic', 'WidgetStormSystem', $params, 'php');
?>

Remote-Einbindung (externer Server)

<?php
// wgclient.php und wghandler.php auf eigenem Server platzieren
require_once 'wgclient.php';

// Zugangsdaten sind in wgclient.php eingebettet
$wg->get('basic', 'WidgetStormSystem', $params, 'php');
?>

Support-Chat wg_chat nach dem Kauf einrichten

Der Chat läuft auf Ihrem eigenen Webserver: PHP ab Version 7.0 mit den Erweiterungen openssl und curl. Nach dem Kauf steht dieselbe Anleitung mit Ihrer Domain in der Station unter „Ihre gekauften Widgets“.

  1. Laden Sie in der Station wgclient.php und wghandler.php und legen Sie beide in das Hauptverzeichnis Ihrer Website. Danach muss https://ihre-seite.de/wgclient.php erreichbar sein, denn der Chat ruft genau diese Adresse auf. Erneutes Laden behält Ihren Schlüssel.
  2. Bauen Sie den Chat in eine PHP-Seite im selben Verzeichnis ein, zum Beispiel kontakt.php (Code unten). Die erste Zeile steht ganz am Anfang der Datei, vor jeder anderen Ausgabe.
  3. Öffnen Sie die Seite einmal mit ?wg_chat_key= und einem selbst gewählten Betreiber-Schlüssel von mindestens 12 Zeichen am Ende der Adresse. Danach sehen Sie die Betreiber-Ansicht. Richten Sie den Chat ein, bevor Sie die Seite verlinken: Bis dahin sehen Besucher einen Einrichtungshinweis, und der erste Schlüssel gilt.
  4. Zum Antworten öffnen Sie dieselbe Adresse mit Ihrem Schlüssel. Die Betreiber-Ansicht bleibt bis 12 Stunden nach der letzten Nutzung angemeldet. Besucher öffnen die Seite ohne Schlüssel.
<?php require_once __DIR__ . '/wgclient.php'; ?>
<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="/wgclient.php?wgname=wg_chat&amp;wgauthor=WidgetStormSystem&amp;wgmode=css">
</head>
<body>
  <?php $wg->get('wg_chat', 'WidgetStormSystem', ['uid' => 'support'], 'php'); ?>
  <script src="/wgclient.php?wgname=wg_chat&amp;wgauthor=WidgetStormSystem&amp;wgmode=js"></script>
</body>
</html>
ParameterBedeutung
uidName des Chats. Besucher- und Betreiberseite brauchen denselben Wert. Ohne uid gilt der Hostname Ihrer Website, ohne www. und Port.
wglangen für englische Schaltflächen und Hinweise; ohne Angabe Deutsch.
titleÜberschrift des Chatfensters (Standard: Support-Chat).
greetingBegrüßung über dem Verlauf.
pollAbfrageintervall in Millisekunden, mindestens 1500 (Standard 4000).
maxlenHöchstlänge einer Nachricht, 20 bis 4000 Zeichen (Standard 1000).
Daten: Die Gespräche liegen AES-256-verschlüsselt auf Ihrem Server im Ordner wgdata/wg_chat, eine Ebene über dem Hauptverzeichnis. PHP muss ihn anlegen dürfen; sonst nennt der Chat den Pfad. Im Browser der Besucher liegt nur eine signierte Gesprächs-ID.
Neue Fassung: Ihr Server speichert den Widget-Code beim ersten Abruf unter wgbuilds/WidgetStormSystem/. Mit einem Handler ab Version 4.2 (steht oben in wghandler.php) holt er Korrekturen selbst, spätestens nach einer Stunde. Bei einem älteren Handler laden Sie ihn neu herunter oder verschieben dort wg_chat.php, wg_chat.js und wg_chat.css in einen anderen Ordner; der nächste Seitenaufruf lädt dann die aktuelle Fassung.
Schlüssel vergessen: Verschieben Sie in wgdata/wg_chat die Dateien Ihres Chats (config_…, data_… und rate_… mit derselben Kennung) in einen anderen Ordner und richten Sie den Chat neu ein. Die alten Gespräche bleiben verschlüsselt in den verschobenen Dateien.

Ausführungsmodi (wgexecutionmode)

Der Entwickler steuert über den wgexecutionmode, ob ein Widget lokal aus dem CodeVault gerendert wird oder live vom Widget-Storm-Server abgerufen werden soll. Der Standard-Modus nutzt den lokalen Cache — das bedeutet keine Netzwerk-Latenz und maximale Ladegeschwindigkeit.

ModusVerhaltenEinsatz
(Standard)Lokaler CodeVault — Widgets aus dem Cache ladenProduktion: schnellste Auslieferung, keine Server-Abhängigkeit
liveRemote Fetch — Widget live vom Server laden und ausführenEntwicklung: immer aktuelle Version, keine lokale Datei nötig. Gewählt im eigenen PHP (sechstes Argument von $wg->get()); über eine URL wird es ignoriert
uploadwidgetsBatch-Upload — lokale Widgets in wgbuilds/ hochladenDeployment: alle eigenen Widgets aus dem lokalen Verzeichnis synchronisieren. Nur auf der Kommandozeile: php wgclient.php uploadwidgets; über eine URL wird es ignoriert
Rendering-Kontrolle: Der Modus bestimmt woher der Widget-Code kommt — das Rendering selbst erfolgt immer serverseitig via PHP (evaleval() führt den Widget-Code im Server-Kontext aus. Der Code stammt entweder aus dem lokalen CodeVault (Dateisystem) oder aus der Datenbank — beides autorengeprüfte Quellen, keine Nutzereingaben.). Dadurch erhält jede Widget-Instanz ihre eigenen Parameter und CSS-Selektoren.

9. Verschlüsselung

Die Kommunikation zwischen Client und Server ist verschlüsselt. Das System unterstützt zwei Verschlüsselungsversionen pro Benutzer: RIJNDAEL-256 (das ursprüngliche Verfahren seit 2008) und AES-256-CBC (der moderne Standard für neue Nutzer). Beide koexistieren über einen zentralen EncryptionNegotiator, der automatisch die passende Version pro Benutzer wählt.

VersionAlgorithmusModusStatus
v1_rijndaelRIJNDAEL-256ECBLegacy (seit 2008)
v2_aesAES-256-CBCCBC mit zufälligem IVStandard für neue Nutzer

Beide Richtungen (Server → Client und Client → Server) sind auf Anwendungsebene verschlüsselt. Jeder Nutzer hat einen individuellen Schlüssel, der bei jedem Client-Download rotiert wird.

RIJNDAEL-256 ≠ AES-256. AES verwendet 128-Bit-Blöcke (von NIST standardisiert), RIJNDAEL-256 verwendet 256-Bit-Blöcke (verwandter Algorithmus, aber nicht Teil des AES-Standards).
Historischer Kontext: RIJNDAEL-256 wurde 2008 gewählt, als PHP’s mcrypt-Extension der Standard-Weg für Kryptografie war und openssl_encrypt() noch nicht verfügbar war. Die Entscheidung war dem damaligen Stand der Technik entsprechend. Seit der Modernisierung auf PHP 8.3 wird phpseclib3 als Drop-in-Ersatz für die entfernte mcrypt-Extension verwendet. Ausführliche Hintergründe dazu finden Sie in den FAQ.

10. Rate Limiting

EndpunktLimitFensterHTTP-Status bei Überschreitung
wgcall.php120 Anfragen60 Sekunden429 Too Many Requests
wgregistration.php30 Uploads60 Sekunden429 Too Many Requests

Tracking erfolgt pro IP-Adresse und Endpunkt. Zustandsdateien in /tmp/ws-ratelimit/.

11. CodeVault

Der CodeVault ist das Herzstück der Widget-Auslieferung. Er speichert Widget-Code als lokale Dateien auf dem Client-Server — das bedeutet direkten Dateisystem-Zugriff statt Netzwerk-Roundtrips. Widgets werden so schnell geladen wie jede andere lokale PHP-Datei, ohne Abhängigkeit vom zentralen Widget-Storm-Server.

Zweck & Vorteile

EigenschaftBeschreibung
GeschwindigkeitLokale Datei-Reads statt HTTP-Anfragen — Ladezeiten im Mikrosekundenbereich
UnabhängigkeitWidgets funktionieren auch wenn der Widget-Storm-Server nicht erreichbar ist
RedundanzDoppelte Speicherung: Datenbank (Server) + Dateisystem (Client)
Autoren-IsolationJeder Autor hat sein eigenes Unterverzeichnis — kein Überschreiben fremder Widgets möglich

Verzeichnisstruktur

wgbuilds/
  ├─ {Autor}/
  │   ├─ {widget_name}.php
  │   ├─ {widget_name}.css
  │   └─ {widget_name}.js
  └─ WidgetStormSystem/
      ├─ basic.php
      ├─ basic.css
      ├─ basic.js
      ├─ wg_nav.php
      └─ ...

Die Verzeichnisstruktur ist nach Autoren organisiert. Beim Batch-Upload (uploadwidgets-Modus) scannt der wghandler das wgbuilds/ Verzeichnis und lädt geänderte Dateien automatisch auf den Server hoch — dabei werden nur eigene Widgets verarbeitet. Widgets anderer Autoren bleiben unberührt.

Rendering aus dem CodeVault

Im Standard-Modus liest der wgclient den Widget-Code direkt aus wgbuilds/ und führt ihn lokal aus (evalDer CodeVault-Code wird via eval() im Server-Kontext ausgeführt. Die Dateien stammen aus dem authentifizierten Download oder eigenem Upload — sie sind identisch mit dem Datenbank-Original. Kein externer Input fließt in die Ausführung ein.). Der Live-Modus umgeht den CodeVault und fragt den Widget-Storm-Server direkt ab — nützlich während der Entwicklung, aber langsamer als der lokale Cache.

Design-Philosophie: Der CodeVault ist bewusst als erstes Speichermedium für die Auslieferung konzipiert — nicht als Fallback. Lokale Dateien sind die schnellstmögliche Art, Widgets auszuliefern, und machen jede Website mit Widget-Storm-Integration resilient gegen temporäre Server-Ausfälle.