Architektur

Eine Anfrage, vom Rewrite, der sie an index.php schickt, bis zu den Bytes, die zurückgehen.

Die Anfrage, verfolgt

public/index.php ├─ set_exception_handler(…) the last resort, depending on nothing └─ Site::current()->run() ├─ ErrorLog::install(…) every diagnostic into data/logs/ ├─ SecurityHeaders::send() CSP, HSTS, Permissions-Policy, COOP, CORP — before anything can fail ├─ Request::fromGlobals() $_SERVER → a typed, readonly Request ├─ App::handle() the request → an Answer, sending nothing │ ├─ App::layers() what stands around every route: a layer answers, or hands on │ ├─ Router::dispatch() the path → a route → its method gate → its layers → a controller │ └─ Response::answer() status, headers and body — the security headers first └─ Answer::send() the one place anything is sent

Der Exception-Handler wird zuerst installiert, weil er funktionieren muss, wenn nichts anderes funktioniert hat: Er protokolliert, sendet ein schlichtes 500, wenn die Header noch nicht raus sind, und sagt dem Besucher sonst nichts.

Die Schichten

src/ ├── App.php what a site tells the framework about itself ├── Router.php URL → controller, and nothing else ├── Controller/ the Controller interface, and the API's ├── Http/ Request, Input, Upload, Session, Answer, the responses, every header typed; Api/, Security/ ├── View/ View, Shell; Html/ — the markup tree, MarkupParser, Vocabulary ├── Form/ a form as an enum of fields, its rules, a submission read and re-rendered ├── Data/ SQLite through PDO: statements, typed rows, transactions, migrations ├── Text/ Translatable, Translation, Language, Languages, an address per language ├── Support/ Collection, File, Directory, Path and Route, Throttle, PublicKey, TarArchive ├── Model/ Api/ (a signed call), Update/ (a push, the release it replaced), Health/ (requirements) ├── Service/ Auth, Login, ApiGate, UpdateApplier, ReleaseRecord; Layer/, and the API's handlers └── Exception/ SiteException and every condition under it

Die Abhängigkeiten zeigen in eine Richtung. Controller benutzen Services und Views, Views und Models bauen Elemente aus View\Html, und View\Html hängt von nichts darüber ab.

Die App

Eine pro Prozess, vom Autoloader der Website gebootet und mit App::current() wieder gelesen. Eine zu konstruieren tut nichts, sie zweimal zu booten heißt, sie einmal zu booten, und eine zweite App wird abgelehnt. Der tiefe Code des Frameworks — der Schlüssel und die Replay-Seriennummer der API, der Health-Report — fragt die gebootete App, statt dass jeder Konstruktor auf dem Weg nach unten die Fakten der Website mitträgt.

Die Leitung

Eine Anfrage wird defensiv geparst. Eine unbekannte Methode ist null, nicht geraten als GET, und ein Ziel, das der Parser von PHP nicht lesen kann, bleibt der Pfad, der es ist, statt mit der Startseite beantwortet zu werden. Die Security-Header sind typisierte Objekte, gesendet vor allem, was scheitern könnte, und jede Seite variiert genau nach den Headern, aus denen sie gerendert wurde.

Die signierte API

Ein Update ist ein gzip-komprimiertes Tar im Body eines einzigen POST, signiert mit einem ECDSA-P-256-Schlüssel, von dem der Server nur die öffentliche Hälfte hat. Die Signatur deckt die Aktion ab, einen Zeitstempel, eine Seriennummer, die der Server verbraucht, bevor er irgendetwas anwendet, und einen Hash des Bodys. Ein Aufruf, der nicht oder falsch signiert ist, wird genau so beantwortet wie eine Adresse, die es nicht gibt.

SPA-Navigation

Jeder Link ist ein echtes href. Navigation fängt einen Klick auf einen Link ab, der auf diesem Origin bleibt, fragt die Seite mit X-Requested-With an und tauscht die Antwort in #content ein. Ein Server mit dem Framework antwortet mit einem Fragment; ein statischer Host wie dieser antwortet mit der ganzen Seite, und nur ihr Inhalt und ihr Titel werden genommen — und, wenn die Seite in einer anderen Sprache ist, die Teile der Shell, die in der Sprache geschrieben sind, die sie ablöst.

Weiterlesen