Einführung & Philosophie

ArtiFrame basiert auf dem Prinzip "Convention over Configuration" (Konvention vor Konfiguration). Die Stärke eines Frameworks ergibt sich nicht aus dem Reichtum der angebotenen Tools, sondern aus der Konsistenz der aufgebauten Ordnung.

Zero Overhead

Null Abhängigkeit von Composer-Paketen, Framework-Kernen oder Drittanbieter-Bibliotheken. Jede Zeile Code gehört Ihnen – ohne Bloat, frei von unnötigen Abstraktionsschichten.

Sicherheit an erster Stelle

XSS-Schutz, CSRF-Validierung, Bereinigung gegen SQL-Injection und HTTP-Methoden-Kontrolle sind standardmäßig integriert. Sicherheit ist keine Option, sondern ein Standard.

Strikter Regelsatz

Ein Junior-Entwickler, der neu im Projekt ist, versteht die data-js-Architektur und die Verzeichnisstruktur in wenigen Minuten. Team-Konsistenz ist auf Framework-Ebene garantiert.

CLI-Fokussiert

Kein manuelles Erstellen von View-, API- oder Class-Dateien. Die CLI generiert sie aus Stub-Dateien, richtet Asset-Verbindungen ein und hält das Projekt konsistent.

ℹ️ AGPLv3-Lizenz: ArtiFrame ist Open-Source. Abgeleitete Werke können frei verwendet werden, solange der Quellcode offen bleibt. Der Urheberrechtshinweis darf nicht entfernt werden.

Installation

ArtiFrame CLI wird als globales PHP-Tool installiert. Es wird einmal installiert und in jedem Projekt verwendet.

1. CLI-Tool global installieren

# Globale Installation über NPM
npm install -g @artilingo/artiframe-cli

# Installation überprüfen
artiframe

2. Interaktive Shell

Geben Sie einfach artiframe im Terminal ein und drücken Sie Eingabe. Die CLI schließt sich nicht; es öffnet sich eine interaktive Shell, die kontinuierlich auf Befehle hört:

==================================================
        ArtiFrame CLI Interactive Shell v1.0.0
==================================================
Type 'help' for commands, or 'exit' to quit.

artiframe> 

3. Neues Projekt starten

artiframe> new benim-projem

Dieser Befehl erstellt das Verzeichnis benim-projem/ und kopiert die gesamte Skelettstruktur hinein: app/, bin/, config/, public/, src/, .env.example und die erste index.php-Seite.

4. Umgebungseinstellungen

cp .env.example .env

Öffnen Sie Ihre .env-Datei und füllen Sie Datenbank- und Anwendungsinformationen aus. Diese Datei wird niemals in die Versionskontrolle aufgenommen.

⚠️ Webserver-Einstellung: Leiten Sie das Document Root von Apache/Nginx auf den Ordner /public/ um. Andere Verzeichnisse dürfen niemals nach außen hin zugänglich sein.

Verzeichnisstruktur

Die beim Projektstart erstellte Architektur sorgt für eine klare Trennung der Zuständigkeiten (SoC).

proje-adi/ ├── app/ # Infrastrukturschicht │ ├── ViewControl.php # View (HTML-Seite) Bootstrapper │ ├── ApiControl.php # API-Endpunkt Bootstrapper │ ├── Database.php # PDO-basierte Datenbankverbindung │ ├── DotEnv.php # .env-Reader │ └── R2Manager.php # Cloudflare R2 Dateimanager │ ├── bin/ # ⚠️ Systemkern — nicht direkt bearbeiten │ ├── SystemMethod.php # API/Backend globale Helfer │ ├── ViewMethod.php # View/Frontend globale Helfer │ └── stubs/ # Vorlagendateien für die CLI │ ├── view.stub │ ├── api-standart.stub │ ├── api-switch-case.stub │ └── class.stub │ ├── config/ # Konfigurationsdateien │ └── app-version.php # APP_VERSION- und APP_ENV-Konstanten │ ├── public/ # ← Das einzige öffentlich zugängliche Verzeichnis des Webservers │ ├── assets/ │ │ ├── css/ # View-spezifische CSS-Dateien │ │ └── js/ # View-spezifische JS-Dateien │ ├── includes/ # Geteilte Komponenten │ │ ├── head.php │ │ ├── header.php │ │ └── footer.php │ ├── api/ # API-Endpunkt-Dateien │ └── index.php # Hauptseite │ ├── src/ # Geschäftslogik und Klassen ├── .env # Umgebungsvariablen (nicht in Git) ├── .env.example # Vorlage — in Git enthalten └── kilavuz.html # Dieses Dokument
🚫 Fass den bin/-Ordner nicht an: Dateien in bin/ sind der Kern des Frameworks. Projektspezifische Geschäftslogik wird hier nicht hinzugefügt. Klassen und Dienste gehören unter src/, Infrastrukturkomponenten unter app/.

Bootstrapper-Architektur Kritisch

ArtiFrame verwendet zwei völlig unabhängige Bootstrapper. Diese Architektur verhindert von Grund auf HTML-Header-Probleme und Sicherheitslücken.

View ViewControl.php

Wird für HTML-Seiten (View-Dateien) verwendet. Startet eine Session und lädt ViewMethod.

// public/profil.php — GANZ OBEN, bevor HTML ausgegeben wird
<?php
require_once $_SERVER['DOCUMENT_ROOT']
    . '/../app/ViewControl.php';
use Bin\ViewMethod;
?>
<!DOCTYPE html>
...

API ApiControl.php

Wird für API-Endpunkt-Dateien verwendet. Setzt den JSON-Header, führt HTTP-Methodenkontrolle durch und lädt SystemMethod.

// public/api/kullanici/getir.php
<?php
// $allowedMethods MUSS VOR require definiert werden
$allowedMethods = ['GET'];

require_once $_SERVER['DOCUMENT_ROOT']
    . '/../app/ApiControl.php';

use Bin\SystemMethod;
🚫 ViewControl und ApiControl dürfen niemals verwechselt werden: Wenn ViewControl in einer API-Datei eingebunden wird, wird möglicherweise ein HTML-Header statt eines JSON-Headers zurückgegeben und die gesamte API-Antwort schlägt fehl. Wenn ApiControl in einer HTML-Seite eingebunden wird, startet die Session nicht und die Seite bricht ab.

Regelsatz Standard

Regel 1: data-js-Architektur Kritisch

JavaScript-Events dürfen niemals über eine class oder id abgehört werden. Diese sind visuelle / Styling-Identifikatoren. Alle JS-Interaktionen werden über das Attribut data-js verwaltet. Wenn CSS eine Klasse löscht, stürzt JavaScript niemals ab.

<!-- ❌ Anti-Pattern — nicht unterstützt -->
<button id="submitBtn" class="btn">Senden</button>
// JS: document.getElementById('submitBtn').addEventListener(...)

<!-- ✅ ArtiFrame-Standard -->
<button class="btn btn-primary" data-js="login-submit">Senden</button>
// JS: document.querySelector('[data-js="login-submit"]').addEventListener(...)

Regel 2: Theme-Architektur

Dunkel-/Hell-Modus und Themes werden über die Attribute data-theme und data-mode des <html>-Tags verwaltet. Body-Klassen werden nicht verwendet.

<!-- HTML-Eröffnungstag aus der view.stub-Vorlage -->
<html lang="de" data-theme="default" data-mode="light">

/* Theme-Definition in app.css */
html[data-theme="default"][data-mode="dark"] {
    --bg-color: #0b0c0e;
    --text-main: #ffffff;
}
html[data-theme="default"][data-mode="light"] {
    --bg-color: #ffffff;
    --text-main: #111111;
}

Regel 3: Sicherer Datenfluss

Alle aus der Datenbank stammenden Daten werden mit display() umschlossen, bevor sie im DOM ausgegeben werden. Alle an die API gesendeten Daten werden mit sanitizeString() oder sanitizeInt() bereinigt, bevor sie verarbeitet werden.

Regel 4: Fehlerbehandlung mit APP_ENV

Der Wert von APP_ENV in der .env-Datei bestimmt die Sichtbarkeit von Fehlern. In der Production-Umgebung werden dem Benutzer keine Fehlermeldungen angezeigt.

// config/app-version.php
define('APP_ENV', (int)$_ENV['APP_ENV']); // 1=Debug, 0=Production

if (APP_ENV === 1) {
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
} else {
    ini_set('display_errors', 0);
}

CLI-Ökosystem

Die ArtiFrame CLI öffnet eine interaktive Shell, wenn artiframe im Terminal eingegeben wird. Alle Befehle werden in dieser Shell ausgeführt. Befehle können auch einmalig ausgeführt werden.

# Interaktiver Modus (empfohlen)
artiframe
artiframe> make:view admin/kullanicilar.php

# Einmaliger Modus
artiframe make:view admin/kullanicilar.php

new CLI-Befehl

Erstellt ein neues ArtiFrame-Projekt. Generiert die gesamte Verzeichnisskelettstruktur, Bootstrapper-Dateien und die erste Index-Seite.

artiframe> new proje-adi

Erstellte Struktur:

proje-adi/ ├── app/ (ViewControl.php, ApiControl.php, Database.php, DotEnv.php) ├── bin/ (SystemMethod.php, ViewMethod.php, stubs/) ├── config/ (app-version.php) ├── public/ (index.php, assets/, includes/, api/) ├── src/ ├── .env.example └── kilavuz.html

make:view CLI-Befehl

Erstellt eine neue Seiten- (View-) Datei und deren spezifische CSS/JS-Assets. Assets werden automatisch mit der Seite verknüpft und Cache-Busting wird mit ?v=APP_VERSION angewendet.

artiframe> make:view admin/kullanicilar.php

Erstellte Dateien:

✔  public/admin/kullanicilar.php
✔  public/assets/css/admin/kullanicilar.css
✔  public/assets/js/admin/kullanicilar.js

Die erstellte View-Datei enthält am Anfang ein eingebundenes ViewControl, hinzugefügte Head/Header/Footer-Includes und per Cache-Busting verknüpfte CSS/JS-Links.

make:api CLI-Befehl

Erstellt eine API-Endpunkt-Dateien durch Auswahl aus zwei verschiedenen Vorlagen. Jede neue API-Datei enthält bereits die Variable $allowedMethods und die Einbindung von ApiControl.php.

standart — Einzelaktions-API

Für Endpunkte, die eine einzelne Aufgabe ausführen (Login, Senden, Löschen). Die Geschäftslogik wird direkt geschrieben.

artiframe> make:api standart api/auth/giris.php
<?php
$allowedMethods = ['POST']; // Nur POST akzeptieren
require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';

use Bin\SystemMethod;

// Geschäftslogik hier...
jsonResponse(['status' => 'success'], 200);

switch-case — Multiaktions-API

Eine Struktur, die CRUD-Operationen für ein Modul in einem einzigen Endpunkt verwaltet. Die auszuführende Aktion wird durch den Parameter action bestimmt.

artiframe> make:api switch-case api/kullanici/yonet.php
<?php
$allowedMethods = ['POST'];
require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';

use Bin\SystemMethod;

$action = sanitizeString($_POST['action'] ?? '');

switch ($action) {
    case 'create':
        jsonResponse(['status' => 'success', 'message' => 'Erstellt.'], 200);
        break;
    case 'update':
        jsonResponse(['status' => 'success', 'message' => 'Aktualisiert.'], 200);
        break;
    case 'delete':
        jsonResponse(['status' => 'success', 'message' => 'Gelöscht.'], 200);
        break;
    default:
        jsonResponse(['status' => 'error', 'message' => 'Ungültige Aktion.'], 400);
}

make:class CLI-Befehl

Erstellt eine neue PHP-Klassendatei mit vorbereitetem Namespace- und Klassen-Boilerplate.

artiframe> make:class src/Service/EmailService.php

Wenn das Klassenverzeichnis nicht angegeben wird, gibt der Befehl einen Fehler zurück:

artiframe> make:class
❌ Fehler: Das Verzeichnis für die Klasse muss angegeben werden! (z.B. /app oder /src)
Example: /src/Service/PaymentService

version CLI-Befehl

Aktualisiert die Versionsnummer in config/app-version.php gemäß den Regeln der semantischen Versionierung (SemVer). Versionsformat: MAJOR.MINOR.PATCH

BefehlBeschreibungBeispiel
version upgrade patchFehlerbehebung, kleine Verbesserung1.2.3 → 1.2.4
version upgrade minorAbwärtskompatible neue Funktion1.2.3 → 1.3.0
version upgrade majorBreaking Change (brechende Änderung)1.2.3 → 2.0.0
version downgrade patchLetzten Patch rückgängig machen1.2.4 → 1.2.3
version downgrade minorLetztes Minor-Release rückgängig machen1.3.0 → 1.2.0
version downgrade majorLetztes Major-Release rückgängig machen2.0.0 → 1.0.0
artiframe> version upgrade minor
✔  Version von 1.2.0 auf 1.3.0 aktualisiert.

View Helpers — display() ViewMethod

Wendet obligatorischen XSS-Schutz an, wenn Daten aus der Datenbank oder Benutzereingaben im DOM ausgegeben werden. Gibt bei Null- oder leeren Werten einen Standardwert zurück, anstatt einen Fehler zu werfen.

string display(mixed $data, string $default = '')
💡 Tipp: Verwendung von $default
Der zweite Parameter ($default) ist der Fallback-Text, der auf dem Bildschirm ausgegeben wird, wenn die aus der Datenbank stammenden Daten leer sind (null, false, leere Zeichenkette). Wenn Sie beispielsweise display($isim, 'Unbenannter Benutzer') für einen Benutzer verwenden, dessen Name nicht eingegeben wurde, bietet Ihre Seite sinnvolle Inhalte statt unschöner Lücken.
<!-- ❌ Unsicher — erzeugt XSS-Lücke -->
<h1><?= $user['isim'] ?></h1>

<!-- ✅ Sichere ArtiFrame-Verwendung -->
<h1><?= display($user['isim'], 'Unbenannter Benutzer') ?></h1>

View Helpers — escapeUrl() ViewMethod

Wird verwendet, wenn von Benutzern erhaltene Links (z. B. Profil-Websites) in <a href="..."> oder <img src="..."> ausgegeben werden. Macht gefährliche Payloads wie javascript:alert(1) (Stored XSS) unschädlich und verhindert die Ausführung von Code über den Link.

string escapeUrl(string $url)
<!-- ❌ Unsicher — JS-Code kann über URL eingeschleust werden -->
<a href="<?= $user['website'] ?>">Website besuchen</a>

<!-- ✅ Sichere ArtiFrame-Verwendung -->
<a href="<?= escapeUrl($user['website']) ?>">Website besuchen</a>

View Helpers — csrfField() ViewMethod

Fügt HTML-Formularen ein verstecktes Token-Feld zum Schutz vor CSRF-Angriffen hinzu. Muss auf jeder Seite mit einem POST-Formular verwendet werden.

string csrfField()
<form action="/api/kaydet.php" method="POST">
    <?= csrfField() ?>   <!-- Aus Sicherheitsgründen erforderlich -->
    <input type="text" name="ad">
    <button type="submit" data-js="kaydet-btn">Speichern</button>
</form>

View Helpers — Datumsfunktionen ViewMethod

Verarbeitet Datums-Strings im Format Y-m-d H:i:s oder UNIX-Timestamp-Werte aus der Datenbank. Alle Textausgaben werden je nach Sprache (tr, en, de, fr, es) lokalisiert.

FunktionAusgabebeispielBeschreibung
day($date)24Nur Tag
month($date)07Nur Monat (Zahl)
year($date)2026Jahr
timeOnly($date)14:30Stunde:Minute
fulldate($date)24.07.2026Vollständiges Datum
formatDate($date, $format)24.07.2026 14:30Benutzerdefiniertes Format
monthName($date, $lang)Temmuz / July / JuliMonatsname (je nach Sprache)
fulldateName($date, $lang)24 Temmuz 2026 / July 24, 2026Vollständiges Datum (mit Monatsname, je nach Sprache)
timeAgo($date, $lang)5 dakika önce / 5 minutes agoSocial-Media-Stil (je nach Sprache)
💡 Parameter verstehen: $format und $lang
  • $format (Format): Wird nur mit der Funktion formatDate() verwendet. Akzeptiert Standard-PHP-Datumsbuchstaben. (Z. B.: 'd/m/Y' ➔ 24/07/2026 oder 'H:i' ➔ 15:30). Ermöglicht das Erstellen eigener Datums-Muster, wenn andere vordefinierte Funktionen (day, year usw.) unzureichend sind.
  • $lang (Sprache): Wird in Funktionen verwendet, die Text in ihrer Ausgabe enthalten (Monatsname, Wort "vor"). Wenn Sie diesen Parameter leer lassen, arbeitet das System standardmäßig mit 'tr' (Türkisch). Wenn Sie ein mehrsprachiges Projekt erstellen, reicht es aus, den Sprachcode (tr, en, de, fr, es) als zweiten Parameter einzugeben. (Z. B.: timeAgo($tarih, 'en') ➔ 5 minutes ago)
<!-- Angenommen, es ist ein UNIX-Timestamp von der Funktion time() -->
<?php $tarih = time(); ?>

<!-- Vollständiges Datum je nach Sprache -->
<span><?= fulldateName($tarih, 'tr') ?></span>
<!-- Ausgabe: 24 Temmuz 2026 -->

<!-- Zeitdarstellung im Social-Media-Stil -->
<span><?= timeAgo($tarih, 'en') ?></span>
<!-- Ausgabe: 5 minutes ago -->

<span><?= timeAgo($tarih, 'de') ?></span>
<!-- Ausgabe: vor 5 Minuten -->

View Helpers — Textformatierung ViewMethod

truncate($text, $length, $append)

string truncate(string $text, int $length = 100, string $append = '...')

Kürzt lange Texte (z. B. Blog-Zusammenfassungen) auf das gewünschte Zeichenlimit, ohne das letzte Wort zu zerschneiden, und fügt das angegebene Suffix am Ende hinzu.

<p><?= truncate($post['icerik'], 160, '...') ?></p>

View Helpers — money() ViewMethod

Formatiert den Betrag mit dem Währungssymbol. Der Währungscode (ISO) bestimmt automatisch die Platzierung des Symbols. Die Standardwährung ist usd.

string money(float $amount, string $currency = 'usd')
CodeAusgabeWährung
usd$1.250,00US-Dollar
eur1.250,00 €Euro
try / tl1.250,00 ₺Türkische Lira
gbp£1.250,00Britisches Pfund
jpy1.250,00 ¥Japanischer Yen
inr1.250,00 ₹Indische Rupie
rub1.250,00 ₽Russischer Rubel
krw1.250,00 ₩Südkoreanischer Won
brlR$1.250,00Brasilianischer Real
aed1.250,00 د.إVAE-Dirham
<span><?= money($urun['fiyat'], 'try') ?></span>
<!-- Ausgabe: 1.250,00 ₺ -->

<span><?= money($urun['fiyat'], 'usd') ?></span>
<!-- Ausgabe: $1.250,00 -->

System Helpers — jsonResponse() SystemMethod

Setzt den JSON-Header, übergibt den HTTP-Statuscode, gibt die Ausgabe sicher mit json_encode aus und beendet anschließend das Skript. Alle API-Antworten müssen über diese Funktion gegeben werden.

void jsonResponse(array $data, int $statusCode = 200)
// Erfolgreiche Antwort
jsonResponse(['status' => 'success', 'data' => $kullanici], 200);

// Fehlerantwort
jsonResponse(['status' => 'error', 'message' => 'Unbefugter Zugriff.'], 401);

System Helpers — verifyCsrf() SystemMethod

Überprüft, ob die eingehende POST-Anfrage von einem legitimen Formular stammt. Gibt false zurück, wenn csrfField() nicht im Formular enthalten ist oder das Token ungültig ist.

bool verifyCsrf(string $token)
if (!verifyCsrf($_POST['csrf_token'] ?? '')) {
    jsonResponse(['status' => 'error', 'message' => 'Ungültiges CSRF-Token.'], 403);
}

System Helpers — Bereinigungsfunktionen SystemMethod

FunktionBeschreibung
sanitizeInt($value)Entfernt alle Buchstaben, Symbole und Kommas und lässt nur Ganzzahlen übrig. Wird für IDs oder Limits verwendet.
sanitizeFloat($value)Bereinigt alles außer Dezimalzahlen. Wird für Geldbeträge oder Metriken verwendet.
sanitizeString($value)Eliminiert alle HTML- und PHP-Tags (<script>, <iframe> usw.), um XSS- und ähnliche Angriffe zu verhindern. Hinterlässt sicheren Klartext.
sanitizeEmail($email)Filtert alle ungültigen und gefährlichen Zeichen heraus, die nicht dem E-Mail-Format entsprechen.
$id    = sanitizeInt($_POST['id'] ?? 0);
$ad    = sanitizeString($_POST['ad'] ?? '');
$email = sanitizeEmail($_POST['email'] ?? '');

System Helpers — HTTP & Anfragen SystemMethod

FunktionBeschreibung
isPost()Anfrage POST?
isGet()Anfrage GET?
isPut()Anfrage PUT?
isDelete()Anfrage DELETE?
isAjax()Anfrage über XHR/Fetch-API?
getClientIp()Echte IP-Adresse (mit Cloudflare- & Proxy-Unterstützung)
redirect($url)Leitet zur angegebenen URL weiter und beendet das Skript
// Direktzugriff über den Browser verhindern
if (!isAjax()) {
    jsonResponse(['error' => 'Direkter Zugriff eingeschränkt.'], 403);
}

// Weiterleiten, wenn keine Sitzung vorhanden ist
if (!isset($_SESSION['user'])) {
    redirect('/giris.php');
}

$ip = getClientIp(); // Echte IP auch hinter Cloudflare

System Helpers — Sicherheit SystemMethod

FunktionBeschreibung
generateCsrf()Generiert ein neues CSRF-Token und speichert es in der Session
generateToken($length)Kryptografisch sichere zufällige Hex-Zeichenkette (Passwort-Reset, API-Key usw.)
hashPassword($password)Hasht das Passwort mit bcrypt
verifyPassword($password, $hash)Überprüft das Passwort anhand des Hashes
// Sichere Token-Generierung (API-Key, E-Mail-Bestätigungslink usw.)
$token = generateToken(32); 
// ⚠️ Hinweis: 32 Byte Daten werden generiert, aber da sie ins Hex-Format (Basis 16)
// umgewandelt werden, ist die Ausgabe genau doppelt so lang, d. h. eine 64 Zeichen lange Zeichenkette.

// Passwortspeicherung
$hash = hashPassword($_POST['sifre']);

// Passwortüberprüfung
if (!verifyPassword($_POST['sifre'], $kullanici['sifre_hash'])) {
    jsonResponse(['error' => 'Falsches Passwort.'], 401);
}

API — HTTP-Methoden-Kontrolle ApiControl

Das Array $allowedMethods muss vor dem Einbinden von ApiControl definiert werden. ApiControl liest dieses Array und lehnt Anfragen von nicht zugelassenen Methoden automatisch mit 405 Method Not Allowed ab.

// Ein Endpunkt, der nur GET und POST akzeptiert
$allowedMethods = ['GET', 'POST'];
require_once ... . '/../app/ApiControl.php';

// Ein Endpunkt, der nur DELETE akzeptiert
$allowedMethods = ['DELETE'];
require_once ... . '/../app/ApiControl.php';

Preflight-OPTIONS-Anfragen geben für CORS automatisch 200 zurück und das Skript beendet sich — kein manueller Eingriff erforderlich.

API — CORS ApiControl (Auskommentiert)

Wenn Sie den API-Zugriff von anderen Domains oder mobilen Anwendungen erlauben möchten, aktivieren Sie den CORS-Block in ApiControl.php.

// In ApiControl.php — wird durch Einkommentieren aktiviert
header("Access-Control-Allow-Origin: https://sizin-domaininiz.com");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
⚠️ Verwenden Sie in der Production-Umgebung kein * (alle Domains). Geben Sie die Domainadresse explizit an.

API — Rate Limiting ApiControl (Auskommentiert)

Sie können den Rate-Limiting-Block in ApiControl.php aktivieren, um zu verhindern, dass bösartige Benutzer oder Bots die API überfluten. Standardregel: 60 Anfragen in 60 Sekunden / IP.

⚠️ Redis-Server erforderlich: Die Rate-Limiting-Funktion (Ratenbegrenzung) funktioniert über die Klasse \Src\Service\RedisService::getInstance() unter Verwendung von Redis. Stellen Sie vor dem Aktivieren dieses Codeblocks sicher, dass Sie einen Redis-Dienst in Ihrem Projekt eingerichtet und eine Verbindungsklasse unter src/Service/ erstellt haben.
// Wenn von derselben IP mehr als 60 Anfragen in 60 Sekunden eingehen:
http_response_code(429); // Too Many Requests
echo json_encode(['error' => 'Zu viele Anfragen. Bitte warten Sie.']);

Vollständiger Arbeitsablauf: Kontaktformular (End-to-End)

Schauen wir uns Schritt für Schritt an, wie Sie eine Kontaktformular-Funktion nach ArtiFrame-Standards von Anfang bis Ende entwickeln.

  1. Erstellen Sie die View-Datei
    artiframe> make:view iletisim.php
    ✔  public/iletisim.php
    ✔  public/assets/css/iletisim.css
    ✔  public/assets/js/iletisim.js
  2. Erstellen Sie den API-Endpunkt
    artiframe> make:api standart api/iletisim/gonder.php
  3. Codieren Sie das HTML-Formular
    Fügen Sie das folgende Formular zur Datei public/iletisim.php hinzu:
    <form action="/api/iletisim/gonder.php" method="POST">
        <?= csrfField() ?>
        <input type="text"  name="ad"      placeholder="Ihr Name">
        <input type="email" name="eposta"  placeholder="E-Mail">
        <textarea name="mesaj" placeholder="Ihre Nachricht"></textarea>
        <button type="submit" data-js="iletisim-gonder">Senden</button>
    </form>
  4. Verbinden Sie die Fetch-API mit JavaScript
    In der Datei public/assets/js/iletisim.js:
    document.querySelector('[data-js="iletisim-gonder"]').addEventListener('click', async (e) => {
        e.preventDefault();
        const formData = new FormData(e.target.closest('form'));
        const res = await fetch('/api/iletisim/gonder.php', {
            method: 'POST',
            body: formData
        });
        const data = await res.json();
        console.log(data);
    });
  5. Vervollständigen Sie die Server-Logik (Backend)
    In der Datei public/api/iletisim/gonder.php:
    <?php
    $allowedMethods = ['POST'];
    require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';
    use Bin\SystemMethod;
    
    // 1. CSRF-Validierung
    if (!verifyCsrf($_POST['csrf_token'] ?? '')) {
        jsonResponse(['error' => 'Ungültiges Token.'], 403);
    }
    
    // 2. Daten bereinigen
    $ad     = sanitizeString($_POST['ad'] ?? '');
    $eposta = sanitizeEmail($_POST['eposta'] ?? '');
    $mesaj  = sanitizeString($_POST['mesaj'] ?? '');
    
    // 3. Geschäftslogik (E-Mail senden, in DB speichern usw.)
    // ...
    
    // 4. Antwort geben
    jsonResponse(['status' => 'success', 'message' => 'Ihre Nachricht wurde empfangen.'], 200);
✅ Abgeschlossen! Sie haben einen vollkommen sicheren und standardkonformen Formularablauf mit XSS-Schutz, CSRF-Validierung, HTTP-Methodeneinschränkung und data-js-Architektur erstellt.