Zum Inhalt springen

DotBridge

DotBridge ist eine zentrale Komponente des DotApp-Frameworks und gewährleistet eine sichere, effiziente Kommunikation zwischen serverseitigem PHP und clientseitigem JavaScript über AJAX-Anfragen. Sie können PHP-Funktionen definieren, die vom Frontend aufrufbar sind, Eingaben verwalten und die Kommunikation vor unbefugtem Zugriff oder Missbrauch schützen. DotBridge ist darauf ausgelegt, Flexibilität, Sicherheit und eine einfache Integration dynamischer Funktionen in Webanwendungen zu bieten.

1.1 Was ist DotBridge?

DotBridge im DotApp-Framework ist die Klasse Dotsystems\App\Parts\Bridge, die als Brücke zwischen der Backend-PHP-Logik und Frontend-JavaScript-Aktionen dient. Sie ermöglicht den Aufruf von PHP-Funktionen aus HTML-Elementen (z. B. Schaltflächen, Formulareingaben) über verschlüsselte AJAX-Anfragen. Bridge sendet POST an die aktuelle Seiten-URL. Die Hauptaufgabe besteht darin, die Client-Server-Kommunikation zu vereinfachen und gleichzeitig zu gewährleisten, dass sie geprüft, verschlüsselt und vor Angriffen wie CSRF oder Request-Replay geschützt ist.

Bridge-Funktionen werden in einem Modul mit Bridge::listen() oder Router::bridge() (Controller-Zeichenkette) registriert.

1.2 Wichtige Funktionen

DotBridge bietet ein breites Spektrum an Funktionen, die die Entwicklung sicherer und dynamischer Anwendungen vereinfachen:

  • Sichere Kommunikation: Schützt Anfragen durch Datenverschlüsselung, Schlüsselprüfung und CRC-Prüfungen.
  • Aufruf von PHP-Funktionen: Definieren Sie PHP-Funktionen, die aus JavaScript aufrufbar sind, mit Unterstützung für before- und after-Callbacks.
  • Validierungsfilter: Echtzeit-Validierung von Eingaben (z. B. E-Mail, URL, Passwort) mit visuellem Feedback auf der Clientseite.
  • Rate Limiting: Möglichkeit, Anfragelimits pro Zeit festzulegen (rateLimit(seconds,clicks)).
  • Einmal-Schlüssel: Unterstützung für oneTimeUse und regenerateId für erhöhte Sicherheit.
  • Flexibilität: Unterstützt verschiedene Ereignisse (z. B. click, keyup) und dynamische Eingaben aus HTML.
  • Verkettung: Method Chaining für übersichtlicheren Code auf PHP- und JavaScript-Seite.

1.3 Grundlegende Funktionsweise

DotBridge steuert die Kommunikation zwischen Client und Server in den folgenden Schritten:

  1. Erzeugt einen eindeutigen Sitzungsschlüssel und registriert PHP-Funktionen auf der Serverseite über Bridge::listen() oder Router::bridge().
  2. In HTML werden Ereignisse (z. B. {{ dotbridge:on(click)="fnName" }}) und Eingaben (z. B. {{ dotbridge:input="name" }} oder kurz dotbridge="name") definiert und mit PHP-Funktionen verknüpft.
  3. Wenn ein Ereignis ausgelöst wird (z. B. ein Klick), wird ein AJAX-POST an die gebundene Seiten-URL gesendet (Standard: die aktuelle Seite) mit verschlüsselten Daten.
  4. Der Server prüft den Schlüssel, entschlüsselt die Daten, kontrolliert die Anfragelimits und führt die angeforderte PHP-Funktion aus.
  5. Das Ergebnis wird als JSON-Antwort zurückgegeben, die JavaScript weiterverarbeiten kann.

Die Kommunikation wird durch Datenverschlüsselung, Schlüsselprüfung und Limits abgesichert, um Missbrauch oder unbefugten Zugriff zu verhindern.

Beispiel für die grundlegende Verwendung:

<button {{ dotbridge:on(click)="sayHello" }}>Click me</button>
        

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;

$urls = ['/hello', '/hello/'];
Bridge::listen($urls, "sayHello", function ($request) {
    return ["status" => 1, "message" => "Hello from the server!"];
}, Router::STATIC_ROUTE);
        

Beim Klick auf die Schaltfläche wird die PHP-Funktion sayHello aufgerufen und eine JSON-Antwort mit der Meldung „Hello from the server!“ zurückgegeben.

2. Erste Schritte

Dieses Kapitel führt Sie durch die Grundlagen der Arbeit mit DotBridge im DotApp-Framework – von der Initialisierung über die Definition Ihrer ersten Funktion und das Hinzufügen eines Frontend-Ereignisses bis zur Verarbeitung der Antwort in JavaScript.

Registrieren Sie Handler mit Router::bridge(['/path','/path/'], 'fnName', 'Examples:Forms@submit3!', Router::STATIC_ROUTE) oder Bridge::listen($urls, 'fnName', $callback, Router::STATIC_ROUTE) in der initialize() des Moduls.

2.1 DotBridge initialisieren

DotBridge startet mit der Anwendung. Ein eindeutiger Sitzungsschlüssel wird in _bridge.key gespeichert. Registrieren Sie Seiten-Handler aus einem Modul mit Bridge::listen() oder Router::bridge(). Bridge-AJAX-Anfragen senden POST an die aktuelle Seiten-URL; der Vorlagenmodifikator url(/path) bindet einen Aufruf an eine andere URL (ungültige gebundene URL: HTTP 403, error_code 6). Binden Sie /assets/dotapp/dotapp.js auf Seiten ein, die Bridge-Ereignisse verwenden.

2.2 Eine PHP-Funktion definieren

Registrieren Sie auf der Serverseite eine Funktion mit Bridge::listen(). Der Callback erhält ein $request-Objekt; Nutzdatenfelder liegen in $request->data(true)['data']. Geben Sie eine Zeichenkette oder ein Array zurück (z. B. ['ok' => true, 'message' => '...']) — das Framework verpackt es als JSON { status: 1, body: <your return> }. Platzieren Sie Handler in der initialize() eines Moduls oder in einer Controller-Methode des Moduls.

Beispiel:

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;

$urls = ['/contact', '/contact/'];
Bridge::listen($urls, "sendMessage", function ($request) {
    $data = $request->data(true)['data'];
    $message = $data["user.message"] ?? "No message";
    return ["ok" => true, "message" => "Message received: " . $message];
}, Router::STATIC_ROUTE);
    

Die Funktion sendMessage ist jetzt vom Frontend aufrufbar und gibt eine JSON-Antwort mit der empfangenen Nachricht zurück.

2.3 Ein Frontend-Ereignis hinzufügen

Verwenden Sie in HTML das Attribut {{ dotbridge:on(event)="functionName(params)" }}, um ein Ereignis (z. B. click, keyup) mit einer PHP-Funktion zu verknüpfen. Definieren Sie Eingaben mit {{ dotbridge:input="name" }} oder der Kurzform dotbridge="name" an normalen HTML-Elementen. Fügen Sie Modifikatoren wie rateLimit(60,5) oder oneTimeUse hinzu, um das Verhalten zu steuern.

Beispiel:

<input type="text" {{ dotbridge:input="user.message" }}>
<button {{ dotbridge:on(click)="sendMessage(user.message)" rateLimit(60,5) }}>Send</button>
    

Beim Klick auf die Schaltfläche wird der Wert aus der Eingabe user.message an die Funktion sendMessage gesendet, mit einem Limit von 5 Anfragen pro 60 Sekunden.

2.4 Die Antwort in JavaScript verarbeiten

Binden Sie auf der Clientseite /assets/dotapp/dotapp.js ein und verwenden Sie $dotapp().bridge(), um before- und after-Callbacks zu definieren. Der after-Callback erhält body (Ihren PHP-Rückgabewert). Verwenden Sie onResponseCode mit $dotapp().parseReply(), um Framework-Fehlerhüllen zu lesen (status_txt bei HTTP 400/403/429).

Beispiel:

$dotapp().bridge("sendMessage", "click")
    .before(function () {
        $dotapp("button").html("Sending...");
    })
    .after(function (body) {
        $dotapp("button").html("Done!");
        alert(body.message || body);
    })
    .onResponseCode(function (status, text) {
        var reply = $dotapp().parseReply(text);
        alert((reply && reply.status_txt) ? reply.status_txt : "Failed");
    }, 429);
    

Vor dem Senden ändert sich der Schaltflächentext in „Sending...“, und nach dem Empfang der Antwort wird die Meldung aus der PHP-Funktion angezeigt. Rate-Limit- und andere Framework-Fehler werden über onResponseCode und parseReply behandelt.

3. Erweiterte Nutzung

Dieses Kapitel behandelt erweiterte Funktionen von DotBridge wie Validierungsfilter, Rate Limiting, Methodenverkettung und die Arbeit mit dynamischen Daten. Diese Werkzeuge ermöglichen robustere und sicherere Anwendungen mit größerer Kontrolle über das Verhalten.

3.1 Validierungsfilter

DotBridge stellt integrierte Validierungsfilter für die Echtzeit-Validierung von Eingaben auf der Clientseite bereit. Filter wie email, url, phone oder password wenden reguläre Ausdrücke und visuelles Feedback (CSS-Klassen) anhand der Gültigkeit der Eingabe an. Sie werden in HTML über das Attribut dotbridge-result="0" dotbridge-input="name" verwendet.

Verfügbare Argumente:

  • filter: Name des Filters (z. B. email).
  • start_checking_length: Mindestanzahl von Zeichen, ab der die Validierung beginnt.
  • class_ok: CSS-Klasse für gültige Eingabe.
  • class_bad: CSS-Klasse für ungültige Eingabe.
Beispiel:

<input type="text" {{ dotbridge:input="user.email(email, 5, 'valid-email', 'invalid-email')" }}>
    

Die Eingabe user.email beginnt nach 5 Zeichen mit der Validierung. Ist die E-Mail gültig, wird die Klasse valid-email hinzugefügt; ist sie ungültig, invalid-email.

3.2 Rate Limiting und Sicherheitsmechanismen

DotBridge ermöglicht es, die Anzahl der Anfragen mit den Parametern rateLimit(seconds,clicks) zu begrenzen und so die Anwendung vor Missbrauch zu schützen. Weitere Sicherheitsfunktionen sind oneTimeUse (Einmalschlüssel) und regenerateId (Schlüsselneugenerierung nach jeder Verwendung).

Verwendung:

  • rateLimit(seconds,clicks): Maximal clicks Anfragen pro seconds. Wiederholen Sie den Modifikator für mehrere Zeitfenster (z. B. rateLimit(60,2) rateLimit(3600,5)).
  • oneTimeUse: Der Schlüssel ist nur für eine Verwendung gültig.
  • regenerateId: Erzeugt nach jedem Aufruf einen neuen Schlüssel.
  • url(path): POST-Ziel-URL (Standard: aktuelle Seite).
  • internalID(id): Weist dem Bridge-Objekt eine stabile interne ID zu.
  • expireAt(timestamp): Lässt den Bridge-Schlüssel zu einem Unix-Zeitstempel ablaufen.
Beispiel:

<button {{ dotbridge:on(click)="submitForm" rateLimit(60,10) rateLimit(3600,100) }}>Submit</button>
<button {{ dotbridge:on(click)="submitForm" oneTimeUse }}>Submit</button>
<button {{ dotbridge:on(click)="submitForm" regenerateId }}>Submit</button>
    

1. Beispiel – Die Schaltfläche erlaubt maximal 10 Klicks pro Minute, 100 pro Stunde.

2. Beispiel – Die Schaltfläche erlaubt nur einen Klick, und der Listener wird entfernt.

3. Beispiel – Die Schaltfläche regeneriert ihre ID bei jedem Klick.

3.3 Methodenverkettung

In PHP registrieren Sie mit Bridge::listen(); optional können Sie before() / after() an diesen Aufruf ketten. In JavaScript verwenden Sie $dotapp().bridge() mit before() und after().

Beispiel:

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;

$urls = ['/process', '/process/'];
Bridge::listen($urls, "processData", function ($request) {
    $data = $request->data(true)['data'];
    return ["result" => trim($data["value"] ?? "")];
}, Router::STATIC_ROUTE)
->before(function ($request) {
    return null;
})
->after(function ($request) {
    return null;
});
    

// JavaScript
$dotapp().bridge("processData", "click")
    .before(function () {
        $dotapp(".trigger").addClass("loading");
    })
    .after(function (body) {
        $dotapp(".trigger").removeClass("loading");
        console.log(body.result);
    });
    

Der Handler kürzt die Eingabe auf dem Server; die Hooks before und after erhalten $request. Auf dem Client wird um den Aufruf herum ein Ladezustand umgeschaltet.

3.4 Arbeiten mit dynamischen Daten

DotBridge ermöglicht das Senden und Verarbeiten dynamischer Daten aus mehreren in HTML definierten Eingaben. Eingaben verwenden {{ dotbridge:input="name" }} oder die Kurzform dotbridge="name" und kommen auf dem Server in $request->data(true)['data'] an.

Beispiel:

<input type="text" {{ dotbridge:input="user.name" }}>
<input type="text" {{ dotbridge:input="user.email" }}>
<button {{ dotbridge:on(click)="saveUser(user.name, user.email)" }}>Save</button>
    

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;

$urls = ['/account', '/account/'];
Bridge::listen($urls, "saveUser", function ($request) {
    $data = $request->data(true)['data'];
    $name = $data["user.name"] ?? "";
    $email = $data["user.email"] ?? "";
    return ["ok" => true, "message" => "User $name ($email) saved"];
}, Router::STATIC_ROUTE);
    

Beim Klick werden die Werte aus den Eingaben user.name und user.email an die Funktion saveUser gesendet und in der Antwort zurückgegeben.

4. Bewährte Vorgehensweisen und Tipps

Dieses Kapitel gibt Empfehlungen und Tipps für die effektive und sichere Nutzung von DotBridge. Es behandelt Sicherheitsoptimierung, Fehlerdiagnose und die Integration mit anderen Teilen des DotApp-Frameworks.

4.1 Sicherheit optimieren

Sicherheit ist ein entscheidender Aspekt bei der Nutzung von DotBridge. Die folgenden Empfehlungen helfen, Risiken zu minimieren und eine robuste Kommunikation sicherzustellen:

  • Rate Limiting verwenden: Setzen Sie rateLimit(seconds,count) für Aktionen, die empfindlich auf wiederholte Aufrufe reagieren (z. B. rateLimit(60,2) rateLimit(3600,5) für mehrere Zeitfenster).
  • Einmalschlüssel aktivieren: Verwenden Sie für kritische Operationen (z. B. Formularübermittlung) oneTimeUse oder regenerateId, um die Wiederverwendung desselben Schlüssels zu verhindern.
  • Eingaben validieren: Kombinieren Sie Validierungsfilter mit zusätzlichen serverseitigen Prüfungen (z. B. filter_var()), um eine konsistente Validierung zu gewährleisten.
  • Sitzungen überwachen: Prüfen und bereinigen Sie regelmäßig alte Schlüssel in _bridge.objects, um Speicherüberläufe zu vermeiden.
  • Verschlüsselung nutzen: Nutzen Sie die integrierte DotApp-Verschlüsselung (encrypt(), decrypt()) für sensible Daten in der Kommunikation.
Beispiel:

<button {{ dotbridge:on(click)="secureAction" rateLimit(60,2) oneTimeUse }}>Execute</button>
    

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\Router;

$urls = ['/secure', '/secure/'];
Bridge::listen($urls, "secureAction", function ($request) {
    return ["ok" => true, "message" => "Action executed securely"];
}, Router::STATIC_ROUTE);
    

Dieses Beispiel begrenzt die Aktion auf 2 Aufrufe pro 60 Sekunden und erlaubt nur eine Verwendung des Schlüssels.

4.2 Debugging und Fehlerbehebung

Bei der Arbeit mit DotBridge können Fehler auftreten. Hier sind häufige Probleme und ihre Lösungen:

  • CRC check failed (error_code 1): Prüfen Sie, ob die vom Frontend gesendeten Daten nicht verändert wurden. Kontrollieren Sie die Integrität des JavaScript-Codes und der Netzwerkanfragen.
  • Bridge key does not match (error_code 2): Stellen Sie sicher, dass der Sitzungsschlüssel (_bridge.key) mit dem übereinstimmt, den der Client sendet. Ursache kann eine abgelaufene Sitzung sein.
  • Function not found (error_code 3): Bestätigen Sie, dass die Funktion mit Bridge::listen() oder Router::bridge() registriert ist und der Name mit dem HTML-Aufruf übereinstimmt.
  • Rate limit exceeded (error_code 4): Sie haben das festgelegte Limit überschritten. Passen Sie rateLimit(seconds,count) an oder informieren Sie den Benutzer, dass er warten soll.

Tipp: Aktivieren Sie das Debugging in DotApp und prüfen Sie Bridge-POST-Antworten in den Entwicklertools des Browsers (Registerkarte Netzwerk). Das Standard-POST-Ziel ist die aktuelle Seiten-URL.

4.3 Integration mit anderen Teilen von DotApp

DotBridge ist so entworfen, dass es nahtlos mit anderen DotApp-Komponenten wie Router, Request und der Datenbank zusammenarbeitet. Die Integration ermöglicht komplexe Anwendungen mit minimalem Aufwand.

Integrationsbeispiele:

  • Mit Router: Verwenden Sie Router::bridge($urls, $fnName, 'Module:Controller@method!', Router::STATIC_ROUTE), um Handler an Seiten-URLs zu binden. Signatur: ($url, $function_name, $callback, $static = false).
  • Mit Request: Handler erhalten $request; Nutzdatenfelder liegen in $request->data(true)['data'].
  • Mit der Datenbank: Sie können Frontend-Daten mit DB::module('RAW') einfügen.
Beispiel mit Datenbank:

<input type="text" {{ dotbridge:input="user.email" }}>
<button {{ dotbridge:on(click)="saveEmail(user.email)" }}>Save</button>
    

use Dotsystems\App\Parts\Bridge;
use Dotsystems\App\Parts\DB;
use Dotsystems\App\Parts\Router;

$urls = ['/notes', '/notes/'];
Bridge::listen($urls, "saveEmail", function ($request) {
    $data = $request->data(true)['data'];
    $email = $data["user.email"] ?? "";
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        DB::module('RAW')->q(function ($qb) use ($email) {
            $qb->insert('helloworld_notes', ['email' => $email]);
        })->execute(
            function ($result, $db, $exec) {},
            function ($error) {}
        );
        return ["ok" => true, "message" => "Email saved"];
    }
    return ["ok" => false, "message" => "Invalid email"];
}, Router::STATIC_ROUTE);
    

Beim Klick wird die E-Mail validiert und in der Datenbank gespeichert; zurückgegeben wird eine Erfolgs- oder Fehlerantwort.