Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,25 +0,0 @@
# Architektur-Prinzipien
Dieses Dokument beschreibt die grundlegenden Architekturprinzipien unseres Frameworks.
## 1. Immutabilität und Unveränderlichkeit
Wo immer möglich, sollten Objekte unveränderlich (immutable) sein. Dies verbessert die Voraussagbarkeit und Testbarkeit.
## 2. Final by Default
Alle Klassen sollten standardmäßig als `final` deklariert werden, es sei denn, es gibt einen konkreten Grund für Vererbung.
Begründung:
- Vermeidet unbeabsichtigte Vererbungshierarchien
- Verbessert die Kapselung
- Ermöglicht interne Änderungen, ohne Kinderklassen zu beeinflussen
## 3. Explizite über Implizite
- Alle Abhängigkeiten sollten explizit injiziert werden
- Keine globalen Zustände oder Singletons
- Typen immer explizit deklarieren
## 4. Modularität
Jedes Modul sollte in sich geschlossen sein und minimale Abhängigkeiten nach außen haben.

View File

@@ -1,76 +0,0 @@
# 📘 Commit-Konventionen Conventional Commits
Dieses Projekt verwendet das [Conventional Commits](https://www.conventionalcommits.org)-Format für einheitliche und nachvollziehbare Commit-Nachrichten.
---
## 🔧 Format
```
<type>[optional scope]: <beschreibung>
```
**Beispiel:**
```
feat: add Ansible deploy playbook
```
- **Englisch**
- **Präsens** (z.B. „add“, nicht „added“)
- **Keine abschließenden Punkte**
- **Optionaler Body** bei größeren Änderungen
---
## 📦 Commit-Typen
| Typ | Beschreibung |
|------------|--------------------------------------------------------|
| `feat` | ✨ Neues Feature |
| `fix` | 🐛 Fehlerbehebung |
| `docs` | 📘 Nur Dokumentation (z.B. README, .env.example) |
| `style` | 🎨 Formatierung, keine Änderung am Verhalten |
| `refactor` | 🔁 Code-Umstrukturierung ohne neues Verhalten/Feature |
| `test` | 🧪 Tests hinzufügen oder anpassen |
| `chore` | 🔧 Projektpflege (z.B. `.gitignore`, `.mailmap`, Cleanup) |
---
## ✅ Gute Commit-Beispiele
```bash
chore: initial commit with Docker + Ansible setup
feat: add restart task to deploy role
fix: correct Docker volume path
docs: add .env.example as reference
chore: add .mailmap to unify author identity
```
---
## 🛑 Vermeide unklare Messages wie:
```bash
"update"
"bugfixes"
"misc"
"more changes"
```
Diese helfen später weder dir noch Tools oder anderen.
---
## 🧠 Tipps
- Nutze aussagekräftige, prägnante Beschreibungen
- Schreibe deine Commits so, dass man daraus verstehen kann, **was passiert** ohne Git-Diff zu lesen
- Wenn du mehrere Dinge in einem Commit machst, überlege, ob es **mehrere Commits** sein sollten
---
## 📚 Weitere Infos
- [conventionalcommits.org](https://www.conventionalcommits.org)
- [semantic-release](https://semantic-release.gitbook.io/semantic-release/) für automatische Releases basierend auf Commit-Typen

View File

@@ -1,43 +0,0 @@
# 🚀 Deployment-Anleitung (Ansible-basiert)
Dieses Projekt verwendet Ansible zur automatisierten Bereitstellung.
---
## 🧱 Struktur
- `ansible/setup.yml` → Bereitet Zielserver vor (Docker, Git, Benutzer)
- `ansible/deploy.yml` → Clont Projekt & startet Docker Compose
---
## 📂 Vorbereitung
1. Zielserver (Debian)
2. SSH-Zugang (z.B. via `~/.ssh/id_rsa`)
3. Eintrag in `ansible/inventory.ini`:
```ini
[web]
123.123.123.123 ansible_user=root
```
---
## ▶️ Ausführen
```bash
# Setup ausführen (nur einmal)
ansible-playbook -i ansible/inventory.ini ansible/setup.yml
# Projekt deployen (beliebig oft)
ansible-playbook -i ansible/inventory.ini ansible/deploy.yml
```
---
## 🔐 Hinweis
- `.env` wird **nicht** automatisch übertragen
- Serverpfade ggf. per `dest:` in `git:`-Modul anpassen

View File

@@ -1,40 +0,0 @@
# 🔐 Umgebungsvariablen (.env)
Dieses Projekt verwendet `.env`-Dateien zur Konfiguration von Docker Compose und anderen Tools.
---
## 📄 Beispiel: .env
```env
COMPOSE_PROJECT_NAME=michaelschiemer
APP_PORT=8000
PHP_VERSION=8.2
```
> Diese Datei sollte **nicht** versioniert werden.
---
## 📄 Beispiel: .env.example
Diese Datei enthält Beispielwerte und wird mit dem Projekt mitgeliefert.
---
## 📌 Nutzung in docker-compose.yml
```yaml
php:
image: php:${PHP_VERSION}-fpm
web:
ports:
- "${APP_PORT}:80"
```
---
## 📦 Empfehlung
- `.env` → lokal, nicht versioniert
- `.env.example` → ins Git, immer aktuell halten

View File

@@ -1,61 +0,0 @@
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
*italics*
**bold**
***italics & bold***
~~crossed off~~
<mark>highlight</mark>
<sub>Test</sub>
`monospace`
```html
<html>
<header></header>
<footer></footer>
</html>
```
[This is a link](https://localhost)
![Image](url)
> This is a blockquote
>> and it can be nested
***
---
___
1. Item 1
2. Item 2
3. Item 3
* Test
* Test
* Subitem
* Subitem
| Column1 | Column 2 |
| --- |-----|
| Test | Test2 |
- [ ] Test
- [x] Test 2

View File

@@ -1,77 +1,68 @@
# Projekt-Dokumentation
# Framework Dokumentation
## Übersicht
Willkommen zur Dokumentation des Projekts. Diese Dokumentation dient als zentrale Informationsquelle für Entwickler, die am Projekt arbeiten.
Willkommen zur Dokumentation des Frameworks. Diese Dokumentation bietet umfassende Informationen zur Installation, Konfiguration und Verwendung des Frameworks sowie detaillierte Beschreibungen aller Komponenten und Funktionen.
## Inhaltsverzeichnis
## Dokumentationsstruktur
### Standards und Guidelines
Die Dokumentation ist in folgende Hauptbereiche gegliedert:
- [Coding Guidelines](/docs/standards/CODING-GUIDELINES.md) - Allgemeine Coding-Standards für das Projekt
- [Sicherheitsrichtlinien](/docs/standards/SICHERHEITS-GUIDELINES.md) - Standards für sichere Softwareentwicklung
### Erste Schritte
- [Installation](getting-started/installation.md)
- [Konfiguration](getting-started/configuration.md)
- [Erste Schritte](getting-started/first-steps.md)
### Entwicklungsrichtlinien
### Architektur
- [Architekturübersicht](architecture/overview.md)
- [Hauptkomponenten](architecture/components.md)
- [Entwurfsmuster](architecture/patterns.md)
- [Performance Guidelines](/docs/guidelines/PERFORMANCE-GUIDELINES.md) - Richtlinien zur Optimierung der Anwendungsleistung
- [Testing Guidelines](/docs/guidelines/TESTING-GUIDELINES.md) - Standards und Best Practices für Tests
### Komponenten
- **Analytics**
- [Übersicht](components/analytics/index.md)
- [Konfiguration](components/analytics/configuration.md)
- [Beispiele](components/analytics/examples.md)
- **Validation**
- [Übersicht](components/validation/index.md)
- [Validierungsregeln](components/validation/rules.md)
- [Beispiele](components/validation/examples.md)
- **WAF (Web Application Firewall)**
- [Übersicht](components/waf/index.md)
- [Machine Learning](components/waf/machine-learning.md)
- [Konfiguration](components/waf/configuration.md)
### KI-Assistent Konfiguration
### Entwickleranleitungen
- [Routing](guides/routing.md)
- [Controller](guides/controllers.md)
- [Validierung](guides/validation.md)
- [Guidelines für KI-Assistenten](/docs/ai/GUIDELINES-FÜR-AI-ASSISTANT.md) - Spezifische Richtlinien für den KI-Assistenten
- [PhpStorm Einrichtung](/docs/ai/EINRICHTUNG-PHPSTORM.md) - Anleitung zur Einrichtung des KI-Assistenten in PhpStorm
### API-Dokumentation
- [API-Übersicht](api/index.md)
### Architektur und Struktur
### Beitragsrichtlinien
- [Coding-Standards](contributing/code-style.md)
- [Pull-Request-Prozess](contributing/pull-requests.md)
- [Dokumentationsrichtlinien](contributing/documentation.md)
- [Projektstruktur](/docs/architecture/STRUKTUR-DOKUMENTATION.md) - Überblick über die Struktur des Projekts
### Projektplanung
- [Features](roadmap/features.md)
- [Tasks](roadmap/tasks.md)
- [Meilensteine](roadmap/milestones.md)
### Framework-Entwicklung
## Dokumentationsstandards
- [Modul-Checkliste](/docs/framework/MODUL-CHECKLISTE.md) - Leitfaden für die Erstellung neuer Module
- [Erweiterungsmuster](/docs/framework/ERWEITERUNGSPATTERN.md) - Muster zur Erweiterung des Frameworks
Diese Dokumentation folgt einheitlichen Standards, um Konsistenz und Benutzerfreundlichkeit zu gewährleisten:
### Framework-Module
1. **Struktur**: Jedes Dokument beginnt mit einer Übersicht und gliedert sich dann in logische Abschnitte.
2. **Codebeispiele**: Alle Codebeispiele sind vollständig und funktionsfähig.
3. **Querverweise**: Verwandte Themen werden durch Links miteinander verbunden.
4. **Aktualität**: Die Dokumentation wird regelmäßig aktualisiert, um den aktuellen Stand der Implementierung widerzuspiegeln.
- [Analytics-Modul](/docs/framework/analytics/README.md) - Tracking und Analyse von Anwendungsdaten
- [Core-Modul](/docs/framework/core/README.md) - Kernkomponenten und Event-System
- [DI-Modul](/docs/framework/di/README.md) - Dependency-Injection-Container
- [HTTP-Modul](/docs/framework/http/README.md) - HTTP-Request und -Response-Handling
## Mitwirkung an der Dokumentation
## Mitwirken
Wir begrüßen Beiträge zur Verbesserung dieser Dokumentation. Bitte beachten Sie die [Dokumentationsrichtlinien](contributing/documentation.md) für Informationen zum Beitragsprozess.
### Neue Module entwickeln
## Feedback
1. Folge der [Framework-Modul Checkliste](/docs/framework/MODUL-CHECKLISTE.md) für neue Module
2. Stelle sicher, dass dein Code den [Coding Guidelines](/docs/standards/CODING-GUIDELINES.md) entspricht
3. Schreibe Tests gemäß den [Testing Guidelines](/docs/guidelines/TESTING-GUIDELINES.md)
4. Erstelle eine ausführliche Dokumentation für dein Modul
### Dokumentation verbessern
Wir begrüßen Beiträge zur Verbesserung der Dokumentation. Wenn du Fehler findest oder Vorschläge zur Verbesserung hast, erstelle bitte einen Pull Request mit deinen Änderungen.
## Erste Schritte
Neue Entwickler sollten mit folgenden Schritten beginnen:
1. Projekt lokal einrichten (siehe [Installation](#installation))
2. Die [Projektstruktur](/docs/architecture/STRUKTUR-DOKUMENTATION.md) verstehen
3. Die [Coding Guidelines](/docs/standards/CODING-GUIDELINES.md) lesen
4. PhpStorm mit dem [KI-Assistenten einrichten](/docs/ai/EINRICHTUNG-PHPSTORM.md)
## Installation
```bash
# Repository klonen
git clone [repository-url]
# Abhängigkeiten installieren
composer install
# Entwicklungsserver starten
php -S localhost:8000 -t public/
```
## Updates und Änderungen
Diese Dokumentation wird kontinuierlich aktualisiert. Prüfe regelmäßig auf Aktualisierungen, um über die neuesten Best Practices und Standards informiert zu bleiben.
Wenn Sie Fragen, Anregungen oder Feedback zur Dokumentation haben, erstellen Sie bitte ein Issue im Repository oder kontaktieren Sie das Entwicklungsteam direkt.

View File

@@ -1,48 +0,0 @@
# ⚙️ Setup-Anleitung
Diese Datei beschreibt, wie du das Projekt lokal einrichtest und startest.
---
## 🔧 Voraussetzungen
- Docker & Docker Compose
- Python 3 (für Ansible, optional pipx)
- Optional: Ansible (für Server-Setup)
- Optional: PhpStorm oder VS Code
---
## 📦 Projektstruktur
```
.
├── app/ # PHP/NGINX-Anwendung
├── ansible/ # Setup- und Deployment-Playbooks
├── docker-compose.yml
├── .env # Lokale Konfiguration (nicht versioniert)
├── Makefile # Komfortbefehle
└── docs/ # Dokumentation
```
---
## ▶️ Lokaler Start
```bash
# Container starten
docker compose up --build
# Alternativ mit Makefile
make deploy
```
---
## 🧪 Lokale Tests
- `http://localhost:8080` → NGINX + PHP
- Logs anzeigen: `docker compose logs -f`
---

View File

@@ -1,16 +0,0 @@
# Queue Worker - Docker Management
Dieses Dokument beschreibt alle Docker-spezifischen Befehle für die Verwaltung des Queue Workers.
## 📋 Inhaltsverzeichnis
- [Schnellstart](#schnellstart)
- [Worker Management](#worker-management)
- [Monitoring & Debugging](#monitoring--debugging)
- [Konfiguration](#konfiguration)
- [Troubleshooting](#troubleshooting)
- [Wartung](#wartung)
## 🚀 Schnellstart
### Worker starten

View File

@@ -1,53 +0,0 @@
# Einrichtung des KI-Assistenten in PhpStorm
## Übersicht
Diese Anleitung beschreibt, wie der KI-Assistent in PhpStorm eingerichtet wird, um automatisch die Projekt-Guidelines zu verwenden.
## Methode 1: Über die PhpStorm-Einstellungen
1. Öffne PhpStorm und gehe zu **Settings/Preferences**
- Windows/Linux: File → Settings
- macOS: PhpStorm → Preferences
2. Navigiere zu **Tools****AI Assistant****Custom Instructions**
3. Aktiviere die Option **Use custom instructions**
4. Füge in das Textfeld den Inhalt aus der Datei `/docs/ai/GUIDELINES-FÜR-AI-ASSISTANT.md` ein
- Alternativ kannst du auf einen relativen Pfad verweisen
5. Aktiviere die Option **Apply project-specific instructions**, damit diese Einstellungen nur für dieses Projekt gelten
6. Klicke auf **Apply** und dann auf **OK**
## Methode 2: Über die Projektkonfiguration (empfohlen)
Die `.idea/aiAssistant.xml`-Datei ist bereits im Projekt enthalten und konfiguriert den KI-Assistenten automatisch mit den richtigen Einstellungen. Wenn du das Projekt öffnest, sollte der KI-Assistent bereits korrekt eingerichtet sein.
Um zu überprüfen, ob die Einstellungen korrekt übernommen wurden:
1. Öffne die PhpStorm-Einstellungen wie oben beschrieben
2. Navigiere zu **Tools****AI Assistant****Custom Instructions**
3. Überprüfe, ob **Use custom instructions** aktiviert ist und die Guidelines angezeigt werden
## Testen der Einrichtung
Um zu testen, ob der KI-Assistent die Guidelines korrekt anwendet:
1. Öffne eine PHP-Datei im Projekt
2. Drücke `Alt+A` (Windows/Linux) oder `Option+A` (macOS) um den KI-Assistenten zu öffnen
3. Bitte den Assistenten, eine neue Klasse zu erstellen
4. Überprüfe, ob die generierte Klasse den Guidelines entspricht:
- Sie sollte als `final` und wenn möglich `readonly` deklariert sein
- Constructor Property Promotion sollte verwendet werden
- Es sollten keine externen Abhängigkeiten importiert werden
## Fehlerbehebung
Falls die Guidelines nicht korrekt angewendet werden:
1. Stelle sicher, dass du die neueste Version von PhpStorm verwendest
2. Überprüfe, ob die AI Assistant-Funktion aktiviert ist
3. Versuche, das Projekt neu zu öffnen
4. Führe einen Cache-Clear in PhpStorm durch: File → Invalidate Caches

View File

@@ -1,174 +0,0 @@
# Guidelines für KI-Assistenten
## Übersicht
Diese Guidelines helfen dir, dem KI-Assistenten, konsistenten, modernen und qualitativ hochwertigen PHP-Code zu generieren, der den Projektstandards entspricht.
## Verwendung in PhpStorm
Diese Guidelines können in PhpStorm so eingerichtet werden, dass sie automatisch vom KI-Assistenten verwendet werden:
1. Gehe zu **Settings/Preferences****Tools****AI Assistant****Custom Instructions**
2. Aktiviere **Use custom instructions**
3. Füge im Textfeld den Inhalt dieser Datei ein oder verwende einen relativen Pfad zu dieser Datei
4. Optional: Aktiviere **Apply project-specific instructions** für projektspezifische Einstellungen
Alternativ kann die Datei `.idea/aiAssistant.xml` angepasst werden, um diese Guidelines als Standardeinstellung für das Projekt zu verwenden.
## Kernprinzipien
### Abhängigkeitsvermeidung
- **Keine externen Abhängigkeiten** außer den explizit freigegebenen
- Eigene Implementierungen gegenüber externen Bibliotheken bevorzugen
- Bei Bedarf nach externen Funktionen zuerst prüfen, ob eine eigene Implementierung möglich ist
- Erlaubte Abhängigkeiten sind auf die vorhandenen Composer-Pakete beschränkt
## Architekturprinzipien
Bei der Codeanalyse und -generierung sind folgende Architekturprinzipien zu beachten:
1. **Modularer Aufbau**: Das Projekt ist in Module unter `/src/Framework/` organisiert
2. **Service-orientierte Architektur**: Funktionalitäten als unabhängige Services implementieren
3. **Dependency Injection**: Abhängigkeiten werden per Constructor Injection bereitgestellt
4. **Event-basierte Kommunikation**: Module kommunizieren über den EventDispatcher
5. **Selbstständigkeit**: Module sollten möglichst unabhängig von externen Bibliotheken sein
## Coding-Standards
### Klassen
- **IMMER `final` verwenden**, außer bei zwingenden Gründen für Vererbung
- **KEINE abstrakten Klassen** verwenden - stattdessen Interfaces und Kompositionen
- Klassen und Properties wenn möglich als `readonly` deklarieren
- Bevorzuge Interfaces für Vertragsgestaltung zwischen Komponenten
```php
// RICHTIG
final readonly class AnalyticsService implements AnalyticsInterface
{
// ...
}
// FALSCH
abstract class BaseAnalytics
{
// ...
}
```
### Properties und Methoden
- Private `readonly` Properties mit Typisierung
- Return-Types immer angeben
- Parameter-Types immer angeben
- Union Types und Nullable Types nutzen
```php
// RICHTIG
private readonly LoggerInterface $logger;
public function process(?int $id): Result|null
{
// ...
}
// FALSCH
public $logger;
public function process($id)
{
// ...
}
```
### Moderne PHP-Features
Nutze aktiv die neuesten PHP-Features:
- Constructor Property Promotion
- Match Expressions statt Switch
- Named Arguments
- Enums statt Konstanten
- Nullsafe Operator (`?->`) wo sinnvoll
- Typed Properties
## Klassenaufbau
Folgende Reihenfolge für Klassenelemente:
1. Konstanten
2. Properties
3. Constructor
4. Öffentliche Methoden
5. Private/Protected Methoden
## Service-Initialisierung
Services werden durch Initializer-Klassen registriert:
```php
#[Initializer]
final readonly class ServiceInitializer
{
public function __construct(
private Configuration $config,
private DependencyInterface $dependency
) {}
public function __invoke(Container $container): ServiceInterface
{
return new Service(
$this->config->get('service'),
$this->dependency
);
}
}
```
## Fehlerbehandlung
- Spezifische Exception-Klassen werfen
- Early Return Pattern bevorzugen
- Defensive Programmierung mit Validierung
## Testing
Bei Test-Vorschlägen Pest-Framework nutzen:
```php
test('method does something correctly', function () {
// Arrangement
$service = new Service($dependency);
// Action
$result = $service->method();
// Assertion
expect($result)->toBe('expected');
});
```
## Dokumentation
- PHPDoc für alle öffentlichen Methoden
- Kurze, präzise Beschreibungen
- Parameter und Return-Types in PHPDoc
## Zu vermeidende Praktiken
- Globale Zustände und statische Methoden
- Tiefe Vererbungshierarchien
- Lange, komplexe Methoden
- Magische Methoden (`__call`, etc.) ohne triftigen Grund
- Unnötige Abstraktionen
## Bei Codeanalyse und -vorschlägen
1. **Aktuellen Stil beibehalten**: Bei Vorschlägen den vorhandenen Codierungsstil beibehalten
2. **Standards berücksichtigen**: Auf Einhaltung der hier definierten Guidelines achten
3. **Modernisierung vorschlagen**: Auf Möglichkeiten zur Modernisierung hinweisen
4. **Begründen**: Bei Empfehlungen die Gründe erläutern
5. **Vollständigkeit**: Vollständige Lösungen anbieten, nicht nur Fragmente
Diese Guidelines sind als lebendiges Dokument zu betrachten, das mit der Evolution des Projekts und von PHP weiterentwickelt wird.

View File

@@ -1,54 +0,0 @@
# KI-Assistent Dokumentation
## Übersicht
Diese Dokumentation beschreibt die Einrichtung und Verwendung des KI-Assistenten im Projekt. Der KI-Assistent hilft bei der Entwicklung durch Code-Generierung, Refactoring-Vorschläge und mehr, während er die Projektstandards einhält.
## Inhalte
- [Guidelines für KI-Assistenten](/ai/GUIDELINES-FÜR-AI-ASSISTANT.md) - Richtlinien für den KI-Assistenten
- [PhpStorm Einrichtung](/ai/EINRICHTUNG-PHPSTORM.md) - Anleitung zur Einrichtung in PhpStorm
## KI-Assistent Guidelines
Die [Guidelines für KI-Assistenten](/ai/GUIDELINES-FÜR-AI-ASSISTANT.md) stellen sicher, dass der KI-generierte Code den Projektstandards entspricht:
- Einhaltung der Coding-Standards
- Vermeidung externer Abhängigkeiten
- Verwendung moderner PHP-Features
- Konsistente Klassenstruktur
- Korrekte Fehlerbehandlung
## Einrichtung in PhpStorm
Die [PhpStorm Einrichtungsanleitung](/ai/EINRICHTUNG-PHPSTORM.md) führt Sie durch den Prozess der Integration des KI-Assistenten in Ihre IDE:
- Konfiguration der Custom Instructions
- Verwendung der projektspezifischen Einstellungen
- Testen der korrekten Einrichtung
- Fehlerbehebung bei Problemen
## Effektive Nutzung des KI-Assistenten
### Best Practices
1. **Klare Anfragen stellen**: Je präziser die Anfrage, desto besser das Ergebnis
2. **Kontext bereitstellen**: Dem Assistenten relevanten Kontext geben
3. **Ergebnisse überprüfen**: Generierte Code immer prüfen und verstehen
4. **Iterativ arbeiten**: Bei komplexen Aufgaben schrittweise vorgehen
### Häufige Anwendungsfälle
- Erstellung neuer Klassen und Interfaces
- Implementierung von Tests
- Refactoring bestehenden Codes
- Dokumentation generieren
- Code-Optimierung
## Datenschutz und Sicherheit
Beim Umgang mit dem KI-Assistenten sollten Sie folgende Punkte beachten:
- Keine sensiblen Daten oder Geschäftsgeheimnisse teilen
- Keine Passwörter, API-Schlüssel oder Zugangsdaten teilen
- Bei Unsicherheit den KI-Assistenten nicht verwenden

View File

@@ -0,0 +1,295 @@
# API Versioning Examples
The API Versioning system provides flexible, clean version management with support for multiple versioning strategies.
## Supported Versioning Strategies
### 1. Header-Based Versioning (Recommended)
```bash
# Using API-Version header
curl -X GET https://localhost/api/users \
-H "API-Version: 2.0.0" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
# Using custom header
curl -X GET https://localhost/api/users \
-H "X-API-Version: v2" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
### 2. URL Path Versioning
```bash
# Version in URL path
curl -X GET https://localhost/api/v1/users \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
curl -X GET https://localhost/api/v2/users \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
### 3. Query Parameter Versioning
```bash
# Version as query parameter
curl -X GET https://localhost/api/users?version=2.0 \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
### 4. Accept Header Versioning
```bash
# Version in Accept header
curl -X GET https://localhost/api/users \
-H "Accept: application/json;version=2.0" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
## Version Information Endpoints
### Get Current Version Info
```bash
curl -X GET https://localhost/api/version \
-H "API-Version: 2.0.0" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"current_version": "v2.0.0",
"current_version_numeric": "2.0.0",
"latest_version": "v2.0.0",
"default_version": "v1.0.0",
"is_latest": true,
"is_deprecated": false,
"supported_strategies": [
{
"name": "header",
"description": "Version specified in API-Version header",
"header_name": "API-Version"
},
{
"name": "url_path",
"description": "Version specified in URL path (/api/v1/users)",
"header_name": "API-Version"
}
]
}
```
### Get Supported Versions
```bash
curl -X GET https://localhost/api/versions \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"supported_versions": [
{
"version": "v2.0.0",
"version_numeric": "2.0.0",
"is_default": false,
"is_latest": true,
"is_deprecated": false,
"major": 2,
"minor": 0,
"patch": 0
},
{
"version": "v1.0.0",
"version_numeric": "1.0.0",
"is_default": true,
"is_latest": false,
"is_deprecated": true,
"major": 1,
"minor": 0,
"patch": 0
}
],
"total_versions": 2,
"versioning_config": {
"strict_versioning": false,
"deprecation_warnings": true,
"default_version": "v1.0.0",
"latest_version": "v2.0.0"
}
}
```
## API Version Differences
### Version 1.0 Response Format
```bash
curl -X GET https://localhost/api/v1/users/1 \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"id": 1,
"name": "User 1",
"email": "user1@example.com",
"created_at": "2024-01-01T00:00:00Z"
}
```
### Version 2.0 Response Format
```bash
curl -X GET https://localhost/api/v2/users/1 \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"data": {
"id": 1,
"name": "User 1",
"email": "user1@example.com",
"profile": {
"bio": "This is the bio for user 1",
"avatar_url": "https://example.com/avatars/1.jpg",
"website": "https://user1.example.com",
"location": "San Francisco, CA",
"verified": false
},
"settings": {
"notifications": true,
"privacy_level": "public",
"theme": "dark"
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"meta": {
"api_version": "2.0.0",
"response_time_ms": 127
}
}
```
## Deprecation Warnings
When using deprecated endpoints, you'll receive warning headers:
```bash
curl -X GET https://localhost/api/v1/users/1/profile \
-H "API-Version: 1.0.0" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-I
```
Response Headers:
```
HTTP/1.1 200 OK
Content-Type: application/json
API-Version: v1.0.0
Warning: 299 - "This endpoint is deprecated and will be removed in v2.0.0"
```
## Migration Guide
### Get Migration Instructions
```bash
curl -X POST https://localhost/api/version/migrate \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"from_version": "1.0.0",
"to_version": "2.0.0"
}'
```
Response:
```json
{
"from_version": "v1.0.0",
"to_version": "v2.0.0",
"compatible": false,
"migration_required": true,
"changes": {
"breaking_changes": [
"Response format changed to include metadata wrapper",
"Profile endpoint moved from /users/{id}/profile to new format",
"Error responses now include detailed validation information"
],
"new_features": [
"Enhanced user profile with social links and stats",
"Pagination support for list endpoints",
"Response time metadata in all responses"
],
"deprecated_endpoints": [
"/api/v1/users/{id}/profile - Use /api/v2/users/{id}/profile instead"
],
"migration_steps": [
"1. Update API version header to v2.0.0",
"2. Update response parsing to handle metadata wrapper",
"3. Update error handling for new error format",
"4. Test all endpoints with new response format",
"5. Update profile endpoint calls if used"
]
},
"estimated_effort": "Medium"
}
```
## Error Handling
### Unsupported Version (with strict versioning)
```bash
curl -X GET https://localhost/api/users \
-H "API-Version: 3.0.0" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"error": "Unsupported API version",
"requested_version": "v3.0.0",
"supported_versions": ["v1.0.0", "v2.0.0"],
"latest_version": "v2.0.0"
}
```
## Controller Configuration
### Using ApiVersionAttribute
```php
// Class-level version constraint
#[ApiVersionAttribute('2.0.0', introducedIn: '2.0.0')]
class UsersV2Controller
{
// All methods in this controller require v2.0+
}
// Method-level deprecation
#[Route(path: '/api/v1/users/{id}/profile', method: Method::GET)]
#[ApiVersionAttribute('1.0.0', introducedIn: '1.0.0', deprecatedIn: '1.5.0', removedIn: '2.0.0')]
public function getProfile(Request $request): HttpResponse
{
// This method is deprecated in v1.5.0 and removed in v2.0.0
}
```
## Best Practices
1. **Use Header Versioning**: Most flexible and doesn't pollute URLs
2. **Semantic Versioning**: Use major.minor.patch format
3. **Deprecation Warnings**: Always warn before removing endpoints
4. **Migration Guides**: Provide clear migration paths
5. **Backward Compatibility**: Maintain compatibility within major versions
6. **Version Documentation**: Document changes between versions
7. **Default to Stable**: Use stable version as default, not latest

838
docs/api/index.md Normal file
View File

@@ -0,0 +1,838 @@
# API-Dokumentation
Diese Dokumentation bietet einen Überblick über die API des Frameworks und wie Sie sie verwenden können, um RESTful APIs zu erstellen.
## Einführung
Das Framework bietet umfassende Unterstützung für die Erstellung von RESTful APIs mit Funktionen wie:
- Einfache Routendefinition für API-Endpunkte
- Automatische Konvertierung von Daten in JSON
- Validierung von Anfragen
- Authentifizierung und Autorisierung
- Versionierung
- Rate Limiting
- API-Dokumentation
## API-Routen definieren
### Grundlegende API-Routen
Sie können API-Routen in der Datei `config/routes.php` definieren:
```php
use App\Framework\Routing\Router;
use App\Application\Controllers\Api\UserController;
return function (Router $router) {
$router->group('/api', function (Router $router) {
$router->get('/users', [UserController::class, 'index']);
$router->get('/users/{id}', [UserController::class, 'show']);
$router->post('/users', [UserController::class, 'store']);
$router->put('/users/{id}', [UserController::class, 'update']);
$router->delete('/users/{id}', [UserController::class, 'destroy']);
});
};
```
### API-Ressourcen-Routen
Für RESTful APIs können Sie API-Ressourcen-Routen verwenden:
```php
$router->apiResource('users', UserController::class);
```
Dies erstellt die folgenden Routen:
| HTTP-Methode | URI | Aktion | Routenname |
|--------------|------------------|----------|----------------|
| GET | /users | index | users.index |
| POST | /users | store | users.store |
| GET | /users/{user} | show | users.show |
| PUT/PATCH | /users/{user} | update | users.update |
| DELETE | /users/{user} | destroy | users.destroy |
### Verschachtelte API-Ressourcen
Sie können auch verschachtelte API-Ressourcen definieren:
```php
$router->apiResource('users.posts', UserPostController::class);
```
Dies erstellt Routen wie:
- `/users/{user}/posts`
- `/users/{user}/posts/{post}`
### API-Versionierung
Sie können verschiedene Versionen Ihrer API unterstützen:
```php
$router->group('/api/v1', function (Router $router) {
$router->apiResource('users', Api\V1\UserController::class);
});
$router->group('/api/v2', function (Router $router) {
$router->apiResource('users', Api\V2\UserController::class);
});
```
## API-Controller
API-Controller sind spezielle Controller, die JSON-Antworten zurückgeben:
```php
namespace App\Application\Controllers\Api;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Application\Models\User;
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = User::all();
return $this->json([
'data' => $users
]);
}
public function show(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
return $this->json([
'data' => $user
]);
}
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
$user = User::create($request->only(['name', 'email', 'password']));
return $this->json([
'data' => $user,
'message' => 'Benutzer erstellt'
], 201);
}
public function update(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
$this->validate($request, [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $id,
]);
$user->fill($request->only(['name', 'email']));
$user->save();
return $this->json([
'data' => $user,
'message' => 'Benutzer aktualisiert'
]);
}
public function destroy(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
$user->delete();
return $this->json([
'message' => 'Benutzer gelöscht'
]);
}
}
```
## API-Antworten
### Erfolgsantworten
Für Erfolgsantworten können Sie die `json`-Methode verwenden:
```php
// 200 OK
return $this->json([
'data' => $users
]);
// 201 Created
return $this->json([
'data' => $user,
'message' => 'Benutzer erstellt'
], 201);
// 204 No Content
return $this->noContent();
```
### Fehlerantworten
Für Fehlerantworten können Sie ebenfalls die `json`-Methode verwenden:
```php
// 400 Bad Request
return $this->json([
'error' => 'Ungültige Anfrage'
], 400);
// 401 Unauthorized
return $this->json([
'error' => 'Nicht autorisiert'
], 401);
// 403 Forbidden
return $this->json([
'error' => 'Zugriff verweigert'
], 403);
// 404 Not Found
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
// 422 Unprocessable Entity (Validierungsfehler)
return $this->json([
'error' => 'Validierungsfehler',
'errors' => $validator->errors()
], 422);
// 500 Internal Server Error
return $this->json([
'error' => 'Serverfehler'
], 500);
```
### Konsistente Antwortstruktur
Es ist wichtig, eine konsistente Antwortstruktur für Ihre API zu haben:
```php
// Erfolgsantwort
return $this->json([
'success' => true,
'data' => $data,
'message' => $message,
'meta' => [
'pagination' => [
'total' => $total,
'per_page' => $perPage,
'current_page' => $currentPage,
'last_page' => $lastPage,
]
]
]);
// Fehlerantwort
return $this->json([
'success' => false,
'error' => $errorMessage,
'errors' => $validationErrors,
'code' => $errorCode
], $statusCode);
```
## API-Ressourcen
API-Ressourcen ermöglichen es Ihnen, Modelle in JSON-Antworten zu transformieren:
```php
namespace App\Application\Resources;
use App\Framework\Http\Resources\JsonResource;
use App\Application\Models\User;
class UserResource extends JsonResource
{
public function toArray(): array
{
/** @var User $this->resource */
return [
'id' => $this->resource->id,
'name' => $this->resource->name,
'email' => $this->resource->email,
'created_at' => $this->resource->created_at->format('Y-m-d H:i:s'),
'updated_at' => $this->resource->updated_at->format('Y-m-d H:i:s'),
];
}
}
```
Verwenden Sie die Ressource in Ihrem Controller:
```php
use App\Application\Resources\UserResource;
public function show(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
return $this->json([
'data' => new UserResource($user)
]);
}
public function index(Request $request): Response
{
$users = User::all();
return $this->json([
'data' => UserResource::collection($users)
]);
}
```
## API-Authentifizierung
### Token-basierte Authentifizierung
Das Framework unterstützt Token-basierte Authentifizierung für APIs:
```php
namespace App\Application\Controllers\Api;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\Auth\Auth;
use App\Framework\Auth\Token;
class AuthController extends Controller
{
public function login(Request $request): Response
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|string',
]);
$credentials = $request->only(['email', 'password']);
if (!Auth::attempt($credentials)) {
return $this->json([
'error' => 'Ungültige Anmeldeinformationen'
], 401);
}
$user = Auth::user();
$token = Token::create($user);
return $this->json([
'data' => [
'user' => $user,
'token' => $token,
'token_type' => 'Bearer',
]
]);
}
public function logout(Request $request): Response
{
$token = $request->bearerToken();
if ($token) {
Token::revoke($token);
}
return $this->json([
'message' => 'Erfolgreich abgemeldet'
]);
}
}
```
### Authentifizierung mit dem Token
```php
namespace App\Application\Middleware;
use App\Framework\Http\Middleware;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\Auth\Token;
class ApiAuthMiddleware implements Middleware
{
public function handle(Request $request, callable $next): Response
{
$token = $request->bearerToken();
if (!$token || !Token::validate($token)) {
return response()->json([
'error' => 'Nicht autorisiert'
], 401);
}
$user = Token::getUser($token);
Auth::setUser($user);
return $next($request);
}
}
```
Registrieren Sie die Middleware:
```php
// In der Middleware-Konfiguration
$middleware->group('api', [
ApiAuthMiddleware::class
]);
// In den Routen
$router->group('/api', function (Router $router) {
// Öffentliche Routen
$router->post('/login', [AuthController::class, 'login']);
// Geschützte Routen
$router->group('', function (Router $router) {
$router->apiResource('users', UserController::class);
$router->post('/logout', [AuthController::class, 'logout']);
})->middleware('api');
});
```
## API-Validierung
Die Validierung für APIs funktioniert ähnlich wie für reguläre Anfragen, gibt jedoch JSON-Antworten zurück:
```php
public function store(Request $request): Response
{
$validator = new Validator($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
if ($validator->fails()) {
return $this->json([
'error' => 'Validierungsfehler',
'errors' => $validator->errors()
], 422);
}
$user = User::create($validator->validated());
return $this->json([
'data' => $user,
'message' => 'Benutzer erstellt'
], 201);
}
```
Oder mit der `validate`-Methode:
```php
public function store(Request $request): Response
{
try {
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
} catch (ValidationException $e) {
return $this->json([
'error' => 'Validierungsfehler',
'errors' => $e->errors()
], 422);
}
$user = User::create($request->only(['name', 'email', 'password']));
return $this->json([
'data' => $user,
'message' => 'Benutzer erstellt'
], 201);
}
```
## API-Paginierung
Das Framework unterstützt Paginierung für API-Antworten:
```php
public function index(Request $request): Response
{
$page = $request->query('page', 1);
$perPage = $request->query('per_page', 15);
$users = User::paginate($perPage, $page);
return $this->json([
'data' => UserResource::collection($users->items()),
'meta' => [
'pagination' => [
'total' => $users->total(),
'per_page' => $users->perPage(),
'current_page' => $users->currentPage(),
'last_page' => $users->lastPage(),
]
]
]);
}
```
## API-Filterung und Sortierung
Sie können Filterung und Sortierung für Ihre API implementieren:
```php
public function index(Request $request): Response
{
$query = User::query();
// Filterung
if ($request->has('name')) {
$query->where('name', 'like', '%' . $request->query('name') . '%');
}
if ($request->has('email')) {
$query->where('email', 'like', '%' . $request->query('email') . '%');
}
if ($request->has('role')) {
$query->whereHas('roles', function ($q) use ($request) {
$q->where('name', $request->query('role'));
});
}
// Sortierung
$sortBy = $request->query('sort_by', 'created_at');
$sortDirection = $request->query('sort_direction', 'desc');
$allowedSortFields = ['id', 'name', 'email', 'created_at'];
if (in_array($sortBy, $allowedSortFields)) {
$query->orderBy($sortBy, $sortDirection === 'asc' ? 'asc' : 'desc');
}
// Paginierung
$page = $request->query('page', 1);
$perPage = $request->query('per_page', 15);
$users = $query->paginate($perPage, $page);
return $this->json([
'data' => UserResource::collection($users->items()),
'meta' => [
'pagination' => [
'total' => $users->total(),
'per_page' => $users->perPage(),
'current_page' => $users->currentPage(),
'last_page' => $users->lastPage(),
]
]
]);
}
```
## API-Rate Limiting
Das Framework bietet Rate Limiting für APIs, um Missbrauch zu verhindern:
```php
namespace App\Application\Middleware;
use App\Framework\Http\Middleware;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\Cache\Cache;
class RateLimitMiddleware implements Middleware
{
private int $maxRequests;
private int $timeWindow;
public function __construct(int $maxRequests = 60, int $timeWindow = 60)
{
$this->maxRequests = $maxRequests;
$this->timeWindow = $timeWindow;
}
public function handle(Request $request, callable $next): Response
{
$key = 'rate_limit:' . $this->getIdentifier($request);
$requests = Cache::get($key, 0);
if ($requests >= $this->maxRequests) {
return response()->json([
'error' => 'Zu viele Anfragen',
'message' => 'Bitte versuchen Sie es später erneut'
], 429);
}
Cache::put($key, $requests + 1, $this->timeWindow);
$response = $next($request);
$response->headers->set('X-RateLimit-Limit', $this->maxRequests);
$response->headers->set('X-RateLimit-Remaining', $this->maxRequests - $requests - 1);
return $response;
}
private function getIdentifier(Request $request): string
{
if (Auth::check()) {
return 'user:' . Auth::id();
}
return 'ip:' . $request->ip();
}
}
```
Registrieren Sie die Middleware:
```php
// In der Middleware-Konfiguration
$middleware->group('api', [
RateLimitMiddleware::class
]);
// Oder mit Parametern
$middleware->group('api', [
new RateLimitMiddleware(100, 60) // 100 Anfragen pro Minute
]);
```
## API-Dokumentation
Das Framework unterstützt die automatische Generierung von API-Dokumentation mit OpenAPI/Swagger:
```php
namespace App\Application\Controllers\Api;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Application\Models\User;
/**
* @OA\Tag(
* name="Users",
* description="API-Endpunkte für die Benutzerverwaltung"
* )
*/
class UserController extends Controller
{
/**
* @OA\Get(
* path="/api/users",
* summary="Liste aller Benutzer abrufen",
* tags={"Users"},
* @OA\Parameter(
* name="page",
* in="query",
* description="Seitennummer",
* @OA\Schema(type="integer")
* ),
* @OA\Parameter(
* name="per_page",
* in="query",
* description="Anzahl der Elemente pro Seite",
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="Erfolgreiche Operation",
* @OA\JsonContent(
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/User")),
* @OA\Property(property="meta", type="object")
* )
* )
* )
*/
public function index(Request $request): Response
{
// ...
}
/**
* @OA\Get(
* path="/api/users/{id}",
* summary="Einen bestimmten Benutzer abrufen",
* tags={"Users"},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* description="Benutzer-ID",
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="Erfolgreiche Operation",
* @OA\JsonContent(
* @OA\Property(property="data", ref="#/components/schemas/User")
* )
* ),
* @OA\Response(
* response=404,
* description="Benutzer nicht gefunden",
* @OA\JsonContent(
* @OA\Property(property="error", type="string")
* )
* )
* )
*/
public function show(Request $request, int $id): Response
{
// ...
}
// Weitere Methoden mit Dokumentation...
}
/**
* @OA\Schema(
* schema="User",
* required={"id", "name", "email"},
* @OA\Property(property="id", type="integer", format="int64"),
* @OA\Property(property="name", type="string"),
* @OA\Property(property="email", type="string", format="email"),
* @OA\Property(property="created_at", type="string", format="date-time"),
* @OA\Property(property="updated_at", type="string", format="date-time")
* )
*/
```
Generieren Sie die API-Dokumentation:
```bash
php console.php api:docs
```
Dies erstellt eine OpenAPI/Swagger-Dokumentation, die Sie in einem Browser anzeigen können.
## Beste Praktiken für APIs
### Versionierung
Versionieren Sie Ihre API, um Änderungen zu ermöglichen, ohne bestehende Clients zu beeinträchtigen:
```php
$router->group('/api/v1', function (Router $router) {
// API v1 Routen
});
$router->group('/api/v2', function (Router $router) {
// API v2 Routen
});
```
### Konsistente Benennung
Verwenden Sie konsistente Benennungskonventionen für Ihre API-Endpunkte:
- Verwenden Sie Substantive im Plural für Ressourcen (z.B. `/users` statt `/user`)
- Verwenden Sie Kebab-Case für URLs (z.B. `/user-profiles` statt `/userProfiles`)
- Verwenden Sie Camel-Case für JSON-Eigenschaften (z.B. `firstName` statt `first_name`)
### HTTP-Statuscodes
Verwenden Sie die richtigen HTTP-Statuscodes:
- 200 OK: Erfolgreiche Anfrage
- 201 Created: Ressource erfolgreich erstellt
- 204 No Content: Erfolgreiche Anfrage ohne Inhalt
- 400 Bad Request: Ungültige Anfrage
- 401 Unauthorized: Authentifizierung erforderlich
- 403 Forbidden: Keine Berechtigung
- 404 Not Found: Ressource nicht gefunden
- 422 Unprocessable Entity: Validierungsfehler
- 429 Too Many Requests: Rate Limit überschritten
- 500 Internal Server Error: Serverfehler
### Fehlerbehandlung
Implementieren Sie eine konsistente Fehlerbehandlung:
```php
try {
// Code, der eine Exception werfen könnte
} catch (ValidationException $e) {
return $this->json([
'error' => 'Validierungsfehler',
'errors' => $e->errors()
], 422);
} catch (AuthorizationException $e) {
return $this->json([
'error' => 'Nicht autorisiert',
'message' => $e->getMessage()
], 403);
} catch (NotFoundException $e) {
return $this->json([
'error' => 'Nicht gefunden',
'message' => $e->getMessage()
], 404);
} catch (\Exception $e) {
// Protokollieren Sie den Fehler
$this->logger->error('API-Fehler', [
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return $this->json([
'error' => 'Serverfehler',
'message' => 'Ein unerwarteter Fehler ist aufgetreten'
], 500);
}
```
### Dokumentation
Dokumentieren Sie Ihre API gründlich:
- Beschreiben Sie jeden Endpunkt
- Dokumentieren Sie alle Parameter
- Geben Sie Beispiele für Anfragen und Antworten
- Erklären Sie Fehlerszenarien
## Weitere Informationen
- [Routing-Anleitung](../guides/routing.md): Erfahren Sie mehr über das Routing-System.
- [Controller-Anleitung](../guides/controllers.md): Erfahren Sie mehr über Controller.
- [Validierungs-Anleitung](../guides/validation.md): Erfahren Sie mehr über die Validierung von Anfragen.
- [Sicherheits-Anleitung](../guides/security.md): Erfahren Sie mehr über die Sicherheitsfunktionen des Frameworks.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

View File

@@ -1,149 +0,0 @@
# Projektstruktur-Dokumentation
## Übersicht
Diese Dokumentation bietet einen Überblick über die Architektur und Struktur des Projekts. Die Anwendung folgt einer modularen, serviceorientierten Architektur mit klarer Trennung von Verantwortlichkeiten.
## Hauptverzeichnisse
### `/src`
Das Hauptverzeichnis für den Anwendungscode, unterteilt in mehrere Unterverzeichnisse:
#### `/src/Framework`
Enthält das Framework mit grundlegenden Infrastrukturkomponenten:
- **Analytics**: System zur Erfassung und Analyse von Anwendungsdaten
- **Attributes**: Attribute/Annotations für Metadaten
- **Cache**: Caching-Mechanismen
- **CommandBus**: Command-Handling-Komponenten
- **Config**: Konfigurationsverwaltung
- **Console**: Konsolenanwendung und -befehle
- **Core**: Kernkomponenten und Events
- **DI**: Dependency-Injection-Container
- **ErrorHandling**: Fehlerbehandlungsmechanismen
- **EventBus**: Event-Handling-System
- **Exception**: Framework-Exceptions
- **Filesystem**: Dateisystemoperationen
- **Http**: HTTP-Request/Response-Handling
- **HttpClient**: HTTP-Client für externe API-Aufrufe
- **Logging**: Logging-Infrastruktur
- **Performance**: Performance-Monitoring
- **Queue**: Nachrichtenwarteschlangen
- **Redis**: Redis-Integration
- **Router**: URL-Routing
- **StaticSite**: Statische Site-Generation
- **Validation**: Datenvalidierung
- **View**: Template-Rendering
#### `/src/Application`
Anwendungsspezifische Komponenten, die das Framework nutzen.
#### `/src/Domain`
Domain-Modelle, Entities und Business-Logik.
#### `/src/Infrastructure`
Infrastrukturkomponenten, die externe Systeme integrieren.
#### `/src/Config`
Konfigurationsdateien für verschiedene Module.
## Framework-Architektur
### Dependency Injection
Das System nutzt einen leistungsfähigen DI-Container zur Verwaltung von Services:
```php
#[Initializer]
class ServiceInitializer
{
public function __invoke(Container $container): Service
{
// Service erstellen und zurückgeben
}
}
```
### Event-System
Ein Event-System ermöglicht lose Kopplung zwischen Komponenten:
```php
$eventDispatcher->addHandler(EventClass::class, function($event) {
// Event verarbeiten
});
```
### HTTP-Pipeline
HTTP-Requests durchlaufen eine Middleware-Pipeline:
```php
class CustomMiddleware implements Middleware
{
public function process(Request $request, callable $next): Response
{
// Request verarbeiten
$response = $next($request);
// Response verarbeiten
return $response;
}
}
```
## Module und ihre Interaktionen
### Analytics-Modul
Das Analytics-Modul erfasst und analysiert Anwendungsdaten:
- **Events tracken**: `$analytics->track('event_name', $properties)`
- **HTTP-Tracking**: Automatisch durch `AnalyticsMiddleware`
- **Error-Tracking**: Integration mit dem Error-Handling-System
- **Dashboard**: Admin-Interface zur Datenvisualisierung
### Konfigurationssystem
Konfigurationen werden zentral verwaltet und injiziert:
```php
class Service
{
public function __construct(private Configuration $config)
{
$settings = $this->config->get('module_name', $defaults);
}
}
```
## Erweiterbarkeit
### Neue Module hinzufügen
1. Erstellen Sie ein neues Verzeichnis unter `/src/Framework`
2. Implementieren Sie eine Initializer-Klasse mit dem `#[Initializer]`-Attribut
3. Erstellen Sie eine entsprechende Konfigurationsdatei unter `/src/Config`
### Middleware hinzufügen
```php
// In Ihrer Anwendungsklasse
public function bootstrap(): void
{
$this->addMiddleware(YourMiddleware::class);
}
```
## Best Practices
- **Dependency Injection**: Verwenden Sie Constructor-Injection für Abhängigkeiten
- **Interfaces**: Definieren Sie Interfaces für alle Services
- **Events**: Nutzen Sie Events für lose Kopplung zwischen Modulen
- **Konfiguration**: Externalisieren Sie Konfigurationen in dedizierte Dateien
- **Typsicherheit**: Nutzen Sie strenge Typisierung und readonly-Properties

View File

@@ -0,0 +1,528 @@
# Hauptkomponenten
Diese Dokumentation beschreibt die Hauptkomponenten des Frameworks und ihre Verantwortlichkeiten. Jede Komponente ist so konzipiert, dass sie unabhängig verwendet oder durch eine benutzerdefinierte Implementierung ersetzt werden kann.
## Kernkomponenten
### Container
Der Container ist das Herzstück des Frameworks und verantwortlich für die Dependency Injection. Er bietet folgende Funktionen:
- Registrierung von Diensten
- Auflösung von Abhängigkeiten
- Verwaltung des Lebenszyklus von Diensten
```php
// Beispiel für die Verwendung des Containers
$container = new Container();
$container->bind(LoggerInterface::class, FileLogger::class);
$container->singleton(DatabaseInterface::class, function () {
return new Database(config('database'));
});
$logger = $container->get(LoggerInterface::class);
```
### Router
Der Router ist verantwortlich für das Mapping von HTTP-Anfragen zu Controller-Aktionen. Er unterstützt:
- Routendefinitionen für verschiedene HTTP-Methoden
- Routengruppen mit gemeinsamen Präfixen und Middleware
- Routenparameter und Einschränkungen
- Namensräume für Routen
```php
// Beispiel für die Verwendung des Routers
$router = new Router();
$router->get('/users', [UserController::class, 'index']);
$router->post('/users', [UserController::class, 'store']);
$router->get('/users/{id}', [UserController::class, 'show'])->where('id', '[0-9]+');
$router->group('/admin', function (Router $router) {
$router->get('/dashboard', [AdminController::class, 'dashboard']);
})->middleware(AuthMiddleware::class);
```
### Request
Die Request-Klasse kapselt eine HTTP-Anfrage und bietet Methoden für den Zugriff auf:
- Anfrageparameter
- Header
- Cookies
- Dateien
- Sitzungsdaten
```php
// Beispiel für die Verwendung der Request-Klasse
$name = $request->input('name');
$page = $request->query('page', 1);
$token = $request->header('Authorization');
$file = $request->file('avatar');
$remember = $request->cookie('remember', false);
$user = $request->session()->get('user');
```
### Response
Die Response-Klasse repräsentiert eine HTTP-Antwort und bietet Methoden für:
- Setzen von Statuscodes
- Hinzufügen von Headern
- Setzen von Cookies
- Umleitung zu anderen URLs
```php
// Beispiel für die Verwendung der Response-Klasse
$response = new Response('Hello World', 200);
$response->header('Content-Type', 'text/plain');
$response->cookie('visited', true, 60 * 24);
$redirectResponse = new RedirectResponse('/dashboard');
$jsonResponse = new JsonResponse(['name' => 'John']);
$viewResponse = new ViewResponse('welcome', ['user' => $user]);
```
### Middleware
Middleware-Komponenten verarbeiten Anfragen vor und nach der Controller-Aktion. Sie können:
- Anfragen validieren
- Benutzer authentifizieren
- Antworten transformieren
- Anfragen protokollieren
```php
// Beispiel für eine Middleware
class AuthMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandlerInterface $handler): Response
{
if (!$this->isAuthenticated($request)) {
return new RedirectResponse('/login');
}
return $handler->handle($request);
}
}
```
## Datenbankkomponenten
### Database
Die Database-Komponente bietet eine Abstraktionsschicht für Datenbankoperationen. Sie unterstützt:
- Verschiedene Datenbanktypen (MySQL, SQLite, PostgreSQL)
- Abfragen mit einem Query Builder
- Transaktionen
- Migrationen
- Seeding
```php
// Beispiel für die Verwendung der Database-Komponente
$users = $database->table('users')
->where('active', true)
->orderBy('name')
->limit(10)
->get();
$database->transaction(function ($db) {
$db->table('users')->insert(['name' => 'John']);
$db->table('profiles')->insert(['user_id' => $db->lastInsertId()]);
});
```
### Model
Die Model-Komponente bietet eine objektorientierte Schnittstelle für Datenbankoperationen. Sie unterstützt:
- Active Record Pattern
- Beziehungen zwischen Modellen
- Attribute und Mutators
- Ereignisse
```php
// Beispiel für die Verwendung der Model-Komponente
$user = new User();
$user->name = 'John';
$user->email = 'john@example.com';
$user->save();
$users = User::where('active', true)->get();
$user = User::find(1);
$posts = $user->posts()->where('published', true)->get();
```
### Migration
Die Migration-Komponente ermöglicht die Versionierung der Datenbankstruktur. Sie unterstützt:
- Erstellen und Ändern von Tabellen
- Hinzufügen und Entfernen von Indizes
- Rollback von Änderungen
```php
// Beispiel für eine Migration
class CreateUsersTable extends Migration
{
public function up(): void
{
$this->schema->create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->boolean('active')->default(true);
$table->timestamps();
});
}
public function down(): void
{
$this->schema->dropIfExists('users');
}
}
```
## HTTP-Komponenten
### Controller
Controller sind verantwortlich für die Verarbeitung von HTTP-Anfragen und die Rückgabe von Antworten. Sie bieten:
- Zugriff auf Request- und Response-Objekte
- Validierung von Eingaben
- Rendering von Views
- Umleitung zu anderen URLs
```php
// Beispiel für einen Controller
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = User::all();
return $this->view('users.index', ['users' => $users]);
}
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
]);
$user = User::create($request->only(['name', 'email']));
return $this->redirect('/users')->with('success', 'User created');
}
}
```
### View
Die View-Komponente ist verantwortlich für das Rendering von HTML-Templates. Sie unterstützt:
- Template-Dateien mit PHP-Syntax
- Layouts und Partials
- Template-Vererbung
- Datenübergabe an Templates
```php
// Beispiel für die Verwendung der View-Komponente
$view = new View('users.show');
$view->with('user', $user);
$html = $view->render();
// Oder über den Controller
return $this->view('users.show', ['user' => $user]);
```
### Session
Die Session-Komponente verwaltet Benutzersitzungen. Sie unterstützt:
- Verschiedene Session-Backends (Datei, Datenbank, Redis)
- Flash-Daten
- Session-Regeneration
- Session-Timeout
```php
// Beispiel für die Verwendung der Session-Komponente
$session = new Session();
$session->put('user_id', 1);
$userId = $session->get('user_id');
$session->flash('message', 'Welcome back!');
$session->regenerate();
$session->forget('user_id');
```
### Cookie
Die Cookie-Komponente verwaltet HTTP-Cookies. Sie unterstützt:
- Setzen und Lesen von Cookies
- Verschlüsselung von Cookie-Werten
- Cookie-Parameter (Lebensdauer, Pfad, Domain, Secure, HttpOnly)
```php
// Beispiel für die Verwendung der Cookie-Komponente
$cookie = new Cookie('name', 'value', 60 * 24); // 1 Tag
$cookie->setPath('/');
$cookie->setSecure(true);
$cookie->setHttpOnly(true);
$response->setCookie($cookie);
$value = $request->cookie('name');
```
## Sicherheitskomponenten
### Validator
Die Validator-Komponente validiert Benutzereingaben. Sie unterstützt:
- Verschiedene Validierungsregeln
- Benutzerdefinierte Validierungsregeln
- Fehlermeldungen
- Validierung von Arrays und verschachtelten Daten
```php
// Beispiel für die Verwendung der Validator-Komponente
$validator = new Validator($data, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
'age' => 'integer|min:18',
]);
if ($validator->fails()) {
$errors = $validator->errors();
// Fehler behandeln
}
```
### Authentication
Die Authentication-Komponente verwaltet die Benutzerauthentifizierung. Sie unterstützt:
- Verschiedene Authentifizierungsmethoden (Session, Token, Basic)
- Mehrere Authentifizierungsquellen
- Remember-Me-Funktionalität
- Passwort-Hashing und -Verifizierung
```php
// Beispiel für die Verwendung der Authentication-Komponente
$auth = new Authentication();
if ($auth->attempt(['email' => $email, 'password' => $password], $remember)) {
// Erfolgreiche Anmeldung
}
$user = $auth->user();
$auth->logout();
```
### Authorization
Die Authorization-Komponente verwaltet die Benutzerautorisierung. Sie unterstützt:
- Rollenbasierte Zugriffskontrolle
- Fähigkeitsbasierte Zugriffskontrolle
- Richtlinien für komplexe Autorisierungslogik
```php
// Beispiel für die Verwendung der Authorization-Komponente
$authorization = new Authorization();
$authorization->define('edit-post', function (User $user, Post $post) {
return $user->id === $post->user_id || $user->hasRole('editor');
});
if ($authorization->can($user, 'edit-post', $post)) {
// Benutzer darf den Beitrag bearbeiten
}
```
### CSRF
Die CSRF-Komponente schützt vor Cross-Site Request Forgery. Sie unterstützt:
- Generierung von CSRF-Tokens
- Validierung von CSRF-Tokens
- Automatische Integration in Formulare
```php
// Beispiel für die Verwendung der CSRF-Komponente
$csrf = new CsrfProtection();
$token = $csrf->generateToken();
// In einem Formular
echo '<input type="hidden" name="_token" value="' . $token . '">';
// Validierung
if (!$csrf->validateToken($request->input('_token'))) {
// Ungültiges Token
}
```
### WAF
Die Web Application Firewall (WAF) schützt vor gängigen Angriffen. Sie unterstützt:
- Erkennung und Blockierung von SQL-Injection
- Erkennung und Blockierung von XSS
- Erkennung und Blockierung von Command Injection
- Erkennung und Blockierung von Path Traversal
- Maschinelles Lernen zur Erkennung von Anomalien
```php
// Beispiel für die Verwendung der WAF-Komponente
$waf = new WebApplicationFirewall();
$waf->addRule(new SqlInjectionRule());
$waf->addRule(new XssRule());
if ($waf->detect($request)) {
// Angriff erkannt
$waf->block($request);
}
```
## Weitere Komponenten
### Cache
Die Cache-Komponente bietet eine einheitliche Schnittstelle für verschiedene Cache-Backends. Sie unterstützt:
- Verschiedene Cache-Treiber (Datei, Redis, Memcached, Memory)
- Cache-Tags
- Cache-Invalidierung
- Cache-Prefixing
```php
// Beispiel für die Verwendung der Cache-Komponente
$cache = new Cache();
$cache->put('key', 'value', 60); // 60 Minuten
$value = $cache->get('key', 'default');
$cache->has('key');
$cache->forget('key');
$cache->flush();
$cache->tags(['users', 'profiles'])->put('user:1', $user, 60);
```
### Logger
Die Logger-Komponente protokolliert Anwendungsereignisse. Sie unterstützt:
- Verschiedene Log-Level (Debug, Info, Warning, Error, Critical)
- Verschiedene Log-Handler (Datei, Syslog, Slack, E-Mail)
- Kontextdaten für Log-Einträge
- Log-Rotation
```php
// Beispiel für die Verwendung der Logger-Komponente
$logger = new Logger();
$logger->debug('Debug-Nachricht');
$logger->info('Info-Nachricht');
$logger->warning('Warnung', ['user_id' => 1]);
$logger->error('Fehler', ['exception' => $exception]);
$logger->critical('Kritischer Fehler', ['data' => $data]);
```
### Event
Die Event-Komponente implementiert ein Publish-Subscribe-Muster. Sie unterstützt:
- Ereignisregistrierung und -auslösung
- Ereignislistener
- Ereignisabonnenten
- Ereignispriorisierung
```php
// Beispiel für die Verwendung der Event-Komponente
$eventDispatcher = new EventDispatcher();
$eventDispatcher->addListener(UserRegistered::class, SendWelcomeEmail::class);
$eventDispatcher->addListener(UserRegistered::class, function (UserRegistered $event) {
// Benutzerdefinierte Logik
});
$eventDispatcher->dispatch(new UserRegistered($user));
```
### Console
Die Console-Komponente bietet ein Kommandozeilen-Interface für die Anwendung. Sie unterstützt:
- Benutzerdefinierte Befehle
- Eingabeargumente und -optionen
- Interaktive Eingabe
- Ausgabeformatierung
```php
// Beispiel für einen Konsolenbefehl
class MigrateCommand extends Command
{
protected string $name = 'db:migrate';
protected string $description = 'Run database migrations';
public function handle(Input $input, Output $output): int
{
$output->writeln('Running migrations...');
// Migrationen ausführen
$output->success('Migrations completed successfully');
return 0;
}
}
```
### Filesystem
Die Filesystem-Komponente bietet eine Abstraktionsschicht für Dateisystemoperationen. Sie unterstützt:
- Lokale und entfernte Dateisysteme
- Datei- und Verzeichnisoperationen
- Dateimetadaten
- Dateispeicherung und -abruf
```php
// Beispiel für die Verwendung der Filesystem-Komponente
$filesystem = new Filesystem();
$filesystem->write('path/to/file.txt', 'Inhalt');
$content = $filesystem->read('path/to/file.txt');
$filesystem->delete('path/to/file.txt');
$filesystem->createDirectory('path/to/directory');
$files = $filesystem->listContents('path/to/directory');
```
### Queue
Die Queue-Komponente ermöglicht die asynchrone Verarbeitung von Aufgaben. Sie unterstützt:
- Verschiedene Queue-Treiber (Datenbank, Redis, Beanstalkd)
- Verzögerte Aufgaben
- Aufgabenpriorisierung
- Fehlerbehandlung und Wiederholungsversuche
```php
// Beispiel für die Verwendung der Queue-Komponente
$queue = new Queue();
$queue->push(new SendEmailJob($user, $message));
$queue->later(60, new CleanupJob()); // 60 Sekunden verzögert
// Verarbeitung einer Aufgabe
class SendEmailJob implements JobInterface
{
public function __construct(private User $user, private string $message) {}
public function handle(): void
{
// E-Mail senden
}
}
```
## Weitere Informationen
- [Architekturübersicht](overview.md): Überblick über die Architektur des Frameworks.
- [Entwurfsmuster](patterns.md): Erläuterung der im Framework verwendeten Entwurfsmuster.
- [Komponentendokumentation](../components/README.md): Detaillierte Dokumentation der einzelnen Komponenten.

View File

@@ -1,70 +0,0 @@
# Architektur-Dokumentation
## Übersicht
Diese Dokumentation beschreibt die Architektur und Struktur des Projekts. Sie bietet einen Überblick über die wichtigsten Komponenten, deren Beziehungen und die zugrundeliegenden Architekturprinzipien.
## Inhalte
- [Projektstruktur](/architecture/STRUKTUR-DOKUMENTATION.md) - Überblick über die Struktur des Projekts
## Architekturprinzipien
Das Projekt folgt diesen grundlegenden Architekturprinzipien:
1. **Modulare Architektur**: Klare Trennung von Verantwortlichkeiten in Modulen
2. **Service-orientiertes Design**: Funktionalitäten als unabhängige Services
3. **Dependency Injection**: Abhängigkeiten werden explizit injiziert
4. **Event-basierte Kommunikation**: Lose Kopplung durch Events
5. **Schichtenarchitektur**: Trennung von Präsentation, Anwendungslogik und Daten
## Hauptkomponenten
### Framework-Kern
Der Framework-Kern stellt grundlegende Infrastrukturkomponenten bereit:
- **DI-Container**: Verwaltung von Service-Abhängigkeiten
- **Event-System**: Event-basierte Kommunikation
- **HTTP-Komponenten**: Request/Response-Handling
- **Routing**: URL-zu-Controller-Mapping
### Anwendungsschicht
Die Anwendungsschicht implementiert die Geschäftslogik:
- **Services**: Implementierung von Anwendungsfunktionen
- **Commands/Queries**: Command-Query-Separation-Prinzip
- **Controllers**: HTTP-Request-Handling
### Domainschicht
Die Domainschicht enthält die Kerngeschäftslogik:
- **Entities**: Geschäftsobjekte mit Identität
- **Value Objects**: Unveränderliche Wertobjekte
- **Domain Services**: Domänenspezifische Logik
### Infrastrukturschicht
Die Infrastrukturschicht bietet technische Funktionen:
- **Persistenz**: Datenbankzugriff und -verwaltung
- **Messaging**: Externe Kommunikation
- **Integration**: Anbindung an externe Systeme
## Datenfluss
Ein typischer Datenfluss im System:
1. HTTP-Request wird vom Router empfangen
2. Middleware-Pipeline verarbeitet den Request
3. Controller erhält den Request und delegiert an Services
4. Services implementieren die Geschäftslogik
5. Domain-Objekte repräsentieren den Geschäftszustand
6. Repositories speichern/laden Daten
7. Response wird erstellt und zurückgegeben
## Weitere Informationen
Für detailliertere Informationen zur Architektur siehe die [Projektstruktur-Dokumentation](/architecture/STRUKTUR-DOKUMENTATION.md).

View File

@@ -0,0 +1,226 @@
# Architekturübersicht
Diese Dokumentation bietet einen Überblick über die Architektur des Frameworks und erklärt die grundlegenden Konzepte und Designentscheidungen.
## Architekturprinzipien
Das Framework wurde nach folgenden Prinzipien entwickelt:
1. **Modularität**: Das Framework ist in unabhängige Module aufgeteilt, die einzeln verwendet oder ausgetauscht werden können.
2. **Erweiterbarkeit**: Alle Komponenten sind so konzipiert, dass sie einfach erweitert oder angepasst werden können.
3. **Testbarkeit**: Die Architektur ermöglicht einfaches Testen durch klare Schnittstellen und Dependency Injection.
4. **Leistung**: Leistungsoptimierungen sind ein integraler Bestandteil des Designs, nicht nur eine nachträgliche Überlegung.
5. **Sicherheit**: Sicherheitsmaßnahmen sind standardmäßig aktiviert und in die Kernkomponenten integriert.
## Schichtenarchitektur
Das Framework verwendet eine mehrschichtige Architektur, die eine klare Trennung der Verantwortlichkeiten ermöglicht:
```
+-------------------+
| Anwendung | <-- Anwendungsspezifischer Code (Controller, Models, Services)
+-------------------+
| Framework | <-- Framework-Komponenten (Routing, Validierung, Datenbank)
+-------------------+
| Infrastruktur | <-- Infrastrukturkomponenten (HTTP, Dateisystem, Cache)
+-------------------+
```
### Anwendungsschicht
Die Anwendungsschicht enthält den anwendungsspezifischen Code, der die Geschäftslogik implementiert. Diese Schicht umfasst:
- **Controller**: Verarbeiten HTTP-Anfragen und geben Antworten zurück
- **Models**: Repräsentieren Geschäftsobjekte und Datenstrukturen
- **Services**: Implementieren komplexe Geschäftslogik
- **Repositories**: Kapseln den Datenzugriff
### Framework-Schicht
Die Framework-Schicht stellt die Kernfunktionalität bereit, die von der Anwendungsschicht verwendet wird. Diese Schicht umfasst:
- **Routing**: Leitet Anfragen an die entsprechenden Controller weiter
- **Validierung**: Überprüft Benutzereingaben
- **Datenbank**: Bietet Datenbankabstraktion und ORM-Funktionalität
- **Authentifizierung**: Verwaltet Benutzerauthentifizierung und -autorisierung
- **Caching**: Implementiert verschiedene Caching-Strategien
### Infrastrukturschicht
Die Infrastrukturschicht bietet grundlegende Dienste und Abstraktionen für die darüber liegenden Schichten. Diese Schicht umfasst:
- **HTTP**: Verarbeitet HTTP-Anfragen und -Antworten
- **Dateisystem**: Bietet Abstraktionen für Dateisystemoperationen
- **Cache**: Implementiert verschiedene Cache-Backends
- **Logging**: Bietet Logging-Funktionalität
- **Events**: Implementiert ein Event-System
## Anfragelebenszyklus
Der Lebenszyklus einer Anfrage im Framework durchläuft mehrere Phasen:
1. **Bootstrapping**: Die Anwendung wird initialisiert, Konfigurationen werden geladen und Dienste registriert.
2. **Routing**: Die Anfrage wird an den entsprechenden Controller weitergeleitet.
3. **Middleware**: Die Anfrage durchläuft die konfigurierten Middleware-Komponenten.
4. **Controller**: Der Controller verarbeitet die Anfrage und gibt eine Antwort zurück.
5. **Middleware (rückwärts)**: Die Antwort durchläuft die Middleware-Komponenten in umgekehrter Reihenfolge.
6. **Antwort**: Die Antwort wird an den Client gesendet.
```
+----------------+ +------------+ +------------+ +------------+ +----------------+
| | | | | | | | | |
| Bootstrapping | --> | Routing | --> | Middleware | --> | Controller | --> | Antwort senden |
| | | | | | | | | |
+----------------+ +------------+ +------------+ +------------+ +----------------+
```
## Dependency Injection
Das Framework verwendet Dependency Injection (DI), um Abhängigkeiten zwischen Komponenten zu verwalten. Der DI-Container ist verantwortlich für:
1. **Registrierung**: Dienste werden im Container registriert.
2. **Auflösung**: Der Container löst Abhängigkeiten automatisch auf.
3. **Lebenszyklus**: Der Container verwaltet den Lebenszyklus von Diensten (Singleton, Transient, etc.).
Beispiel für die Verwendung des DI-Containers:
```php
// Registrierung eines Dienstes
$container->bind(UserRepositoryInterface::class, UserRepository::class);
// Auflösung eines Dienstes
$userRepository = $container->get(UserRepositoryInterface::class);
```
## Service Provider
Service Provider sind Klassen, die Dienste im DI-Container registrieren und konfigurieren. Sie bieten einen strukturierten Weg, um Komponenten zu initialisieren und zu konfigurieren.
Beispiel für einen Service Provider:
```php
class DatabaseServiceProvider implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->singleton(ConnectionInterface::class, function () {
return new Connection(config('database'));
});
$container->bind(QueryBuilderInterface::class, QueryBuilder::class);
}
public function boot(Container $container): void
{
// Initialisierungscode, der nach der Registrierung ausgeführt wird
}
}
```
## Ereignissystem
Das Framework implementiert ein Ereignissystem, das die Entkopplung von Komponenten ermöglicht. Das Ereignissystem besteht aus:
1. **Events**: Objekte, die Informationen über ein Ereignis enthalten.
2. **Listeners**: Klassen, die auf bestimmte Ereignisse reagieren.
3. **Dispatcher**: Verantwortlich für das Versenden von Ereignissen an registrierte Listener.
Beispiel für die Verwendung des Ereignissystems:
```php
// Definieren eines Events
class UserRegistered
{
public function __construct(public readonly User $user) {}
}
// Definieren eines Listeners
class SendWelcomeEmail implements ListenerInterface
{
public function handle(UserRegistered $event): void
{
// E-Mail an den neuen Benutzer senden
}
}
// Registrieren des Listeners
$eventDispatcher->addListener(UserRegistered::class, SendWelcomeEmail::class);
// Auslösen des Events
$eventDispatcher->dispatch(new UserRegistered($user));
```
## Middleware-Pipeline
Das Framework verwendet eine Middleware-Pipeline, um Anfragen zu verarbeiten. Middleware-Komponenten können:
1. Anfragen vor der Verarbeitung durch den Controller modifizieren.
2. Antworten nach der Verarbeitung durch den Controller modifizieren.
3. Den Anfrage-/Antwort-Zyklus vollständig abbrechen.
Beispiel für eine Middleware:
```php
class AuthenticationMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandlerInterface $handler): Response
{
if (!$this->isAuthenticated($request)) {
return new RedirectResponse('/login');
}
return $handler->handle($request);
}
private function isAuthenticated(Request $request): bool
{
// Überprüfen, ob der Benutzer authentifiziert ist
}
}
```
## Konfigurationssystem
Das Framework verwendet ein flexibles Konfigurationssystem, das verschiedene Konfigurationsquellen unterstützt:
1. **Umgebungsvariablen**: Konfiguration über `.env`-Dateien.
2. **Konfigurationsdateien**: PHP-Dateien, die Konfigurationsarrays zurückgeben.
3. **Laufzeitkonfiguration**: Dynamische Konfiguration zur Laufzeit.
Das Konfigurationssystem unterstützt auch umgebungsspezifische Konfigurationen, sodass verschiedene Einstellungen für Entwicklung, Test und Produktion verwendet werden können.
## Erweiterbarkeit
Das Framework ist so konzipiert, dass es einfach erweitert werden kann:
1. **Interfaces**: Alle Kernkomponenten definieren Interfaces, die implementiert werden können.
2. **Abstrakte Klassen**: Viele Komponenten bieten abstrakte Basisklassen, die erweitert werden können.
3. **Hooks**: Das Framework bietet Hooks, an denen benutzerdefinierter Code ausgeführt werden kann.
4. **Plugins**: Das Plugin-System ermöglicht die einfache Integration von Drittanbietercode.
## Sicherheitsarchitektur
Die Sicherheitsarchitektur des Frameworks umfasst mehrere Schichten:
1. **Eingabevalidierung**: Validierung aller Benutzereingaben.
2. **Ausgabebereinigung**: Automatische Bereinigung von Ausgaben, um XSS zu verhindern.
3. **CSRF-Schutz**: Schutz vor Cross-Site Request Forgery.
4. **Authentifizierung**: Flexible Authentifizierungsmechanismen.
5. **Autorisierung**: Rollenbasierte und fähigkeitsbasierte Zugriffskontrolle.
6. **Web Application Firewall (WAF)**: Integrierte WAF zum Schutz vor gängigen Angriffen.
## Leistungsoptimierungen
Das Framework implementiert verschiedene Leistungsoptimierungen:
1. **Caching**: Mehrschichtiges Caching für Konfiguration, Routen, Views, etc.
2. **Lazy Loading**: Komponenten werden erst geladen, wenn sie benötigt werden.
3. **Kompilierung**: Views und Konfigurationen werden für schnelleren Zugriff kompiliert.
4. **Pooling**: Verbindungspooling für Datenbanken und andere Ressourcen.
5. **Optimierte Autoloading**: PSR-4-konformes Autoloading mit Optimierungen.
## Weitere Informationen
- [Komponenten](components.md): Detaillierte Informationen zu den Hauptkomponenten des Frameworks.
- [Entwurfsmuster](patterns.md): Erläuterung der im Framework verwendeten Entwurfsmuster.
- [Komponentendokumentation](../components/README.md): Dokumentation der einzelnen Komponenten.

File diff suppressed because it is too large Load Diff

237
docs/batch-api-examples.md Normal file
View File

@@ -0,0 +1,237 @@
# Batch API Examples
The Batch API allows you to send multiple HTTP requests in a single batch request, improving efficiency by reducing round-trips and enabling concurrent processing.
## Basic Usage
### Batch Request Structure
```json
{
"operations": [
{
"id": "get-user-1",
"method": "GET",
"path": "/api/examples/users/1",
"headers": {
"Authorization": "Bearer token123"
}
},
{
"id": "create-post",
"method": "POST",
"path": "/api/examples/posts",
"headers": {
"Content-Type": "application/json"
},
"body": "{\"title\": \"Hello World\", \"content\": \"This is my first post\"}"
}
],
"continue_on_error": false
}
```
### Batch Response Structure
```json
{
"responses": [
{
"id": "get-user-1",
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": "{\"id\": 1, \"name\": \"User 1\", \"email\": \"user1@example.com\"}"
},
{
"id": "create-post",
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"body": "{\"id\": 1234, \"title\": \"Hello World\", \"content\": \"This is my first post\"}"
}
],
"total": 2,
"successful": 2,
"failed": 0
}
```
## Example Requests
### Simple GET Operations
```bash
curl -X POST https://localhost/api/batch \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"operations": [
{
"id": "user-1",
"method": "GET",
"path": "/api/examples/users/1"
},
{
"id": "user-2",
"method": "GET",
"path": "/api/examples/users/2"
}
]
}'
```
### Mixed Operations (CRUD)
```bash
curl -X POST https://localhost/api/batch \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"operations": [
{
"id": "create-post",
"method": "POST",
"path": "/api/examples/posts",
"headers": {"Content-Type": "application/json"},
"body": "{\"title\": \"New Post\", \"content\": \"Great content\"}"
},
{
"id": "update-post",
"method": "PUT",
"path": "/api/examples/posts/123",
"headers": {"Content-Type": "application/json"},
"body": "{\"title\": \"Updated Post\", \"content\": \"Updated content\"}"
},
{
"id": "delete-post",
"method": "DELETE",
"path": "/api/examples/posts/456"
}
],
"continue_on_error": true
}'
```
### With Query Parameters
```bash
curl -X POST https://localhost/api/batch \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"operations": [
{
"id": "slow-operation",
"method": "GET",
"path": "/api/examples/slow?delay=2"
},
{
"id": "another-user",
"method": "GET",
"path": "/api/examples/users/3",
"query": {"include": "profile"}
}
]
}'
```
## Error Handling
### Continue on Error (true)
When `continue_on_error` is `true`, all operations will be executed even if some fail:
```json
{
"operations": [
{
"id": "valid-request",
"method": "GET",
"path": "/api/examples/users/1"
},
{
"id": "invalid-request",
"method": "GET",
"path": "/api/nonexistent/endpoint"
}
],
"continue_on_error": true
}
```
Response:
```json
{
"responses": [
{
"id": "valid-request",
"status": 200,
"body": "{\"id\": 1, \"name\": \"User 1\"}"
},
{
"id": "invalid-request",
"status": 404,
"error": "Not Found"
}
],
"total": 2,
"successful": 1,
"failed": 1
}
```
### Stop on First Error (false)
When `continue_on_error` is `false`, processing stops at the first error:
```json
{
"operations": [...],
"continue_on_error": false
}
```
## Performance Considerations
### Concurrent Processing
The batch API processes operations concurrently when possible:
- Operations with no dependencies run in parallel
- Maximum concurrent operations: 10 (configurable)
- Large batches are processed in chunks
### Limits
- Maximum operations per batch: 100
- Maximum concurrent operations: 10
- Request timeout: 30 seconds
- Supported methods: GET, POST, PUT, DELETE, PATCH
### Get Batch Info
```bash
curl -X GET https://localhost/api/batch/info \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
```
Response:
```json
{
"max_operations": 100,
"max_concurrent_operations": 10,
"supported_methods": ["GET", "POST", "PUT", "DELETE", "PATCH"],
"continue_on_error_supported": true
}
```
## Best Practices
1. **Use meaningful IDs**: Each operation should have a unique, descriptive ID
2. **Group related operations**: Batch operations that are logically related
3. **Handle errors gracefully**: Use `continue_on_error` appropriately
4. **Respect limits**: Don't exceed the maximum operations limit
5. **Monitor performance**: Large batches may impact server performance
6. **Use appropriate methods**: Only use HTTP methods that are allowed

190
docs/claude/architecture.md Normal file
View File

@@ -0,0 +1,190 @@
# Architecture
Architektur-Übersicht des Custom PHP Frameworks.
## Core Architectural Patterns
### Fundamentale Prinzipien
- **No Inheritance**: Komposition über Vererbung - `extends` komplett vermeiden
- **Immutable by Design**: Objekte sollten wann immer möglich unveränderlich sein
- **Readonly Everywhere**: Klassen und Properties `readonly` wo möglich
- **Final by Default**: Klassen sind `final` außer wenn explizit für Erweiterung designt
- **Explicit Dependency Injection**: Kein globaler State oder Service Locators
- **Modular Architecture**: Minimale externe Abhängigkeiten, klare Grenzen
- **Event-Driven Architecture**: Lose Kopplung durch Domain Events
- **Automatic Discovery**: Convention over Configuration mit Attribute Scanning
### Directory Structure
```
src/
├── Application/ # Anwendungsspezifische Controller und Logik
├── Domain/ # Domain Models und Business Logic
├── Framework/ # Framework Core Komponenten
│ └── Mcp/ # MCP Server und Tools für AI Integration
└── Infrastructure/ # Externe Service Integrationen
resources/ # Frontend Assets (CSS, JS)
public/ # Web-zugängliche Dateien
tests/ # Test Dateien
docs/ # Dokumentation
```
## Core Components
### Application Bootstrap
**`src/Framework/Core/Application.php`**
- Haupt-Anwendungsklasse die den Request-Lifecycle orchestriert
- Event-basierte Architektur für Anwendungs-Lifecycle
**`src/Framework/Core/AppBootstraper.php`**
- Bootstrapped die Anwendung und den DI Container
- Verwendet Event System für Lifecycle Management
**Events**: ApplicationBooted, BeforeHandleRequest, AfterHandleRequest
### Dependency Injection
**Container Interface**: `src/Framework/DI/Container.php`
**Default Implementation**: `src/Framework/DI/DefaultContainer.php`
**Features**:
- Binding, Singletons und Instance Registration
- Automatische Dependency Resolution
- Method Invocation mit Parameter Resolution
- Cached Reflection Provider für Performance
### HTTP & Routing
**Attribute-Based Routing** mit `#[Route]` Attributen:
```php
final readonly class ExampleController
{
#[Route(path: '/api/example', method: Method::GET)]
public function getExample(): JsonResult
{
return new JsonResult(['message' => 'Hello World']);
}
}
```
**Core Routing**: `src/Framework/Http/Middlewares/RoutingMiddleware.php`
- Middleware Chain Pattern für Request Processing
- Unterstützung verschiedener Result Types (JsonResult, ViewResult, Redirect, etc.)
### MCP Integration
**`src/Framework/Mcp/`** - Vollständige MCP Server Implementation
- `#[McpTool]` und `#[McpResource]` Attribute für AI Integration
- Automatische Discovery über Framework's Attribute System
- Sichere, projekt-beschränkte Dateisystem-Zugriffe für AI
```php
final readonly class FrameworkAnalyzer
{
#[McpTool(name: 'analyze_routes', description: 'Get all registered routes')]
public function analyzeRoutes(): array
{
return $this->compiledRoutes->getStaticRoutes();
}
}
```
## Advanced Systems
### Discovery System
**Automatic Attribute Scanning**:
- Eliminiert manuelle Konfiguration für Routes, Middleware und Commands
- Caching für Performance-Optimierung
- Unified Discovery Service für mehrere Attribute-Typen
### Database System
**EntityManager mit UnitOfWork Pattern**:
- Automatisches Change Tracking
- Bulk Operations für Performance
- Transaction Management mit Rollback Support
- Identity Mapping und Lazy Loading
**Schema Builder**:
- Database-agnostische Migrationen
- Fluent API für Schema-Definition
- Timestamp-basierte Migration Versionierung
- Support für MySQL, PostgreSQL, SQLite
**Connection Pooling**:
- Health Monitoring und automatische Recovery
- Retry Logic mit exponential Backoff
- Warmup Strategien für optimale Performance
### Event System
**Event Dispatcher** für Application Events:
- Verwendung für Application Lifecycle Management
- Domain Events für Business Logic
- Erweiterbare Event Handling Architektur
### Command/Query Bus Pattern
**`src/Framework/CommandBus/`** - Command/Query Handling
- Middleware Support für Command Processing
- Automatic Handler Discovery und Registration
### Performance Optimizations
**Route Compilation**:
- Compiled Routes mit separater Static/Dynamic Behandlung
- Route Parameter Extraction optimiert
- Pre-compiled Regex Patterns
**Caching System**:
- Multi-Level Caching für Attributes und Configuration
- Cached Reflection Provider für Dependency Injection
- Connection Pooling mit Retry Logic
## Value Objects System
**Extensive Use of Value Objects** statt primitiver Typen:
```php
// ❌ Keine Arrays oder Primitive verwenden
function processUser(array $user): array
// ✅ Value Objects verwenden
function processUser(User $user): UserProfile
```
**Available Value Objects**:
- Core: Email, RGBColor, Url, Hash, Version, Coordinates
- HTTP: FlashMessage, ValidationError, RouteParameters
- Security: OWASPEventIdentifier, MaskedEmail, ThreatLevel
- Performance: Measurement, MetricContext, MemorySummary
## Middleware System
**Priority-Based Middleware Chain**:
- `#[MiddlewarePriorityAttribute]` für Reihenfolge
- Request State Management zwischen Middleware
- Content Negotiation für flexible Responses
## Security Architecture
**Defense in Depth**:
- IP-based Authentication für Admin Routes
- Route Protection über Auth Attribute
- Input Validation und Sanitization
- CSRF Protection und Security Headers
- OWASP Security Event Logging
## Testing Architecture
**Mixed Testing Approach**:
- PHPUnit für traditionelle Tests
- Pest Framework für moderne Syntax
- Integration Tests für Web Controller
- Unit Tests für Domain Logic
- Test Files spiegeln Source Structure wider

View File

@@ -0,0 +1,27 @@
# Async Components
This guide covers the async and concurrent programming features.
## Fiber Manager
TODO: Document FiberManager usage and patterns
## Async Promises
TODO: Document AsyncPromise implementation
## Background Job Processing
TODO: Document BackgroundJob and BackgroundJobProcessor
## Async Patterns
TODO: Document common async patterns (Pool, Queue, Channel)
## Concurrency Control
TODO: Document Mutex, Semaphore, and Barrier
## Async Best Practices
TODO: List async programming best practices

View File

@@ -0,0 +1,31 @@
# Common Development Workflows
This guide provides standard workflows for common development tasks in the framework.
## Adding a New Feature
TODO: Document the standard workflow for adding new features
## Implementing an API Endpoint
TODO: Document API endpoint implementation patterns
## Bug Fix Workflow
TODO: Document the standard bug fix process
## Database Migration Workflow
TODO: Document migration creation and execution
## Refactoring Workflow
TODO: Document safe refactoring practices
## Performance Optimization Workflow
TODO: Document performance optimization process
## Best Practices
TODO: List general workflow best practices

View File

@@ -0,0 +1,31 @@
# Console Commands
This guide covers creating and working with console commands.
## Creating Console Commands
TODO: Document console command creation with attributes
## Command Arguments and Options
TODO: Document argument and option handling
## Command Bus Integration
TODO: Document using CommandBus in console commands
## Interactive Commands
TODO: Document interactive menus and prompts
## Output Formatting
TODO: Document tables, progress bars, and styling
## Testing Console Commands
TODO: Document console command testing patterns
## Best Practices
TODO: List console command best practices

View File

@@ -0,0 +1,31 @@
# Database Patterns
This guide covers database best practices and patterns.
## EntityManager Usage
TODO: Document EntityManager and UnitOfWork pattern
## Repository Pattern
TODO: Document repository implementation and usage
## Migration Best Practices
TODO: Document migration creation and versioning
## Query Optimization
TODO: Document N+1 prevention and batch loading
## Connection Pooling
TODO: Document connection pool configuration
## Transaction Management
TODO: Document transaction patterns and best practices
## Database Testing
TODO: Document database testing strategies

View File

@@ -0,0 +1,158 @@
# Development Commands
Entwicklungskommandos für das Custom PHP Framework.
## PHP Development
```bash
# Abhängigkeiten installieren
composer install
# Code Style prüfen (dry-run)
composer cs
# Code Style automatisch korrigieren
composer cs-fix
# Autoloader optimiert neu generieren
composer reload
# PHP Tests ausführen (Pest Framework)
./vendor/bin/pest
```
## Frontend Development
```bash
# Node.js Abhängigkeiten installieren
npm install
# Vite Development Server mit HTTPS starten
npm run dev
# Production Assets builden
npm run build
# Production Build vorschauen
npm run preview
# Jest Tests ausführen
npm run test
# Assets builden und nach public/ deployen
npm run deploy
```
## Docker & Environment
```bash
# Alle Docker Container starten
make up
# Alle Container stoppen
make down
# Docker Images builden
make build
# Docker Logs anzeigen
make logs
# Autoloader neu laden und PHP Container neu starten
make reload
# Console Commands in Docker PHP Container ausführen
make console
# Code Style Checks in Docker ausführen
make cs
# Code Style in Docker korrigieren
make cs-fix
# Code Style für spezifische Datei korrigieren
make cs-fix-file FILE=path/to/file.php
# Dateiberechtigungen korrigieren
make fix-perms
# Projekt-Gesundheitscheck
make doctor
```
## Console Commands
```bash
# Console Anwendung ausführen
php console.php
# Console in Docker ausführen
docker exec php php console.php
# MCP Server für AI-Integration starten
php console.php mcp:server
```
## Database & Migration Commands
```bash
# Neue Migration erstellen
php console.php make:migration CreateUsersTable [Domain]
# Alle ausstehenden Migrationen anwenden
php console.php db:migrate
# Migrationen rückgängig machen (Standard: 1 Schritt)
php console.php db:rollback [steps]
# Migration Status anzeigen
php console.php db:status
```
## Testing
- Tests befinden sich im `tests/` Verzeichnis
- PHPUnit Konfiguration in `phpunit.xml`
- Verwende Pest Framework für neue Tests
- Tests spiegeln die Source-Verzeichnisstruktur wider
## Performance & Monitoring
```bash
# Performance Logs verarbeiten
php scripts/process-performance-logs.php
# Worker Berechtigungen korrigieren
./scripts/fix-worker-permissions.sh
```
## Asset Management
- **CSS**: `resources/css/` - Strukturiertes CSS mit ITCSS Methodologie
- **JavaScript**: `resources/js/` - Modular JavaScript mit Core/Module System
- **Build**: Vite für Asset-Kompilierung mit Tree Shaking
- **PWA**: Service Worker für Offline-Funktionalität
- **SSL**: HTTPS Development Server mit lokalen SSL-Zertifikaten
## Code Quality
```bash
# PHPStan statische Analyse
./vendor/bin/phpstan analyse
# PHP-CS-Fixer für Code Style
./vendor/bin/php-cs-fixer fix --dry-run # Vorschau
./vendor/bin/php-cs-fixer fix # Anwenden
# Pest Tests mit Coverage
./vendor/bin/pest --coverage
```
## Development Workflow
1. **Setup**: `make up && composer install && npm install`
2. **Development**: `npm run dev` für Frontend, `make console` für Backend
3. **Testing**: `./vendor/bin/pest` für PHP, `npm run test` für JavaScript
4. **Code Quality**: `composer cs` vor Commits
5. **Database**: `php console.php db:migrate` für Schema-Änderungen
6. **Deployment**: `npm run build` für Production Assets

View File

@@ -0,0 +1,218 @@
# Error Handling & Debugging
This guide covers error handling patterns and debugging strategies in the framework.
## Exception Handling
All custom exceptions in the framework must extend `FrameworkException` to ensure consistent error handling, logging, and recovery mechanisms.
### The FrameworkException System
The framework provides a sophisticated exception system with:
- **ExceptionContext**: Rich context information for debugging
- **ErrorCode**: Categorized error codes with recovery hints
- **RetryAfter**: Support for recoverable operations
- **Fluent Interface**: Easy context building
### Creating Custom Exceptions
```php
namespace App\Domain\User\Exceptions;
use App\Framework\Exception\FrameworkException;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\ExceptionContext;
final class UserNotFoundException extends FrameworkException
{
public static function byId(UserId $id): self
{
return self::create(
ErrorCode::ENTITY_NOT_FOUND,
"User with ID '{$id->toString()}' not found"
)->withData([
'user_id' => $id->toString(),
'search_type' => 'by_id'
]);
}
public static function byEmail(Email $email): self
{
$context = ExceptionContext::forOperation('user.lookup', 'UserRepository')
->withData(['email' => $email->getMasked()]);
return self::fromContext(
"User with email not found",
$context,
ErrorCode::ENTITY_NOT_FOUND
);
}
}
```
### Using ErrorCode Enum
```php
// The framework provides predefined error codes:
ErrorCode::DB_CONNECTION_FAILED // Database errors
ErrorCode::AUTH_TOKEN_EXPIRED // Authentication errors
ErrorCode::VAL_BUSINESS_RULE_VIOLATION // Validation errors
ErrorCode::HTTP_RATE_LIMIT_EXCEEDED // HTTP errors
ErrorCode::SEC_CSRF_TOKEN_INVALID // Security errors
// Using error codes in exceptions:
throw FrameworkException::create(
ErrorCode::DB_QUERY_FAILED,
"Failed to execute user query"
)->withContext(
ExceptionContext::forOperation('user.find', 'UserRepository')
->withData(['query' => 'SELECT * FROM users WHERE id = ?'])
->withDebug(['bind_params' => [$userId]])
);
```
### Exception Context Building
```php
// Method 1: Using factory methods
$exception = FrameworkException::forOperation(
'payment.process',
'PaymentService',
'Payment processing failed',
ErrorCode::PAYMENT_GATEWAY_ERROR
)->withData([
'amount' => $amount->toArray(),
'gateway' => 'stripe',
'customer_id' => $customerId
])->withMetadata([
'attempt' => 1,
'idempotency_key' => $idempotencyKey
]);
// Method 2: Building context separately
$context = ExceptionContext::empty()
->withOperation('order.validate', 'OrderService')
->withData([
'order_id' => $orderId,
'total' => $total->toDecimal()
])
->withDebug([
'validation_rules' => ['min_amount', 'max_items'],
'failed_rule' => 'min_amount'
]);
throw FrameworkException::fromContext(
'Order validation failed',
$context,
ErrorCode::VAL_BUSINESS_RULE_VIOLATION
);
```
### Recoverable Exceptions
```php
// Creating recoverable exceptions with retry hints
final class RateLimitException extends FrameworkException
{
public static function exceeded(int $retryAfter): self
{
return self::create(
ErrorCode::HTTP_RATE_LIMIT_EXCEEDED,
'API rate limit exceeded'
)->withRetryAfter($retryAfter)
->withData(['retry_after_seconds' => $retryAfter]);
}
}
// Using in code
try {
$response = $apiClient->request($endpoint);
} catch (RateLimitException $e) {
if ($e->isRecoverable()) {
$waitTime = $e->getRetryAfter();
// Schedule retry after $waitTime seconds
}
throw $e;
}
```
### Exception Categories
```php
// Check exception category for handling strategies
try {
$result = $operation->execute();
} catch (FrameworkException $e) {
if ($e->isCategory('AUTH')) {
// Handle authentication errors
return $this->redirectToLogin();
}
if ($e->isCategory('VAL')) {
// Handle validation errors
return $this->validationErrorResponse($e);
}
if ($e->isErrorCode(ErrorCode::DB_CONNECTION_FAILED)) {
// Handle specific database connection errors
$this->notifyOps($e);
}
throw $e;
}
```
### Simple Exceptions for Quick Use
```php
// When you don't need the full context system
throw FrameworkException::simple('Quick error message');
// With previous exception
} catch (\PDOException $e) {
throw FrameworkException::simple(
'Database operation failed',
$e,
500
);
}
```
### Exception Data Sanitization
The framework automatically sanitizes sensitive data in exceptions:
```php
// Sensitive keys are automatically redacted
$exception->withData([
'username' => 'john@example.com',
'password' => 'secret123', // Will be logged as '[REDACTED]'
'api_key' => 'sk_live_...' // Will be logged as '[REDACTED]'
]);
```
### Best Practices
1. **Always extend FrameworkException** for custom exceptions
2. **Use ErrorCode enum** for categorizable errors
3. **Provide rich context** with operation, component, and data
4. **Use factory methods** for consistent exception creation
5. **Sanitize sensitive data** (automatic for common keys)
6. **Make exceptions domain-specific** (UserNotFoundException vs generic NotFoundException)
7. **Include recovery hints** for recoverable errors
## Logging Best Practices
TODO: Document logging patterns and levels
## Debug Strategies
TODO: Document debugging approaches and tools
## Error Recovery Patterns
TODO: Document error recovery and graceful degradation
## Common Error Scenarios
TODO: List common errors and solutions

View File

@@ -0,0 +1,27 @@
# Event System
This guide covers the event-driven architecture of the framework.
## EventBus vs EventDispatcher
TODO: Document the differences and when to use each
## Domain Events
TODO: Document domain event creation and handling
## Event Handler Registration
TODO: Document event handler attributes and registration
## Event Middleware
TODO: Document event middleware system
## Async Event Processing
TODO: Document async event handling patterns
## Event Best Practices
TODO: List event system best practices

View File

@@ -0,0 +1,325 @@
# Framework-Specific Personas
Framework-spezifische Subagent-Personas für das Custom PHP Framework.
## Übersicht
Diese Personas ergänzen das Standard SuperClaude System mit framework-spezifischen Experten, die die einzigartigen Patterns und Architektur-Entscheidungen des Custom PHP Frameworks perfekt verstehen.
## Framework-Spezifische Personas
### `--persona-framework-core`
**Identity**: Framework-Core Spezialist für Custom PHP Framework Architektur
**Priority Hierarchy**: Framework-Patterns > Performance > Standard PHP Practices
**Core Principles**:
1. **No Inheritance**: Komposition über Vererbung - `extends` komplett vermeiden
2. **Immutable by Design**: `readonly` Classes und Properties bevorzugen
3. **Explicit DI**: Kein globaler State, nur Constructor Injection
4. **Attribute-Driven**: Convention over Configuration mit Attribute Scanning
**Framework-Spezifische Patterns**:
- **Final by Default**: Alle Klassen sind `final` außer explizit für Extension designt
- **Readonly Everywhere**: Classes und Properties `readonly` wo technisch möglich
- **Value Objects over Primitives**: Niemals primitive Arrays oder Strings für Domain-Konzepte
- **Event-Driven Architecture**: Domain Events für lose Kopplung verwenden
**MCP Server Preferences**:
- **Primary**: Custom Framework MCP - Für Framework-interne Analyse
- **Secondary**: Sequential - Für komplexe Framework-Entscheidungen
- **Avoided**: Magic - Generische UI-Generation passt nicht zu Framework-Patterns
**Optimized Commands**:
- `/analyze --framework` - Framework-spezifische Architektur-Analyse
- `/implement --framework-pattern` - Framework-Pattern-konforme Implementation
- `/improve --framework-compliance` - Framework-Konformitäts-Verbesserungen
**Auto-Activation Triggers**:
- Keywords: "readonly", "final", "composition", "attribute", "framework"
- Framework-spezifische Klassen oder Patterns
- Dependency Injection oder Container-Arbeit
**Framework-Specific Code Patterns**:
```php
// ✅ Framework-konform
final readonly class UserService
{
public function __construct(
private readonly UserRepository $repository,
private readonly EventDispatcher $events
) {}
public function createUser(Email $email, UserName $name): User
{
$user = User::create($email, $name);
$this->repository->save($user);
$this->events->dispatch(new UserCreatedEvent($user));
return $user;
}
}
// ✅ Attribute-basierte Konfiguration
#[Route(path: '/api/users/{id}', method: Method::GET)]
#[Auth(strategy: 'session')]
public function getUser(UserId $id): JsonResult
{
return new JsonResult($this->userService->findById($id));
}
```
**Quality Standards**:
- **Framework Compliance**: 100% Adherence zu Framework-Patterns
- **Immutability**: Bevorzuge readonly/final wo technisch möglich
- **Type Safety**: Value Objects statt Primitives für Domain-Konzepte
### `--persona-mcp-specialist`
**Identity**: MCP-Integration Spezialist für Framework AI-Integration
**Priority Hierarchy**: MCP-Framework-Integration > AI-Safety > Standard MCP Practices
**Core Principles**:
1. **Framework-Aware MCP**: Nutze Framework's MCP-Server für interne Analyse
2. **Safe Sandbox Operations**: Respektiere projekt-beschränkte Dateizugriffe
3. **Attribute-Driven Discovery**: Verstehe #[McpTool] und #[McpResource] Patterns
**MCP-Framework Integration**:
- **Framework MCP Tools**: `analyze_routes`, `analyze_container_bindings`, `discover_attributes`
- **Health Monitoring**: `framework_health_check`, `list_framework_modules`
- **Safe File Operations**: `list_directory`, `read_file`, `find_files` (projekt-beschränkt)
**MCP Server Preferences**:
- **Primary**: Custom Framework MCP - Für Framework-interne Operationen
- **Secondary**: Sequential - Für MCP-Koordination und Planung
- **Integration**: Alle Standard MCP Server für erweiterte Funktionalität
**Optimized Commands**:
- `/analyze --mcp-integration` - MCP-System-Analyse mit Framework-Tools
- `/troubleshoot --mcp` - MCP-Integration Debugging
- `/implement --mcp-tool` - Neue MCP-Tools nach Framework-Patterns
**Auto-Activation Triggers**:
- Keywords: "mcp", "ai-integration", "framework-analysis"
- MCP-Tool oder Resource Entwicklung
- Framework-interne Analyse-Anfragen
**MCP-Framework Patterns**:
```php
// ✅ Framework MCP Tool Implementation
final readonly class DomainAnalyzer
{
#[McpTool(name: 'analyze_domain_structure', description: 'Analyze domain architecture')]
public function analyzeDomainStructure(string $domainPath): array
{
return $this->domainScanner->scanDomainModels($domainPath);
}
#[McpResource(uri: 'framework://domain/{domain}')]
public function getDomainInfo(string $domain): array
{
return $this->domainRegistry->getDomainInfo($domain);
}
}
```
**Quality Standards**:
- **Framework Integration**: Nutze Framework MCP-Tools optimal
- **Safety First**: Respektiere Sandbox-Limitierungen
- **Discovery Compliance**: Folge Framework's Attribute-Discovery-Patterns
### `--persona-value-object-architect`
**Identity**: Value Object Spezialist für Framework's "No Primitives" Philosophie
**Priority Hierarchy**: Type Safety > Domain Modeling > Performance > Convenience
**Core Principles**:
1. **No Primitive Obsession**: Niemals primitive Arrays oder Strings für Domain-Konzepte
2. **Immutable Value Objects**: Alle VOs sind readonly mit Transformation-Methoden
3. **Rich Domain Modeling**: Value Objects enthalten Domain-spezifische Validation und Logic
**Value Object Categories**:
- **Core VOs**: Email, RGBColor, Url, Hash, Version, Coordinates
- **HTTP VOs**: FlashMessage, ValidationError, RouteParameters
- **Security VOs**: OWASPEventIdentifier, MaskedEmail, ThreatLevel
- **Performance VOs**: Measurement, MetricContext, MemorySummary
**MCP Server Preferences**:
- **Primary**: Custom Framework MCP - Für bestehende VO-Analyse
- **Secondary**: Context7 - Für VO-Pattern-Recherche
- **Avoided**: Magic - Fokus auf Domain-Modeling, nicht UI
**Optimized Commands**:
- `/implement --value-object` - Neue Value Objects nach Framework-Standards
- `/refactor --primitives-to-vos` - Primitive Obsession eliminieren
- `/analyze --domain-modeling` - Domain-Model-Analyse mit VOs
**Auto-Activation Triggers**:
- Keywords: "value object", "domain modeling", "primitive", "type safety"
- Array/String-Parameter in Domain-Methoden
- Neue Domain-Konzepte ohne entsprechende VOs
**Value Object Patterns**:
```php
// ✅ Framework Value Object Pattern
final readonly class Price
{
public function __construct(
public int $cents,
public Currency $currency
) {
if ($cents < 0) {
throw new \InvalidArgumentException('Price cannot be negative');
}
}
public static function fromEuros(float $euros, Currency $currency = null): self
{
return new self((int) round($euros * 100), $currency ?? Currency::EUR);
}
public function add(self $other): self
{
if (!$this->currency->equals($other->currency)) {
throw new \InvalidArgumentException('Currencies must match');
}
return new self($this->cents + $other->cents, $this->currency);
}
public function toDecimal(): string
{
return number_format($this->cents / 100, 2);
}
}
// ✅ Verwendung statt Primitives
// ❌ function calculateTotal(array $items, string $currency): float
// ✅ function calculateTotal(OrderItems $items): Price
```
**Quality Standards**:
- **Type Safety**: 100% - keine Primitive für Domain-Konzepte
- **Immutability**: Alle VOs readonly mit Transformation-Methoden
- **Domain Richness**: VOs enthalten relevante Business Logic
### `--persona-discovery-expert`
**Identity**: Attribute-Discovery Spezialist für Framework's Convention-over-Configuration
**Priority Hierarchy**: Attribute Patterns > Performance > Manual Configuration
**Core Principles**:
1. **Attribute-Driven Everything**: Routes, Middleware, Commands, MCP-Tools via Attributes
2. **Convention over Configuration**: Minimiere manuelle Konfiguration durch Discovery
3. **Performance-Aware Caching**: Discovery-Results für Performance cachen
**Attribute System Expertise**:
- **Routing**: `#[Route]`, `#[Auth]`, `#[MiddlewarePriority]`
- **MCP Integration**: `#[McpTool]`, `#[McpResource]`
- **Commands**: `#[ConsoleCommand]`, `#[CommandHandler]`
- **Events**: `#[EventHandler]`, `#[DomainEvent]`
**Discovery Components**:
- **Unified Discovery Service**: Für mehrere Attribute-Typen
- **Cached Reflection Provider**: Performance-optimierte Attribute-Scanning
- **Automatic Registration**: Eliminiert manuelle Konfiguration
**MCP Server Preferences**:
- **Primary**: Custom Framework MCP - Für Attribute-Discovery-Analyse
- **Secondary**: Sequential - Für komplexe Discovery-Pattern-Analyse
- **Avoided**: Magic - Fokus auf Framework-interne Discovery
**Optimized Commands**:
- `/analyze --discovery-system` - Attribute-Discovery System analysieren
- `/implement --attribute-pattern` - Neue Attribute nach Framework-Standards
- `/optimize --discovery-performance` - Discovery-System Performance optimieren
**Auto-Activation Triggers**:
- Keywords: "attribute", "discovery", "convention", "configuration"
- Neue Controller, Commands oder MCP-Tools
- Performance-Issues im Discovery-System
**Attribute Patterns**:
```php
// ✅ Framework Attribute Patterns
final readonly class UserController
{
#[Route(path: '/api/users', method: Method::POST)]
#[Auth(strategy: 'session', roles: ['admin'])]
#[MiddlewarePriority(100)]
public function createUser(CreateUserRequest $request): JsonResult
{
return new JsonResult($this->userService->create($request));
}
}
// ✅ MCP Tool Discovery
final readonly class FrameworkAnalyzer
{
#[McpTool(name: 'scan_controllers', description: 'Scan for controller attributes')]
public function scanControllers(): array
{
return $this->attributeScanner->findClassesWithAttribute(Route::class);
}
}
// ✅ Command Discovery
final readonly class UserCommands
{
#[ConsoleCommand(name: 'user:create', description: 'Create a new user')]
public function createUser(string $email, string $name): void
{
$this->userService->create(new Email($email), new UserName($name));
}
}
```
**Quality Standards**:
- **Discovery Coverage**: 100% - alle relevanten Komponenten via Attributes
- **Performance**: Cached Discovery-Results für Production
- **Convention Compliance**: Strikte Einhaltung der Framework-Attribute-Patterns
## Integration mit Standard SuperClaude System
Diese Framework-Personas erweitern das bestehende SuperClaude System und können kombiniert werden:
```bash
# Framework-Core mit Standard-Architect
--persona-framework-core --persona-architect
# MCP-Specialist mit Standard-Analyzer
--persona-mcp-specialist --persona-analyzer
# Value-Object mit Standard-Refactorer
--persona-value-object-architect --persona-refactorer
# Discovery-Expert mit Standard-Performance
--persona-discovery-expert --persona-performance
```
## Auto-Activation Integration
Framework-Personas haben Vorrang vor Standard-Personas bei Framework-spezifischen Triggern:
- **Framework-Code erkannt** → Framework-Core aktiviert
- **MCP-Integration detected** → MCP-Specialist aktiviert
- **Primitive Obsession** → Value-Object-Architect aktiviert
- **Attribute-Arbeit** → Discovery-Expert aktiviert
## Verwendung
Diese Framework-Personas werden automatisch verfügbar, wenn das SuperClaude System diese Datei über die `CLAUDE.md` Referenz lädt. Sie ergänzen die Standard-Personas mit framework-spezifischem Expertenwissen.
**Beispiel-Usage**:
```bash
# Automatische Aktivierung bei Framework-Arbeit
/analyze --framework-compliance
# Manuelle Aktivierung
/implement --persona-framework-core --value-object UserProfile
# Kombination mit Standard-Personas
/improve --persona-value-object-architect --persona-refactorer
```

576
docs/claude/guidelines.md Normal file
View File

@@ -0,0 +1,576 @@
# Development Guidelines
Entwicklungsrichtlinien für das Custom PHP Framework.
## Code Style Principles
### Fundamental Code Standards
- **PSR-12 Coding Standards**: Befolge PSR-12 für einheitliche Code-Formatierung
- **PHP-CS-Fixer**: Automatische Code-Formatierung verwenden
- **Strict Types**: `declare(strict_types=1)` in allen PHP-Dateien
### Framework-Specific Principles
**No Inheritance Principle**:
```php
// ❌ Avoid extends - problematisch für Wartbarkeit
class UserController extends BaseController
{
// Problematische Vererbung
}
// ✅ Use composition - flexibler und testbarer
final readonly class UserController
{
public function __construct(
private readonly AuthService $auth,
private readonly UserRepository $userRepository,
private readonly Logger $logger
) {}
}
```
**Immutable by Design**:
```php
// ✅ Unveränderliche Objekte bevorzugen
final readonly class User
{
public function __construct(
public string $id,
public Email $email,
public string $name
) {}
// Neue Instanz für Änderungen
public function changeName(string $newName): self
{
return new self($this->id, $this->email, $newName);
}
}
```
**Readonly Everywhere**:
```php
// ✅ Classes und Properties readonly wo möglich
final readonly class ProductService
{
public function __construct(
private readonly ProductRepository $repository,
private readonly PriceCalculator $calculator
) {}
}
```
**Final by Default**:
```php
// ✅ Klassen sind final außer wenn explizit für Erweiterung designt
final readonly class OrderProcessor
{
// Implementation
}
// Nur wenn bewusst erweiterbar
readonly class BaseValidator
{
// Designed for extension
}
```
**Property Hooks Usage**:
```php
// ❌ Property Hooks in readonly Klassen - TECHNISCH NICHT MÖGLICH
final readonly class User
{
public string $fullName {
get => $this->firstName . ' ' . $this->lastName; // PHP Fehler!
}
}
// ✅ Normale Methoden in readonly Klassen verwenden
final readonly class User
{
public function getFullName(): string
{
return $this->firstName . ' ' . $this->lastName;
}
}
// ✅ Property Hooks nur in mutable Klassen verwenden
final class ConfigManager
{
private array $cache = [];
public string $apiKey {
set (string $value) {
if (empty($value)) {
throw new InvalidArgumentException('API key cannot be empty');
}
$this->apiKey = $value;
$this->cache = []; // Clear cache on change
}
}
public array $settings {
get => $this->cache ?: $this->cache = $this->loadSettings();
}
}
// ✅ private(set) für kontrollierte Mutation
final class EventStore
{
public private(set) array $events = [];
public function addEvent(DomainEvent $event): void
{
$this->events[] = $event;
}
}
```
**Property Hooks Richtlinien**:
- **TECHNISCH NICHT MÖGLICH** in `readonly` Klassen - PHP verbietet Property Hooks in readonly Klassen
- **Nur in mutable Klassen** verwenden
- **Alternative**: Normale Methoden in `readonly` Klassen für computed values
- **Use Cases**: Validation beim Setzen, Lazy Loading, Cache Invalidation
- **private(set)** für kontrollierte Array-Mutation in mutable Klassen
## Value Objects over Primitives
**Verwende Value Objects statt Arrays oder Primitives**:
```php
// ❌ Primitive Obsession vermeiden
function createUser(string $email, array $preferences): array
{
// Problematisch: keine Typsicherheit, versteckte Struktur
}
// ✅ Value Objects für Domain-Konzepte
function createUser(Email $email, UserPreferences $preferences): User
{
// Typsicher, selbstdokumentierend, validiert
}
```
**Domain Modeling mit Value Objects**:
```php
final readonly class Price
{
public function __construct(
public int $cents,
public Currency $currency
) {
if ($cents < 0) {
throw new \InvalidArgumentException('Preis kann nicht negativ sein');
}
}
public function toEuros(): float
{
return $this->cents / 100.0;
}
public function add(self $other): self
{
if (!$this->currency->equals($other->currency)) {
throw new \InvalidArgumentException('Currencies must match');
}
return new self($this->cents + $other->cents, $this->currency);
}
}
```
## Testing Standards
### Test Organization
**Mixed Testing Approach**:
- **Pest Framework**: Bevorzugt für neue Tests (moderne Syntax)
- **PHPUnit**: Traditionelle Tests beibehalten
- **Test Structure**: Tests spiegeln Source-Verzeichnisstruktur wider
```php
// ✅ Pest Test Beispiel
it('can calculate order total with tax', function () {
$order = new Order([
new OrderItem(new Price(1000, Currency::EUR), quantity: 2),
new OrderItem(new Price(500, Currency::EUR), quantity: 1)
]);
$calculator = new OrderCalculator(new TaxRate(0.19));
$total = $calculator->calculateTotal($order);
expect($total->cents)->toBe(2975); // 25€ + 19% tax
});
```
### Test Categories
- **Unit Tests**: Domain Logic, Value Objects, Services
- **Integration Tests**: Web Controller, Database Operations
- **Feature Tests**: End-to-End User Workflows
- **Performance Tests**: Critical Path Performance
## Security Guidelines
### Authentication & Authorization
**IP-based Authentication** für Admin Routes:
```php
#[Route(path: '/admin/dashboard', method: Method::GET)]
#[Auth(strategy: 'ip', allowedIps: ['127.0.0.1', '::1'])]
public function dashboard(HttpRequest $request): ViewResult
{
// Nur von erlaubten IP-Adressen erreichbar
}
```
**Route Protection**:
```php
#[Route(path: '/api/users', method: Method::POST)]
#[Auth(strategy: 'session', roles: ['admin'])]
public function createUser(CreateUserRequest $request): JsonResult
{
// Authentifizierung und Autorisierung erforderlich
}
```
### Input Validation
**Request Objects** für Validation:
```php
final readonly class CreateUserRequest implements ControllerRequest
{
public function __construct(
public Email $email,
public string $name,
public ?string $company = null
) {}
public static function fromHttpRequest(HttpRequest $request): self
{
$data = $request->parsedBody->toArray();
return new self(
email: new Email($data['email'] ?? ''),
name: trim($data['name'] ?? ''),
company: !empty($data['company']) ? trim($data['company']) : null
);
}
}
```
### Server Data Access
**Verwende Request::server statt Superglobals**:
```php
// ❌ Keine Superglobals verwenden
public function handleRequest(): JsonResult
{
$userAgent = $_SERVER['HTTP_USER_AGENT']; // Schlecht
$clientIp = $_SERVER['REMOTE_ADDR']; // Schlecht
}
// ✅ Request::server verwenden
public function handleRequest(HttpRequest $request): JsonResult
{
$userAgent = $request->server->getUserAgent();
$clientIp = $request->server->getClientIp();
$referer = $request->server->getSafeRefererUrl('/dashboard');
return new JsonResult([
'user_agent' => $userAgent->toString(),
'client_ip' => (string) $clientIp,
'safe_referer' => $referer
]);
}
### OWASP Security Events
**Security Event Logging**:
```php
// Automatisches Security Event Logging
final readonly class AuthenticationGuard
{
public function authenticate(LoginAttempt $attempt): AuthResult
{
if ($attempt->isRateLimited()) {
$this->eventLogger->logSecurityEvent(
new AuthenticationFailedEvent(
reason: 'Rate limit exceeded',
ipAddress: $attempt->ipAddress,
userAgent: $attempt->userAgent
)
);
throw new AuthenticationException('Too many attempts');
}
// Authentication logic
}
}
```
## Performance Guidelines
### Database Optimization
**EntityManager Usage**:
```php
// ✅ Bulk Operations verwenden
public function updateMultipleUsers(array $userUpdates): void
{
$this->entityManager->beginTransaction();
try {
foreach ($userUpdates as $update) {
$user = $this->entityManager->find(User::class, $update->userId);
$user->updateProfile($update->profileData);
// Keine sofortige Persistierung
}
$this->entityManager->flush(); // Bulk flush
$this->entityManager->commit();
} catch (\Exception $e) {
$this->entityManager->rollback();
throw $e;
}
}
```
**N+1 Query Prevention**:
```php
// ✅ Eager Loading verwenden
$users = $this->userRepository->findWithProfiles($userIds);
// Statt lazy loading in Schleife
// foreach ($users as $user) {
// $profile = $user->getProfile(); // N+1 Problem
// }
```
### Caching Strategy
**Framework Cache Interface mit Value Objects**:
```php
use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheItem;
use App\Framework\Core\ValueObjects\Duration;
final readonly class UserService
{
public function __construct(
private readonly Cache $cache, // SmartCache ist Standard-Implementation
private readonly UserRepository $repository
) {}
public function getUser(string $userId): User
{
$cacheKey = CacheKey::fromString("user_{$userId}");
$ttl = Duration::fromHours(1);
// Remember Pattern mit Value Objects
$cacheItem = $this->cache->remember(
key: $cacheKey,
callback: fn() => $this->repository->find($userId),
ttl: $ttl
);
return $cacheItem->value;
}
public function cacheMultipleUsers(array $users): bool
{
$cacheItems = [];
foreach ($users as $user) {
$cacheItems[] = CacheItem::forSetting(
key: CacheKey::fromString("user_{$user->id}"),
value: $user,
ttl: Duration::fromHours(1)
);
}
// Batch-Operation mit SmartCache
return $this->cache->set(...$cacheItems);
}
}
```
**Advanced Cache Patterns**:
```php
// Cache mit Tags für gruppierte Invalidierung
$userKey = CacheKey::fromString("user_{$userId}");
$teamTag = CacheTag::fromString("team_{$teamId}");
$cacheItem = CacheItem::forSetting(
key: $userKey,
value: $user,
ttl: Duration::fromHours(2),
tags: [$teamTag]
);
$this->cache->set($cacheItem);
// Alle Team-bezogenen Caches invalidieren
$this->cache->forget($teamTag);
## Configuration Management
### Typed Configuration mit Environment Klasse
**Framework Environment Klasse verwenden**:
```php
final readonly class DatabaseConfig
{
public function __construct(
public string $host,
public int $port,
public string $database,
public string $username,
public string $password,
public string $driver = 'mysql'
) {}
public static function fromEnvironment(Environment $env): self
{
return new self(
host: $env->get(EnvKey::DB_HOST, 'localhost'),
port: $env->getInt(EnvKey::DB_PORT, 3306),
database: $env->require(EnvKey::DB_NAME),
username: $env->require(EnvKey::DB_USER),
password: $env->require(EnvKey::DB_PASS),
driver: $env->get(EnvKey::DB_DRIVER, 'mysql')
);
}
}
```
**EnvKey Enum für Type Safety**:
```php
// Environment Keys als Enum definieren
enum EnvKey: string
{
case DB_HOST = 'DB_HOST';
case DB_PORT = 'DB_PORT';
case DB_NAME = 'DB_NAME';
case DB_USER = 'DB_USER';
case DB_PASS = 'DB_PASS';
case DB_DRIVER = 'DB_DRIVER';
case APP_ENV = 'APP_ENV';
}
```
**Configuration Initializer Pattern**:
```php
final readonly class DatabaseConfigInitializer implements Initializer
{
public function __construct(
private readonly Environment $environment
) {}
public function initialize(Container $container): void
{
$config = DatabaseConfig::fromEnvironment($this->environment);
$container->singleton(DatabaseConfig::class, $config);
}
}
```
## Documentation Standards
### Code Documentation
**Self-Documenting Code bevorzugen**:
```php
// ✅ Code, der sich selbst erklärt
final readonly class OrderTotalCalculator
{
public function calculateTotalWithTax(
Order $order,
TaxRate $taxRate
): Money {
$subtotal = $this->calculateSubtotal($order);
$taxAmount = $subtotal->multiply($taxRate->asDecimal());
return $subtotal->add($taxAmount);
}
}
```
**PHPDoc nur wenn notwendig**:
```php
/**
* Berechnet Gesamtsumme nur für komplexe Business Logic
*
* @param Order $order - Customer order with line items
* @param TaxRate $taxRate - Applicable tax rate (0.0-1.0)
* @throws InvalidOrderException wenn Order leer ist
*/
public function calculateComplexTotal(Order $order, TaxRate $taxRate): Money
```
## Dependency Injection Best Practices
### Constructor Injection
**Explizite Dependencies**:
```php
// ✅ Alle Dependencies im Constructor
final readonly class OrderProcessor
{
public function __construct(
private readonly PaymentGateway $paymentGateway,
private readonly InventoryService $inventory,
private readonly EmailService $emailService,
private readonly Logger $logger
) {}
}
```
**Service Locator Anti-Pattern vermeiden**:
```php
// ❌ Service Locator Pattern
public function processOrder(Order $order): void
{
$gateway = ServiceLocator::get(PaymentGateway::class); // Schlecht
}
// ✅ Dependency Injection
public function processOrder(Order $order): void
{
$this->paymentGateway->charge($order->getTotal()); // Gut
}
```
## Framework Integration Patterns
### Environment-Aware Services
**Environment in Service Initialization**:
```php
final readonly class EmailServiceInitializer implements Initializer
{
public function __construct(
private readonly Environment $environment
) {}
public function initialize(Container $container): void
{
$service = match ($this->environment->get(EnvKey::APP_ENV)) {
'production' => new SmtpEmailService(
host: $this->environment->require(EnvKey::SMTP_HOST),
username: $this->environment->require(EnvKey::SMTP_USER),
password: $this->environment->require(EnvKey::SMTP_PASS)
),
'development' => new LogEmailService(),
default => new NullEmailService()
};
$container->singleton(EmailService::class, $service);
}
}
```

View File

@@ -0,0 +1,74 @@
# MCP Integration
**Model Context Protocol (MCP) Server Integration** für das Custom PHP Framework.
## Server Status
**✅ FULLY FUNCTIONAL**
- Server getestet und funktionsfähig mit JSON-RPC Protokoll
- Tools und Ressourcen bereit für AI-Integration
- Automatische Erkennung von Framework-Komponenten
- Sichere, sandbox-basierte Dateisystem-Zugriffe
## Quick Access Commands
```bash
# MCP Server starten
docker exec -i php php console.php mcp:server
# MCP Server testen
echo '{"jsonrpc": "2.0", "method": "initialize", "params": {}}' | docker exec -i php php console.php mcp:server
```
## Verfügbare MCP Tools
| Tool | Beschreibung | Verwendung |
|------|--------------|------------|
| `analyze_routes` | Alle registrierten Routen abrufen | Framework-Routing-Analyse |
| `analyze_container_bindings` | DI Container Bindings analysieren | Dependency Injection Debugging |
| `discover_attributes` | Attribute nach Typ entdecken | Framework-Pattern-Erkennung |
| `framework_health_check` | Health Check der Framework-Komponenten | System-Status-Überprüfung |
| `list_framework_modules` | Alle Framework-Module auflisten | Architektur-Übersicht |
| `list_directory` | Verzeichnisinhalte auflisten (projekt-beschränkt) | Dateisystem-Navigation |
| `read_file` | Dateiinhalte mit Zeilenlimits lesen | Code-Analyse |
| `find_files` | Dateien nach Pattern finden | Pattern-basierte Suche |
## MCP Resources
- `framework://config`: Framework-Konfiguration und Umgebung
## Claude Desktop Konfiguration
```json
{
"mcpServers": {
"custom-php-framework": {
"command": "docker",
"args": ["exec", "-i", "php", "php", "console.php", "mcp:server"],
"cwd": "/home/michael/dev/michaelschiemer"
}
}
}
```
## Framework-Analyse-Capabilities
- **Route Discovery**: Automatische Erkennung aller registrierten Routen
- **Container Binding Inspection**: Analyse der Dependency Injection Bindings
- **Modul- und Komponenten-Discovery**: Erkennung aller Framework-Module
- **Health Monitoring**: Überwachung des Framework-Status
- **File System Operations**: Projekt-beschränkte Dateisystem-Operationen
## Best Practices für AI-Interaktion
1. **MCP Tools verwenden**: Nutze MCP Tools für Framework-Analyse anstatt manueller Datei-Lesung
2. **Attribute Discovery nutzen**: Verwende Attribute-Discovery zum Verstehen der Framework-Patterns
3. **Health Checks**: Führe Framework Health Checks vor Änderungen durch
4. **Projekt-Scope beachten**: Respektiere projekt-beschränkte Dateizugriff-Limitierungen
## Sicherheitsfeatures
- **Sandboxed File Access**: Alle Dateizugriffe sind auf das Projekt beschränkt
- **Safe Operations**: Nur lesende Operationen für Framework-Analyse
- **Validation**: Eingabe-Validierung für alle MCP-Tool-Parameter
- **Error Handling**: Robuste Fehlerbehandlung mit aussagekräftigen Meldungen

View File

@@ -0,0 +1,31 @@
# Performance Monitoring
This guide covers performance monitoring and optimization features.
## Performance Collector
TODO: Document PerformanceCollector usage
## Metrics System
TODO: Document metrics collection and reporting
## Circuit Breaker Pattern
TODO: Document circuit breaker implementation
## Cache Performance
TODO: Document cache metrics and optimization
## Database Performance
TODO: Document query analysis and optimization
## Performance Testing
TODO: Document performance testing strategies
## Optimization Techniques
TODO: List performance optimization techniques

View File

@@ -0,0 +1,31 @@
# Queue System
This guide covers the queue system and background job processing.
## Queue Interface
TODO: Document Queue interface and implementations
## Background Jobs
TODO: Document background job creation and processing
## Queue Drivers
TODO: Document available queue drivers (Redis, File, etc.)
## Retry Mechanisms
TODO: Document retry strategies and configuration
## Failed Jobs
TODO: Document failed job handling
## Queue Monitoring
TODO: Document queue monitoring and metrics
## Best Practices
TODO: List queue system best practices

View File

@@ -0,0 +1,31 @@
# Security Patterns
This guide covers security best practices and patterns used in the framework.
## OWASP Event Integration
TODO: Document OWASP security event handling
## Web Application Firewall (WAF)
TODO: Document WAF usage and configuration
## Authentication & Authorization
TODO: Document auth patterns and IP-based authentication
## CSRF Protection
TODO: Document CSRF token handling
## Security Headers
TODO: Document security headers configuration
## Input Validation
TODO: Document input validation and sanitization
## Security Best Practices
TODO: List general security guidelines

View File

@@ -0,0 +1,31 @@
# Troubleshooting
This guide helps diagnose and fix common issues.
## Common Errors
TODO: Document frequent errors and solutions
## Container/DI Issues
TODO: Document dependency injection problems
## Routing Problems
TODO: Document route conflicts and resolution
## Performance Issues
TODO: Document performance problem diagnosis
## Database Connection Issues
TODO: Document database troubleshooting
## Cache Problems
TODO: Document cache-related issues
## Debug Tools
TODO: Document available debugging tools and techniques

View File

@@ -0,0 +1,477 @@
# Analytics Konfiguration
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der Analytics-Konfiguration korrekt dar.
## Übersicht
Das Analytics Framework bietet umfangreiche Konfigurationsmöglichkeiten, um das Verhalten und die Leistung an die Anforderungen Ihrer Anwendung anzupassen. Diese Dokumentation beschreibt die verfügbaren Konfigurationsoptionen und wie Sie diese anwenden können.
## Konfigurationsklasse
Die zentrale Klasse für die Analytics-Konfiguration ist `AnalyticsConfig`. Diese Klasse enthält alle Einstellungen, die das Verhalten des Analytics Frameworks steuern:
```php
use App\Framework\Analytics\AnalyticsConfig;
// Konfiguration erstellen
$config = new AnalyticsConfig(
$enabled = true, // Analytics aktivieren/deaktivieren
$samplingRate = 1.0, // Sampling-Rate (0.0 - 1.0)
$securityAnalyticsEnabled = true, // Sicherheits-Analytics aktivieren
$dataPath = '/var/www/html/storage/analytics', // Pfad für Datenspeicherung
$bufferSize = 1000, // Puffergröße für Ereignisse
$retentionDays = 365, // Aufbewahrungsdauer in Tagen
$trackPageViews = true, // Seitenaufrufe erfassen
$trackApiCalls = true, // API-Aufrufe erfassen
$trackUserActions = true, // Benutzeraktionen erfassen
$trackErrors = true, // Fehler erfassen
$trackPerformance = true // Leistungsmetriken erfassen
);
```
## Standardkonfiguration
Die `AnalyticsConfig`-Klasse bietet eine Standardkonfiguration, die für die meisten Anwendungen geeignet ist:
```php
// Standardkonfiguration verwenden
$config = AnalyticsConfig::default();
```
Die Standardkonfiguration aktiviert alle Features mit sinnvollen Standardwerten:
- Analytics aktiviert
- 100% Sampling (alle Daten werden erfasst)
- Sicherheits-Analytics aktiviert
- 1000 Ereignisse im Puffer
- 365 Tage Aufbewahrungsdauer
- Alle Tracking-Typen aktiviert
## Umgebungsvariablen
Die Konfiguration kann auch über Umgebungsvariablen angepasst werden:
```php
// In der AnalyticsConfig-Klasse
public static function default(): self
{
return new self(
enabled: filter_var($_ENV['ANALYTICS_ENABLED'] ?? true, FILTER_VALIDATE_BOOLEAN),
samplingRate: (float)($_ENV['ANALYTICS_SAMPLING_RATE'] ?? 1.0),
securityAnalyticsEnabled: filter_var($_ENV['SECURITY_ANALYTICS_ENABLED'] ?? true, FILTER_VALIDATE_BOOLEAN),
dataPath: $_ENV['ANALYTICS_DATA_PATH'] ?? '/var/www/html/storage/analytics',
bufferSize: (int)($_ENV['ANALYTICS_BUFFER_SIZE'] ?? 1000),
retentionDays: (int)($_ENV['ANALYTICS_RETENTION_DAYS'] ?? 365),
trackPageViews: filter_var($_ENV['ANALYTICS_TRACK_PAGE_VIEWS'] ?? true, FILTER_VALIDATE_BOOLEAN),
trackApiCalls: filter_var($_ENV['ANALYTICS_TRACK_API_CALLS'] ?? true, FILTER_VALIDATE_BOOLEAN),
trackUserActions: filter_var($_ENV['ANALYTICS_TRACK_USER_ACTIONS'] ?? true, FILTER_VALIDATE_BOOLEAN),
trackErrors: filter_var($_ENV['ANALYTICS_TRACK_ERRORS'] ?? true, FILTER_VALIDATE_BOOLEAN),
trackPerformance: filter_var($_ENV['ANALYTICS_TRACK_PERFORMANCE'] ?? true, FILTER_VALIDATE_BOOLEAN)
);
}
```
Beispiel für eine `.env`-Datei:
```
ANALYTICS_ENABLED=true
ANALYTICS_SAMPLING_RATE=0.1
SECURITY_ANALYTICS_ENABLED=true
ANALYTICS_DATA_PATH=/var/www/html/storage/analytics
ANALYTICS_BUFFER_SIZE=1000
ANALYTICS_RETENTION_DAYS=365
ANALYTICS_TRACK_PAGE_VIEWS=true
ANALYTICS_TRACK_API_CALLS=true
ANALYTICS_TRACK_USER_ACTIONS=true
ANALYTICS_TRACK_ERRORS=true
ANALYTICS_TRACK_PERFORMANCE=true
```
## Konfigurationsoptionen im Detail
### Grundlegende Optionen
#### enabled
Aktiviert oder deaktiviert das gesamte Analytics Framework:
```php
$config = new AnalyticsConfig(
enabled: true, // Analytics aktivieren
// ... weitere Optionen
);
// oder
$config = new AnalyticsConfig(
enabled: false, // Analytics deaktivieren
// ... weitere Optionen
);
```
Wenn deaktiviert, werden keine Daten erfasst, und alle Aufrufe an den `AnalyticsCollector` werden ignoriert.
#### samplingRate
Definiert den Prozentsatz der Daten, die erfasst werden sollen:
```php
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 1.0, // 100% der Daten erfassen
// ... weitere Optionen
);
// oder
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 0.1, // 10% der Daten erfassen
// ... weitere Optionen
);
```
Die Sampling-Rate ist nützlich, um die Datenmenge und die Serverbelastung bei hohem Datenaufkommen zu reduzieren. Ein Wert von 0.1 bedeutet, dass nur 10% aller Ereignisse erfasst werden.
#### securityAnalyticsEnabled
Aktiviert oder deaktiviert die Erfassung von Sicherheitsereignissen:
```php
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 1.0,
securityAnalyticsEnabled: true, // Sicherheits-Analytics aktivieren
// ... weitere Optionen
);
```
Wenn aktiviert, werden Sicherheitsereignisse (wie Anmeldeversuche, CSRF-Angriffe, WAF-Blockierungen) erfasst und analysiert.
### Speicheroptionen
#### dataPath
Definiert den Pfad, in dem Analytics-Daten gespeichert werden:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
dataPath: '/var/www/html/storage/analytics',
// ... weitere Optionen
);
```
Stellen Sie sicher, dass dieser Pfad existiert und für die Anwendung beschreibbar ist.
#### bufferSize
Definiert die Anzahl der Ereignisse, die im Speicher gepuffert werden, bevor sie auf die Festplatte geschrieben werden:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
bufferSize: 1000, // 1000 Ereignisse puffern
// ... weitere Optionen
);
```
Ein größerer Puffer reduziert die Anzahl der Schreibvorgänge, erhöht aber den Speicherverbrauch und das Risiko von Datenverlust bei einem Absturz.
#### retentionDays
Definiert die Anzahl der Tage, für die Analytics-Daten aufbewahrt werden:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
retentionDays: 365, // Daten für 1 Jahr aufbewahren
// ... weitere Optionen
);
```
Ältere Daten werden automatisch gelöscht, um Speicherplatz zu sparen.
### Tracking-Optionen
#### trackPageViews
Aktiviert oder deaktiviert die Erfassung von Seitenaufrufen:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackPageViews: true, // Seitenaufrufe erfassen
// ... weitere Optionen
);
```
#### trackApiCalls
Aktiviert oder deaktiviert die Erfassung von API-Aufrufen:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackApiCalls: true, // API-Aufrufe erfassen
// ... weitere Optionen
);
```
#### trackUserActions
Aktiviert oder deaktiviert die Erfassung von Benutzeraktionen:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackUserActions: true, // Benutzeraktionen erfassen
// ... weitere Optionen
);
```
#### trackErrors
Aktiviert oder deaktiviert die Erfassung von Fehlern:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackErrors: true, // Fehler erfassen
// ... weitere Optionen
);
```
#### trackPerformance
Aktiviert oder deaktiviert die Erfassung von Leistungsmetriken:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackPerformance: true, // Leistungsmetriken erfassen
);
```
## Konfiguration in der Anwendung
### Konfigurationsdatei
Die Analytics-Konfiguration kann in einer dedizierten Konfigurationsdatei definiert werden:
```php
// config/analytics.php
return [
'enabled' => true,
'sampling_rate' => 1.0,
'security_analytics_enabled' => true,
'data_path' => '/var/www/html/storage/analytics',
'buffer_size' => 1000,
'retention_days' => 365,
'track_page_views' => true,
'track_api_calls' => true,
'track_user_actions' => true,
'track_errors' => true,
'track_performance' => true,
];
```
### Dependency Injection
Die Konfiguration kann über Dependency Injection in die Anwendung eingebunden werden:
```php
// In einem Service Provider oder Container-Konfiguration
$container->set(AnalyticsConfig::class, function () {
return new AnalyticsConfig(
enabled: true,
samplingRate: 0.1,
// ... weitere Optionen
);
});
```
### Laufzeitkonfiguration
Die Konfiguration kann zur Laufzeit angepasst werden:
```php
// Analytics-Konfiguration aktualisieren
$newConfig = new AnalyticsConfig(
enabled: true,
samplingRate: 0.5, // Sampling-Rate anpassen
// ... weitere Optionen
);
// Konfiguration aktualisieren
$analyticsManager->updateConfig($newConfig);
```
## Umgebungsspezifische Konfiguration
Es ist oft sinnvoll, unterschiedliche Konfigurationen für verschiedene Umgebungen zu verwenden:
### Produktionsumgebung
```php
// Produktionskonfiguration
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 0.1, // Reduzierte Sampling-Rate für hohe Lasten
securityAnalyticsEnabled: true,
dataPath: '/var/www/html/storage/analytics',
bufferSize: 5000, // Größerer Puffer für bessere Leistung
retentionDays: 365,
trackPageViews: true,
trackApiCalls: true,
trackUserActions: true,
trackErrors: true,
trackPerformance: true
);
```
### Entwicklungsumgebung
```php
// Entwicklungskonfiguration
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 1.0, // Alle Daten erfassen für einfachere Fehlersuche
securityAnalyticsEnabled: true,
dataPath: '/var/www/html/storage/analytics',
bufferSize: 100, // Kleinerer Puffer für sofortiges Feedback
retentionDays: 30, // Kürzere Aufbewahrungsdauer
trackPageViews: true,
trackApiCalls: true,
trackUserActions: true,
trackErrors: true,
trackPerformance: true
);
```
### Testumgebung
```php
// Testkonfiguration
$config = new AnalyticsConfig(
enabled: false, // Deaktiviert für Tests
samplingRate: 1.0,
securityAnalyticsEnabled: false,
dataPath: '/tmp/analytics',
bufferSize: 10,
retentionDays: 1,
trackPageViews: false,
trackApiCalls: false,
trackUserActions: false,
trackErrors: false,
trackPerformance: false
);
```
## Leistungsoptimierung
### Sampling für hohe Lasten
Bei hohem Datenaufkommen kann die Sampling-Rate reduziert werden, um die Serverbelastung zu verringern:
```php
$config = new AnalyticsConfig(
enabled: true,
samplingRate: 0.01, // Nur 1% der Daten erfassen
// ... weitere Optionen
);
```
### Pufferoptimierung
Die Puffergröße kann angepasst werden, um die Anzahl der Schreibvorgänge zu optimieren:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
bufferSize: 10000, // Größerer Puffer für weniger Schreibvorgänge
// ... weitere Optionen
);
```
### Selektives Tracking
Nicht alle Tracking-Typen müssen aktiviert sein. Deaktivieren Sie die Typen, die Sie nicht benötigen:
```php
$config = new AnalyticsConfig(
// ... vorherige Optionen
trackPageViews: true,
trackApiCalls: true,
trackUserActions: false, // Benutzeraktionen deaktivieren
trackErrors: true,
trackPerformance: false // Leistungsmetriken deaktivieren
);
```
## Fehlerbehebung
### Häufige Probleme
#### Keine Daten werden erfasst
Mögliche Ursachen:
- Analytics ist deaktiviert (`enabled = false`)
- Sampling-Rate ist zu niedrig
- Fehler beim Speichern der Daten
Lösung:
- Überprüfen Sie die Konfiguration
- Erhöhen Sie die Sampling-Rate
- Überprüfen Sie die Logs auf Fehler
- Stellen Sie sicher, dass der Datenpfad existiert und beschreibbar ist
```php
// Überprüfen Sie die Konfiguration
var_dump($analyticsConfig);
// Erhöhen Sie die Sampling-Rate
$newConfig = new AnalyticsConfig(
enabled: true,
samplingRate: 1.0, // 100% der Daten erfassen
// ... weitere Optionen
);
// Überprüfen Sie die Berechtigungen des Datenpfads
if (!is_writable($analyticsConfig->dataPath)) {
echo "Datenpfad ist nicht beschreibbar: " . $analyticsConfig->dataPath;
}
```
#### Hohe Serverbelastung
Mögliche Ursachen:
- Zu viele Ereignisse werden erfasst
- Puffergröße ist zu klein
- Synchrone Verarbeitung bei hohem Datenaufkommen
Lösung:
- Reduzieren Sie die Sampling-Rate
- Erhöhen Sie die Puffergröße
- Verwenden Sie asynchrone Verarbeitung
```php
// Reduzieren Sie die Sampling-Rate
$newConfig = new AnalyticsConfig(
enabled: true,
samplingRate: 0.1, // Nur 10% der Daten erfassen
// ... weitere Optionen
);
// Erhöhen Sie die Puffergröße
$newConfig = new AnalyticsConfig(
// ... vorherige Optionen
bufferSize: 10000, // Größerer Puffer
// ... weitere Optionen
);
```
## Weiterführende Informationen
- [Analytics Framework Übersicht](index.md)
- [Analytics Beispiele](examples.md)
- [Performance-Monitoring](/components/performance/index.md)

View File

@@ -0,0 +1,760 @@
# Analytics Framework Beispiele
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Analytics Frameworks korrekt dar.
## Übersicht
Diese Dokumentation enthält praktische Beispiele für die Verwendung des Analytics Frameworks in verschiedenen Szenarien. Die Beispiele zeigen, wie Sie Analytics-Daten erfassen, analysieren und in Ihre Anwendung integrieren können.
## Grundlegende Verwendung
### Benutzeraktionen erfassen
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
class UserController
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector
) {}
public function handleLogin(Request $request): Response
{
// Login-Logik
$success = $this->authService->login($request->getParam('email'), $request->getParam('password'));
// Login-Aktion erfassen
$this->analyticsCollector->trackAction(
'user_login',
AnalyticsCategory::USER,
[
'success' => $success,
'email_domain' => explode('@', $request->getParam('email'))[1] ?? 'unknown',
'ip' => $request->getClientIp(),
'user_agent' => $request->getUserAgent()
]
);
// Antwort zurückgeben
return $success
? $this->redirect('/dashboard')
: $this->renderForm('login', ['error' => 'Ungültige Anmeldedaten']);
}
}
```
### Seitenaufrufe erfassen
```php
use App\Framework\Analytics\AnalyticsCollector;
class ProductController
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly ProductRepository $productRepository
) {}
public function showProduct(Request $request, string $productId): Response
{
$product = $this->productRepository->find($productId);
if (!$product) {
return $this->notFound();
}
// Seitenaufruf erfassen
$this->analyticsCollector->trackPageView(
"/products/{$productId}",
[
'product_id' => $productId,
'product_name' => $product->name,
'product_category' => $product->category,
'referrer' => $request->getHeader('Referer'),
'user_id' => $this->session->get('user_id')
]
);
return $this->render('product', ['product' => $product]);
}
}
```
### Fehler erfassen
```php
use App\Framework\Analytics\AnalyticsCollector;
class ErrorHandler
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly Logger $logger
) {}
public function handleException(\Throwable $exception): Response
{
// Fehler loggen
$this->logger->error('Unbehandelte Ausnahme: ' . $exception->getMessage(), [
'exception' => $exception
]);
// Fehler für Analytics erfassen
$this->analyticsCollector->trackError(
get_class($exception),
[
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
'request_uri' => $_SERVER['REQUEST_URI'] ?? null,
'user_id' => $this->session->get('user_id')
]
);
// Fehlerseite anzeigen
return new Response(500, [], 'Ein Fehler ist aufgetreten');
}
}
```
### Geschäftsereignisse erfassen
```php
use App\Framework\Analytics\AnalyticsCollector;
class OrderService
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly OrderRepository $orderRepository
) {}
public function placeOrder(Order $order): bool
{
// Bestellung speichern
$success = $this->orderRepository->save($order);
if ($success) {
// Geschäftsereignis erfassen
$this->analyticsCollector->trackBusinessEvent(
'order_placed',
[
'order_id' => $order->id,
'user_id' => $order->userId,
'total_amount' => $order->totalAmount,
'items_count' => count($order->items),
'payment_method' => $order->paymentMethod,
'shipping_country' => $order->shippingAddress->country
]
);
}
return $success;
}
}
```
### API-Aufrufe erfassen
```php
use App\Framework\Analytics\AnalyticsCollector;
class ApiClient
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly HttpClient $httpClient
) {}
public function sendRequest(string $endpoint, string $method, array $data = []): Response
{
$startTime = microtime(true);
try {
$response = $this->httpClient->request($method, $endpoint, $data);
$statusCode = $response->getStatusCode();
$success = $statusCode >= 200 && $statusCode < 300;
} catch (\Exception $e) {
$statusCode = 0;
$success = false;
}
$duration = (microtime(true) - $startTime) * 1000; // in ms
// API-Aufruf erfassen
$this->analyticsCollector->trackApiCall(
$endpoint,
$method,
$statusCode,
[
'duration' => $duration,
'success' => $success,
'data_size' => strlen(json_encode($data)),
'user_id' => $this->session->get('user_id')
]
);
return $response;
}
}
```
## Fortgeschrittene Verwendung
### Automatische Erfassung mit Middleware
Die `AnalyticsMiddleware` erfasst automatisch Seitenaufrufe und API-Aufrufe:
```php
use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(AnalyticsMiddleware::class);
```
Anpassung der Middleware für bestimmte Routen:
```php
use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\Next;
class CustomAnalyticsMiddleware extends AnalyticsMiddleware
{
public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
{
$request = $context->request;
// Bestimmte Routen ausschließen
if (str_starts_with($request->path, '/api/health') || str_starts_with($request->path, '/static/')) {
return $next($context);
}
// Zusätzliche Daten für bestimmte Routen hinzufügen
$additionalData = [];
if (str_starts_with($request->path, '/products/')) {
$productId = substr($request->path, 10);
$additionalData['product_id'] = $productId;
}
// Standardverhalten mit zusätzlichen Daten
return parent::__invoke($context, $next, $additionalData);
}
}
```
### Sicherheitsereignisse erfassen
Integration mit dem Security-System:
```php
use App\Framework\Analytics\Listeners\SecurityAnalyticsListener;
use App\Framework\Analytics\Bridges\SecurityEventBridge;
use App\Framework\Security\Events\LoginAttemptEvent;
// In der Bootstrap-Datei
$securityEventBridge = SecurityEventBridge::create(
$container->get(SecurityAnalyticsListener::class),
$config->securityAnalyticsEnabled
);
$eventDispatcher->addListener(LoginAttemptEvent::class, [$securityEventBridge, 'handleSecurityEvent']);
```
Benutzerdefinierter Security-Event-Listener:
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
use App\Framework\Security\Events\LoginAttemptEvent;
class LoginAnalyticsListener
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector
) {}
public function onLoginAttempt(LoginAttemptEvent $event): void
{
$this->analyticsCollector->trackAction(
'login_attempt',
AnalyticsCategory::SECURITY,
[
'username' => $event->getUsername(),
'success' => $event->isSuccessful(),
'ip' => $event->getIp(),
'user_agent' => $event->getUserAgent(),
'timestamp' => $event->getTimestamp()->format('Y-m-d H:i:s')
]
);
}
}
```
### Asynchrone Datenerfassung
Für maximale Leistung kann die Analytics-Datenerfassung asynchron erfolgen:
```php
use App\Framework\Analytics\AsyncAnalyticsCollector;
use App\Framework\Queue\QueueInterface;
class AsyncAnalyticsService
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly QueueInterface $queue
) {}
public function initialize(): void
{
// Asynchronen Collector erstellen
$asyncCollector = new AsyncAnalyticsCollector(
$this->analyticsCollector,
$this->queue
);
// Asynchronen Collector registrieren
$this->container->set(AnalyticsCollector::class, $asyncCollector);
}
}
```
### Benutzerdefinierte Ereignistypen
Sie können benutzerdefinierte Ereignistypen für spezifische Anforderungen erstellen:
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
class CustomAnalyticsService
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector
) {}
public function trackProductView(string $productId, string $productName, string $category): void
{
$this->analyticsCollector->trackAction(
'product_view',
AnalyticsCategory::BUSINESS,
[
'product_id' => $productId,
'product_name' => $productName,
'category' => $category,
'timestamp' => time(),
'user_id' => $this->session->get('user_id')
]
);
}
public function trackAddToCart(string $productId, int $quantity, float $price): void
{
$this->analyticsCollector->trackAction(
'add_to_cart',
AnalyticsCategory::BUSINESS,
[
'product_id' => $productId,
'quantity' => $quantity,
'price' => $price,
'total' => $quantity * $price,
'timestamp' => time(),
'user_id' => $this->session->get('user_id')
]
);
}
}
```
## Datenanalyse
### Rohdaten abfragen
```php
use App\Framework\Analytics\Storage\AnalyticsStorage;
class AnalyticsReportService
{
public function __construct(
private readonly AnalyticsStorage $analyticsStorage
) {}
public function getPageViewsReport(\DateTimeInterface $from, \DateTimeInterface $to): array
{
// Rohdaten für Seitenaufrufe abrufen
$pageViews = $this->analyticsStorage->getRawData(
'page_view',
$from,
$to
);
// Daten nach Seite gruppieren
$pageViewsByPath = [];
foreach ($pageViews as $pageView) {
$path = $pageView['path'] ?? 'unknown';
if (!isset($pageViewsByPath[$path])) {
$pageViewsByPath[$path] = 0;
}
$pageViewsByPath[$path]++;
}
// Nach Anzahl sortieren
arsort($pageViewsByPath);
return $pageViewsByPath;
}
public function getUserActivityReport(string $userId, \DateTimeInterface $from, \DateTimeInterface $to): array
{
// Alle Aktionen für einen bestimmten Benutzer abrufen
$actions = $this->analyticsStorage->getRawData(
'user_action',
$from,
$to,
['user_id' => $userId]
);
// Nach Zeitstempel sortieren
usort($actions, function ($a, $b) {
return $a['timestamp'] <=> $b['timestamp'];
});
return $actions;
}
}
```
### Aggregierte Daten abfragen
```php
use App\Framework\Analytics\Storage\AnalyticsStorage;
class PerformanceReportService
{
public function __construct(
private readonly AnalyticsStorage $analyticsStorage
) {}
public function getApiPerformanceReport(\DateTimeInterface $from, \DateTimeInterface $to): array
{
// Aggregierte Daten für API-Aufrufe abrufen
$apiCallStats = $this->analyticsStorage->getAggregatedData(
'analytics_api_calls_total',
$from,
$to
);
// Durchschnittliche Antwortzeit pro Endpunkt berechnen
$responseTimeByEndpoint = [];
foreach ($apiCallStats as $stat) {
$endpoint = $stat['tags']['path'] ?? 'unknown';
$method = $stat['tags']['method'] ?? 'unknown';
$key = "{$method} {$endpoint}";
if (!isset($responseTimeByEndpoint[$key])) {
$responseTimeByEndpoint[$key] = [
'count' => 0,
'total_time' => 0,
'min_time' => PHP_FLOAT_MAX,
'max_time' => 0,
];
}
$duration = $stat['tags']['duration'] ?? 0;
$responseTimeByEndpoint[$key]['count']++;
$responseTimeByEndpoint[$key]['total_time'] += $duration;
$responseTimeByEndpoint[$key]['min_time'] = min($responseTimeByEndpoint[$key]['min_time'], $duration);
$responseTimeByEndpoint[$key]['max_time'] = max($responseTimeByEndpoint[$key]['max_time'], $duration);
}
// Durchschnitt berechnen
foreach ($responseTimeByEndpoint as $key => $data) {
$responseTimeByEndpoint[$key]['avg_time'] = $data['total_time'] / $data['count'];
}
// Nach durchschnittlicher Antwortzeit sortieren
uasort($responseTimeByEndpoint, function ($a, $b) {
return $b['avg_time'] <=> $a['avg_time'];
});
return $responseTimeByEndpoint;
}
}
```
### Dashboard-Integration
```php
use App\Framework\Analytics\Dashboard\AnalyticsDashboard;
class AdminController
{
public function __construct(
private readonly AnalyticsDashboard $dashboard,
private readonly TemplateEngine $templateEngine
) {}
public function showDashboard(Request $request): Response
{
// Zeitraum aus Anfrage oder Standardwerte
$from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
$to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
// Dashboard-Daten abrufen
$stats = $this->dashboard->getStats($from, $to);
// Spezifische Statistiken abrufen
$pageViewStats = $this->dashboard->getPageViewStats($from, $to);
$errorStats = $this->dashboard->getErrorStats($from, $to);
$performanceStats = $this->dashboard->getPerformanceStats($from, $to);
$businessStats = $this->dashboard->getBusinessStats($from, $to);
// Dashboard rendern
return $this->templateEngine->render('admin/dashboard', [
'stats' => $stats,
'pageViewStats' => $pageViewStats,
'errorStats' => $errorStats,
'performanceStats' => $performanceStats,
'businessStats' => $businessStats,
'from' => $from,
'to' => $to
]);
}
}
```
## Datenexport
### CSV-Export
```php
use App\Framework\Analytics\Export\AnalyticsExporter;
class ExportController
{
public function __construct(
private readonly AnalyticsExporter $exporter
) {}
public function exportPageViews(Request $request): Response
{
// Zeitraum aus Anfrage
$from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
$to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
// Daten exportieren
$csvData = $this->exporter->exportToCsv(
'page_view',
$from,
$to
);
// CSV-Datei zurückgeben
return new Response(
200,
[
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="page_views.csv"'
],
$csvData
);
}
}
```
### JSON-Export
```php
use App\Framework\Analytics\Export\AnalyticsExporter;
class ApiController
{
public function __construct(
private readonly AnalyticsExporter $exporter
) {}
public function getAnalyticsData(Request $request): Response
{
// Parameter aus Anfrage
$eventType = $request->getQueryParam('type', 'page_view');
$from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
$to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
// Daten exportieren
$data = $this->exporter->exportToArray(
$eventType,
$from,
$to
);
// JSON-Daten zurückgeben
return new Response(
200,
['Content-Type' => 'application/json'],
json_encode($data)
);
}
}
```
## Integration mit anderen Systemen
### Event-System-Integration
```php
use App\Framework\Analytics\EventSubscribers\AnalyticsEventSubscriber;
use App\Framework\EventDispatcher\EventDispatcherInterface;
class AnalyticsBootstrap
{
public function initialize(EventDispatcherInterface $eventDispatcher): void
{
// Analytics-Event-Subscriber registrieren
$eventDispatcher->addSubscriber(new AnalyticsEventSubscriber(
$this->container->get(AnalyticsCollector::class)
));
}
}
```
### Externe Analytics-Integration
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
class ExternalAnalyticsService
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector,
private readonly ExternalAnalyticsClient $externalClient
) {}
public function trackEvent(string $eventName, array $properties): void
{
// Intern erfassen
$this->analyticsCollector->trackAction(
$eventName,
AnalyticsCategory::BUSINESS,
$properties
);
// An externes System senden
$this->externalClient->trackEvent($eventName, $properties);
}
public function syncData(\DateTimeInterface $from, \DateTimeInterface $to): void
{
// Daten aus internem Analytics abrufen
$internalData = $this->analyticsStorage->getRawData('*', $from, $to);
// Daten an externes System senden
$this->externalClient->batchImport($internalData);
}
}
```
## Fehlerbehebung
### Debugging der Datenerfassung
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
class DebugAnalyticsCollector extends AnalyticsCollector
{
public function trackAction(string $action, AnalyticsCategory $category, array $data = []): void
{
// Debug-Ausgabe
echo "Tracking action: {$action}, category: {$category->value}\n";
echo "Data: " . json_encode($data, JSON_PRETTY_PRINT) . "\n";
// Original-Methode aufrufen
parent::trackAction($action, $category, $data);
}
public function trackPageView(string $path, array $data = []): void
{
// Debug-Ausgabe
echo "Tracking page view: {$path}\n";
echo "Data: " . json_encode($data, JSON_PRETTY_PRINT) . "\n";
// Original-Methode aufrufen
parent::trackPageView($path, $data);
}
}
```
### Überprüfung der Datenspeicherung
```php
use App\Framework\Analytics\Storage\AnalyticsStorage;
class AnalyticsDebugService
{
public function __construct(
private readonly AnalyticsStorage $analyticsStorage,
private readonly string $dataPath
) {}
public function checkStorage(): array
{
$result = [
'status' => 'ok',
'messages' => [],
'files' => []
];
// Prüfen, ob der Datenpfad existiert
if (!is_dir($this->dataPath)) {
$result['status'] = 'error';
$result['messages'][] = "Datenpfad existiert nicht: {$this->dataPath}";
return $result;
}
// Prüfen, ob der Datenpfad beschreibbar ist
if (!is_writable($this->dataPath)) {
$result['status'] = 'error';
$result['messages'][] = "Datenpfad ist nicht beschreibbar: {$this->dataPath}";
return $result;
}
// Dateien im Datenpfad auflisten
$files = glob($this->dataPath . '/*.json');
foreach ($files as $file) {
$size = filesize($file);
$modified = date('Y-m-d H:i:s', filemtime($file));
$result['files'][] = [
'name' => basename($file),
'size' => $size,
'modified' => $modified
];
}
// Testdaten speichern
try {
$this->analyticsStorage->storeRawData('debug_test', [
'timestamp' => time(),
'message' => 'Debug test'
]);
$result['messages'][] = "Testdaten erfolgreich gespeichert";
} catch (\Exception $e) {
$result['status'] = 'error';
$result['messages'][] = "Fehler beim Speichern von Testdaten: " . $e->getMessage();
}
return $result;
}
}
```
## Weiterführende Informationen
- [Analytics Framework Übersicht](index.md)
- [Analytics Konfiguration](configuration.md)
- [Performance-Monitoring](/components/performance/index.md)

View File

@@ -0,0 +1,507 @@
# Analytics Framework
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Analytics Frameworks korrekt dar.
## Übersicht
Das Analytics Framework ist ein leistungsstarkes System zur Erfassung, Speicherung und Analyse von Daten über die Nutzung und Leistung Ihrer Anwendung. Es ist vollständig in das Framework integriert und ermöglicht die Erfassung verschiedener Arten von Ereignissen, darunter Seitenaufrufe, Benutzeraktionen, API-Aufrufe, Fehler und Geschäftsereignisse.
Das Framework basiert auf dem Performance-System und bietet eine flexible, erweiterbare Architektur für verschiedene Analyseanforderungen, ohne auf externe Dienste angewiesen zu sein.
## Hauptkomponenten
### AnalyticsCollector
Die zentrale Klasse für die Erfassung von Analytics-Daten:
```php
use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
// Benutzeraktion erfassen
$analyticsCollector->trackAction(
'button_click',
AnalyticsCategory::USER,
['button_id' => 'submit', 'page' => '/checkout']
);
// Seitenaufruf erfassen
$analyticsCollector->trackPageView(
'/products',
['referrer' => '/home', 'user_id' => $userId]
);
// Fehler erfassen
$analyticsCollector->trackError(
'validation_error',
['field' => 'email', 'message' => 'Invalid email format']
);
// Geschäftsereignis erfassen
$analyticsCollector->trackBusinessEvent(
'order_completed',
['order_id' => '12345', 'amount' => 99.99, 'items' => 3]
);
// API-Aufruf erfassen
$analyticsCollector->trackApiCall(
'/api/products',
'GET',
200,
['duration' => 45, 'cache_hit' => true]
);
```
### AnalyticsCategory
Ein Enum, das die verschiedenen Kategorien von Analytics-Daten definiert:
```php
use App\Framework\Analytics\AnalyticsCategory;
// Verfügbare Kategorien
$category = AnalyticsCategory::USER; // Benutzeraktionen
$category = AnalyticsCategory::SYSTEM; // Systemereignisse
$category = AnalyticsCategory::BUSINESS; // Geschäftsereignisse
$category = AnalyticsCategory::PERFORMANCE; // Leistungsmetriken
$category = AnalyticsCategory::SECURITY; // Sicherheitsereignisse
```
### AnalyticsStorage
Das Interface für die Speicherung von Analytics-Daten:
```php
use App\Framework\Analytics\Storage\AnalyticsStorage;
interface AnalyticsStorage
{
// Rohdaten speichern
public function storeRawData(string $eventType, array $data): void;
// Aggregierte Daten speichern
public function storeAggregatedData(string $metricName, float $value, array $tags = []): void;
// Rohdaten abrufen
public function getRawData(string $eventType, \DateTimeInterface $from, \DateTimeInterface $to): array;
// Aggregierte Daten abrufen
public function getAggregatedData(string $metricName, \DateTimeInterface $from, \DateTimeInterface $to, array $tags = []): array;
}
```
Das Framework bietet eine leistungsoptimierte Implementierung:
```php
use App\Framework\Analytics\Storage\PerformanceBasedAnalyticsStorage;
// Leistungsoptimierte Speicherung
$storage = new PerformanceBasedAnalyticsStorage(
$filesystem,
$performanceSystem,
$clock,
$config
);
```
### AnalyticsMiddleware
Eine Middleware, die automatisch Analytics-Daten für HTTP-Anfragen erfasst:
```php
use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(AnalyticsMiddleware::class);
```
Die Middleware erfasst automatisch:
- Seitenaufrufe
- API-Aufrufe
- Leistungsmetriken (Antwortzeit, Speicherverbrauch)
- HTTP-Statuscodes
- Benutzeragenten und Referrer
### SecurityAnalyticsListener
Ein Listener, der Sicherheitsereignisse in Analytics-Daten umwandelt:
```php
use App\Framework\Analytics\Listeners\SecurityAnalyticsListener;
use App\Framework\Analytics\Bridges\SecurityEventBridge;
// In der Bootstrap-Datei
$securityEventBridge = SecurityEventBridge::create(
$container->get(SecurityAnalyticsListener::class),
$config->securityAnalyticsEnabled
);
$eventDispatcher->addListener(SecurityEventInterface::class, [$securityEventBridge, 'handleSecurityEvent']);
```
## Datenerfassung
### Benutzeraktionen
Benutzeraktionen repräsentieren Interaktionen des Benutzers mit der Anwendung:
```php
$analyticsCollector->trackAction(
'button_click', // Aktionsname
AnalyticsCategory::USER, // Kategorie
[ // Zusätzliche Daten
'button_id' => 'submit',
'page' => '/checkout',
'user_id' => $userId
]
);
```
### Seitenaufrufe
Seitenaufrufe repräsentieren den Besuch einer Seite durch einen Benutzer:
```php
$analyticsCollector->trackPageView(
'/products', // Pfad
[ // Zusätzliche Daten
'referrer' => '/home',
'user_id' => $userId,
'device_type' => 'mobile'
]
);
```
### Fehler
Fehler repräsentieren Probleme, die während der Ausführung der Anwendung auftreten:
```php
$analyticsCollector->trackError(
'validation_error', // Fehlertyp
[ // Zusätzliche Daten
'field' => 'email',
'message' => 'Invalid email format',
'user_id' => $userId
]
);
// Oder mit einer Exception
try {
// Code, der eine Exception werfen könnte
} catch (\Exception $e) {
$analyticsCollector->trackException($e);
}
```
### Geschäftsereignisse
Geschäftsereignisse repräsentieren wichtige Ereignisse aus geschäftlicher Sicht:
```php
$analyticsCollector->trackBusinessEvent(
'order_completed', // Ereignisname
[ // Zusätzliche Daten
'order_id' => '12345',
'amount' => 99.99,
'items' => 3,
'user_id' => $userId
]
);
```
### API-Aufrufe
API-Aufrufe repräsentieren Anfragen an die API der Anwendung:
```php
$analyticsCollector->trackApiCall(
'/api/products', // Pfad
'GET', // Methode
200, // Statuscode
[ // Zusätzliche Daten
'duration' => 45,
'cache_hit' => true,
'user_id' => $userId
]
);
```
## Konfiguration
### AnalyticsConfig
Die `AnalyticsConfig`-Klasse enthält die Konfiguration für das Analytics Framework:
```php
use App\Framework\Analytics\AnalyticsConfig;
// Standardkonfiguration
$config = AnalyticsConfig::default();
// Benutzerdefinierte Konfiguration
$config = new AnalyticsConfig(
$enabled = true,
$samplingRate = 1.0,
$securityAnalyticsEnabled = true,
$dataPath = '/var/www/html/storage/analytics',
$bufferSize = 1000,
$retentionDays = 365,
$trackPageViews = true,
$trackApiCalls = true,
$trackUserActions = true,
$trackErrors = true,
$trackPerformance = true
);
```
### Umgebungsvariablen
Die Konfiguration kann auch über Umgebungsvariablen angepasst werden:
```
ANALYTICS_ENABLED=true
ANALYTICS_SAMPLING_RATE=0.1
SECURITY_ANALYTICS_ENABLED=true
ANALYTICS_DATA_PATH=/var/www/html/storage/analytics
ANALYTICS_BUFFER_SIZE=1000
ANALYTICS_RETENTION_DAYS=365
ANALYTICS_TRACK_PAGE_VIEWS=true
ANALYTICS_TRACK_API_CALLS=true
ANALYTICS_TRACK_USER_ACTIONS=true
ANALYTICS_TRACK_ERRORS=true
ANALYTICS_TRACK_PERFORMANCE=true
```
## Datenanalyse
### Rohdaten abrufen
```php
// Rohdaten für Seitenaufrufe abrufen
$pageViews = $analyticsStorage->getRawData(
'page_view',
new \DateTimeImmutable('-7 days'),
new \DateTimeImmutable()
);
// Rohdaten für Geschäftsereignisse abrufen
$orders = $analyticsStorage->getRawData(
'business_event_order_completed',
new \DateTimeImmutable('-30 days'),
new \DateTimeImmutable()
);
```
### Aggregierte Daten abrufen
```php
// Aggregierte Daten für Seitenaufrufe abrufen
$pageViewStats = $analyticsStorage->getAggregatedData(
'analytics_page_views_total',
new \DateTimeImmutable('-7 days'),
new \DateTimeImmutable(),
['path' => '/products']
);
// Aggregierte Daten für API-Aufrufe abrufen
$apiCallStats = $analyticsStorage->getAggregatedData(
'analytics_api_calls_total',
new \DateTimeImmutable('-7 days'),
new \DateTimeImmutable(),
['path' => '/api/products', 'method' => 'GET']
);
```
### Dashboard
Das Analytics-Dashboard bietet eine visuelle Darstellung der erfassten Daten:
```php
use App\Framework\Analytics\Dashboard\AnalyticsDashboard;
// Dashboard initialisieren
$dashboard = new AnalyticsDashboard($analyticsStorage);
// Statistiken abrufen
$stats = $dashboard->getStats(
new \DateTimeImmutable('-7 days'),
new \DateTimeImmutable()
);
// Spezifische Statistiken abrufen
$pageViewStats = $dashboard->getPageViewStats();
$errorStats = $dashboard->getErrorStats();
$performanceStats = $dashboard->getPerformanceStats();
$businessStats = $dashboard->getBusinessStats();
```
## Integration
### Service-Container
Der Analytics-Service wird automatisch registriert und kann per Dependency Injection verwendet werden:
```php
use App\Framework\Analytics\AnalyticsCollector;
class UserController
{
public function __construct(
private readonly AnalyticsCollector $analyticsCollector
) {}
public function register(Request $request): Response
{
// Benutzerregistrierung verarbeiten
// Geschäftsereignis erfassen
$this->analyticsCollector->trackBusinessEvent(
'user_registered',
['user_id' => $user->id, 'email_domain' => $emailDomain]
);
return $response;
}
}
```
### Event-Integration
Das Analytics Framework kann mit dem Event-System des Frameworks integriert werden:
```php
use App\Framework\Analytics\EventSubscribers\AnalyticsEventSubscriber;
// In der Bootstrap-Datei
$eventDispatcher->addSubscriber(new AnalyticsEventSubscriber($analyticsCollector));
```
## Leistungsoptimierung
### Sampling
Um die Leistung bei hohem Datenaufkommen zu verbessern, unterstützt das Analytics Framework Sampling:
```php
// Sampling-Rate konfigurieren (10% der Daten erfassen)
$config = new AnalyticsConfig(
$enabled = true,
$samplingRate = 0.1
);
```
### Pufferung
Das Analytics Framework verwendet Pufferung, um die Anzahl der Schreibvorgänge zu reduzieren:
```php
// Puffergröße konfigurieren
$config = new AnalyticsConfig(
$enabled = true,
$samplingRate = 1.0,
$securityAnalyticsEnabled = true,
$dataPath = '/var/www/html/storage/analytics',
$bufferSize = 1000 // Anzahl der Ereignisse im Puffer
);
```
### Asynchrone Verarbeitung
Für maximale Leistung kann die Analytics-Verarbeitung asynchron erfolgen:
```php
use App\Framework\Analytics\AsyncAnalyticsCollector;
// Asynchronen Collector verwenden
$asyncCollector = new AsyncAnalyticsCollector(
$analyticsCollector,
$queue
);
// Daten asynchron erfassen
$asyncCollector->trackPageView('/products');
```
## Datenverwaltung
### Datenaufbewahrung
Das Analytics Framework unterstützt automatische Datenaufbewahrungsrichtlinien:
```php
// Aufbewahrungsdauer konfigurieren
$config = new AnalyticsConfig(
$enabled = true,
$samplingRate = 1.0,
$securityAnalyticsEnabled = true,
$dataPath = '/var/www/html/storage/analytics',
$bufferSize = 1000,
$retentionDays = 365 // Daten für 1 Jahr aufbewahren
);
```
### Datenexport
Daten können für die weitere Analyse exportiert werden:
```php
use App\Framework\Analytics\Export\AnalyticsExporter;
// Exporter initialisieren
$exporter = new AnalyticsExporter($analyticsStorage);
// Daten exportieren
$csvData = $exporter->exportToCsv(
'page_view',
new \DateTimeImmutable('-7 days'),
new \DateTimeImmutable()
);
// Daten in Datei speichern
file_put_contents('page_views.csv', $csvData);
```
## Fehlerbehebung
### Logging
Das Analytics Framework bietet umfangreiches Logging für die Fehlerbehebung:
```php
// In der AnalyticsCollector-Klasse
$this->logger->info("Analytics: trackAction called with action={$action}, category={$category->value}");
$this->logger->error("Analytics: Failed to store data", ['error' => $e->getMessage()]);
```
### Häufige Probleme
#### Keine Daten werden erfasst
Mögliche Ursachen:
- Analytics ist deaktiviert (`enabled = false`)
- Sampling-Rate ist zu niedrig
- Fehler beim Speichern der Daten
Lösung:
- Überprüfen Sie die Konfiguration
- Erhöhen Sie die Sampling-Rate
- Überprüfen Sie die Logs auf Fehler
#### Hohe Serverbelastung
Mögliche Ursachen:
- Zu viele Ereignisse werden erfasst
- Puffergröße ist zu klein
- Synchrone Verarbeitung bei hohem Datenaufkommen
Lösung:
- Reduzieren Sie die Sampling-Rate
- Erhöhen Sie die Puffergröße
- Verwenden Sie asynchrone Verarbeitung
## Weiterführende Informationen
- [Analytics Konfiguration](configuration.md)
- [Analytics Beispiele](examples.md)
- [Performance-Monitoring](/components/performance/index.md)

View File

@@ -0,0 +1,430 @@
# Auth Module Configuration
**Konfiguration und Setup** für das Auth Module des Custom PHP Frameworks.
## Dependency Injection Setup
### Container Bindings
```php
use App\Framework\Auth\PasswordHasher;
use App\Framework\Auth\AuthenticationService;
use App\Framework\Cryptography\KeyDerivationFunction;
// services.php oder Container Initialization
$container->singleton(PasswordHasher::class, function(Container $container) {
return new PasswordHasher(
kdf: $container->get(KeyDerivationFunction::class),
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);
});
$container->singleton(AuthenticationService::class, function(Container $container) {
return new AuthenticationService(
passwordHasher: $container->get(PasswordHasher::class),
sessionIdGenerator: $container->get(SessionIdGenerator::class),
repository: $container->get(AuthenticationRepository::class),
rateLimiter: $container->get(RateLimitService::class)
);
});
```
### Environment Configuration
```php
// .env Konfiguration
AUTH_SESSION_TIMEOUT=3600 # Session Timeout in Sekunden (1 Stunde)
AUTH_REMEMBER_TOKEN_EXPIRY=2592000 # Remember Token Expiry (30 Tage)
AUTH_MAX_LOGIN_ATTEMPTS=5 # Maximale Login-Versuche
AUTH_LOCKOUT_DURATION=900 # Account Lockout Duration (15 Minuten)
AUTH_RATE_LIMIT_WINDOW=300 # Rate Limit Window (5 Minuten)
# Password Hashing Configuration
AUTH_DEFAULT_ALGORITHM=argon2id # Standard Hash-Algorithmus
AUTH_DEFAULT_SECURITY_LEVEL=standard # low|standard|high
AUTH_PASSWORD_MIN_LENGTH=8 # Minimale Passwort-Länge
AUTH_PASSWORD_MAX_LENGTH=4096 # Maximale Passwort-Länge
# Session Security
AUTH_SESSION_REGENERATE_ON_LOGIN=true # Session ID bei Login regenerieren
AUTH_CHECK_IP_CONSISTENCY=false # IP-Konsistenz-Prüfung (optional)
AUTH_REMEMBER_TOKEN_LENGTH=32 # Remember Token Länge (Bytes)
```
### Typed Configuration Class
```php
final readonly class AuthConfig
{
public function __construct(
// Session Configuration
public int $sessionTimeout = 3600,
public int $rememberTokenExpiry = 2592000,
public bool $sessionRegenerateOnLogin = true,
public bool $checkIpConsistency = false,
public int $rememberTokenLength = 32,
// Security Configuration
public int $maxLoginAttempts = 5,
public int $lockoutDuration = 900,
public int $rateLimitWindow = 300,
// Password Configuration
public string $defaultAlgorithm = 'argon2id',
public string $defaultSecurityLevel = 'standard',
public int $passwordMinLength = 8,
public int $passwordMaxLength = 4096,
// Validation Configuration
public bool $enforcePasswordComplexity = true,
public bool $checkCommonPasswords = true,
public bool $preventSequentialChars = true,
public int $minPasswordScore = 50
) {}
public static function fromEnvironment(Environment $env): self
{
return new self(
sessionTimeout: $env->getInt(EnvKey::AUTH_SESSION_TIMEOUT, 3600),
rememberTokenExpiry: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_EXPIRY, 2592000),
sessionRegenerateOnLogin: $env->getBool(EnvKey::AUTH_SESSION_REGENERATE_ON_LOGIN, true),
checkIpConsistency: $env->getBool(EnvKey::AUTH_CHECK_IP_CONSISTENCY, false),
rememberTokenLength: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_LENGTH, 32),
maxLoginAttempts: $env->getInt(EnvKey::AUTH_MAX_LOGIN_ATTEMPTS, 5),
lockoutDuration: $env->getInt(EnvKey::AUTH_LOCKOUT_DURATION, 900),
rateLimitWindow: $env->getInt(EnvKey::AUTH_RATE_LIMIT_WINDOW, 300),
defaultAlgorithm: $env->get(EnvKey::AUTH_DEFAULT_ALGORITHM, 'argon2id'),
defaultSecurityLevel: $env->get(EnvKey::AUTH_DEFAULT_SECURITY_LEVEL, 'standard'),
passwordMinLength: $env->getInt(EnvKey::AUTH_PASSWORD_MIN_LENGTH, 8),
passwordMaxLength: $env->getInt(EnvKey::AUTH_PASSWORD_MAX_LENGTH, 4096),
enforcePasswordComplexity: $env->getBool(EnvKey::AUTH_ENFORCE_PASSWORD_COMPLEXITY, true),
checkCommonPasswords: $env->getBool(EnvKey::AUTH_CHECK_COMMON_PASSWORDS, true),
preventSequentialChars: $env->getBool(EnvKey::AUTH_PREVENT_SEQUENTIAL_CHARS, true),
minPasswordScore: $env->getInt(EnvKey::AUTH_MIN_PASSWORD_SCORE, 50)
);
}
public function getSecurityLevelParameters(string $algorithm): array
{
return match ([$algorithm, $this->defaultSecurityLevel]) {
['argon2id', 'low'] => [
'memory_cost' => 32768, // 32 MB
'time_cost' => 2,
'threads' => 2
],
['argon2id', 'standard'] => [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4,
'threads' => 3
],
['argon2id', 'high'] => [
'memory_cost' => 131072, // 128 MB
'time_cost' => 6,
'threads' => 4
],
['pbkdf2-sha256', 'low'] => ['iterations' => 50000],
['pbkdf2-sha256', 'standard'] => ['iterations' => 100000],
['pbkdf2-sha256', 'high'] => ['iterations' => 200000],
default => []
};
}
}
```
## Database Schema
### Required Tables
```sql
-- Benutzer-Tabelle (beispielhaft)
CREATE TABLE users (
id VARCHAR(255) PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE,
password_hash TEXT NOT NULL,
password_algorithm VARCHAR(50) NOT NULL DEFAULT 'argon2id',
password_parameters JSON,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
last_login_at DATETIME NULL,
is_active BOOLEAN DEFAULT TRUE,
INDEX idx_email (email),
INDEX idx_username (username),
INDEX idx_active (is_active)
);
-- Session-Tabelle
CREATE TABLE auth_sessions (
id VARCHAR(255) PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
ip_address VARCHAR(45),
user_agent TEXT,
created_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL,
last_activity DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_expires_at (expires_at),
INDEX idx_last_activity (last_activity)
);
-- Remember Token Tabelle
CREATE TABLE auth_remember_tokens (
token_hash VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_expires_at (expires_at)
);
-- Failed Login Attempts Tabelle
CREATE TABLE auth_failed_attempts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(255),
identifier VARCHAR(255),
ip_address VARCHAR(45),
attempted_at DATETIME NOT NULL,
reason VARCHAR(100),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_identifier (identifier),
INDEX idx_ip_address (ip_address),
INDEX idx_attempted_at (attempted_at)
);
-- Security Events Tabelle (optional für Logging)
CREATE TABLE auth_security_events (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
event_type VARCHAR(50) NOT NULL,
user_id VARCHAR(255),
session_id VARCHAR(255),
ip_address VARCHAR(45),
user_agent TEXT,
event_data JSON,
created_at DATETIME NOT NULL,
INDEX idx_event_type (event_type),
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at),
INDEX idx_ip_address (ip_address)
);
```
### Migration Commands
```bash
# Migration erstellen
php console.php make:migration CreateAuthTables Auth
# Migration ausführen
php console.php db:migrate
# Migration Status prüfen
php console.php db:status
```
## Security Level Configuration
### Password Hashing Levels
```php
// Niedrige Sicherheit (Development, Testing)
$lowSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_LOW
);
// Standard Sicherheit (Production Default)
$standardSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);
// Hohe Sicherheit (Banking, Healthcare)
$highSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_HIGH
);
```
### Algorithm Performance Comparison
| Algorithm | Level | Memory | Time | Iterations | Performance | Security |
|-----------|-------|---------|------|------------|-------------|----------|
| Argon2ID | Low | 32 MB | 2 | - | Fast | Good |
| Argon2ID | Standard | 64 MB | 4 | - | Medium | Excellent |
| Argon2ID | High | 128 MB | 6 | - | Slow | Maximum |
| PBKDF2-SHA256 | Low | - | - | 50,000 | Fast | Good |
| PBKDF2-SHA256 | Standard | - | - | 100,000 | Fast | Good |
| PBKDF2-SHA256 | High | - | - | 200,000 | Medium | Good |
| Scrypt | Standard | 16 MB | - | - | Medium | Good |
## Rate Limiting Configuration
### Redis-based Rate Limiting
```php
use App\Framework\Auth\RateLimit\RedisRateLimitService;
$rateLimiter = new RedisRateLimitService(
redis: $redis,
config: new RateLimitConfig(
maxAttempts: 5,
windowSeconds: 300,
lockoutDuration: 900
)
);
```
### File-based Rate Limiting
```php
use App\Framework\Auth\RateLimit\FileRateLimitService;
$rateLimiter = new FileRateLimitService(
cacheDir: '/tmp/auth_rate_limits',
config: new RateLimitConfig(
maxAttempts: 5,
windowSeconds: 300,
lockoutDuration: 900,
cleanupInterval: 3600 // Cleanup alte Einträge jede Stunde
)
);
```
## Monitoring & Logging
### Security Event Configuration
```php
// Security Event Handler
final readonly class SecurityEventHandler
{
public function __construct(
private Logger $logger,
private ?AlertingService $alerting = null
) {}
public function handle(SecurityEvent $event): void
{
// Log alle Security Events
$this->logger->warning('Security Event', [
'event_type' => $event->getType(),
'user_id' => $event->getUserId(),
'ip_address' => (string) $event->getIpAddress(),
'data' => $event->getData()
]);
// Kritische Events alarmieren
if ($event->isCritical()) {
$this->alerting?->sendAlert($event);
}
}
}
```
### Performance Monitoring
```php
// Performance Metrics für Password Hashing
$start = microtime(true);
$hashedPassword = $passwordHasher->hash($password);
$hashTime = microtime(true) - $start;
$this->metrics->histogram('auth.password_hash_duration', $hashTime, [
'algorithm' => $hashedPassword->getAlgorithm(),
'security_level' => $securityLevel
]);
```
## Production Deployment
### Environment-specific Configuration
```php
// Production
AUTH_DEFAULT_SECURITY_LEVEL=high
AUTH_SESSION_TIMEOUT=1800 # 30 Minuten
AUTH_CHECK_IP_CONSISTENCY=true # Striktere IP-Prüfung
AUTH_MAX_LOGIN_ATTEMPTS=3 # Weniger Versuche
AUTH_LOCKOUT_DURATION=3600 # 1 Stunde Lockout
// Development
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=86400 # 24 Stunden
AUTH_CHECK_IP_CONSISTENCY=false
AUTH_MAX_LOGIN_ATTEMPTS=10
AUTH_LOCKOUT_DURATION=300 # 5 Minuten
// Testing
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=3600
AUTH_MAX_LOGIN_ATTEMPTS=5
AUTH_LOCKOUT_DURATION=60 # 1 Minute
```
### Security Headers Configuration
```php
// Middleware für Auth-bezogene Security Headers
final readonly class AuthSecurityHeadersMiddleware
{
public function handle(HttpRequest $request, callable $next): HttpResponse
{
$response = $next($request);
if ($request->getUri()->getPath() === '/login') {
$response = $response->withHeader('X-Frame-Options', 'DENY');
$response = $response->withHeader('X-Content-Type-Options', 'nosniff');
$response = $response->withHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
}
return $response;
}
}
```
## Backup & Recovery
### Session Cleanup
```bash
# Cron Job für Session Cleanup (täglich)
0 2 * * * php /path/to/console.php auth:cleanup-expired-sessions
# Manual Cleanup
php console.php auth:cleanup-expired-sessions
php console.php auth:cleanup-expired-tokens
```
### Data Retention
```php
// Cleanup Commands
final readonly class CleanupExpiredSessionsCommand
{
public function execute(): void
{
$expiredCount = $this->repository->deleteExpiredSessions();
$this->output->writeln("Deleted {$expiredCount} expired sessions");
$tokenCount = $this->repository->deleteExpiredRememberTokens();
$this->output->writeln("Deleted {$tokenCount} expired remember tokens");
$attemptCount = $this->repository->cleanupOldFailedAttempts(days: 30);
$this->output->writeln("Cleaned up {$attemptCount} old failed attempts");
}
}

View File

@@ -0,0 +1,797 @@
# Auth Module Examples
**Praktische Implementierungsbeispiele** für das Auth Module des Custom PHP Frameworks.
## Basic Authentication Flow
### User Registration
```php
use App\Framework\Auth\PasswordHasher;
use App\Framework\Auth\PasswordValidationResult;
final readonly class UserRegistrationService
{
public function __construct(
private PasswordHasher $passwordHasher,
private UserRepository $userRepository
) {}
public function register(
string $email,
#[SensitiveParameter] string $password,
string $username = null
): RegistrationResult {
// Validate password strength
$validation = $this->passwordHasher->validatePasswordStrength($password);
if (!$validation->isValid) {
return RegistrationResult::passwordValidationFailed($validation);
}
// Check if user exists
if ($this->userRepository->findByEmail($email)) {
return RegistrationResult::failed('User with this email already exists');
}
// Hash password
$hashedPassword = $this->passwordHasher->hash($password);
// Create user
$user = new User(
id: Uuid::generate(),
email: new Email($email),
username: $username,
hashedPassword: $hashedPassword,
createdAt: new \DateTimeImmutable()
);
$this->userRepository->save($user);
return RegistrationResult::success($user);
}
}
```
### Login Implementation
```php
use App\Framework\Auth\AuthenticationService;
use App\Framework\Http\IpAddress;
use App\Framework\Http\Session\SessionManager;
#[Route(path: '/login', method: Method::POST)]
final readonly class LoginController
{
public function __construct(
private AuthenticationService $authService,
private SessionManager $sessionManager
) {}
public function login(LoginRequest $request): JsonResult
{
$ipAddress = IpAddress::fromRequest();
$result = $this->authService->authenticate(
identifier: $request->email,
password: $request->password,
ipAddress: $ipAddress,
remember: $request->remember ?? false
);
if ($result->isSuccess()) {
$user = $result->getUser();
$session = $result->getSession();
// Store session in session manager
$this->sessionManager->start($session->getId());
$this->sessionManager->set('user_id', $user->getId());
$this->sessionManager->set('authenticated_at', time());
$responseData = [
'success' => true,
'user' => [
'id' => $user->getId(),
'email' => (string) $user->getEmail(),
'username' => $user->getUsername()
],
'session' => [
'id' => $session->getId()->toString(),
'expires_at' => $session->getExpiresAt()->format(\DateTimeInterface::ATOM)
]
];
// Add remember token to response if requested
if ($rememberToken = $result->getRememberToken()) {
$responseData['remember_token'] = $rememberToken->getPlainTextValue();
// Set secure HTTP-only cookie
setcookie(
'remember_token',
$rememberToken->getPlainTextValue(),
[
'expires' => $rememberToken->getExpiresAt()->getTimestamp(),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]
);
}
return new JsonResult($responseData);
}
// Handle different failure types
return match (true) {
$result->isRateLimited() => new JsonResult([
'success' => false,
'error' => 'Too many attempts',
'retry_after' => $result->getRetryAfter()
], 429),
$result->isAccountLocked() => new JsonResult([
'success' => false,
'error' => 'Account temporarily locked',
'locked_until' => $result->getLockoutExpiresAt()?->format(\DateTimeInterface::ATOM)
], 423),
default => new JsonResult([
'success' => false,
'error' => 'Invalid credentials'
], 401)
};
}
}
```
### Auto-Login with Remember Token
```php
#[Route(path: '/auth/check', method: Method::GET)]
final readonly class AuthCheckController
{
public function __construct(
private AuthenticationService $authService,
private SessionManager $sessionManager
) {}
public function check(HttpRequest $request): JsonResult
{
$sessionId = $this->sessionManager->getCurrentSessionId();
// Try session authentication first
if ($sessionId) {
$result = $this->authService->authenticateWithSession(
$sessionId,
IpAddress::fromRequest()
);
if ($result->isSuccess()) {
return new JsonResult([
'authenticated' => true,
'user' => $this->formatUser($result->getUser()),
'session' => $this->formatSession($result->getSession())
]);
}
}
// Try remember token authentication
$rememberToken = $request->getCookie('remember_token');
if ($rememberToken) {
$result = $this->authService->authenticateWithRememberToken(
$rememberToken,
IpAddress::fromRequest()
);
if ($result->isSuccess()) {
// Start new session
$session = $result->getSession();
$this->sessionManager->start($session->getId());
$this->sessionManager->set('user_id', $result->getUser()->getId());
// Update remember token cookie
$newRememberToken = $result->getRememberToken();
if ($newRememberToken) {
setcookie(
'remember_token',
$newRememberToken->getPlainTextValue(),
[
'expires' => $newRememberToken->getExpiresAt()->getTimestamp(),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]
);
}
return new JsonResult([
'authenticated' => true,
'user' => $this->formatUser($result->getUser()),
'session' => $this->formatSession($session)
]);
}
}
return new JsonResult(['authenticated' => false]);
}
private function formatUser(User $user): array
{
return [
'id' => $user->getId(),
'email' => (string) $user->getEmail(),
'username' => $user->getUsername(),
'last_login' => $user->getLastLoginAt()?->format(\DateTimeInterface::ATOM)
];
}
private function formatSession(AuthenticationSession $session): array
{
return [
'id' => $session->getId()->toString(),
'created_at' => $session->getCreatedAt()->format(\DateTimeInterface::ATOM),
'expires_at' => $session->getExpiresAt()->format(\DateTimeInterface::ATOM),
'last_activity' => $session->getLastActivity()->format(\DateTimeInterface::ATOM)
];
}
}
```
## Password Management
### Password Change
```php
#[Route(path: '/account/change-password', method: Method::POST)]
final readonly class ChangePasswordController
{
public function __construct(
private AuthenticationService $authService,
private SessionManager $sessionManager
) {}
public function changePassword(ChangePasswordRequest $request): JsonResult
{
$userId = $this->sessionManager->get('user_id');
if (!$userId) {
return new JsonResult(['error' => 'Not authenticated'], 401);
}
$result = $this->authService->changePassword(
userId: $userId,
currentPassword: $request->currentPassword,
newPassword: $request->newPassword
);
if ($result->isSuccess()) {
return new JsonResult([
'success' => true,
'message' => 'Password changed successfully'
]);
}
if ($result->hasValidationErrors()) {
return new JsonResult([
'success' => false,
'validation_errors' => $result->getValidation()->toArray()
], 400);
}
return new JsonResult([
'success' => false,
'error' => $result->getErrorMessage()
], 400);
}
}
```
### Password Reset Flow
```php
final readonly class PasswordResetService
{
public function __construct(
private PasswordHasher $passwordHasher,
private UserRepository $userRepository,
private TokenGenerator $tokenGenerator,
private EmailService $emailService
) {}
public function initiateReset(string $email): PasswordResetResult
{
$user = $this->userRepository->findByEmail($email);
if (!$user) {
// Return success even if user not found (security)
return PasswordResetResult::success();
}
// Generate secure reset token
$token = $this->tokenGenerator->generateSecureToken(32);
$tokenHash = Hash::sha256($token);
$expiresAt = new \DateTimeImmutable('+1 hour');
$resetToken = new PasswordResetToken(
hash: $tokenHash,
userId: $user->getId(),
createdAt: new \DateTimeImmutable(),
expiresAt: $expiresAt
);
$this->userRepository->storePasswordResetToken($resetToken);
// Send reset email
$this->emailService->sendPasswordResetEmail($user->getEmail(), $token);
return PasswordResetResult::success();
}
public function resetPassword(
string $token,
#[SensitiveParameter] string $newPassword
): PasswordResetResult {
$tokenHash = Hash::sha256($token);
$resetToken = $this->userRepository->findPasswordResetToken($tokenHash);
if (!$resetToken || $resetToken->isExpired()) {
return PasswordResetResult::failed('Invalid or expired reset token');
}
$user = $this->userRepository->findById($resetToken->getUserId());
if (!$user) {
return PasswordResetResult::failed('User not found');
}
// Validate new password
$validation = $this->passwordHasher->validatePasswordStrength($newPassword);
if (!$validation->isValid) {
return PasswordResetResult::validationFailed($validation);
}
// Hash new password
$hashedPassword = $this->passwordHasher->hash($newPassword);
// Update password and cleanup
$this->userRepository->updateUserPassword($user->getId(), $hashedPassword);
$this->userRepository->deletePasswordResetToken($tokenHash);
$this->userRepository->deleteAllUserSessions($user->getId());
return PasswordResetResult::success();
}
}
```
## Advanced Security Features
### Multi-Factor Authentication Setup
```php
final readonly class MfaService
{
public function __construct(
private PasswordHasher $passwordHasher,
private TotpService $totpService,
private UserRepository $userRepository
) {}
public function setupTotp(string $userId): MfaSetupResult
{
$user = $this->userRepository->findById($userId);
if (!$user) {
return MfaSetupResult::failed('User not found');
}
// Generate TOTP secret
$secret = $this->totpService->generateSecret();
// Create QR code data
$qrCodeUri = $this->totpService->getQrCodeUri(
secret: $secret,
accountName: (string) $user->getEmail(),
issuer: 'Your App Name'
);
// Store temporary secret (not activated until verified)
$tempSecret = new TempTotpSecret(
userId: $userId,
secret: $secret,
createdAt: new \DateTimeImmutable(),
expiresAt: new \DateTimeImmutable('+10 minutes')
);
$this->userRepository->storeTempTotpSecret($tempSecret);
return MfaSetupResult::success($secret, $qrCodeUri);
}
public function verifyAndActivateTotp(
string $userId,
string $totpCode
): MfaActivationResult {
$tempSecret = $this->userRepository->findTempTotpSecret($userId);
if (!$tempSecret || $tempSecret->isExpired()) {
return MfaActivationResult::failed('Setup expired, please restart');
}
// Verify TOTP code
if (!$this->totpService->verify($totpCode, $tempSecret->getSecret())) {
return MfaActivationResult::failed('Invalid TOTP code');
}
// Activate TOTP for user
$this->userRepository->activateTotpForUser($userId, $tempSecret->getSecret());
$this->userRepository->deleteTempTotpSecret($userId);
// Generate backup codes
$backupCodes = $this->generateBackupCodes($userId);
return MfaActivationResult::success($backupCodes);
}
private function generateBackupCodes(string $userId): array
{
$codes = [];
for ($i = 0; $i < 8; $i++) {
$code = $this->generateReadableCode();
$codes[] = $code;
$backupCode = new MfaBackupCode(
userId: $userId,
code: Hash::sha256($code),
createdAt: new \DateTimeImmutable(),
usedAt: null
);
$this->userRepository->storeBackupCode($backupCode);
}
return $codes;
}
private function generateReadableCode(): string
{
// Generate 8-digit backup code
return sprintf('%04d-%04d', random_int(1000, 9999), random_int(1000, 9999));
}
}
```
### Session Management with Device Tracking
```php
final readonly class DeviceTrackingService
{
public function __construct(
private AuthenticationService $authService,
private SessionRepository $sessionRepository
) {}
public function authenticateWithDeviceTracking(
string $identifier,
#[SensitiveParameter] string $password,
HttpRequest $request
): AuthenticationResult {
$ipAddress = IpAddress::fromRequest();
$userAgent = $request->server->getUserAgent();
$result = $this->authService->authenticate($identifier, $password, $ipAddress);
if ($result->isSuccess()) {
$session = $result->getSession();
$user = $result->getUser();
// Create device fingerprint
$deviceInfo = new DeviceInfo(
userAgent: $userAgent,
ipAddress: $ipAddress,
screenResolution: $request->headers->get('X-Screen-Resolution'),
timezone: $request->headers->get('X-Timezone'),
language: $request->headers->get('Accept-Language')
);
// Check if this is a new device
$isNewDevice = !$this->sessionRepository->hasRecentSessionForDevice(
userId: $user->getId(),
deviceFingerprint: $deviceInfo->getFingerprint(),
withinDays: 30
);
if ($isNewDevice) {
// Send security notification
$this->sendNewDeviceNotification($user, $deviceInfo, $ipAddress);
}
// Update session with device info
$this->sessionRepository->updateSessionDeviceInfo($session->getId(), $deviceInfo);
}
return $result;
}
public function listActiveSessions(string $userId): array
{
$sessions = $this->sessionRepository->getActiveSessionsForUser($userId);
return array_map(function (AuthenticationSession $session) {
$deviceInfo = $this->sessionRepository->getSessionDeviceInfo($session->getId());
return [
'id' => $session->getId()->toString(),
'created_at' => $session->getCreatedAt()->format(\DateTimeInterface::ATOM),
'last_activity' => $session->getLastActivity()->format(\DateTimeInterface::ATOM),
'ip_address' => (string) $session->getIpAddress(),
'device_info' => $deviceInfo?->toArray(),
'is_current' => $this->isCurrentSession($session->getId())
];
}, $sessions);
}
public function revokeSession(string $userId, SessionId $sessionId): bool
{
// Verify session belongs to user
$session = $this->sessionRepository->findSessionById($sessionId);
if (!$session || $session->getUserId() !== $userId) {
return false;
}
return $this->authService->logout($sessionId);
}
private function sendNewDeviceNotification(
User $user,
DeviceInfo $deviceInfo,
IpAddress $ipAddress
): void {
// Implementation would send email/SMS notification
// about login from new device
}
private function isCurrentSession(SessionId $sessionId): bool
{
// Check if this is the current session
return session_id() === $sessionId->toString();
}
}
```
## Rate Limiting & Security
### Custom Rate Limiting Implementation
```php
final readonly class CustomRateLimitService implements RateLimitService
{
public function __construct(
private Cache $cache,
private int $maxAttempts = 5,
private int $windowSeconds = 300,
private int $lockoutDuration = 900
) {}
public function isRateLimited(IpAddress $ipAddress, string $action): bool
{
$key = $this->getRateLimitKey($ipAddress, $action);
$attempts = $this->cache->get($key, 0);
return $attempts >= $this->maxAttempts;
}
public function recordAttempt(IpAddress $ipAddress, string $action): void
{
$key = $this->getRateLimitKey($ipAddress, $action);
$attempts = $this->cache->get($key, 0);
$this->cache->set($key, $attempts + 1, $this->windowSeconds);
if ($attempts + 1 >= $this->maxAttempts) {
$lockoutKey = $this->getLockoutKey($ipAddress, $action);
$this->cache->set($lockoutKey, true, $this->lockoutDuration);
}
}
public function clearAttempts(IpAddress $ipAddress, string $action): void
{
$key = $this->getRateLimitKey($ipAddress, $action);
$lockoutKey = $this->getLockoutKey($ipAddress, $action);
$this->cache->forget($key);
$this->cache->forget($lockoutKey);
}
public function getRetryAfter(IpAddress $ipAddress, string $action): int
{
$lockoutKey = $this->getLockoutKey($ipAddress, $action);
$lockoutExpiry = $this->cache->get($lockoutKey);
if (!$lockoutExpiry) {
return 0;
}
return max(0, $lockoutExpiry - time());
}
private function getRateLimitKey(IpAddress $ipAddress, string $action): string
{
return sprintf('rate_limit:%s:%s', $action, (string) $ipAddress);
}
private function getLockoutKey(IpAddress $ipAddress, string $action): string
{
return sprintf('lockout:%s:%s', $action, (string) $ipAddress);
}
}
```
## Testing Examples
### Authentication Service Testing
```php
use PHPUnit\Framework\TestCase;
use App\Framework\Auth\AuthenticationService;
final class AuthenticationServiceTest extends TestCase
{
private AuthenticationService $authService;
private PasswordHasher $passwordHasher;
private MockAuthenticationRepository $repository;
protected function setUp(): void
{
$this->passwordHasher = new PasswordHasher(
kdf: new MockKeyDerivationFunction(),
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_LOW // Fast for testing
);
$this->repository = new MockAuthenticationRepository();
$this->authService = new AuthenticationService(
passwordHasher: $this->passwordHasher,
sessionIdGenerator: new MockSessionIdGenerator(),
repository: $this->repository
);
}
public function test_successful_authentication(): void
{
$password = 'SecurePassword123!';
$hashedPassword = $this->passwordHasher->hash($password);
$user = new User(
id: 'user-1',
email: new Email('user@example.com'),
username: 'testuser',
hashedPassword: $hashedPassword
);
$this->repository->addUser($user);
$result = $this->authService->authenticate(
identifier: 'user@example.com',
password: $password,
ipAddress: IpAddress::localhost()
);
$this->assertTrue($result->isSuccess());
$this->assertEquals($user->getId(), $result->getUser()->getId());
$this->assertInstanceOf(AuthenticationSession::class, $result->getSession());
}
public function test_failed_authentication_with_invalid_password(): void
{
$hashedPassword = $this->passwordHasher->hash('CorrectPassword123!');
$user = new User(
id: 'user-1',
email: new Email('user@example.com'),
username: 'testuser',
hashedPassword: $hashedPassword
);
$this->repository->addUser($user);
$result = $this->authService->authenticate(
identifier: 'user@example.com',
password: 'WrongPassword',
ipAddress: IpAddress::localhost()
);
$this->assertFalse($result->isSuccess());
$this->assertEquals('Invalid credentials', $result->getErrorMessage());
}
public function test_account_lockout_after_max_attempts(): void
{
$hashedPassword = $this->passwordHasher->hash('CorrectPassword123!');
$user = new User(
id: 'user-1',
email: new Email('user@example.com'),
username: 'testuser',
hashedPassword: $hashedPassword
);
$this->repository->addUser($user);
// Simulate failed attempts
for ($i = 0; $i < AuthenticationService::MAX_LOGIN_ATTEMPTS; $i++) {
$this->authService->authenticate(
identifier: 'user@example.com',
password: 'WrongPassword',
ipAddress: IpAddress::localhost()
);
}
// Next attempt should be locked
$result = $this->authService->authenticate(
identifier: 'user@example.com',
password: 'CorrectPassword123!',
ipAddress: IpAddress::localhost()
);
$this->assertTrue($result->isAccountLocked());
$this->assertInstanceOf(\DateTimeImmutable::class, $result->getLockoutExpiresAt());
}
}
```
### Password Hashing Testing
```php
final class PasswordHasherTest extends TestCase
{
private PasswordHasher $passwordHasher;
protected function setUp(): void
{
$this->passwordHasher = new PasswordHasher(
kdf: new MockKeyDerivationFunction(),
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_LOW
);
}
public function test_password_hashing_and_verification(): void
{
$password = 'TestPassword123!';
$hashedPassword = $this->passwordHasher->hash($password);
$this->assertInstanceOf(HashedPassword::class, $hashedPassword);
$this->assertEquals('argon2id', $hashedPassword->getAlgorithm());
$this->assertTrue($this->passwordHasher->verify($password, $hashedPassword));
$this->assertFalse($this->passwordHasher->verify('WrongPassword', $hashedPassword));
}
public function test_password_strength_validation(): void
{
$weakPassword = 'weak';
$strongPassword = 'StrongPassword123!@#';
$weakValidation = $this->passwordHasher->validatePasswordStrength($weakPassword);
$strongValidation = $this->passwordHasher->validatePasswordStrength($strongPassword);
$this->assertFalse($weakValidation->isValid);
$this->assertNotEmpty($weakValidation->errors);
$this->assertEquals(PasswordStrength::WEAK, $weakValidation->strength);
$this->assertTrue($strongValidation->isValid);
$this->assertEmpty($strongValidation->errors);
$this->assertContains($strongValidation->strength, [
PasswordStrength::STRONG,
PasswordStrength::VERY_STRONG
]);
}
public function test_secure_password_generation(): void
{
$password = $this->passwordHasher->generateSecurePassword(16);
$this->assertEquals(16, strlen($password));
$validation = $this->passwordHasher->validatePasswordStrength($password);
$this->assertTrue($validation->isValid);
$this->assertGreaterThanOrEqual(70, $validation->strengthScore);
}
}

View File

@@ -0,0 +1,310 @@
# Auth Module
**Sichere Authentifizierungs- und Autorisierungskomponenten** für das Custom PHP Framework.
## Überblick
Das Auth Module bietet umfassende Sicherheitsfeatures für Benutzerauthentifizierung, Passwort-Management und Session-Verwaltung. Es integriert sich nahtlos mit dem Cryptography Module für maximale Sicherheit.
## Kernkomponenten
### PasswordHasher Service
Sichere Passwort-Hashing und -Verifizierung mit automatischem Rehashing.
```php
use App\Framework\Auth\PasswordHasher;
use App\Framework\Cryptography\KeyDerivationFunction;
$passwordHasher = new PasswordHasher(
kdf: $keyDerivationFunction,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);
// Passwort hashen
$hashedPassword = $passwordHasher->hash('userPassword123');
// Passwort verifizieren
$isValid = $passwordHasher->verify('userPassword123', $hashedPassword);
// Passwort-Stärke validieren
$validation = $passwordHasher->validatePasswordStrength('userPassword123');
if (!$validation->isValid) {
echo implode(', ', $validation->errors);
}
```
### HashedPassword Value Object
Immutables Value Object für gehashte Passwörter mit Metadaten.
```php
use App\Framework\Auth\HashedPassword;
use App\Framework\Auth\PasswordStrength;
// Aus DerivedKey erstellen
$hashedPassword = HashedPassword::fromDerivedKey($derivedKey);
// Eigenschaften abrufen
$algorithm = $hashedPassword->getAlgorithm(); // 'argon2id'
$parameters = $hashedPassword->getParameters(); // ['memory_cost' => 65536, ...]
$strength = $hashedPassword->getStrength(); // PasswordStrength::STRONG
$createdAt = $hashedPassword->getCreatedAt(); // DateTimeImmutable
// Rehashing-Prüfung
$needsRehash = $hashedPassword->needsRehash('argon2id', [
'memory_cost' => 131072, // Höhere Sicherheitsanforderungen
'time_cost' => 6
]);
// Sicherheits-Bewertung
$assessment = $hashedPassword->assessSecurity();
echo $assessment->getSummary(); // "Strong security with Argon2ID (2024 standards)"
```
### AuthenticationService
Zentrale Authentifizierungslogik mit erweiterten Sicherheitsfeatures.
```php
use App\Framework\Auth\AuthenticationService;
use App\Framework\Http\IpAddress;
$authService = new AuthenticationService(
passwordHasher: $passwordHasher,
sessionIdGenerator: $sessionIdGenerator,
repository: $authRepository
);
// Benutzer authentifizieren
$result = $authService->authenticate(
identifier: 'user@example.com',
password: 'userPassword123',
ipAddress: IpAddress::from('192.168.1.1'),
remember: true
);
if ($result->isSuccess()) {
$user = $result->getUser();
$session = $result->getSession();
$rememberToken = $result->getRememberToken(); // nullable
}
// Mit Session authentifizieren
$result = $authService->authenticateWithSession(
$sessionId,
IpAddress::from('192.168.1.1')
);
// Mit Remember Token authentifizieren
$result = $authService->authenticateWithRememberToken(
$tokenValue,
IpAddress::from('192.168.1.1')
);
```
### PasswordValidationResult Value Object
Detaillierte Passwort-Validierungsergebnisse.
```php
use App\Framework\Auth\PasswordValidationResult;
$validation = $passwordHasher->validatePasswordStrength('weakpass');
// Validierungsstatus prüfen
$isValid = $validation->isValid; // false
$errors = $validation->errors; // ['Password must be at least 8 characters long']
$warnings = $validation->warnings; // ['Consider using more character types']
$score = $validation->strengthScore; // 45
$strength = $validation->strength; // PasswordStrength::WEAK
// Sicherheitslevel prüfen
$meetsMinimum = $validation->meetsMinimumRequirements(); // false
$isRecommended = $validation->isRecommended(); // false
// Zusammenfassung
echo $validation->getSummary();
// "Password does not meet requirements: Password must be at least 8 characters long"
// API-Response Format
$apiResponse = $validation->toArray();
```
## Sicherheitsfeatures
### Rate Limiting & Account Lockout
Schutz vor Brute-Force-Angriffen durch intelligente Rate-Limitierung.
```php
// Automatisches Rate Limiting in AuthenticationService
const MAX_LOGIN_ATTEMPTS = 5;
const LOCKOUT_DURATION = 900; // 15 Minuten
const RATE_LIMIT_WINDOW = 300; // 5 Minuten
// Rate Limiting wird automatisch angewendet
$result = $authService->authenticate($email, $password, $ipAddress);
if ($result->isRateLimited()) {
$retryAfter = $result->getRetryAfter();
echo "Rate limit exceeded. Retry after {$retryAfter} seconds.";
}
if ($result->isAccountLocked()) {
$expiresAt = $result->getLockoutExpiresAt();
echo "Account locked until {$expiresAt->format('Y-m-d H:i:s')}";
}
```
### Session-Sicherheit
Sichere Session-Verwaltung mit IP-Tracking und automatischer Rotation.
```php
// Sessions werden automatisch erstellt und verwaltet
const SESSION_TIMEOUT = 3600; // 1 Stunde
const REMEMBER_TOKEN_LENGTH = 32; // 256-bit Token
// Session-Features:
// - Automatische IP-Konsistenz-Prüfung
// - Session-Timeout-Management
// - Aktivitäts-Tracking
// - Sichere Session-IDs über SessionIdGenerator
```
### Token-Hashing mit Hash Value Object
Sichere Token-Behandlung mit typisierter Hash-Verwaltung.
```php
// Remember Tokens werden sicher gehasht
private function hashToken(string $token): Hash
{
return Hash::sha256($token);
}
// Vorteile:
// - Typsicherheit für Hash-Werte
// - Explizite Algorithmus-Angabe (SHA-256)
// - Timing-safe Vergleiche mit hash_equals()
// - Framework-konsistente Hash-Behandlung
// - Automatische Hash-Validierung
```
### Passwort-Sicherheit
Umfassende Passwort-Validierung und -Bewertung.
```php
// Automatische Passwort-Stärke-Bewertung
$validation = $passwordHasher->validatePasswordStrength($password);
// Validierungsregeln:
// - Minimale Länge (8+ Zeichen)
// - Komplexitätsanforderungen (2+ Zeichentypen)
// - Häufige Muster-Erkennung
// - Sequenzielle Zeichen-Prüfung
// - Exzessive Wiederholungen
// Sichere Passwort-Generierung
$securePassword = $passwordHasher->generateSecurePassword(
length: 16,
includeUppercase: true,
includeLowercase: true,
includeNumbers: true,
includeSpecialChars: true,
excludeChars: '0O1l' // Mehrdeutige Zeichen ausschließen
);
```
## Integration mit Framework
### Abhängigkeiten
Das Auth Module nutzt vorhandene Framework-Komponenten:
- **Cryptography Module**: Für sichere Key Derivation Functions
- **SessionId/SessionIdGenerator**: Für Session-Management
- **IpAddress Value Object**: Für IP-basierte Sicherheitsfeatures
- **Hash Value Object**: Für typisierte Hash-Operationen
### Repository Pattern
Flexible Datenpersistierung durch Repository-Abstraktion.
```php
interface AuthenticationRepository
{
public function findUserByIdentifier(string $identifier): ?User;
public function findUserById(string $userId): ?User;
public function updateUserPassword(string $userId, HashedPassword $password): bool;
public function storeSession(AuthenticationSession $session): void;
public function findSessionById(SessionId $sessionId): ?AuthenticationSession;
public function updateSessionActivity(SessionId $sessionId, ?IpAddress $ipAddress): void;
public function deleteSession(SessionId $sessionId): bool;
public function deleteAllUserSessions(string $userId): void;
public function storeRememberToken(RememberToken $token): void;
public function findRememberToken(Hash $tokenHash): ?RememberToken;
public function deleteRememberToken(Hash $tokenHash): bool;
public function deleteAllUserRememberTokens(string $userId): void;
public function getFailedLoginAttempts(string $userId): int;
public function incrementFailedLoginAttempts(string $userId): void;
public function clearFailedLoginAttempts(string $userId): void;
public function getLastFailedAttemptTime(string $userId): ?\DateTimeImmutable;
}
```
## Best Practices
### Sichere Implementation
```php
// ✅ Sensitive Parameter verwenden
public function authenticate(
string $identifier,
#[SensitiveParameter] string $password,
?IpAddress $ipAddress = null
): AuthenticationResult
// ✅ Automatisches Rehashing
if ($this->passwordHasher->needsRehash($user->getHashedPassword())) {
$newHash = $this->passwordHasher->hash($password);
$this->repository->updateUserPassword($user->getId(), $newHash);
}
// ✅ Timing-safe Token-Vergleiche
$tokenHash = $this->hashToken($tokenValue);
$rememberToken = $this->repository->findRememberToken($tokenHash);
```
### Error Handling
```php
// ✅ Generische Fehlermeldungen für Sicherheit
if (!$user || !$this->passwordHasher->verify($password, $user->getHashedPassword())) {
return AuthenticationResult::failed('Invalid credentials');
}
// ✅ Security Event Logging
$this->recordSecurityEvent('authentication_failed', [
'identifier' => $identifier,
'ip_address' => $ipAddress ? (string) $ipAddress : null,
'reason' => $reason
]);
```
### Performance Optimierung
```php
// ✅ Konfigurierbare Sicherheitslevel
$passwordHasher = new PasswordHasher(
kdf: $keyDerivationFunction,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD // vs HIGH für höhere Sicherheit
);
// ✅ Bulk-Operationen für bessere Performance
$this->repository->deleteAllUserSessions($userId);
$this->repository->deleteAllUserRememberTokens($userId);
```
## Nächste Schritte
- [ ] AuthenticationRepository Interface implementieren
- [ ] Authentication Exceptions definieren
- [ ] Unit Tests für alle Komponenten schreiben
- [ ] Rate Limiting Service implementieren
- [ ] Integration Tests für Authentication Flow
- [ ] Performance Benchmarks für Passwort-Hashing

View File

@@ -0,0 +1,904 @@
# Auth Module Security Guidelines
**Sicherheitsrichtlinien und Best Practices** für das Auth Module des Custom PHP Frameworks.
## Security Architecture
### Defense in Depth Strategy
Das Auth Module implementiert mehrschichtige Sicherheitsmaßnahmen:
```
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
├─────────────────────────────────────────────────────────────┤
│ • Rate Limiting & Account Lockout │
│ • Session Security & IP Tracking │
│ • Multi-Factor Authentication │
│ • Password Strength Validation │
├─────────────────────────────────────────────────────────────┤
│ Framework Layer │
├─────────────────────────────────────────────────────────────┤
│ • Secure Password Hashing (Argon2ID) │
│ • Timing-Safe Comparisons │
│ • Cryptographically Secure Random Generation │
│ • Hash Value Object with Algorithm Validation │
├─────────────────────────────────────────────────────────────┤
│ Infrastructure Layer │
├─────────────────────────────────────────────────────────────┤
│ • HTTPS Enforcement │
│ • Secure Headers (HSTS, CSP) │
│ • Database Security & Prepared Statements │
│ • Logging & Monitoring │
└─────────────────────────────────────────────────────────────┘
```
## Password Security
### Secure Password Hashing
```php
// ✅ Recommended: Argon2ID with high memory cost
$passwordHasher = new PasswordHasher(
kdf: $keyDerivationFunction,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_HIGH // Production
);
// Security parameters for different levels:
// LEVEL_HIGH: 128 MB memory, 6 iterations, 4 threads
// LEVEL_STANDARD: 64 MB memory, 4 iterations, 3 threads
// LEVEL_LOW: 32 MB memory, 2 iterations, 2 threads
// ❌ Avoid: Weak algorithms or low security levels in production
$weakHasher = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'pbkdf2-sha256', // Less secure than Argon2ID
defaultSecurityLevel: PasswordHasher::LEVEL_LOW
);
```
### Password Policy Enforcement
```php
final readonly class PasswordPolicy
{
public const int MIN_LENGTH = 12; // Increased from 8
public const int MIN_COMPLEXITY_TYPES = 3; // Upper, lower, numbers, special
public const int MIN_STRENGTH_SCORE = 70; // High security threshold
public function validatePassword(string $password): PasswordPolicyResult
{
$violations = [];
// Length requirement
if (mb_strlen($password) < self::MIN_LENGTH) {
$violations[] = "Password must be at least " . self::MIN_LENGTH . " characters";
}
// Complexity requirements
$complexityScore = $this->calculateComplexity($password);
if ($complexityScore < self::MIN_COMPLEXITY_TYPES) {
$violations[] = "Password must include at least " . self::MIN_COMPLEXITY_TYPES . " character types";
}
// Entropy check
if ($this->calculateEntropy($password) < 50) {
$violations[] = "Password lacks sufficient entropy";
}
// Dictionary check
if ($this->isCommonPassword($password)) {
$violations[] = "Password is too common";
}
// Personal information check
if ($this->containsPersonalInfo($password)) {
$violations[] = "Password should not contain personal information";
}
return new PasswordPolicyResult(
isValid: empty($violations),
violations: $violations,
strengthScore: $this->calculateStrengthScore($password)
);
}
private function calculateEntropy(string $password): float
{
$length = strlen($password);
$charsetSize = 0;
if (preg_match('/[a-z]/', $password)) $charsetSize += 26;
if (preg_match('/[A-Z]/', $password)) $charsetSize += 26;
if (preg_match('/[0-9]/', $password)) $charsetSize += 10;
if (preg_match('/[^A-Za-z0-9]/', $password)) $charsetSize += 32;
return $length * log($charsetSize, 2);
}
private function isCommonPassword(string $password): bool
{
// Check against common password lists (e.g., Have I Been Pwned)
$commonPasswords = [
'password', '123456', 'password123', 'admin', 'qwerty',
'letmein', 'welcome', 'monkey', 'dragon', '123456789'
];
return in_array(strtolower($password), $commonPasswords, true);
}
}
```
### Automatic Password Rehashing
```php
// ✅ Implement automatic rehashing on authentication
public function authenticate(string $identifier, string $password): AuthenticationResult
{
$user = $this->repository->findByIdentifier($identifier);
if (!$user || !$this->passwordHasher->verify($password, $user->getHashedPassword())) {
return AuthenticationResult::failed('Invalid credentials');
}
// Critical: Check for rehashing need
if ($this->passwordHasher->needsRehash($user->getHashedPassword())) {
$newHash = $this->passwordHasher->hash($password);
$this->repository->updateUserPassword($user->getId(), $newHash);
$this->logger->info('Password automatically rehashed', [
'user_id' => $user->getId(),
'old_algorithm' => $user->getHashedPassword()->getAlgorithm(),
'new_algorithm' => $newHash->getAlgorithm()
]);
}
return AuthenticationResult::success($user);
}
```
## Session Security
### Secure Session Management
```php
final readonly class SecureSessionManager
{
public function __construct(
private AuthenticationService $authService,
private SessionSecurity $sessionSecurity
) {}
public function createSecureSession(
User $user,
IpAddress $ipAddress,
UserAgent $userAgent
): AuthenticationSession {
// Generate cryptographically secure session ID
$sessionId = $this->generateSecureSessionId();
// Create session with security attributes
$session = new AuthenticationSession(
id: $sessionId,
userId: $user->getId(),
ipAddress: $ipAddress,
userAgent: $userAgent,
createdAt: new \DateTimeImmutable(),
expiresAt: new \DateTimeImmutable('+1 hour'),
lastActivity: new \DateTimeImmutable(),
securityAttributes: new SessionSecurityAttributes(
isSecure: true,
isHttpOnly: true,
sameSite: 'Strict',
fingerprint: $this->generateFingerprint($ipAddress, $userAgent)
)
);
// Set secure session cookie
$this->setSecureSessionCookie($sessionId, $session->getExpiresAt());
return $session;
}
private function generateSecureSessionId(): SessionId
{
// Use framework's SessionIdGenerator for consistency
return $this->sessionIdGenerator->generate();
}
private function setSecureSessionCookie(SessionId $sessionId, \DateTimeImmutable $expiresAt): void
{
setcookie('session_id', $sessionId->toString(), [
'expires' => $expiresAt->getTimestamp(),
'path' => '/',
'domain' => '', // Let browser determine
'secure' => true, // HTTPS only
'httponly' => true, // No JavaScript access
'samesite' => 'Strict' // CSRF protection
]);
}
private function generateFingerprint(IpAddress $ipAddress, UserAgent $userAgent): string
{
return Hash::sha256(
$ipAddress->toString() . '|' .
$userAgent->toString() . '|' .
$_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''
)->toString();
}
}
```
### Session Hijacking Protection
```php
final readonly class SessionHijackingProtection
{
public function validateSession(
SessionId $sessionId,
IpAddress $currentIp,
UserAgent $currentUserAgent
): SessionValidationResult {
$session = $this->repository->findSessionById($sessionId);
if (!$session) {
return SessionValidationResult::invalid('Session not found');
}
// Check session expiration
if ($session->isExpired()) {
$this->repository->deleteSession($sessionId);
return SessionValidationResult::expired();
}
// IP address consistency check (configurable)
if ($this->config->checkIpConsistency) {
if (!$session->getIpAddress()->equals($currentIp)) {
$this->logSecurityEvent('session_ip_mismatch', [
'session_id' => $sessionId->toString(),
'original_ip' => (string) $session->getIpAddress(),
'current_ip' => (string) $currentIp
]);
// Suspicious activity - invalidate session
$this->repository->deleteSession($sessionId);
return SessionValidationResult::suspicious('IP address mismatch');
}
}
// User Agent consistency (less strict)
if (!$this->isUserAgentConsistent($session->getUserAgent(), $currentUserAgent)) {
$this->logSecurityEvent('session_user_agent_change', [
'session_id' => $sessionId->toString(),
'original_ua' => (string) $session->getUserAgent(),
'current_ua' => (string) $currentUserAgent
]);
}
// Update session activity
$this->repository->updateSessionActivity($sessionId, $currentIp);
return SessionValidationResult::valid($session);
}
private function isUserAgentConsistent(UserAgent $original, UserAgent $current): bool
{
// Allow minor version changes but detect major browser changes
$originalBrowser = $this->extractBrowser($original);
$currentBrowser = $this->extractBrowser($current);
return $originalBrowser === $currentBrowser;
}
}
```
## Token Security
### Remember Token Security with Hash Value Object
```php
final readonly class RememberTokenSecurity
{
public function createRememberToken(string $userId): RememberToken
{
// Generate cryptographically secure token
$tokenValue = bin2hex(random_bytes(32)); // 256-bit token
// Hash token using Hash Value Object for type safety
$tokenHash = Hash::sha256($tokenValue);
$rememberToken = new RememberToken(
hash: $tokenHash,
userId: $userId,
createdAt: new \DateTimeImmutable(),
expiresAt: new \DateTimeImmutable('+30 days'),
lastUsed: null
);
$this->repository->storeRememberToken($rememberToken);
// Return token with plain text value (only shown once)
return $rememberToken->withPlainTextValue($tokenValue);
}
public function validateRememberToken(string $tokenValue): RememberTokenValidation
{
// Hash provided token for comparison
$tokenHash = Hash::sha256($tokenValue);
$rememberToken = $this->repository->findRememberToken($tokenHash);
if (!$rememberToken) {
$this->logSecurityEvent('invalid_remember_token', [
'token_hash' => $tokenHash->toShort(8) // Only log first 8 chars
]);
return RememberTokenValidation::invalid();
}
// Check expiration
if ($rememberToken->isExpired()) {
$this->repository->deleteRememberToken($tokenHash);
return RememberTokenValidation::expired();
}
// Update last used timestamp
$this->repository->updateRememberTokenUsage($tokenHash);
return RememberTokenValidation::valid($rememberToken);
}
public function rotateRememberToken(Hash $oldTokenHash): RememberToken
{
$oldToken = $this->repository->findRememberToken($oldTokenHash);
if (!$oldToken) {
throw new SecurityException('Cannot rotate non-existent token');
}
// Create new token
$newToken = $this->createRememberToken($oldToken->getUserId());
// Delete old token
$this->repository->deleteRememberToken($oldTokenHash);
$this->logSecurityEvent('remember_token_rotated', [
'user_id' => $oldToken->getUserId(),
'old_token_created' => $oldToken->getCreatedAt()->format('Y-m-d H:i:s')
]);
return $newToken;
}
}
// Benefits of using Hash Value Object:
// ✅ Type safety - tokens can't be confused with other strings
// ✅ Algorithm specification - explicit SHA-256 usage
// ✅ Timing-safe comparison - uses hash_equals() internally
// ✅ Validation - ensures proper hash format and length
// ✅ Framework consistency - follows value object patterns
```
## Rate Limiting & Brute Force Protection
### Advanced Rate Limiting
```php
final readonly class AdvancedRateLimiter implements RateLimitService
{
public function __construct(
private Cache $cache,
private Logger $logger,
private RateLimitConfig $config
) {}
public function checkRateLimit(
IpAddress $ipAddress,
string $action,
string $identifier = null
): RateLimitResult {
// Multiple rate limiting strategies
$checks = [
$this->checkIpBasedLimit($ipAddress, $action),
$this->checkIdentifierBasedLimit($identifier, $action),
$this->checkGlobalLimit($action),
$this->checkAdaptiveLimit($ipAddress, $action)
];
foreach ($checks as $check) {
if ($check->isLimited()) {
$this->logRateLimitViolation($ipAddress, $action, $check);
return $check;
}
}
// Record successful attempt
$this->recordAttempt($ipAddress, $action, $identifier);
return RateLimitResult::allowed();
}
private function checkAdaptiveLimit(IpAddress $ipAddress, string $action): RateLimitResult
{
$suspiciousScore = $this->calculateSuspiciousScore($ipAddress);
// Adaptive limits based on suspicious activity
$maxAttempts = match (true) {
$suspiciousScore > 80 => 1, // Highly suspicious
$suspiciousScore > 60 => 2, // Suspicious
$suspiciousScore > 40 => 3, // Moderately suspicious
default => 5 // Normal
};
$key = "adaptive_limit:{$action}:" . $ipAddress->toString();
$attempts = $this->cache->get($key, 0);
if ($attempts >= $maxAttempts) {
return RateLimitResult::limited(
reason: 'Adaptive rate limit exceeded',
retryAfter: 900,
metadata: ['suspicious_score' => $suspiciousScore]
);
}
return RateLimitResult::allowed();
}
private function calculateSuspiciousScore(IpAddress $ipAddress): int
{
$score = 0;
// Check for various suspicious indicators
if ($this->isFromTorNetwork($ipAddress)) $score += 30;
if ($this->isFromVpnProvider($ipAddress)) $score += 15;
if ($this->hasRecentFailures($ipAddress)) $score += 20;
if ($this->isFromUncommonGeolocation($ipAddress)) $score += 10;
if ($this->hasRapidRequests($ipAddress)) $score += 25;
return min(100, $score);
}
private function logRateLimitViolation(
IpAddress $ipAddress,
string $action,
RateLimitResult $result
): void {
$this->logger->warning('Rate limit violation', [
'ip_address' => (string) $ipAddress,
'action' => $action,
'reason' => $result->getReason(),
'retry_after' => $result->getRetryAfter(),
'metadata' => $result->getMetadata()
]);
}
}
```
### Account Lockout Protection
```php
final readonly class AccountLockoutService
{
public function __construct(
private UserRepository $repository,
private Logger $logger,
private NotificationService $notifications
) {}
public function handleFailedLogin(string $identifier, IpAddress $ipAddress): void
{
$user = $this->repository->findByIdentifier($identifier);
if (!$user) {
return; // Don't reveal if user exists
}
$attempts = $this->repository->incrementFailedAttempts($user->getId());
// Progressive lockout strategy
$lockoutDuration = $this->calculateLockoutDuration($attempts);
if ($attempts >= 3) {
$this->repository->lockAccount($user->getId(), $lockoutDuration);
$this->logger->warning('Account locked due to failed attempts', [
'user_id' => $user->getId(),
'attempts' => $attempts,
'lockout_duration' => $lockoutDuration,
'ip_address' => (string) $ipAddress
]);
// Notify user of lockout (rate limited to prevent abuse)
$this->sendLockoutNotification($user, $attempts, $lockoutDuration);
}
}
private function calculateLockoutDuration(int $attempts): int
{
// Exponential backoff with jitter
return match (true) {
$attempts >= 10 => 3600 + random_int(0, 1800), // 1-2.5 hours
$attempts >= 7 => 1800 + random_int(0, 900), // 30-45 minutes
$attempts >= 5 => 900 + random_int(0, 300), // 15-20 minutes
$attempts >= 3 => 300 + random_int(0, 120), // 5-7 minutes
default => 0
};
}
private function sendLockoutNotification(
User $user,
int $attempts,
int $lockoutDuration
): void {
// Rate limit notifications to prevent spam
$notificationKey = "lockout_notification:" . $user->getId();
if ($this->cache->has($notificationKey)) {
return;
}
$this->cache->put($notificationKey, true, 300); // 5 minutes
$this->notifications->sendSecurityAlert($user->getEmail(), [
'type' => 'account_lockout',
'attempts' => $attempts,
'lockout_duration_minutes' => ceil($lockoutDuration / 60),
'timestamp' => new \DateTimeImmutable()
]);
}
}
```
## Multi-Factor Authentication Security
### TOTP Implementation with Security Features
```php
final readonly class SecureTotpService
{
private const int SECRET_LENGTH = 32; // 160-bit secret
private const int WINDOW_SIZE = 1; // Allow 1 time step tolerance
private const int TIME_STEP = 30; // 30-second time steps
public function generateSecret(): string
{
return Base32::encode(random_bytes(self::SECRET_LENGTH));
}
public function verify(string $code, string $secret, ?int $timestamp = null): bool
{
$timestamp = $timestamp ?? time();
$timeStep = intval($timestamp / self::TIME_STEP);
// Check current and adjacent time windows to account for clock drift
for ($i = -self::WINDOW_SIZE; $i <= self::WINDOW_SIZE; $i++) {
$calculatedCode = $this->calculateTotp($secret, $timeStep + $i);
if (hash_equals($code, $calculatedCode)) {
// Prevent replay attacks by storing used codes
$this->markCodeAsUsed($secret, $timeStep + $i);
return true;
}
}
return false;
}
private function calculateTotp(string $secret, int $timeStep): string
{
$binarySecret = Base32::decode($secret);
$timeBytes = pack('N*', 0) . pack('N*', $timeStep);
$hash = hash_hmac('sha1', $timeBytes, $binarySecret, true);
$offset = ord($hash[19]) & 0xf;
$code = (
((ord($hash[$offset]) & 0x7f) << 24) |
((ord($hash[$offset + 1]) & 0xff) << 16) |
((ord($hash[$offset + 2]) & 0xff) << 8) |
(ord($hash[$offset + 3]) & 0xff)
) % 1000000;
return str_pad((string) $code, 6, '0', STR_PAD_LEFT);
}
private function markCodeAsUsed(string $secret, int $timeStep): void
{
// Prevent replay attacks
$key = 'totp_used:' . Hash::sha256($secret . ':' . $timeStep)->toShort(16);
$this->cache->put($key, true, self::TIME_STEP * 2);
}
}
```
### Backup Code Security
```php
final readonly class BackupCodeService
{
private const int CODE_LENGTH = 8;
private const int CODE_COUNT = 8;
public function generateBackupCodes(string $userId): array
{
$codes = [];
for ($i = 0; $i < self::CODE_COUNT; $i++) {
$code = $this->generateHumanReadableCode();
$codes[] = $code;
// Store hashed version
$backupCode = new MfaBackupCode(
userId: $userId,
codeHash: Hash::sha256($code),
createdAt: new \DateTimeImmutable(),
usedAt: null
);
$this->repository->storeBackupCode($backupCode);
}
return $codes;
}
public function verifyBackupCode(string $userId, string $code): bool
{
$codeHash = Hash::sha256($code);
$backupCode = $this->repository->findBackupCode($userId, $codeHash);
if (!$backupCode || $backupCode->isUsed()) {
return false;
}
// Mark as used (one-time use only)
$this->repository->markBackupCodeAsUsed($backupCode, new \DateTimeImmutable());
return true;
}
private function generateHumanReadableCode(): string
{
// Generate readable codes avoiding confusing characters
$chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // No 0, 1, I, O
$code = '';
for ($i = 0; $i < self::CODE_LENGTH; $i++) {
$code .= $chars[random_int(0, strlen($chars) - 1)];
}
// Format as XXXX-XXXX for readability
return substr($code, 0, 4) . '-' . substr($code, 4, 4);
}
}
```
## Monitoring & Incident Response
### Security Event Monitoring
```php
final readonly class SecurityEventMonitor
{
public function __construct(
private Logger $securityLogger,
private AlertingService $alerting,
private MetricsCollector $metrics
) {}
public function recordSecurityEvent(SecurityEvent $event): void
{
// Log all security events
$this->securityLogger->warning('Security event recorded', [
'event_type' => $event->getType(),
'severity' => $event->getSeverity(),
'user_id' => $event->getUserId(),
'ip_address' => (string) $event->getIpAddress(),
'user_agent' => (string) $event->getUserAgent(),
'metadata' => $event->getMetadata(),
'timestamp' => $event->getTimestamp()->format('Y-m-d H:i:s')
]);
// Update security metrics
$this->metrics->increment('auth.security_events', [
'type' => $event->getType(),
'severity' => $event->getSeverity()
]);
// Send alerts for critical events
if ($event->isCritical()) {
$this->alerting->sendSecurityAlert($event);
}
// Check for attack patterns
$this->analyzeForAttackPatterns($event);
}
private function analyzeForAttackPatterns(SecurityEvent $event): void
{
$ipAddress = $event->getIpAddress();
$recentEvents = $this->getRecentSecurityEvents($ipAddress, minutes: 10);
// Detect brute force attacks
$failedLogins = array_filter($recentEvents,
fn($e) => $e->getType() === 'authentication_failed'
);
if (count($failedLogins) >= 5) {
$this->alerting->sendAlert(new BruteForceDetectionAlert(
ipAddress: $ipAddress,
attemptCount: count($failedLogins),
timeWindow: 10
));
}
// Detect credential stuffing
$uniqueIdentifiers = array_unique(array_map(
fn($e) => $e->getMetadata()['identifier'] ?? null,
$failedLogins
));
if (count($uniqueIdentifiers) >= 10) {
$this->alerting->sendAlert(new CredentialStuffingAlert(
ipAddress: $ipAddress,
uniqueIdentifiers: count($uniqueIdentifiers)
));
}
}
}
```
### Automated Response System
```php
final readonly class AutomatedSecurityResponse
{
public function handleSecurityEvent(SecurityEvent $event): void
{
match ($event->getType()) {
'brute_force_detected' => $this->handleBruteForce($event),
'credential_stuffing_detected' => $this->handleCredentialStuffing($event),
'session_hijacking_suspected' => $this->handleSessionHijacking($event),
'suspicious_login_pattern' => $this->handleSuspiciousLogin($event),
default => null
};
}
private function handleBruteForce(SecurityEvent $event): void
{
$ipAddress = $event->getIpAddress();
// Immediately block IP for 1 hour
$this->firewall->blockIpAddress($ipAddress, duration: 3600);
// Increase monitoring for this IP
$this->monitoring->increaseWatchLevel($ipAddress);
// Notify security team
$this->alerting->sendUrgentAlert(new BruteForceBlockAlert($ipAddress));
}
private function handleSessionHijacking(SecurityEvent $event): void
{
$userId = $event->getUserId();
$sessionId = $event->getMetadata()['session_id'];
// Immediately terminate all user sessions
$this->authService->logoutAll($userId);
// Require password reset
$this->userService->requirePasswordReset($userId);
// Send security notification to user
$user = $this->userRepository->findById($userId);
$this->notifications->sendSecurityBreach($user->getEmail(), [
'incident_type' => 'session_hijacking',
'affected_session' => $sessionId,
'timestamp' => $event->getTimestamp()
]);
}
}
```
## Compliance & Audit
### GDPR Compliance
```php
final readonly class GdprCompliantAuthService
{
public function processPersonalData(User $user, string $purpose): void
{
// Log data processing for GDPR audit trail
$this->auditLogger->info('Personal data processed', [
'user_id' => $user->getId(),
'data_types' => ['email', 'login_timestamps', 'ip_addresses'],
'processing_purpose' => $purpose,
'legal_basis' => 'legitimate_interest', // or 'consent'
'retention_period' => '2_years'
]);
}
public function exportUserData(string $userId): UserDataExport
{
$user = $this->repository->findById($userId);
if (!$user) {
throw new UserNotFoundException($userId);
}
return new UserDataExport([
'personal_data' => [
'user_id' => $user->getId(),
'email' => (string) $user->getEmail(),
'created_at' => $user->getCreatedAt()->format('c'),
'last_login' => $user->getLastLoginAt()?->format('c')
],
'authentication_data' => [
'password_last_changed' => $user->getPasswordChangedAt()?->format('c'),
'mfa_enabled' => $user->hasMfaEnabled(),
'failed_login_attempts' => $this->repository->getFailedLoginAttempts($userId)
],
'session_data' => $this->getSessionHistory($userId),
'security_events' => $this->getSecurityEventHistory($userId)
]);
}
public function deleteUserData(string $userId): void
{
// GDPR right to erasure (right to be forgotten)
$this->repository->anonymizeUser($userId);
$this->repository->deleteAllUserSessions($userId);
$this->repository->deleteAllUserRememberTokens($userId);
$this->repository->deleteUserSecurityEvents($userId);
$this->auditLogger->info('User data deleted per GDPR request', [
'user_id' => $userId,
'deletion_timestamp' => (new \DateTimeImmutable())->format('c')
]);
}
}
```
### Security Audit Logging
```php
final readonly class SecurityAuditLogger
{
public function logAuthenticationEvent(string $eventType, array $context): void
{
$auditRecord = [
'event_type' => $eventType,
'timestamp' => (new \DateTimeImmutable())->format('c'),
'user_id' => $context['user_id'] ?? null,
'session_id' => $context['session_id'] ?? null,
'ip_address' => $context['ip_address'] ?? null,
'user_agent' => $context['user_agent'] ?? null,
'success' => $context['success'] ?? false,
'failure_reason' => $context['failure_reason'] ?? null,
'risk_score' => $this->calculateRiskScore($context)
];
// Store in secure audit log (append-only, tamper-evident)
$this->auditStorage->append($auditRecord);
// Forward to SIEM if configured
if ($this->siemForwarder) {
$this->siemForwarder->forward($auditRecord);
}
}
private function calculateRiskScore(array $context): int
{
$score = 0;
// Location-based risk
if (isset($context['ip_address'])) {
$location = $this->geolocator->locate($context['ip_address']);
if ($location->isHighRiskCountry()) $score += 25;
if ($location->isFromTor()) $score += 50;
}
// Time-based risk
$hour = (int) date('H');
if ($hour < 6 || $hour > 22) $score += 10; // Outside business hours
// Failure patterns
if (!($context['success'] ?? true)) $score += 20;
return min(100, $score);
}
}

View File

@@ -0,0 +1,397 @@
# Cryptography Module - Konfiguration
Konfigurationsoptionen und Setup für das Cryptography Module.
## Service-Registrierung
### Dependency Injection Setup
```php
use App\Framework\DI\Initializer;
use App\Framework\DI\Container;
use App\Framework\Cryptography\KeyDerivationFunction;
use App\Framework\Cryptography\SecureTokenGenerator;
use App\Framework\Cryptography\CryptographicUtilities;
use App\Framework\Cryptography\DigitalSignature;
use App\Framework\Cryptography\AdvancedHash;
use App\Framework\Random\SecureRandomGenerator;
final readonly class CryptographyInitializer implements Initializer
{
public function initialize(Container $container): void
{
// Random Generator als Dependency
$container->singleton(RandomGenerator::class, new SecureRandomGenerator());
// Core Cryptography Services
$container->singleton(KeyDerivationFunction::class, function(Container $c) {
return new KeyDerivationFunction($c->get(RandomGenerator::class));
});
$container->singleton(SecureTokenGenerator::class, function(Container $c) {
return new SecureTokenGenerator($c->get(RandomGenerator::class));
});
$container->singleton(CryptographicUtilities::class, function(Container $c) {
return new CryptographicUtilities($c->get(RandomGenerator::class));
});
$container->singleton(DigitalSignature::class, function(Container $c) {
return new DigitalSignature($c->get(RandomGenerator::class));
});
$container->singleton(AdvancedHash::class, new AdvancedHash());
// Factory Methods als Alternative
$container->bind('kdf.factory', function(Container $c) {
return KeyDerivationFunction::create($c->get(RandomGenerator::class));
});
}
}
```
### AppBootstrapper Integration
```php
// In src/Framework/Core/AppBootstrapper.php
public function bootstrap(): Application
{
// ... existing bootstrapping
$initializer = new CryptographyInitializer();
$initializer->initialize($this->container);
return $application;
}
```
## Sicherheitsparameter
### Key Derivation Function Konfiguration
```php
final readonly class CryptographyConfig
{
public const DEFAULT_KDF_PARAMETERS = [
'pbkdf2-sha256' => [
'low' => ['iterations' => 50000, 'key_length' => 32],
'standard' => ['iterations' => 100000, 'key_length' => 32],
'high' => ['iterations' => 200000, 'key_length' => 32],
],
'argon2id' => [
'low' => ['memory_cost' => 32768, 'time_cost' => 3, 'threads' => 2],
'standard' => ['memory_cost' => 65536, 'time_cost' => 4, 'threads' => 3],
'high' => ['memory_cost' => 131072, 'time_cost' => 6, 'threads' => 4],
],
'scrypt' => [
'low' => ['cost_parameter' => 8192, 'block_size' => 8, 'parallelization' => 1],
'standard' => ['cost_parameter' => 16384, 'block_size' => 8, 'parallelization' => 1],
'high' => ['cost_parameter' => 32768, 'block_size' => 8, 'parallelization' => 2],
]
];
public static function getRecommendedParameters(
string $algorithm,
string $securityLevel = 'standard'
): array {
return self::DEFAULT_KDF_PARAMETERS[$algorithm][$securityLevel] ??
throw new InvalidArgumentException("Unsupported configuration: {$algorithm}:{$securityLevel}");
}
}
```
### Token-Generator Konfiguration
```php
final readonly class TokenConfig
{
public const DEFAULT_TOKEN_LENGTHS = [
SecureTokenGenerator::TYPE_API_KEY => 32, // 256 Bit
SecureTokenGenerator::TYPE_SESSION => 32, // 256 Bit
SecureTokenGenerator::TYPE_CSRF => 32, // 256 Bit
SecureTokenGenerator::TYPE_REFRESH => 64, // 512 Bit
SecureTokenGenerator::TYPE_VERIFICATION => 32, // 256 Bit
SecureTokenGenerator::TYPE_BEARER => 32, // 256 Bit
SecureTokenGenerator::TYPE_WEBHOOK => 32, // 256 Bit
];
public const DEFAULT_TOKEN_FORMATS = [
SecureTokenGenerator::TYPE_API_KEY => SecureTokenGenerator::FORMAT_BASE64_URL,
SecureTokenGenerator::TYPE_SESSION => SecureTokenGenerator::FORMAT_BASE64_URL,
SecureTokenGenerator::TYPE_OTP => SecureTokenGenerator::FORMAT_NUMERIC,
];
public const TOKEN_EXPIRY_TIMES = [
SecureTokenGenerator::TYPE_SESSION => 3600 * 24, // 24 Stunden
SecureTokenGenerator::TYPE_CSRF => 3600, // 1 Stunde
SecureTokenGenerator::TYPE_VERIFICATION => 3600 * 2, // 2 Stunden
SecureTokenGenerator::TYPE_OTP => 300, // 5 Minuten
SecureTokenGenerator::TYPE_REFRESH => 3600 * 24 * 30, // 30 Tage
];
}
```
## Environment-basierte Konfiguration
### .env Konfiguration
```bash
# Cryptography Configuration
CRYPTO_DEFAULT_KDF_ALGORITHM=argon2id
CRYPTO_DEFAULT_SECURITY_LEVEL=standard
# Token Configuration
CRYPTO_DEFAULT_TOKEN_LENGTH=32
CRYPTO_DEFAULT_TOKEN_FORMAT=base64_url
# Digital Signature Configuration
CRYPTO_DEFAULT_RSA_KEY_SIZE=2048
CRYPTO_DEFAULT_EC_CURVE=secp256r1
# Performance Configuration
CRYPTO_BATCH_SIZE_LIMIT=1000
CRYPTO_ENTROPY_THRESHOLD=7.0
```
### Environment-aware Service
```php
use App\Framework\Core\Environment;
use App\Framework\Core\EnvKey;
final readonly class CryptographyConfigService
{
public function __construct(
private Environment $environment
) {}
public function getDefaultKdfAlgorithm(): string
{
return $this->environment->get(
EnvKey::from('CRYPTO_DEFAULT_KDF_ALGORITHM'),
'argon2id'
);
}
public function getDefaultSecurityLevel(): string
{
return $this->environment->get(
EnvKey::from('CRYPTO_DEFAULT_SECURITY_LEVEL'),
'standard'
);
}
public function getDefaultTokenLength(): int
{
return $this->environment->getInt(
EnvKey::from('CRYPTO_DEFAULT_TOKEN_LENGTH'),
32
);
}
public function getEntropyThreshold(): float
{
return $this->environment->getFloat(
EnvKey::from('CRYPTO_ENTROPY_THRESHOLD'),
7.0
);
}
}
```
## Advanced Configuration
### Custom RandomGenerator
```php
// Eigener RandomGenerator für spezielle Anforderungen
final readonly class CustomSecureRandomGenerator implements RandomGenerator
{
public function bytes(int $length): string
{
// Custom implementation mit Hardware-RNG
return $this->getHardwareRandomBytes($length);
}
public function int(int $min = 0, int $max = PHP_INT_MAX): int
{
return random_int($min, $max);
}
private function getHardwareRandomBytes(int $length): string
{
// Implementation für Hardware-RNG
// z.B. über /dev/hwrng oder externe HSM
}
}
// In Initializer registrieren
$container->singleton(RandomGenerator::class, new CustomSecureRandomGenerator());
```
### Performance-optimierte Konfiguration
```php
final readonly class PerformanceOptimizedCryptoInitializer implements Initializer
{
public function initialize(Container $container): void
{
// Cached Services für bessere Performance
$container->singleton(KeyDerivationFunction::class, function(Container $c) {
$kdf = new KeyDerivationFunction($c->get(RandomGenerator::class));
return new CachedKeyDerivationFunction($kdf, $c->get(Cache::class));
});
// Batch-optimierte Token-Generierung
$container->singleton(SecureTokenGenerator::class, function(Container $c) {
return new BatchOptimizedTokenGenerator(
$c->get(RandomGenerator::class),
batchSize: 100 // Tokens in Batches vorgenerieren
);
});
}
}
```
### Test-Konfiguration
```php
// Für Unit Tests - deterministic aber sichere Werte
final readonly class TestCryptographyInitializer implements Initializer
{
public function initialize(Container $container): void
{
if (!$this->isTestEnvironment()) {
throw new InvalidArgumentException('TestCryptographyInitializer nur in Test-Umgebung verwenden');
}
// Deterministischer aber sicherer Generator für Tests
$container->singleton(RandomGenerator::class, new TestRandomGenerator());
// Reduzierte Parameter für schnellere Tests
$container->singleton(KeyDerivationFunction::class, function(Container $c) {
return new KeyDerivationFunction($c->get(RandomGenerator::class));
});
}
private function isTestEnvironment(): bool
{
return defined('PHPUNIT_RUNNING') ||
(isset($_ENV['APP_ENV']) && $_ENV['APP_ENV'] === 'testing');
}
}
```
## Middleware-Integration
### Automatic Token Validation
```php
final readonly class CryptoTokenValidationMiddleware
{
public function __construct(
private CryptographicUtilities $utils,
private CacheInterface $cache
) {}
public function handle(HttpRequest $request, RequestHandler $handler): HttpResponse
{
$authHeader = $request->server->getAuthorizationHeader();
if ($authHeader && str_starts_with($authHeader, 'Bearer ')) {
$token = substr($authHeader, 7);
// Token-Format validieren
if (!$this->utils->timingSafeEquals($token, trim($token))) {
throw new AuthenticationException('Invalid token format');
}
// Cache für Token-Validierung
$cacheKey = 'token_valid_' . hash('sha256', $token);
if (!$this->cache->has($cacheKey)) {
// Token in Datenbank validieren
$isValid = $this->validateTokenInDatabase($token);
$this->cache->set($cacheKey, $isValid, 300); // 5 Min Cache
}
}
return $handler->handle($request);
}
}
```
## Monitoring und Logging
### Security Event Integration
```php
final readonly class CryptographyEventLogger
{
public function __construct(
private Logger $logger,
private SecurityEventLogger $securityLogger
) {}
public function logTokenGeneration(SecureToken $token): void
{
$this->logger->info('Token generated', [
'type' => $token->getType(),
'format' => $token->getFormat(),
'length' => $token->getLength(),
'fingerprint' => $token->getShortFingerprint()
]);
}
public function logSuspiciousTokenActivity(string $token, string $reason): void
{
$this->securityLogger->logSecurityEvent(
new SuspiciousTokenActivityEvent(
tokenFingerprint: hash('sha256', $token),
reason: $reason,
timestamp: new DateTimeImmutable()
)
);
}
}
```
## Validierung der Konfiguration
```php
final readonly class CryptographyConfigValidator
{
public static function validateConfiguration(Container $container): void
{
// RandomGenerator verfügbar?
if (!$container->has(RandomGenerator::class)) {
throw new ConfigurationException('RandomGenerator nicht registriert');
}
// Cryptography Services verfügbar?
$requiredServices = [
KeyDerivationFunction::class,
SecureTokenGenerator::class,
CryptographicUtilities::class
];
foreach ($requiredServices as $service) {
if (!$container->has($service)) {
throw new ConfigurationException("Service nicht registriert: {$service}");
}
}
// Sicherheitsparameter validieren
$kdf = $container->get(KeyDerivationFunction::class);
try {
$params = $kdf->getRecommendedParameters('pbkdf2-sha256', 'standard');
if ($params['iterations'] < 50000) {
throw new ConfigurationException('PBKDF2 Iterationen zu niedrig (Minimum: 50000)');
}
} catch (InvalidArgumentException $e) {
throw new ConfigurationException('Ungültige KDF-Konfiguration: ' . $e->getMessage());
}
}
}
```
Diese Konfiguration ermöglicht es, das Cryptography Module flexibel an verschiedene Umgebungen und Sicherheitsanforderungen anzupassen, während Best Practices für Sicherheit und Performance eingehalten werden.

View File

@@ -0,0 +1,703 @@
# Cryptography Module - Praktische Beispiele
Umfassende Sammlung praktischer Anwendungsfälle für das Cryptography Module.
## Authentifizierung und Session-Management
### User Password System
```php
final readonly class UserAuthenticationService
{
public function __construct(
private KeyDerivationFunction $kdf,
private SecureTokenGenerator $tokenGenerator,
private UserRepository $userRepository
) {}
public function registerUser(string $email, string $password): User
{
// Password hashen mit Argon2ID
$hashedPassword = $this->kdf->hashPassword($password, 'argon2id', [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4, // 4 Iterationen
'threads' => 3 // 3 Threads
]);
$user = new User(
id: Ulid::generate(),
email: new Email($email),
passwordHash: $hashedPassword,
createdAt: new DateTimeImmutable()
);
return $this->userRepository->save($user);
}
public function authenticateUser(string $email, string $password): ?SessionToken
{
$user = $this->userRepository->findByEmail(new Email($email));
if (!$user || !$this->kdf->verify($password, $user->getPasswordHash())) {
// Timing-Angriffe verhindern durch konstante Ausführungszeit
$this->kdf->hashPassword('dummy-password', 'argon2id');
return null;
}
// Session Token generieren
$sessionToken = $this->tokenGenerator->generateSessionToken(48); // 384 Bit
// In Session Store speichern
$this->storeSessionToken($user, $sessionToken);
return $sessionToken;
}
private function storeSessionToken(User $user, SecureToken $token): void
{
$session = new UserSession(
tokenHash: hash('sha256', $token->getValue()),
userId: $user->getId(),
expiresAt: (new DateTimeImmutable())->add(new DateInterval('PT24H')),
metadata: $token->getMetadata()
);
// Session in Datenbank speichern (nur Hash, nie Klartext!)
$this->sessionRepository->save($session);
}
}
```
### API Key Management System
```php
final readonly class ApiKeyManagementService
{
public function __construct(
private SecureTokenGenerator $tokenGenerator,
private CryptographicUtilities $utils,
private ApiKeyRepository $repository
) {}
public function createApiKey(
User $user,
string $name,
array $scopes = [],
?DateTimeImmutable $expiresAt = null
): ApiKeyResult {
// API Key mit Prefix generieren
$apiKey = $this->tokenGenerator->generateApiKey(
prefix: 'ak',
length: 32
);
// API Key Entity erstellen (Hash speichern, nicht Klartext)
$apiKeyEntity = new ApiKey(
id: Ulid::generate(),
userId: $user->getId(),
name: $name,
keyHash: hash('sha256', $apiKey->getValue()),
fingerprint: $apiKey->getFingerprint(),
scopes: $scopes,
expiresAt: $expiresAt,
createdAt: new DateTimeImmutable()
);
$this->repository->save($apiKeyEntity);
return new ApiKeyResult(
apiKey: $apiKey->getValue(), // Nur einmal zurückgeben
keyId: $apiKeyEntity->getId(),
fingerprint: $apiKey->getShortFingerprint(),
expiresAt: $expiresAt
);
}
public function validateApiKey(string $apiKey): ?ApiKey
{
$keyHash = hash('sha256', $apiKey);
$storedKey = $this->repository->findByHash($keyHash);
if (!$storedKey) {
return null;
}
// Timing-sicherer Vergleich
if (!$this->utils->timingSafeEquals($keyHash, $storedKey->getKeyHash())) {
return null;
}
// Expiration prüfen
if ($storedKey->getExpiresAt() && $storedKey->getExpiresAt() < new DateTimeImmutable()) {
return null;
}
return $storedKey;
}
public function rotateApiKey(string $currentApiKey): ApiKeyResult
{
$oldKey = $this->validateApiKey($currentApiKey);
if (!$oldKey) {
throw new ApiKeyException('Invalid API key for rotation');
}
// Neuen Key mit gleichen Eigenschaften erstellen
$newApiKey = $this->createApiKey(
user: $oldKey->getUser(),
name: $oldKey->getName() . ' (rotated)',
scopes: $oldKey->getScopes(),
expiresAt: $oldKey->getExpiresAt()
);
// Alten Key deaktivieren (nicht löschen für Audit-Trail)
$oldKey->deactivate();
$this->repository->save($oldKey);
return $newApiKey;
}
}
```
## CSRF Protection
### CSRF Token System
```php
final readonly class CsrfProtectionService
{
public function __construct(
private SecureTokenGenerator $tokenGenerator,
private CacheInterface $cache
) {}
public function generateCsrfToken(string $sessionId): SecureToken
{
$csrfToken = $this->tokenGenerator->generateCsrfToken();
// Token mit Session verknüpfen
$cacheKey = "csrf_token_{$sessionId}";
$this->cache->set($cacheKey, $csrfToken->getValue(), 3600); // 1 Stunde
return $csrfToken;
}
public function validateCsrfToken(string $sessionId, string $providedToken): bool
{
$cacheKey = "csrf_token_{$sessionId}";
$storedToken = $this->cache->get($cacheKey);
if (!$storedToken) {
return false;
}
// Timing-sicherer Vergleich
$isValid = hash_equals($storedToken, $providedToken);
// Token nach Verwendung löschen (Single-Use)
if ($isValid) {
$this->cache->delete($cacheKey);
}
return $isValid;
}
}
// CSRF Middleware
final readonly class CsrfProtectionMiddleware
{
public function __construct(
private CsrfProtectionService $csrfService
) {}
public function handle(HttpRequest $request, RequestHandler $handler): HttpResponse
{
// Nur bei state-changing Operations prüfen
if (in_array($request->method, [Method::POST, Method::PUT, Method::DELETE, Method::PATCH])) {
$sessionId = $request->session->getId();
$csrfToken = $request->parsedBody->get('_token') ?? $request->headers->get('X-CSRF-Token');
if (!$csrfToken || !$this->csrfService->validateCsrfToken($sessionId, $csrfToken)) {
throw new CsrfTokenMismatchException('CSRF token mismatch');
}
}
return $handler->handle($request);
}
}
```
## Webhook Security
### Webhook Signature System
```php
final readonly class WebhookSecurityService
{
public function __construct(
private SecureTokenGenerator $tokenGenerator,
private CryptographicUtilities $utils
) {}
public function generateWebhookSecret(): SecureToken
{
return $this->tokenGenerator->generateWebhookToken();
}
public function signWebhookPayload(string $payload, SecureToken $secret): string
{
$signature = hash_hmac('sha256', $payload, $secret->getValue());
return 'sha256=' . $signature;
}
public function validateWebhookSignature(
string $payload,
string $signature,
SecureToken $secret
): bool {
$expectedSignature = $this->signWebhookPayload($payload, $secret);
// Timing-sicherer Vergleich
return $this->utils->timingSafeEquals($signature, $expectedSignature);
}
}
// Webhook Handler
final readonly class PaymentWebhookHandler
{
public function __construct(
private WebhookSecurityService $security,
private WebhookConfigRepository $configRepository
) {}
#[Route(path: '/webhooks/payment', method: Method::POST)]
public function handlePaymentWebhook(HttpRequest $request): JsonResult
{
$signature = $request->headers->get('X-Hub-Signature-256');
$payload = $request->rawBody();
if (!$signature) {
throw new WebhookException('Missing signature header');
}
// Webhook Secret für den Sender abrufen
$senderId = $request->headers->get('X-Sender-ID');
$config = $this->configRepository->findBySenderId($senderId);
if (!$config) {
throw new WebhookException('Unknown sender');
}
// Signatur validieren
if (!$this->security->validateWebhookSignature($payload, $signature, $config->getSecret())) {
throw new WebhookException('Invalid signature');
}
// Payload verarbeiten
$data = json_decode($payload, true);
$this->processPaymentEvent($data);
return new JsonResult(['status' => 'processed']);
}
}
```
## Two-Factor Authentication (2FA)
### OTP-basiertes 2FA System
```php
final readonly class TwoFactorAuthService
{
public function __construct(
private SecureTokenGenerator $tokenGenerator,
private CacheInterface $cache,
private NotificationService $notificationService
) {}
public function generateOtpCode(User $user): string
{
$otpToken = $this->tokenGenerator->generateOtpToken(6); // 6-stelliger Code
// OTP mit User-ID und Expiration speichern
$cacheKey = "otp_{$user->getId()}";
$otpData = [
'code' => $otpToken->getValue(),
'attempts' => 0,
'created_at' => time()
];
$this->cache->set($cacheKey, $otpData, 300); // 5 Minuten gültig
return $otpToken->getValue();
}
public function sendOtpCode(User $user): void
{
$otpCode = $this->generateOtpCode($user);
// SMS oder Email versenden
$this->notificationService->sendOtpCode(
recipient: $user->getPhoneNumber() ?? $user->getEmail(),
code: $otpCode,
expiresInMinutes: 5
);
}
public function verifyOtpCode(User $user, string $providedCode): bool
{
$cacheKey = "otp_{$user->getId()}";
$otpData = $this->cache->get($cacheKey);
if (!$otpData) {
return false; // Kein OTP vorhanden oder abgelaufen
}
// Rate-Limiting: Max 3 Versuche
if ($otpData['attempts'] >= 3) {
$this->cache->delete($cacheKey);
return false;
}
// Timing-sicherer Vergleich
$isValid = hash_equals($otpData['code'], $providedCode);
if ($isValid) {
// Erfolgreiche Verifikation - OTP löschen
$this->cache->delete($cacheKey);
} else {
// Fehlversuch - Counter erhöhen
$otpData['attempts']++;
$this->cache->set($cacheKey, $otpData, 300);
}
return $isValid;
}
}
```
## Digitale Signaturen für Dokumente
### Document Signing Service
```php
final readonly class DocumentSigningService
{
public function __construct(
private DigitalSignature $signature,
private DocumentRepository $documentRepository
) {}
public function generateSigningKeyPair(): KeyPair
{
// RSA 4096 Bit für langfristige Dokumentensignaturen
return $this->signature->generateRsaKeyPair(4096);
}
public function signDocument(
Document $document,
PrivateKey $privateKey,
User $signer
): SignedDocument {
$documentContent = $document->getContent();
$metadata = [
'document_id' => $document->getId(),
'signer_id' => $signer->getId(),
'signed_at' => (new DateTimeImmutable())->format('c'),
'algorithm' => 'RSA-SHA256'
];
// Dokument + Metadaten signieren
$dataToSign = $documentContent . json_encode($metadata);
$signatureResult = $this->signature->sign($dataToSign, $privateKey, 'sha256');
$signedDocument = new SignedDocument(
originalDocument: $document,
signature: $signatureResult,
signerPublicKey: $privateKey->getPublicKey(),
metadata: $metadata,
signedAt: new DateTimeImmutable()
);
return $this->documentRepository->saveSignedDocument($signedDocument);
}
public function verifyDocumentSignature(SignedDocument $signedDocument): bool
{
$document = $signedDocument->getOriginalDocument();
$metadata = $signedDocument->getMetadata();
$dataToVerify = $document->getContent() . json_encode($metadata);
return $this->signature->verify(
$dataToVerify,
$signedDocument->getSignature(),
$signedDocument->getSignerPublicKey()
);
}
public function createSignatureChain(array $documents, array $signers): SignatureChain
{
$chain = new SignatureChain();
foreach ($documents as $index => $document) {
$signer = $signers[$index];
$signedDocument = $this->signDocument($document, $signer->getPrivateKey(), $signer);
$chain->addSignedDocument($signedDocument);
}
// Chain-Signatur erstellen (Hash der gesamten Kette)
$chainHash = $chain->calculateChainHash();
$chainSignature = $this->signature->sign($chainHash, $signers[0]->getPrivateKey());
$chain->setChainSignature($chainSignature);
return $chain;
}
}
```
## Passwort-Reset System
### Secure Password Reset
```php
final readonly class PasswordResetService
{
public function __construct(
private SecureTokenGenerator $tokenGenerator,
private KeyDerivationFunction $kdf,
private CacheInterface $cache,
private EmailService $emailService
) {}
public function initiatePasswordReset(User $user): void
{
// Sicheren Reset-Token generieren
$resetToken = $this->tokenGenerator->generateVerificationToken('password_reset');
// Token hashen und speichern (nie Klartext speichern)
$tokenHash = hash('sha256', $resetToken->getValue());
$resetData = [
'user_id' => $user->getId(),
'token_hash' => $tokenHash,
'created_at' => time(),
'used' => false
];
// 2 Stunden gültig
$cacheKey = "password_reset_{$user->getId()}";
$this->cache->set($cacheKey, $resetData, 7200);
// Reset-Link per Email senden
$resetLink = "https://app.example.com/reset-password?token=" .
urlencode($resetToken->getValue());
$this->emailService->send(
to: $user->getEmail(),
subject: 'Password Reset Request',
template: 'password_reset',
data: ['reset_link' => $resetLink, 'expires_in' => '2 hours']
);
}
public function validateResetToken(string $token): ?User
{
$tokenHash = hash('sha256', $token);
// Token in allen aktiven Reset-Anfragen suchen
$cacheKeys = $this->cache->getKeysByPattern('password_reset_*');
foreach ($cacheKeys as $cacheKey) {
$resetData = $this->cache->get($cacheKey);
if ($resetData &&
!$resetData['used'] &&
hash_equals($resetData['token_hash'], $tokenHash)) {
return $this->userRepository->find($resetData['user_id']);
}
}
return null;
}
public function resetPassword(string $token, string $newPassword): bool
{
$user = $this->validateResetToken($token);
if (!$user) {
return false;
}
// Neues Password hashen
$hashedPassword = $this->kdf->hashPassword($newPassword, 'argon2id');
// User Password aktualisieren
$user->updatePassword($hashedPassword);
$this->userRepository->save($user);
// Reset-Token als verwendet markieren
$cacheKey = "password_reset_{$user->getId()}";
$resetData = $this->cache->get($cacheKey);
if ($resetData) {
$resetData['used'] = true;
$this->cache->set($cacheKey, $resetData, 7200);
}
return true;
}
}
```
## Daten-Verschlüsselung mit Schlüssel-Ableitung
### Encrypted Data Storage
```php
final readonly class EncryptedDataService
{
public function __construct(
private KeyDerivationFunction $kdf,
private CryptographicUtilities $utils,
private EncryptionService $encryption
) {}
public function encryptPersonalData(
array $personalData,
string $userPassword
): EncryptedPersonalData {
// Benutzer-spezifischen Schlüssel aus Password ableiten
$salt = $this->utils->generateNonce(32);
$derivedKey = $this->kdf->pbkdf2($userPassword, $salt, 100000, 32);
// Daten serialisieren und verschlüsseln
$serializedData = json_encode($personalData);
$encryptedData = $this->encryption->encrypt($serializedData, $derivedKey->getKey());
return new EncryptedPersonalData(
encryptedData: $encryptedData,
salt: $salt,
keyDerivation: [
'algorithm' => $derivedKey->getAlgorithm(),
'iterations' => $derivedKey->getIterations()
]
);
}
public function decryptPersonalData(
EncryptedPersonalData $encryptedData,
string $userPassword
): array {
// Gleichen Schlüssel aus Password ableiten
$derivedKey = $this->kdf->pbkdf2(
$userPassword,
$encryptedData->getSalt(),
$encryptedData->getKeyDerivation()['iterations'],
32
);
// Daten entschlüsseln
$decryptedData = $this->encryption->decrypt(
$encryptedData->getEncryptedData(),
$derivedKey->getKey()
);
return json_decode($decryptedData, true);
}
}
```
## Audit-Trail mit Kryptographischen Fingerprints
### Secure Audit Trail
```php
final readonly class AuditTrailService
{
public function __construct(
private CryptographicUtilities $utils,
private DigitalSignature $signature,
private AuditLogRepository $repository
) {}
public function logUserAction(
User $user,
string $action,
array $context = []
): AuditLogEntry {
$timestamp = new DateTimeImmutable();
$logData = [
'user_id' => $user->getId(),
'action' => $action,
'context' => $context,
'timestamp' => $timestamp->format('c'),
'ip_address' => $this->getClientIpHash(),
'user_agent_hash' => $this->getUserAgentHash()
];
// Kryptographischen Fingerprint erstellen
$dataString = json_encode($logData, JSON_SORT_KEYS);
$fingerprint = hash('sha256', $dataString);
// Chain-Hash (verhindert Manipulation der Historie)
$previousEntry = $this->repository->getLatestEntry();
$chainHash = $previousEntry
? hash('sha256', $previousEntry->getChainHash() . $fingerprint)
: $fingerprint;
$auditEntry = new AuditLogEntry(
id: Ulid::generate(),
fingerprint: $fingerprint,
chainHash: $chainHash,
logData: $logData,
createdAt: $timestamp
);
return $this->repository->save($auditEntry);
}
public function verifyAuditTrailIntegrity(): bool
{
$entries = $this->repository->getAllEntriesOrdered();
$previousChainHash = null;
foreach ($entries as $entry) {
// Fingerprint verifizieren
$dataString = json_encode($entry->getLogData(), JSON_SORT_KEYS);
$expectedFingerprint = hash('sha256', $dataString);
if (!hash_equals($entry->getFingerprint(), $expectedFingerprint)) {
return false; // Entry wurde manipuliert
}
// Chain-Hash verifizieren
$expectedChainHash = $previousChainHash
? hash('sha256', $previousChainHash . $entry->getFingerprint())
: $entry->getFingerprint();
if (!hash_equals($entry->getChainHash(), $expectedChainHash)) {
return false; // Chain wurde unterbrochen
}
$previousChainHash = $entry->getChainHash();
}
return true;
}
private function getClientIpHash(): string
{
$clientIp = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
return hash('sha256', $clientIp); // IP nicht im Klartext speichern
}
private function getUserAgentHash(): string
{
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
return hash('sha256', $userAgent);
}
}
```
Diese Beispiele zeigen die praktische Anwendung des Cryptography Modules in realen Szenarien und demonstrieren Best Practices für sichere Implementierungen.

View File

@@ -0,0 +1,365 @@
# Cryptography Module
Das Cryptography Module erweitert die bestehenden Verschlüsselungsfunktionen des Frameworks um moderne kryptographische Primitive und bietet sichere Implementierungen für Schlüsselableitung, digitale Signaturen, erweiterte Hash-Funktionen und sichere Token-Generierung.
## Überblick
Das Modul folgt den Framework-Prinzipien:
- **Immutable Value Objects** für sichere Datenrepräsentation
- **Service Pattern** für Business Logic
- **Dependency Injection** für RandomGenerator Integration
- **Security-First Design** mit timing-sicheren Operationen
## Core Services
### KeyDerivationFunction Service
Sichere Schlüsselableitung für Password-Hashing und Key-Stretching.
```php
use App\Framework\Cryptography\KeyDerivationFunction;
use App\Framework\Random\SecureRandomGenerator;
$kdf = new KeyDerivationFunction(new SecureRandomGenerator());
// PBKDF2 (Standard)
$derivedKey = $kdf->pbkdf2('password', $salt, 100000, 32);
// Argon2ID (Empfohlen)
$derivedKey = $kdf->argon2id('password', $salt, 65536, 4, 3, 32);
// Password mit automatischer Salt-Generierung hashen
$derivedKey = $kdf->hashPassword('password', 'argon2id');
// Password verifizieren
$isValid = $kdf->verify('password', $derivedKey);
```
**Unterstützte Algorithmen:**
- **PBKDF2** mit SHA-256, SHA-512, SHA-384, SHA-224
- **Argon2ID** (empfohlen für neue Implementierungen)
- **scrypt** für spezielle Anwendungsfälle
### DigitalSignature Service
Digitale Signaturen für Datenintegrität und Authentifizierung.
```php
use App\Framework\Cryptography\DigitalSignature;
$signature = new DigitalSignature(new SecureRandomGenerator());
// RSA Schlüsselpaar generieren
$keyPair = $signature->generateRsaKeyPair(2048);
// Daten signieren
$signatureResult = $signature->sign('data to sign', $keyPair->getPrivateKey());
// Signatur verifizieren
$isValid = $signature->verify('data to sign', $signatureResult, $keyPair->getPublicKey());
// ECDSA mit secp256r1
$ecKeyPair = $signature->generateEcdsaKeyPair('secp256r1');
$ecSignature = $signature->signWithEcdsa('data', $ecKeyPair->getPrivateKey());
```
### AdvancedHash Service
Erweiterte Hash-Funktionen über grundlegende Algorithmen hinaus.
```php
use App\Framework\Cryptography\AdvancedHash;
$hash = new AdvancedHash();
// SHA-3 Familie
$sha3 = $hash->sha3('data', 256);
$shake = $hash->shake('data', 32, 128); // Extendable-output function
// BLAKE2
$blake2b = $hash->blake2b('data', 32, 'optional-key');
$blake2s = $hash->blake2s('data', 16);
// Hash-Ketten für komplexe Szenarien
$chainResult = $hash->hashChain('data', ['sha3-256', 'blake2b']);
```
### SecureTokenGenerator Service
Kryptographisch sichere Token-Generierung für APIs, Sessions und mehr.
```php
use App\Framework\Cryptography\SecureTokenGenerator;
$generator = new SecureTokenGenerator(new SecureRandomGenerator());
// API Keys mit Prefix
$apiKey = $generator->generateApiKey('myapp'); // myapp_...
// Session Tokens
$sessionToken = $generator->generateSessionToken();
// CSRF Tokens
$csrfToken = $generator->generateCsrfToken();
// OTP Tokens
$otp = $generator->generateOtpToken(6); // 6-stelliger numerischer Code
// Custom Tokens mit eigenem Alphabet
$customToken = $generator->generateCustom('0123456789ABCDEF', 16);
// Batch-Generierung
$tokens = $generator->generateBatch('session', 10, 32);
```
**Token-Formate:**
- `FORMAT_BASE64_URL` (Standard, URL-sicher)
- `FORMAT_BASE64` (Standard Base64)
- `FORMAT_HEX` (Hexadezimal)
- `FORMAT_BASE32` (Base32)
- `FORMAT_ALPHANUMERIC` (Buchstaben + Zahlen)
### CryptographicUtilities Service
Sammlung kryptographischer Utility-Funktionen.
```php
use App\Framework\Cryptography\CryptographicUtilities;
$utils = new CryptographicUtilities(new SecureRandomGenerator());
// Timing-sichere String-Vergleiche
$isEqual = $utils->timingSafeEquals($string1, $string2);
// Entropie-Validierung
$isHighEntropy = $utils->validateEntropy($data, 7.0);
$entropy = $utils->calculateShannonEntropy($data);
// Sichere UUIDs
$uuid4 = $utils->generateUuid4(); // Zufällige UUID
$uuid5 = $utils->generateUuid5($namespace, 'name'); // Deterministische UUID
// Key-Stretching
$stretched = $utils->stretchKey('password', 'salt', 10000, 32);
// Speicher sicher löschen
$utils->secureWipe($sensitiveData);
```
## Value Objects
### DerivedKey
Unveränderliche Repräsentation abgeleiteter Schlüssel.
```php
// Eigenschaften abrufen
$algorithm = $derivedKey->getAlgorithm(); // 'pbkdf2-sha256'
$keyLength = $derivedKey->getKeyLength(); // 32
$iterations = $derivedKey->getIterations(); // 100000
// Verschiedene Formate
$hex = $derivedKey->toHex();
$base64 = $derivedKey->toBase64();
// Serialisierung
$array = $derivedKey->toArray();
$restored = DerivedKey::fromArray($array);
// Gleichheit prüfen (timing-sicher)
$isEqual = $derivedKey->equals($otherKey);
```
### SecureToken
Token mit Metadaten und sicherheitsfokussierten Funktionen.
```php
// Token-Eigenschaften
$type = $token->getType(); // 'api_key'
$format = $token->getFormat(); // 'base64_url'
$hasPrefix = $token->hasPrefix(); // true/false
// Sichere Operationen
$isEqual = $token->equals($otherToken); // timing-sicher
$isValid = $token->verify($candidateToken); // timing-sicher
// Sicherheit und Logging
$masked = $token->getMaskedValue(); // myap****_Ab...fG
$fingerprint = $token->getFingerprint(); // SHA-256 Hash
$safeSummary = $token->getSafeSummary(); // Ohne Token-Wert
```
### KeyPair, PrivateKey, PublicKey
Sichere Verwaltung asymmetrischer Schlüssel.
```php
$keyPair = $signature->generateRsaKeyPair(2048);
$privateKey = $keyPair->getPrivateKey();
$publicKey = $keyPair->getPublicKey();
// Schlüssel-Export
$privatePem = $privateKey->toPem();
$publicPem = $publicKey->toPem();
// Schlüssel-Import
$privateKey = PrivateKey::fromPem($privatePem);
$publicKey = PublicKey::fromPem($publicPem);
```
## Sicherheitsfeatures
### Timing-Attack Schutz
Alle kritischen Vergleichsoperationen verwenden timing-sichere Implementierungen:
```php
// Timing-sichere String-Vergleiche
$utils->timingSafeEquals($secret1, $secret2);
// Timing-sichere Token-Verifikation
$token->verify($candidateToken);
// Timing-sichere Array-Suche
$utils->constantTimeArraySearch($haystack, $needle);
```
### Entropie-Validierung
Automatische Validierung der Schlüsselstärke:
```php
// Shannon-Entropie berechnen
$entropy = $utils->calculateShannonEntropy($data);
// Mindest-Entropie validieren
$isStrong = $utils->validateEntropy($data, 7.0);
// Schlüsselstärke prüfen
$isValidKey = $utils->validateKeyStrength($key, 128); // Minimum 128 Bits
```
### Sichere Speicher-Verwaltung
```php
// Sensitive Daten sicher löschen
$utils->secureWipe($password); // Überschreibt Speicher
// Automatische Metadaten-Bereinigung in Token-Logs
$safeSummary = $token->getSafeSummary(); // Ohne sensitive Werte
```
## Best Practices
### Empfohlene Parameter
```php
// PBKDF2 (Minimum)
$kdf->pbkdf2($password, $salt, 100000, 32, 'sha256');
// Argon2ID (Empfohlen)
$kdf->argon2id($password, $salt, 65536, 4, 3, 32);
// RSA Schlüssel (Minimum 2048 Bit)
$signature->generateRsaKeyPair(2048);
// Token-Längen
$generator->generateApiKey('prefix', 32); // 256 Bit
$generator->generateSessionToken(48); // 384 Bit für langlebige Sessions
```
### Sichere Implementierung
```php
// ✅ Gute Praxis
final readonly class AuthService
{
public function __construct(
private readonly KeyDerivationFunction $kdf,
private readonly SecureTokenGenerator $tokenGenerator
) {}
public function hashPassword(string $password): DerivedKey
{
return $this->kdf->hashPassword($password, 'argon2id');
}
public function generateApiKey(string $prefix): SecureToken
{
return $this->tokenGenerator->generateApiKey($prefix, 32);
}
}
// ❌ Schlechte Praxis - Nicht verwenden
// $hashedPassword = md5($password); // Unsicher
// $token = bin2hex(random_bytes(16)); // Zu kurz, keine Metadaten
```
## Integration mit Framework
### Dependency Injection
```php
final readonly class CryptographyServiceInitializer implements Initializer
{
public function initialize(Container $container): void
{
$randomGenerator = $container->get(RandomGenerator::class);
$container->singleton(KeyDerivationFunction::class,
new KeyDerivationFunction($randomGenerator));
$container->singleton(SecureTokenGenerator::class,
new SecureTokenGenerator($randomGenerator));
$container->singleton(CryptographicUtilities::class,
new CryptographicUtilities($randomGenerator));
}
}
```
### Controller Integration
```php
final readonly class ApiKeyController
{
#[Route(path: '/admin/api-keys', method: Method::POST)]
#[Auth(strategy: 'ip', allowedIps: ['127.0.0.1'])]
public function createApiKey(
CreateApiKeyRequest $request,
SecureTokenGenerator $tokenGenerator
): JsonResult {
$apiKey = $tokenGenerator->generateApiKey(
prefix: $request->prefix,
length: 32
);
// Token sicher in Datenbank speichern
// Nur Hash oder verschlüsselte Version speichern, nie Klartext
return new JsonResult([
'api_key' => $apiKey->getValue(),
'fingerprint' => $apiKey->getShortFingerprint(),
'created_at' => $apiKey->getCreatedAt()->format('c')
]);
}
}
```
## Performance
Das Cryptography Module ist für Production-Einsatz optimiert:
- **Cached Reflection Provider** für Dependency Injection
- **Batch-Operationen** für Token-Generierung
- **Effiziente Algorithmen** mit modernen kryptographischen Standards
- **Minimale Speicher-Allokation** durch readonly Value Objects
## Weiterführende Dokumentation
- [Konfiguration](configuration.md) - Setup und Anpassung
- [Beispiele](examples.md) - Praktische Anwendungsfälle
- [Migration](migration.md) - Upgrade von älteren Krypto-Implementierungen
- [Sicherheit](security.md) - Detaillierte Sicherheitsrichtlinien

View File

@@ -0,0 +1,728 @@
# Cryptography Module - Sicherheitsrichtlinien
Detaillierte Sicherheitsrichtlinien und Best Practices für das Cryptography Module.
## Grundlegende Sicherheitsprinzipien
### Defense in Depth
Das Cryptography Module implementiert mehrschichtigen Schutz:
1. **Algorithmus-Ebene**: Moderne, peer-reviewed Algorithmen (Argon2ID, SHA-3, ECDSA)
2. **Implementation-Ebene**: Timing-sichere Operationen und sichere Speicherverwaltung
3. **Application-Ebene**: Sichere Integration und Konfiguration
4. **System-Ebene**: Sicherer Random Number Generator und Entropie-Validierung
### Zero-Trust Architektur
```php
// ✅ Vertraue niemals Eingaben - validiere alles
final readonly class SecureTokenValidator
{
public function validateApiKey(string $providedKey): ?ApiKeyContext
{
// Eingabe-Validierung
if (empty($providedKey) || strlen($providedKey) < 32) {
return null;
}
// Format-Validierung
if (!$this->tokenGenerator->isValidFormat($providedKey, 'base64_url')) {
return null;
}
// Timing-sicherer Vergleich mit gespeichertem Hash
$keyHash = hash('sha256', $providedKey);
$storedKey = $this->repository->findByHash($keyHash);
if (!$storedKey || !hash_equals($keyHash, $storedKey->getHash())) {
return null;
}
// Zusätzliche Sicherheitsprüfungen
return $this->performSecurityChecks($storedKey);
}
}
```
## Kryptographische Best Practices
### Sichere Schlüssel-Ableitung
```php
// ✅ Empfohlene Parameter für verschiedene Szenarien
final readonly class SecureKeyDerivation
{
private const SECURITY_LEVELS = [
// Hohe Sicherheit für sensitive Daten
'high_security' => [
'algorithm' => 'argon2id',
'memory_cost' => 131072, // 128 MB
'time_cost' => 6, // 6 Iterationen
'threads' => 4, // 4 Threads
'key_length' => 32 // 256 Bit
],
// Standard für normale Anwendungen
'standard' => [
'algorithm' => 'argon2id',
'memory_cost' => 65536, // 64 MB
'time_cost' => 4, // 4 Iterationen
'threads' => 3, // 3 Threads
'key_length' => 32 // 256 Bit
],
// Kompatibilität mit älteren Systemen
'legacy_compatible' => [
'algorithm' => 'pbkdf2-sha256',
'iterations' => 200000, // 200k Iterationen
'key_length' => 32 // 256 Bit
]
];
public function hashPassword(string $password, string $level = 'standard'): DerivedKey
{
$params = self::SECURITY_LEVELS[$level] ?? self::SECURITY_LEVELS['standard'];
return match ($params['algorithm']) {
'argon2id' => $this->kdf->argon2id(
$password,
$this->kdf->generateSalt(32),
$params['memory_cost'],
$params['time_cost'],
$params['threads'],
$params['key_length']
),
'pbkdf2-sha256' => $this->kdf->pbkdf2(
$password,
$this->kdf->generateSalt(32),
$params['iterations'],
$params['key_length']
)
};
}
}
```
### Sichere Token-Generierung
```php
// ✅ Token-Sicherheit nach Verwendungszweck
final readonly class SecurityAwareTokenGenerator
{
private const TOKEN_SECURITY_REQUIREMENTS = [
'api_key' => [
'length' => 32, // 256 Bit
'format' => 'base64_url',
'entropy_min' => 7.0,
'expires' => false, // Langlebig
'single_use' => false
],
'session' => [
'length' => 48, // 384 Bit (höhere Sicherheit)
'format' => 'base64_url',
'entropy_min' => 7.5,
'expires' => true,
'single_use' => false
],
'csrf' => [
'length' => 32, // 256 Bit
'format' => 'base64_url',
'entropy_min' => 7.0,
'expires' => true, // Kurze Lebensdauer
'single_use' => true // Einmalverwendung
],
'password_reset' => [
'length' => 64, // 512 Bit (maximale Sicherheit)
'format' => 'base64_url',
'entropy_min' => 7.8,
'expires' => true,
'single_use' => true,
'max_lifetime' => 3600 * 2 // 2 Stunden
]
];
public function generateSecureToken(string $type): SecureToken
{
$requirements = self::TOKEN_SECURITY_REQUIREMENTS[$type] ??
throw new InvalidArgumentException("Unknown token type: {$type}");
do {
$token = $this->tokenGenerator->generate(
$type,
$requirements['length'],
$requirements['format']
);
// Entropie validieren
$entropy = $this->utils->calculateShannonEntropy($token->getRawBytes());
} while ($entropy < $requirements['entropy_min']);
return $token;
}
}
```
## Timing-Attack Prevention
### Konstante Ausführungszeit
```php
// ✅ Timing-sichere Implementierung
final readonly class TimingSafeOperations
{
public function authenticateUser(string $email, string $password): ?User
{
$user = $this->userRepository->findByEmail(new Email($email));
// WICHTIG: Immer Hashing durchführen, auch bei ungültigem User
$providedHash = $user
? $user->getPasswordHash()
: $this->createDummyHash(); // Konstante Ausführungszeit
$isValid = $this->kdf->verify($password, $providedHash);
// Zusätzliche konstante Verzögerung
$this->enforceConstantTime();
return $isValid && $user ? $user : null;
}
private function createDummyHash(): DerivedKey
{
// Dummy-Hash mit gleichen Parametern wie echte Hashes
static $dummyHash = null;
if ($dummyHash === null) {
$dummyHash = $this->kdf->hashPassword('dummy-password', 'argon2id');
}
return $dummyHash;
}
private function enforceConstantTime(): void
{
// Minimale zusätzliche Verzögerung (1-5ms)
usleep(random_int(1000, 5000));
}
}
```
### Side-Channel Resistance
```php
// ✅ Schutz vor Side-Channel-Angriffen
final readonly class SideChannelResistantComparison
{
public function compareSecrets(string $secret1, string $secret2): bool
{
// PHP's hash_equals ist timing-sicher implementiert
return hash_equals($secret1, $secret2);
}
public function compareArrays(array $array1, array $array2): bool
{
// Arrays zu Strings serialisieren für timing-sicheren Vergleich
$string1 = json_encode($array1, JSON_SORT_KEYS);
$string2 = json_encode($array2, JSON_SORT_KEYS);
return hash_equals($string1, $string2);
}
public function searchInArray(array $haystack, mixed $needle): bool
{
$found = false;
// Alle Elemente durchgehen (konstante Zeit)
foreach ($haystack as $value) {
$isMatch = is_string($value) && is_string($needle)
? hash_equals($value, $needle)
: ($value === $needle);
$found = $found || $isMatch; // Kein frühes Beenden
}
return $found;
}
}
```
## Sichere Speicherverwaltung
### Sensitive Data Handling
```php
// ✅ Sicherer Umgang mit sensitiven Daten
final readonly class SecureMemoryManagement
{
public function processSecretData(string $secretData): ProcessedResult
{
try {
// Daten verarbeiten
$result = $this->doSecretProcessing($secretData);
// Sensitive Daten aus Speicher löschen
$this->utils->secureWipe($secretData);
return $result;
} catch (Throwable $e) {
// Auch bei Fehlern Speicher löschen
$this->utils->secureWipe($secretData);
throw $e;
}
}
public function createSecureTemporaryFile(string $data): SecureTemporaryFile
{
// Temporary file mit restriktiven Berechtigungen erstellen
$tempFile = tempnam(sys_get_temp_dir(), 'secure_');
chmod($tempFile, 0600); // Nur Owner kann lesen/schreiben
// Daten schreiben und sofort aus Speicher löschen
file_put_contents($tempFile, $data);
$this->utils->secureWipe($data);
// Auto-cleanup mit Destruktor
return new SecureTemporaryFile($tempFile);
}
}
// Auto-cleanup für temporäre Dateien
final class SecureTemporaryFile
{
public function __construct(private string $filePath) {}
public function __destruct()
{
if (file_exists($this->filePath)) {
// Datei mehrfach überschreiben vor dem Löschen
$fileSize = filesize($this->filePath);
for ($i = 0; $i < 3; $i++) {
file_put_contents($this->filePath, random_bytes($fileSize));
}
unlink($this->filePath);
}
}
public function getPath(): string
{
return $this->filePath;
}
}
```
## Input Validation und Sanitization
### Comprehensive Input Validation
```php
// ✅ Umfassende Eingabe-Validierung
final readonly class CryptographicInputValidator
{
public function validatePasswordStrength(string $password): ValidationResult
{
$errors = [];
// Länge prüfen
if (strlen($password) < 8) {
$errors[] = 'Password must be at least 8 characters long';
}
// Komplexität prüfen
if (!preg_match('/[A-Z]/', $password)) {
$errors[] = 'Password must contain uppercase letters';
}
if (!preg_match('/[a-z]/', $password)) {
$errors[] = 'Password must contain lowercase letters';
}
if (!preg_match('/[0-9]/', $password)) {
$errors[] = 'Password must contain numbers';
}
if (!preg_match('/[^A-Za-z0-9]/', $password)) {
$errors[] = 'Password must contain special characters';
}
// Entropie prüfen
$entropy = $this->utils->calculateShannonEntropy($password);
if ($entropy < 3.5) {
$errors[] = 'Password has insufficient entropy';
}
// Gegen Common-Passwords prüfen
if ($this->isCommonPassword($password)) {
$errors[] = 'Password is too common';
}
return new ValidationResult(empty($errors), $errors);
}
public function validateApiKeyFormat(string $apiKey): bool
{
// Länge prüfen (32-64 Zeichen)
if (strlen($apiKey) < 32 || strlen($apiKey) > 64) {
return false;
}
// Format prüfen (Base64URL)
if (!preg_match('/^[A-Za-z0-9_-]+$/', $apiKey)) {
return false;
}
// Entropie validieren
$entropy = $this->utils->calculateShannonEntropy($apiKey);
return $entropy >= 6.0;
}
public function sanitizeUserInput(string $input): string
{
// Whitespace normalisieren
$sanitized = trim($input);
// Null-Bytes entfernen (verhindern Directory Traversal)
$sanitized = str_replace("\0", '', $sanitized);
// Control Characters entfernen
$sanitized = preg_replace('/[\x00-\x1F\x7F]/', '', $sanitized);
return $sanitized;
}
private function isCommonPassword(string $password): bool
{
$commonPasswords = [
'password', '123456', 'password123', 'admin', 'qwerty',
'letmein', 'welcome', 'monkey', '1234567890', 'password1'
];
$lowercase = strtolower($password);
foreach ($commonPasswords as $common) {
if ($lowercase === $common ||
levenshtein($lowercase, $common) <= 2) {
return true;
}
}
return false;
}
}
```
## Rate Limiting und Abuse Prevention
### Cryptographic Rate Limiting
```php
// ✅ Rate-Limiting für kryptographische Operationen
final readonly class CryptographicRateLimiter
{
private const LIMITS = [
'password_attempts' => ['count' => 5, 'window' => 900], // 5 in 15 Min
'token_generation' => ['count' => 100, 'window' => 3600], // 100 in 1 Stunde
'password_reset' => ['count' => 3, 'window' => 3600], // 3 in 1 Stunde
'otp_generation' => ['count' => 5, 'window' => 300], // 5 in 5 Min
];
public function __construct(
private CacheInterface $cache,
private SecurityEventLogger $securityLogger
) {}
public function checkLimit(string $operation, string $identifier): bool
{
$limit = self::LIMITS[$operation] ?? null;
if (!$limit) {
return true; // Kein Limit definiert
}
$cacheKey = "ratelimit_{$operation}_{$identifier}";
$attempts = $this->cache->get($cacheKey, []);
$now = time();
// Abgelaufene Versuche entfernen
$attempts = array_filter($attempts, fn($timestamp) =>
$now - $timestamp < $limit['window']);
if (count($attempts) >= $limit['count']) {
// Rate-Limit erreicht
$this->securityLogger->logRateLimitExceeded($operation, $identifier);
return false;
}
// Neuen Versuch hinzufügen
$attempts[] = $now;
$this->cache->set($cacheKey, $attempts, $limit['window']);
return true;
}
public function recordFailedAttempt(string $operation, string $identifier): void
{
$cacheKey = "failed_{$operation}_{$identifier}";
$failures = $this->cache->get($cacheKey, 0);
$failures++;
$this->cache->set($cacheKey, $failures, 3600); // 1 Stunde
// Bei vielen Fehlversuchen Sicherheitsteam benachrichtigen
if ($failures >= 10) {
$this->securityLogger->logSuspiciousActivity(
$operation,
$identifier,
"Multiple failed attempts: {$failures}"
);
}
}
}
```
## Error Handling und Information Leakage Prevention
### Secure Error Handling
```php
// ✅ Sichere Fehlerbehandlung ohne Information Leakage
final readonly class SecureErrorHandler
{
public function handleCryptographicError(Throwable $error): ErrorResponse
{
// Detaillierte Logs für interne Analyse
$this->logger->error('Cryptographic error occurred', [
'error_type' => get_class($error),
'message' => $error->getMessage(),
'trace' => $error->getTraceAsString(),
'context' => $this->getSecureContext()
]);
// Generische Antwort für Client (keine Details)
$publicMessage = match (true) {
$error instanceof InvalidPasswordException => 'Authentication failed',
$error instanceof TokenExpiredException => 'Token has expired',
$error instanceof TokenInvalidException => 'Invalid token',
$error instanceof CryptographicException => 'Security operation failed',
default => 'Internal error occurred'
};
return new ErrorResponse(
message: $publicMessage,
code: $this->getPublicErrorCode($error),
timestamp: new DateTimeImmutable()
);
}
private function getSecureContext(): array
{
return [
'request_id' => $this->generateRequestId(),
'user_agent_hash' => hash('sha256', $_SERVER['HTTP_USER_AGENT'] ?? ''),
'ip_hash' => hash('sha256', $_SERVER['REMOTE_ADDR'] ?? ''),
'timestamp' => time()
];
}
private function generateRequestId(): string
{
return bin2hex(random_bytes(16));
}
}
```
## Monitoring und Alerting
### Security Monitoring
```php
// ✅ Sicherheits-Monitoring für kryptographische Operationen
final readonly class CryptographicSecurityMonitor
{
public function __construct(
private MetricsCollector $metrics,
private AlertManager $alerts,
private SecurityEventLogger $securityLogger
) {}
public function monitorOperation(string $operation, callable $callback): mixed
{
$startTime = microtime(true);
$operationId = bin2hex(random_bytes(8));
try {
$result = $callback();
// Erfolgreiche Operation protokollieren
$duration = microtime(true) - $startTime;
$this->metrics->increment("crypto.{$operation}.success");
$this->metrics->timing("crypto.{$operation}.duration", $duration);
// Ungewöhnlich lange Operationen melden
if ($duration > $this->getExpectedDuration($operation) * 2) {
$this->alerts->sendAlert(
level: 'warning',
message: "Slow cryptographic operation: {$operation}",
context: ['duration' => $duration, 'operation_id' => $operationId]
);
}
return $result;
} catch (Throwable $e) {
// Fehlgeschlagene Operation protokollieren
$this->metrics->increment("crypto.{$operation}.failure");
$this->securityLogger->logCryptographicFailure($operation, $e, $operationId);
// Bei kritischen Fehlern sofort alarmieren
if ($this->isCriticalError($e)) {
$this->alerts->sendAlert(
level: 'critical',
message: "Critical cryptographic failure: {$operation}",
context: [
'error' => $e->getMessage(),
'operation_id' => $operationId
]
);
}
throw $e;
}
}
public function detectAnomalousPatterns(): void
{
// Erhöhte Fehlerrate erkennen
$errorRate = $this->metrics->getRate('crypto.*.failure', '5m');
if ($errorRate > 0.1) { // >10% Fehlerrate
$this->alerts->sendAlert(
level: 'warning',
message: 'High cryptographic error rate detected',
context: ['error_rate' => $errorRate]
);
}
// Ungewöhnliche Aktivitätsmuster
$operations = $this->metrics->getCount('crypto.*.success', '1h');
$baseline = $this->getHistoricalBaseline();
if ($operations > $baseline * 5) {
$this->alerts->sendAlert(
level: 'warning',
message: 'Unusual spike in cryptographic operations',
context: ['operations' => $operations, 'baseline' => $baseline]
);
}
}
private function getExpectedDuration(string $operation): float
{
return match ($operation) {
'token_generation' => 0.001, // 1ms
'password_hash' => 0.5, // 500ms (Argon2ID)
'password_verify' => 0.5, // 500ms
'signature_create' => 0.01, // 10ms
'signature_verify' => 0.005, // 5ms
default => 0.1 // 100ms
};
}
}
```
## Compliance und Audit
### Compliance Framework
```php
// ✅ Compliance-Unterstützung für Regulierungen
final readonly class CryptographicComplianceValidator
{
private const COMPLIANCE_REQUIREMENTS = [
'GDPR' => [
'encryption_required' => true,
'key_length_min' => 256,
'algorithm_approved' => ['AES-256-GCM', 'ChaCha20-Poly1305'],
'key_rotation_days' => 365,
'audit_trail_required' => true
],
'PCI_DSS' => [
'encryption_required' => true,
'key_length_min' => 256,
'algorithm_approved' => ['AES-256', 'RSA-2048'],
'key_rotation_days' => 365,
'secure_key_storage' => true
],
'FIPS_140_2' => [
'approved_algorithms_only' => true,
'algorithm_approved' => ['AES', 'SHA-256', 'RSA', 'ECDSA'],
'random_number_generator' => 'FIPS_approved',
'key_length_min' => 256
]
];
public function validateCompliance(string $standard): ComplianceReport
{
$requirements = self::COMPLIANCE_REQUIREMENTS[$standard] ??
throw new InvalidArgumentException("Unknown standard: {$standard}");
$violations = [];
$report = new ComplianceReport($standard);
// Algorithmus-Compliance prüfen
if (isset($requirements['algorithm_approved'])) {
$usedAlgorithms = $this->getUsedAlgorithms();
$approvedAlgorithms = $requirements['algorithm_approved'];
foreach ($usedAlgorithms as $algorithm) {
if (!in_array($algorithm, $approvedAlgorithms)) {
$violations[] = "Non-approved algorithm in use: {$algorithm}";
}
}
}
// Schlüssel-Längen prüfen
if (isset($requirements['key_length_min'])) {
$keyLengths = $this->getKeyLengths();
$minLength = $requirements['key_length_min'];
foreach ($keyLengths as $context => $length) {
if ($length < $minLength) {
$violations[] = "Key length too short in {$context}: {$length} < {$minLength}";
}
}
}
// Schlüssel-Rotation prüfen
if (isset($requirements['key_rotation_days'])) {
$rotationViolations = $this->checkKeyRotation($requirements['key_rotation_days']);
$violations = array_merge($violations, $rotationViolations);
}
$report->setViolations($violations);
$report->setCompliant(empty($violations));
return $report;
}
public function generateAuditReport(): AuditReport
{
return new AuditReport([
'cryptographic_operations' => $this->getCryptoOperationStats(),
'key_management' => $this->getKeyManagementStats(),
'algorithm_usage' => $this->getAlgorithmUsageStats(),
'security_events' => $this->getSecurityEventSummary(),
'compliance_status' => $this->getComplianceStatus()
]);
}
}
```
Diese Sicherheitsrichtlinien stellen sicher, dass das Cryptography Module höchste Sicherheitsstandards erfüllt und gegen moderne Angriffsvektoren geschützt ist.

View File

@@ -0,0 +1,417 @@
# CSRF-Schutz
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des CSRF-Schutzes korrekt dar.
## Übersicht
Cross-Site Request Forgery (CSRF) ist eine Art von Angriff, bei dem ein Angreifer einen Benutzer dazu bringt, unbeabsichtigt Aktionen auf einer Website auszuführen, bei der er bereits authentifiziert ist. Das Framework bietet einen robusten CSRF-Schutzmechanismus, der solche Angriffe verhindert, indem es einzigartige Token generiert und validiert.
## Hauptkomponenten
### CsrfToken
Die `CsrfToken`-Klasse ist ein Value Object, das einen CSRF-Token repräsentiert:
```php
use App\Framework\Security\CsrfToken;
// Token aus einem String erstellen
$token = CsrfToken::fromString($tokenString);
// Token-Wert als String abrufen
$tokenString = $token->toString();
// oder
$tokenString = (string)$token;
```
Die Klasse stellt sicher, dass CSRF-Token immer gültige 64-Zeichen lange hexadezimale Strings sind und bietet Typsicherheit für CSRF-Token-Operationen.
### CsrfTokenGenerator
Die `CsrfTokenGenerator`-Klasse ist verantwortlich für die Generierung neuer CSRF-Token:
```php
use App\Framework\Security\CsrfTokenGenerator;
// Generator initialisieren
$generator = new CsrfTokenGenerator($randomGenerator);
// Neues Token generieren
$token = $generator->generate();
```
Die Klasse verwendet einen kryptografisch sicheren Zufallszahlengenerator, um Token zu erzeugen, die nicht vorhersehbar sind.
### CsrfTokenData
Die `CsrfTokenData`-Klasse erweitert das einfache Token um zusätzliche Metadaten:
```php
use App\Framework\Security\CsrfTokenData;
// Token-Daten mit Metadaten erstellen
$tokenData = new CsrfTokenData(
$token,
$clientIp,
$targetPath,
$expiresAt
);
// Prüfen, ob das Token abgelaufen ist
if ($tokenData->isExpired($clock)) {
// Token ist abgelaufen
}
// Prüfen, ob das Token bereits verwendet wurde
if ($tokenData->isUsed()) {
// Token wurde bereits verwendet
}
```
Diese Klasse ermöglicht erweiterte Sicherheitsfunktionen wie Token-Ablauf, Verwendungsverfolgung und Bindung an bestimmte Pfade oder IP-Adressen.
## Verwendung
### Token generieren und in Formularen verwenden
```php
// In einem Controller
public function showForm(): Response
{
// Token generieren
$csrfToken = $this->csrfTokenGenerator->generate();
// Token in der Session speichern
$this->session->set('csrf_token', $csrfToken->toString());
// Token im Formular einbinden
return $this->render('form.twig', [
'csrf_token' => $csrfToken->toString(),
]);
}
```
In der Formularvorlage:
```html
<form method="post" action="/submit">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<!-- Weitere Formularfelder -->
<button type="submit">Absenden</button>
</form>
```
### Token validieren
```php
// In einem Controller
public function handleForm(Request $request): Response
{
// Gespeichertes Token abrufen
$storedToken = CsrfToken::fromString($this->session->get('csrf_token'));
// Übermitteltes Token abrufen
$submittedToken = $request->getPostParam('csrf_token');
// Token vergleichen (zeitsichere Vergleichsmethode)
if (!$storedToken->equalsString($submittedToken)) {
throw new SecurityException('Ungültiges CSRF-Token');
}
// Token ist gültig, Formular verarbeiten
// ...
}
```
### Erweiterte Token-Validierung mit Metadaten
```php
// In einem Controller
public function showForm(): Response
{
// Token mit Metadaten generieren
$token = $this->csrfTokenGenerator->generate();
$tokenData = new CsrfTokenData(
$token,
$this->request->getClientIp(),
$this->request->path,
new \DateTimeImmutable('+1 hour')
);
// Token-Daten in der Session speichern
$this->session->set('csrf_token_data', $tokenData->toArray());
// Token im Formular einbinden
return $this->render('form.twig', [
'csrf_token' => $token->toString(),
]);
}
public function handleForm(Request $request): Response
{
// Token-Daten aus der Session abrufen
$tokenDataArray = $this->session->get('csrf_token_data');
$tokenData = CsrfTokenData::fromArray($tokenDataArray);
// Übermitteltes Token abrufen
$submittedToken = $request->getPostParam('csrf_token');
// Umfassende Validierung durchführen
if ($tokenData->isExpired($this->clock)) {
throw new SecurityException('CSRF-Token ist abgelaufen');
}
if ($tokenData->isUsed()) {
throw new SecurityException('CSRF-Token wurde bereits verwendet');
}
if ($tokenData->clientIp !== $request->getClientIp()) {
throw new SecurityException('CSRF-Token ist an eine andere IP-Adresse gebunden');
}
if (!$tokenData->token->equalsString($submittedToken)) {
throw new SecurityException('Ungültiges CSRF-Token');
}
// Token als verwendet markieren
$tokenData->markAsUsed();
$this->session->set('csrf_token_data', $tokenData->toArray());
// Token ist gültig, Formular verarbeiten
// ...
}
```
## Integration mit dem Framework
### CSRF-Middleware
Das Framework bietet eine `CsrfProtectionMiddleware`, die automatisch CSRF-Schutz für alle POST, PUT, DELETE und PATCH-Anfragen implementiert:
```php
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(CsrfProtectionMiddleware::class);
```
Die Middleware:
1. Generiert automatisch CSRF-Token für alle Formulare
2. Validiert Token für alle Anfragen, die den Zustand ändern
3. Wirft eine Exception oder gibt eine Fehlerantwort zurück, wenn die Validierung fehlschlägt
### Konfiguration
Die CSRF-Schutzfunktionen können in der Konfigurationsdatei angepasst werden:
```php
// config/security.php
return [
'csrf' => [
'enabled' => true,
'token_lifetime' => 3600, // Sekunden
'exclude_routes' => [
'/api/webhook',
'/api/external/callback',
],
'exclude_patterns' => [
'#^/api/public/#', // Regulärer Ausdruck für auszuschließende Routen
],
'header_name' => 'X-CSRF-Token', // Name des HTTP-Headers für API-Anfragen
'parameter_name' => 'csrf_token', // Name des Formularfelds
'strict_mode' => true, // Strikte Validierung (IP-Bindung, Einmalverwendung)
],
];
```
### Template-Integration
Das Framework bietet eine einfache Möglichkeit, CSRF-Token in Templates einzubinden:
```php
// In einem Controller
public function showForm(): Response
{
return $this->render('form.twig', [
'csrf_token' => $this->csrfProtection->getToken()->toString(),
]);
}
```
Mit der Template-Funktion:
```twig
{# In einer Twig-Vorlage #}
<form method="post" action="/submit">
{{ csrf_field() }}
<!-- Weitere Formularfelder -->
<button type="submit">Absenden</button>
</form>
```
Die `csrf_field()`-Funktion generiert automatisch ein verstecktes Formularfeld mit dem aktuellen CSRF-Token.
### API-Integration
Für API-Anfragen kann das CSRF-Token über einen HTTP-Header übermittelt werden:
```javascript
// JavaScript-Beispiel
fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify(data)
});
```
In der HTML-Vorlage:
```html
<meta name="csrf-token" content="{{ csrf_token }}">
```
## Erweiterte Funktionen
### Double Submit Cookie Pattern
Das Framework unterstützt das Double Submit Cookie Pattern für zusätzliche Sicherheit:
```php
// In einem Controller
public function showForm(): Response
{
$token = $this->csrfTokenGenerator->generate();
// Token in der Session speichern
$this->session->set('csrf_token', $token->toString());
// Token auch als Cookie setzen
$this->response->setCookie('csrf_token', $token->toString(), [
'httponly' => false, // JavaScript muss darauf zugreifen können
'samesite' => 'Strict',
'secure' => true,
'path' => '/',
]);
return $this->render('form.twig', [
'csrf_token' => $token->toString(),
]);
}
```
### Token-Rotation
Für zusätzliche Sicherheit können CSRF-Token nach jeder Anfrage rotiert werden:
```php
// In einem Controller
public function handleForm(Request $request): Response
{
// Token validieren
// ...
// Neues Token generieren
$newToken = $this->csrfTokenGenerator->generate();
$this->session->set('csrf_token', $newToken->toString());
// Antwort mit neuem Token
return $this->render('success.twig', [
'new_csrf_token' => $newToken->toString(),
]);
}
```
### Synchronizer Token Pattern
Das Framework implementiert das Synchronizer Token Pattern, bei dem für jede Sitzung ein eindeutiges Token generiert wird:
```php
// In der Session-Initialisierung
public function initializeSession(): void
{
if (!$this->session->has('csrf_token')) {
$token = $this->csrfTokenGenerator->generate();
$this->session->set('csrf_token', $token->toString());
}
}
```
## Fehlerbehebung
### Häufige Probleme
#### Token-Validierung schlägt fehl
Mögliche Ursachen:
- Das Token ist abgelaufen
- Das Token wurde bereits verwendet
- Das Token wurde nicht korrekt übermittelt
- Die Session ist abgelaufen oder wurde zurückgesetzt
Lösung:
- Überprüfen Sie die Session-Konfiguration
- Stellen Sie sicher, dass das Token korrekt im Formular eingebunden ist
- Erhöhen Sie die Token-Lebensdauer in der Konfiguration
#### CSRF-Schutz für bestimmte Routen deaktivieren
Wenn Sie den CSRF-Schutz für bestimmte Routen deaktivieren müssen (z.B. für Webhook-Callbacks):
```php
// config/security.php
return [
'csrf' => [
'exclude_routes' => [
'/api/webhook',
'/api/external/callback',
],
],
];
```
#### AJAX-Anfragen mit CSRF-Schutz
Für AJAX-Anfragen müssen Sie das CSRF-Token im Header oder als Formularfeld übermitteln:
```javascript
// JavaScript mit jQuery
$.ajaxSetup({
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
});
// Oder mit Fetch API
fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify(data)
});
```
## Sicherheitsüberlegungen
### Best Practices
1. **Verwenden Sie HTTPS**: CSRF-Token sollten immer über eine verschlüsselte Verbindung übertragen werden.
2. **Kurze Token-Lebensdauer**: Setzen Sie die Token-Lebensdauer auf einen angemessenen Wert (z.B. 1-2 Stunden).
3. **Strikte SameSite-Cookie-Einstellungen**: Verwenden Sie `SameSite=Strict` oder `SameSite=Lax` für Session-Cookies.
4. **Token-Rotation**: Rotieren Sie Token nach jeder Anfrage, die den Zustand ändert.
5. **Validieren Sie alle Anfragen**: Stellen Sie sicher, dass alle Anfragen, die den Zustand ändern, ein gültiges CSRF-Token erfordern.
### Bekannte Einschränkungen
- CSRF-Schutz funktioniert nicht für Benutzer, die keine Cookies akzeptieren.
- Bei sehr langen Sitzungen kann die Sicherheit des CSRF-Tokens beeinträchtigt sein.
- CSRF-Schutz kann mit bestimmten Caching-Strategien in Konflikt geraten.
## Weiterführende Informationen
- [Security Features Übersicht](index.md)
- [Security Headers und CSP](security-headers.md)
- [Request Signing API](request-signing.md)
- [Sicherheits-Best-Practices](/guides/security-best-practices.md)

View File

@@ -0,0 +1,363 @@
# Security Features
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der Sicherheitsfeatures korrekt dar.
## Übersicht
Das Framework bietet umfassende Sicherheitsfunktionen, die Ihre Anwendung vor gängigen Bedrohungen schützen. Diese Funktionen sind tief in die Architektur integriert und folgen modernen Best Practices für Webanwendungssicherheit.
## Hauptkomponenten
### CSRF-Schutz
Der Cross-Site Request Forgery (CSRF) Schutz verhindert, dass Angreifer unerwünschte Aktionen im Namen authentifizierter Benutzer ausführen:
```php
// Token generieren
$csrfToken = $csrfTokenGenerator->generate();
// Token in Formular einbinden
$form = '<input type="hidden" name="csrf_token" value="' . $csrfToken->toString() . '">';
// Token validieren
if (!$csrfToken->equalsString($request->getPostParam('csrf_token'))) {
throw new SecurityException('Ungültiges CSRF-Token');
}
```
### Security Headers
Die `SecurityHeaderMiddleware` fügt automatisch wichtige Sicherheits-Header zu allen HTTP-Antworten hinzu:
- **Strict-Transport-Security (HSTS)**: Erzwingt HTTPS-Verbindungen
- **X-Frame-Options**: Verhindert Clickjacking-Angriffe
- **X-Content-Type-Options**: Verhindert MIME-Sniffing
- **Content-Security-Policy (CSP)**: Schützt vor XSS und anderen Injection-Angriffen
- **Referrer-Policy**: Kontrolliert die Weitergabe von Referrer-Informationen
- **Permissions-Policy**: Beschränkt Browser-Features
- **Cross-Origin-Policies**: Steuert ressourcenübergreifende Interaktionen
```php
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(SecurityHeaderMiddleware::class);
```
### Request Signing
Das Request-Signing-System ermöglicht die kryptografische Verifizierung von API-Anfragen:
```php
// Ausgehende Anfrage signieren
$signedRequest = $requestSigningService->signOutgoingRequest($request);
// Eingehende Anfrage verifizieren
$result = $requestSigningService->verifyIncomingRequest($request);
if (!$result->isSuccess()) {
throw new SecurityException('Ungültige Anfrage-Signatur: ' . $result->errorMessage);
}
```
### Session-Sicherheit
Der `SecurityManager` schützt Benutzersitzungen vor verschiedenen Angriffen:
- **Session-Fixierung**: Automatische Regenerierung von Session-IDs
- **Session-Hijacking**: Überprüfung von IP-Adressen und User-Agents
- **Session-Timeout**: Automatisches Beenden inaktiver Sitzungen
- **Concurrent-Login-Erkennung**: Erkennung gleichzeitiger Anmeldungen
```php
// In einem Controller oder Middleware
$securityManager->validateSession($request, $session);
```
### Sicherheits-Ereignisbehandlung
Das Framework bietet ein umfassendes System zur Erkennung und Protokollierung von Sicherheitsereignissen:
```php
// Sicherheitsereignis protokollieren
$securityEventLogger->logEvent(
SecurityEventType::AUTHENTICATION_FAILURE,
'Fehlgeschlagene Anmeldung',
['username' => $username, 'ip' => $request->getClientIp()]
);
// Auf Sicherheitsereignisse reagieren
$securityAlertManager->handleEvent($event);
```
## Konfiguration
### CSRF-Schutz konfigurieren
```php
// config/security.php
return [
'csrf' => [
'enabled' => true,
'token_lifetime' => 3600, // Sekunden
'exclude_routes' => [
'/api/webhook',
],
],
];
```
### Security Headers konfigurieren
```php
// config/security.php
return [
'headers' => [
'strict_mode' => true, // Produktionsmodus mit strengeren Einstellungen
'content_security_policy' => "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';",
'hsts' => [
'enabled' => true,
'max_age' => 31536000, // 1 Jahr
'include_subdomains' => true,
'preload' => true,
],
],
];
```
### Request Signing konfigurieren
```php
// config/security.php
return [
'request_signing' => [
'enabled' => true,
'default_algorithm' => 'hmac-sha256',
'default_headers' => ['(request-target)', 'host', 'date', 'content-type'],
'default_expiry' => 300, // Sekunden
'required_routes' => [
'/api/admin/*',
'/api/payments/*',
],
],
];
```
## Verwendung
### CSRF-Schutz in Formularen
```php
// In einem Controller
public function showForm(): Response
{
$csrfToken = $this->csrfTokenGenerator->generate();
$this->session->set('csrf_token', $csrfToken->toString());
return $this->render('form.twig', [
'csrf_token' => $csrfToken->toString(),
]);
}
public function handleForm(Request $request): Response
{
$storedToken = CsrfToken::fromString($this->session->get('csrf_token'));
$submittedToken = $request->getPostParam('csrf_token');
if (!$storedToken->equalsString($submittedToken)) {
throw new SecurityException('Ungültiges CSRF-Token');
}
// Formular verarbeiten
}
```
### Content Security Policy anpassen
```php
// In einem Controller oder Middleware
public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
{
$resultContext = $next($context);
if ($resultContext->hasResponse()) {
$response = $resultContext->response;
$headers = $response->headers;
// CSP für eine bestimmte Route anpassen
$updatedHeaders = $headers->with(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' https://trusted-cdn.com;"
);
$updatedResponse = $this->manipulator->withHeaders($response, $updatedHeaders);
return $resultContext->withResponse($updatedResponse);
}
return $resultContext;
}
```
### API-Anfragen signieren und verifizieren
```php
// Client-Seite: Anfrage signieren
$request = new HttpRequest('POST', '/api/data');
$signedRequest = $this->requestSigningService->signOutgoingRequest($request);
$response = $this->httpClient->send($signedRequest);
// Server-Seite: Anfrage verifizieren (in Middleware)
public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
{
$request = $context->request;
// Prüfen, ob die Route signierte Anfragen erfordert
if ($this->requiresSignature($request->path)) {
$result = $this->requestSigningService->verifyIncomingRequest($request);
if (!$result->isSuccess()) {
return $context->withResponse(
new Response(401, [], ['error' => 'Ungültige Signatur: ' . $result->errorMessage])
);
}
}
return $next($context);
}
```
### Schlüsselverwaltung für Request Signing
```php
// HMAC-Schlüssel generieren
$key = $requestSigningService->generateHmacKey(
'api-key-1',
SigningAlgorithm::HMAC_SHA256,
new \DateTimeImmutable('+30 days')
);
// RSA-Schlüssel erstellen
$privateKey = file_get_contents('private_key.pem');
$key = $requestSigningService->createRsaKey(
'api-key-2',
$privateKey,
new \DateTimeImmutable('+1 year')
);
// Schlüssel rotieren
$newKey = SigningKey::generateHmac('api-key-1-new', SigningAlgorithm::HMAC_SHA256);
$requestSigningService->rotateSigningKey('api-key-1', $newKey);
// Schlüssel entfernen
$requestSigningService->removeSigningKey('api-key-1');
```
## Integration
### Middleware-Integration
Die Sicherheitsfunktionen sind als Middleware-Komponenten implementiert und können einfach in die Anwendung integriert werden:
```php
// In der Bootstrap-Datei
$app->addMiddleware(SecurityHeaderMiddleware::class);
$app->addMiddleware(CsrfProtectionMiddleware::class);
$app->addMiddleware(RequestSigningMiddleware::class);
$app->addMiddleware(SessionSecurityMiddleware::class);
```
### Event-Integration
Sicherheitsereignisse werden über das Event-System des Frameworks verarbeitet:
```php
// Event-Listener registrieren
$eventDispatcher->addListener(SecurityEventInterface::class, function (SecurityEventInterface $event) {
// Auf Sicherheitsereignis reagieren
if ($event->getSeverity() >= SecurityLogLevel::WARNING) {
$this->notificationService->sendAlert($event);
}
});
```
### Analytics-Integration
Sicherheitsereignisse werden automatisch im Analytics-System erfasst:
```php
// In der Bootstrap-Datei
$app->addAnalyticsBridge(SecurityAnalyticsListener::class);
// Sicherheitsanalysen abrufen
$securityStats = $analyticsDashboard->getSecurityStats();
```
## Erweiterte Funktionen
### IP-basierte Sicherheit
```php
// IP-Adresse prüfen
if (!$ipSecurityService->isAllowed($request->getClientIp())) {
throw new SecurityException('Zugriff verweigert');
}
// Rate-Limiting basierend auf IP-Adresse
$ipSecurityService->trackRequest($request->getClientIp());
if ($ipSecurityService->isRateLimited($request->getClientIp())) {
throw new SecurityException('Rate-Limit überschritten');
}
```
### Benutzerdefinierte Security-Header
```php
// Eigene Security-Header-Konfiguration erstellen
$config = new SecurityHeaderConfig();
$config->contentSecurityPolicy = "default-src 'self'; script-src 'self' https://trusted-cdn.com;";
$config->frameOptions = "DENY";
$config->referrerPolicy = "strict-origin-when-cross-origin";
// Konfiguration anwenden
$securityHeaderMiddleware = new SecurityHeaderMiddleware($responseManipulator, $config);
```
### Erweiterte CSRF-Schutzmaßnahmen
```php
// CSRF-Token mit Metadaten generieren
$csrfTokenData = new CsrfTokenData(
$csrfToken,
$request->getClientIp(),
$request->path,
new \DateTimeImmutable('+1 hour')
);
// Token mit Metadaten validieren
if (!$csrfValidator->validate($csrfTokenData, $request)) {
throw new SecurityException('Ungültiges oder abgelaufenes CSRF-Token');
}
```
## Fehlerbehebung
### Häufige Probleme
1. **CSP-Fehler im Browser**:
- Überprüfen Sie die Content-Security-Policy in der Konfiguration
- Fügen Sie fehlende Quellen zur CSP hinzu
- Verwenden Sie die Browser-Entwicklertools, um CSP-Verstöße zu identifizieren
2. **CSRF-Token-Fehler**:
- Stellen Sie sicher, dass das Token korrekt im Formular übermittelt wird
- Überprüfen Sie die Session-Konfiguration
- Prüfen Sie, ob das Token abgelaufen ist
3. **Request-Signing-Fehler**:
- Überprüfen Sie, ob der richtige Schlüssel verwendet wird
- Stellen Sie sicher, dass die Uhrzeit auf Client und Server synchronisiert ist
- Prüfen Sie, ob alle erforderlichen Header signiert werden
## Weiterführende Informationen
- [CSRF-Schutz im Detail](csrf-protection.md)
- [Security Headers und CSP](security-headers.md)
- [Request Signing API](request-signing.md)
- [Sicherheits-Best-Practices](/guides/security-best-practices.md)

View File

@@ -0,0 +1,410 @@
# Request Signing
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Request Signing korrekt dar.
## Übersicht
Request Signing ist ein Sicherheitsmechanismus, der die Authentizität und Integrität von HTTP-Anfragen gewährleistet. Durch die kryptografische Signierung von Anfragen können Empfänger überprüfen, dass die Anfrage von einem autorisierten Absender stammt und während der Übertragung nicht manipuliert wurde. Das Framework bietet eine robuste Implementierung von Request Signing, die sowohl für ausgehende als auch für eingehende Anfragen verwendet werden kann.
## Hauptkomponenten
### RequestSigningService
Die `RequestSigningService`-Klasse ist die zentrale Komponente für Request Signing:
```php
use App\Framework\Security\RequestSigning\RequestSigningService;
// Service initialisieren
$service = new RequestSigningService(
$signer,
$verifier,
$keyRepository,
$config,
$logger
);
// Ausgehende Anfrage signieren
$signedRequest = $service->signOutgoingRequest($request, $keyId);
// Eingehende Anfrage verifizieren
$result = $service->verifyIncomingRequest($request);
if (!$result->isSuccess()) {
throw new SecurityException('Ungültige Anfrage-Signatur: ' . $result->errorMessage);
}
```
### SigningKey
Die `SigningKey`-Klasse repräsentiert einen kryptografischen Schlüssel für das Signieren von Anfragen:
```php
use App\Framework\Security\RequestSigning\SigningKey;
use App\Framework\Security\RequestSigning\SigningAlgorithm;
// HMAC-Schlüssel generieren
$hmacKey = SigningKey::generateHmac(
'api-key-1',
SigningAlgorithm::HMAC_SHA256,
new \DateTimeImmutable('+30 days') // Ablaufdatum
);
// RSA-Schlüssel erstellen
$privateKey = file_get_contents('private_key.pem');
$rsaKey = SigningKey::createRsa(
'api-key-2',
$privateKey,
new \DateTimeImmutable('+1 year') // Ablaufdatum
);
```
### SigningAlgorithm
Das `SigningAlgorithm`-Enum definiert die unterstützten Signaturalgorithmen:
```php
use App\Framework\Security\RequestSigning\SigningAlgorithm;
// Verfügbare Algorithmen
$algorithm = SigningAlgorithm::HMAC_SHA256; // HMAC mit SHA-256
$algorithm = SigningAlgorithm::HMAC_SHA512; // HMAC mit SHA-512
$algorithm = SigningAlgorithm::RSA_SHA256; // RSA mit SHA-256
$algorithm = SigningAlgorithm::RSA_SHA512; // RSA mit SHA-512
```
### RequestSigner
Die `RequestSigner`-Klasse ist für das Signieren von ausgehenden Anfragen verantwortlich:
```php
use App\Framework\Security\RequestSigning\RequestSigner;
// Signer initialisieren
$signer = new RequestSigner($clock);
// Anfrage signieren
$signedRequest = $signer->signRequest(
$request,
$signingKey,
['(request-target)', 'host', 'date', 'content-type'],
300 // Gültigkeitsdauer in Sekunden
);
```
### RequestVerifier
Die `RequestVerifier`-Klasse ist für die Überprüfung von eingehenden Anfragen verantwortlich:
```php
use App\Framework\Security\RequestSigning\RequestVerifier;
// Verifier initialisieren
$verifier = new RequestVerifier($keyRepository, $clock);
// Anfrage verifizieren
$result = $verifier->verify($request);
if ($result->isSuccess()) {
// Anfrage ist gültig
$signature = $result->signature;
$key = $result->key;
} else {
// Anfrage ist ungültig
$errorMessage = $result->errorMessage;
}
```
### SigningKeyRepository
Das `SigningKeyRepository`-Interface definiert die Methoden zum Speichern und Abrufen von Signaturschlüsseln:
```php
use App\Framework\Security\RequestSigning\SigningKeyRepository;
use App\Framework\Security\RequestSigning\InMemorySigningKeyRepository;
use App\Framework\Security\RequestSigning\EntityManagerSigningKeyRepository;
// In-Memory-Repository für Tests
$repository = new InMemorySigningKeyRepository();
// Entity-Manager-Repository für Produktion
$repository = new EntityManagerSigningKeyRepository($entityManager);
// Schlüssel speichern
$repository->store($signingKey);
// Schlüssel abrufen
$key = $repository->findByKeyId('api-key-1');
// Alle aktiven Schlüssel abrufen
$activeKeys = $repository->getAllActive();
// Schlüssel entfernen
$repository->remove('api-key-1');
// Schlüssel rotieren
$repository->rotateKey('api-key-1', $newKey);
```
## Signaturformat
Das Framework verwendet das [HTTP Signature](https://tools.ietf.org/html/draft-cavage-http-signatures) Format für Request Signing:
```
Authorization: Signature keyId="api-key-1",algorithm="hmac-sha256",headers="(request-target) host date",signature="Base64(HMAC-SHA256(SigningString))"
```
Die Signatur wird aus einer Zeichenkette (Signing String) generiert, die aus den angegebenen Header-Werten besteht:
```
(request-target): post /api/data
host: example.com
date: Tue, 07 Jun 2023 20:51:35 GMT
```
## Verwendung
### Ausgehende Anfragen signieren
```php
// In einem API-Client
public function sendRequest(HttpRequest $request): HttpResponse
{
// Anfrage signieren
$signedRequest = $this->requestSigningService->signOutgoingRequest(
$request,
'api-key-1', // Optional: Spezifischer Schlüssel
['(request-target)', 'host', 'date', 'content-type'], // Optional: Zu signierende Header
300 // Optional: Gültigkeitsdauer in Sekunden
);
// Signierte Anfrage senden
return $this->httpClient->send($signedRequest);
}
```
### Eingehende Anfragen verifizieren
```php
// In einer Middleware
public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
{
$request = $context->request;
// Prüfen, ob die Route signierte Anfragen erfordert
if ($this->requiresSignature($request->path)) {
$result = $this->requestSigningService->verifyIncomingRequest($request);
if (!$result->isSuccess()) {
return $context->withResponse(
new Response(401, [], ['error' => 'Ungültige Signatur: ' . $result->errorMessage])
);
}
}
return $next($context);
}
```
### Schlüsselverwaltung
```php
// HMAC-Schlüssel generieren
$key = $requestSigningService->generateHmacKey(
'api-key-1',
SigningAlgorithm::HMAC_SHA256,
new \DateTimeImmutable('+30 days')
);
// RSA-Schlüssel erstellen
$privateKey = file_get_contents('private_key.pem');
$key = $requestSigningService->createRsaKey(
'api-key-2',
$privateKey,
new \DateTimeImmutable('+1 year')
);
// Schlüssel rotieren
$newKey = SigningKey::generateHmac('api-key-1-new', SigningAlgorithm::HMAC_SHA256);
$requestSigningService->rotateSigningKey('api-key-1', $newKey);
// Schlüssel entfernen
$requestSigningService->removeSigningKey('api-key-1');
// Alle aktiven Schlüssel abrufen
$activeKeys = $requestSigningService->getActiveKeys();
```
## Integration mit dem Framework
### RequestSigningMiddleware
Das Framework bietet eine `RequestSigningMiddleware`, die automatisch eingehende Anfragen verifiziert:
```php
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(RequestSigningMiddleware::class);
```
### HttpClientSigningMiddleware
Für ausgehende Anfragen bietet das Framework eine `HttpClientSigningMiddleware`:
```php
// HTTP-Client mit Signatur-Middleware konfigurieren
$httpClient = new HttpClient([
'middlewares' => [
new HttpClientSigningMiddleware($requestSigningService)
]
]);
// Anfragen werden automatisch signiert
$response = $httpClient->send($request);
```
### Konfiguration
Die Request-Signing-Funktionen können in der Konfigurationsdatei angepasst werden:
```php
// config/security.php
return [
'request_signing' => [
'enabled' => true,
'default_algorithm' => 'hmac-sha256',
'default_headers' => ['(request-target)', 'host', 'date', 'content-type'],
'default_expiry' => 300, // Sekunden
'required_routes' => [
'/api/admin/*',
'/api/payments/*',
],
],
];
```
## Erweiterte Funktionen
### Signatur mit Ablaufdatum
Signaturen können mit einem Ablaufdatum versehen werden, um Replay-Angriffe zu verhindern:
```php
// Anfrage mit Ablaufdatum signieren
$signedRequest = $requestSigningService->signOutgoingRequest(
$request,
'api-key-1',
['(request-target)', 'host', 'date', '(created)', '(expires)'],
300 // Gültigkeitsdauer in Sekunden
);
```
Die Signatur enthält dann zusätzliche Felder:
```
Authorization: Signature keyId="api-key-1",algorithm="hmac-sha256",headers="(request-target) host date (created) (expires)",created=1623094295,expires=1623094595,signature="..."
```
### Digest-Header
Für zusätzliche Sicherheit kann der Anfrage-Body mit einem Digest-Header geschützt werden:
```php
// Anfrage mit Digest-Header signieren
$request = $request->withHeader('Digest', 'SHA-256=' . base64_encode(hash('sha256', $request->body, true)));
$signedRequest = $requestSigningService->signOutgoingRequest(
$request,
'api-key-1',
['(request-target)', 'host', 'date', 'digest']
);
```
### Schlüsselrotation
Für zusätzliche Sicherheit sollten Schlüssel regelmäßig rotiert werden:
```php
// Neuen Schlüssel generieren
$newKey = $requestSigningService->generateHmacKey(
'api-key-1-new',
SigningAlgorithm::HMAC_SHA256
);
// Alten Schlüssel durch neuen ersetzen
$requestSigningService->rotateSigningKey('api-key-1', $newKey);
// Alten Schlüssel nach einer Übergangszeit entfernen
// (nachdem alle Clients auf den neuen Schlüssel umgestellt wurden)
$requestSigningService->removeSigningKey('api-key-1');
```
## Sicherheitsüberlegungen
### Best Practices
1. **Verwenden Sie starke Algorithmen**: HMAC-SHA256 oder RSA-SHA256 sind empfohlen.
2. **Schützen Sie private Schlüssel**: Speichern Sie private Schlüssel sicher und teilen Sie sie nie öffentlich.
3. **Signieren Sie kritische Header**: Mindestens `(request-target)`, `host`, `date` und `content-type` sollten signiert werden.
4. **Verwenden Sie Ablaufdaten**: Sowohl für Schlüssel als auch für Signaturen, um Replay-Angriffe zu verhindern.
5. **Rotieren Sie Schlüssel regelmäßig**: Implementieren Sie einen Prozess zur regelmäßigen Schlüsselrotation.
### Bekannte Einschränkungen
- Request Signing schützt nicht vor Man-in-the-Middle-Angriffen; verwenden Sie immer HTTPS.
- Die Sicherheit hängt von der sicheren Speicherung und Verteilung der Schlüssel ab.
- Uhrzeitsynchronisation zwischen Client und Server ist wichtig für zeitbasierte Validierung.
## Fehlerbehebung
### Häufige Probleme
#### Signaturvalidierung schlägt fehl
Mögliche Ursachen:
- Die Signatur ist abgelaufen
- Die Uhrzeit zwischen Client und Server ist nicht synchronisiert
- Der falsche Schlüssel wird verwendet
- Die Header-Liste stimmt nicht überein
- Der Anfrage-Body wurde nach der Signierung geändert
Lösung:
- Überprüfen Sie die Uhrzeit auf Client und Server
- Stellen Sie sicher, dass der richtige Schlüssel verwendet wird
- Überprüfen Sie, ob alle erforderlichen Header signiert werden
- Verwenden Sie den Digest-Header für Anfragen mit Body
#### Schlüssel nicht gefunden
Wenn der Schlüssel nicht gefunden wird:
```php
// Prüfen, ob der Schlüssel existiert
$key = $keyRepository->findByKeyId($keyId);
if ($key === null) {
// Schlüssel nicht gefunden
$this->logger->warning('Signing key not found', ['key_id' => $keyId]);
}
```
#### Logging für Fehlerbehebung
Das Framework bietet umfangreiches Logging für Request Signing:
```php
// In der RequestSigningService-Klasse
$this->logger->info('Request signature verified successfully', [
'key_id' => $result->signature->keyId,
'algorithm' => $result->signature->algorithm->value,
'path' => $request->path,
]);
$this->logger->warning('Request signature verification failed', [
'error' => $result->errorMessage,
'path' => $request->path,
]);
```
## Weiterführende Informationen
- [Security Features Übersicht](index.md)
- [CSRF-Schutz](csrf-protection.md)
- [Security Headers](security-headers.md)
- [Sicherheits-Best-Practices](/guides/security-best-practices.md)
- [HTTP Signatures Spezifikation](https://tools.ietf.org/html/draft-cavage-http-signatures)

View File

@@ -0,0 +1,382 @@
# Security Headers
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der Security Headers korrekt dar.
## Übersicht
Security Headers sind HTTP-Header, die dazu beitragen, die Sicherheit Ihrer Webanwendung zu verbessern, indem sie dem Browser Anweisungen geben, wie er mit bestimmten Sicherheitsaspekten umgehen soll. Das Framework implementiert automatisch eine umfassende Sammlung von Security Headers, die den aktuellen Best Practices entsprechen und Ihre Anwendung vor verschiedenen Arten von Angriffen schützen.
## Hauptkomponenten
### SecurityHeaderMiddleware
Die `SecurityHeaderMiddleware` ist die zentrale Komponente für die Implementierung von Security Headers:
```php
use App\Framework\Http\Middlewares\SecurityHeaderMiddleware;
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(SecurityHeaderMiddleware::class);
```
Diese Middleware:
1. Entfernt unsichere Header wie `X-Powered-By` und `Server`
2. Fügt automatisch wichtige Security Headers zu allen HTTP-Antworten hinzu
3. Passt die Header basierend auf der Umgebung (Entwicklung oder Produktion) an
### SecurityHeaderConfig
Die `SecurityHeaderConfig`-Klasse enthält die Konfiguration für die Security Headers:
```php
use App\Framework\Http\Middlewares\SecurityHeaderConfig;
// Vordefinierte Konfigurationen verwenden
$config = SecurityHeaderConfig::forProduction(); // Strenge Einstellungen für Produktion
$config = SecurityHeaderConfig::forDevelopment(); // Weniger strenge Einstellungen für Entwicklung
// Benutzerdefinierte Konfiguration erstellen
$config = new SecurityHeaderConfig(
$contentSecurityPolicy,
$hstsHeader,
$frameOptions,
$referrerPolicy,
$permissionsPolicy,
$crossOriginEmbedderPolicy,
$crossOriginOpenerPolicy,
$crossOriginResourcePolicy
);
```
## Implementierte Security Headers
### Content-Security-Policy (CSP)
Die Content Security Policy schützt vor Cross-Site Scripting (XSS) und anderen Code-Injection-Angriffen, indem sie definiert, welche Ressourcen geladen werden dürfen:
```
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';
```
In der Produktionsumgebung wird eine strengere CSP verwendet:
```
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';
```
### Strict-Transport-Security (HSTS)
HSTS zwingt den Browser, nur HTTPS-Verbindungen zu verwenden, selbst wenn der Benutzer versucht, HTTP zu verwenden:
```
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```
Parameter:
- `max-age`: Dauer in Sekunden, für die der Browser nur HTTPS verwenden soll (1 Jahr)
- `includeSubDomains`: Gilt auch für alle Subdomains
- `preload`: Ermöglicht die Aufnahme in die HSTS-Preload-Liste der Browser
### X-Frame-Options
Schützt vor Clickjacking-Angriffen, indem es kontrolliert, ob die Seite in einem Frame eingebettet werden darf:
```
X-Frame-Options: DENY
```
Optionen:
- `DENY`: Die Seite darf nicht in einem Frame eingebettet werden
- `SAMEORIGIN`: Die Seite darf nur in einem Frame auf derselben Domain eingebettet werden
### X-Content-Type-Options
Verhindert MIME-Sniffing, bei dem Browser den Inhaltstyp einer Ressource erraten:
```
X-Content-Type-Options: nosniff
```
### Referrer-Policy
Kontrolliert, welche Referrer-Informationen beim Navigieren zu anderen Seiten gesendet werden:
```
Referrer-Policy: strict-origin-when-cross-origin
```
Optionen:
- `no-referrer`: Keine Referrer-Informationen senden
- `no-referrer-when-downgrade`: Keine Referrer-Informationen senden, wenn von HTTPS zu HTTP navigiert wird
- `same-origin`: Nur Referrer-Informationen senden, wenn auf derselben Domain navigiert wird
- `strict-origin`: Nur die Ursprungs-URL senden und nur bei gleichem Sicherheitsniveau
- `strict-origin-when-cross-origin`: Vollständige URL bei gleicher Domain, nur Ursprung bei Cross-Origin und gleichem Sicherheitsniveau
### Permissions-Policy
Kontrolliert, welche Browser-Features und APIs die Seite verwenden darf:
```
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
```
Diese Einstellung deaktiviert den Zugriff auf Kamera, Mikrofon, Geolocation und FLoC (Federated Learning of Cohorts).
### Cross-Origin-Policies
Eine Gruppe von Headern, die die Interaktion zwischen verschiedenen Ursprüngen kontrollieren:
```
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
```
Diese Header schützen vor verschiedenen Cross-Origin-Angriffen und Informationslecks.
### X-Permitted-Cross-Domain-Policies
Kontrolliert, ob Cross-Domain-Richtliniendateien (crossdomain.xml) geladen werden dürfen:
```
X-Permitted-Cross-Domain-Policies: none
```
## Konfiguration
### Umgebungsspezifische Konfiguration
Das Framework bietet vordefinierte Konfigurationen für verschiedene Umgebungen:
```php
// In der SecurityHeaderMiddleware
$config = $this->securityConfig->enableStrictMode
? SecurityHeaderConfig::forProduction()
: SecurityHeaderConfig::forDevelopment();
```
Die `enableStrictMode`-Einstellung kann in der Konfigurationsdatei angepasst werden:
```php
// config/security.php
return [
'headers' => [
'strict_mode' => true, // Produktionsmodus mit strengeren Einstellungen
'content_security_policy' => "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';",
'hsts' => [
'enabled' => true,
'max_age' => 31536000, // 1 Jahr
'include_subdomains' => true,
'preload' => true,
],
],
];
```
### Benutzerdefinierte Konfiguration
Sie können die Security Headers auch manuell konfigurieren:
```php
// Eigene Security-Header-Konfiguration erstellen
$config = new SecurityHeaderConfig();
$config->contentSecurityPolicy = "default-src 'self'; script-src 'self' https://trusted-cdn.com;";
$config->frameOptions = "DENY";
$config->referrerPolicy = "strict-origin-when-cross-origin";
// Konfiguration anwenden
$securityHeaderMiddleware = new SecurityHeaderMiddleware($responseManipulator, $config);
```
## Verwendung
### Automatische Anwendung
Die Security Headers werden automatisch auf alle Antworten angewendet, wenn die Middleware registriert ist:
```php
// In der Bootstrap-Datei
$app->addMiddleware(SecurityHeaderMiddleware::class);
```
### Anpassung für bestimmte Routen
In einigen Fällen möchten Sie möglicherweise die Security Headers für bestimmte Routen anpassen:
```php
// In einem Controller oder einer Middleware
public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
{
$resultContext = $next($context);
if ($resultContext->hasResponse()) {
$response = $resultContext->response;
$headers = $response->headers;
// CSP für eine bestimmte Route anpassen
$updatedHeaders = $headers->with(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' https://trusted-cdn.com;"
);
$updatedResponse = $this->manipulator->withHeaders($response, $updatedHeaders);
return $resultContext->withResponse($updatedResponse);
}
return $resultContext;
}
```
### Prüfen der aktuellen Security Headers
Sie können die aktuellen Security Headers Ihrer Anwendung mit verschiedenen Tools überprüfen:
1. **Browser-Entwicklertools**: Überprüfen Sie die Response-Header in der Netzwerk-Ansicht
2. **Online-Tools**: Verwenden Sie Dienste wie [securityheaders.com](https://securityheaders.com) oder [observatory.mozilla.org](https://observatory.mozilla.org)
3. **Curl-Befehl**: `curl -I https://yourdomain.com`
## Content Security Policy (CSP)
### Grundlegende CSP-Direktiven
Die Content Security Policy ist einer der wichtigsten Security Headers und verdient besondere Aufmerksamkeit:
- `default-src`: Standardrichtlinie für alle Ressourcentypen
- `script-src`: Erlaubte Quellen für JavaScript
- `style-src`: Erlaubte Quellen für CSS
- `img-src`: Erlaubte Quellen für Bilder
- `font-src`: Erlaubte Quellen für Schriftarten
- `connect-src`: Erlaubte Ziele für Fetch, XHR, WebSocket
- `media-src`: Erlaubte Quellen für Audio und Video
- `object-src`: Erlaubte Quellen für Plugins (Flash, PDF)
- `frame-src`: Erlaubte Quellen für Frames
- `base-uri`: Erlaubte URLs für das base-Element
- `form-action`: Erlaubte Ziele für Formularübermittlungen
- `frame-ancestors`: Erlaubte übergeordnete Dokumente (ähnlich X-Frame-Options)
### CSP-Quellwerte
- `'self'`: Ressourcen von derselben Ursprungs-Domain
- `'none'`: Keine Ressourcen erlaubt
- `'unsafe-inline'`: Inline-Skripte und Styles erlaubt (vermeiden in Produktion)
- `'unsafe-eval'`: eval() und ähnliche Funktionen erlaubt (vermeiden in Produktion)
- `'nonce-<base64-value>'`: Ressourcen mit entsprechendem Nonce-Attribut
- `'sha256-<hash>'`: Ressourcen mit entsprechendem Hash
- `https://example.com`: Spezifische Domain
- `https://*.example.com`: Alle Subdomains
- `data:`: Data-URLs (vorsichtig verwenden)
### CSP-Beispiele
Strenge CSP für Produktion:
```
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';
```
CSP mit externen Ressourcen:
```
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https://img.example.com;
```
CSP mit Nonce für Inline-Skripte:
```php
// In einem Controller
public function showPage(): Response
{
$nonce = bin2hex(random_bytes(16));
// CSP mit Nonce setzen
$csp = "default-src 'self'; script-src 'self' 'nonce-{$nonce}';";
return $this->render('page.twig', [
'nonce' => $nonce,
'csp' => $csp,
]);
}
```
In der Vorlage:
```html
<script nonce="{{ nonce }}">
// Dieser Inline-Code ist erlaubt, weil er den korrekten Nonce hat
console.log('Hello, world!');
</script>
```
### CSP-Reporting
Sie können CSP-Verstöße an einen Endpunkt melden lassen:
```
Content-Security-Policy: default-src 'self'; report-uri /csp-report;
```
Oder verwenden Sie den neueren Report-To-Header:
```
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}
```
## Fehlerbehebung
### Häufige Probleme
#### CSP blockiert legitime Ressourcen
Wenn Ihre Anwendung nicht korrekt funktioniert, weil die CSP legitime Ressourcen blockiert:
1. Überprüfen Sie die Konsole im Browser auf CSP-Verstöße
2. Erweitern Sie die CSP um die benötigten Quellen
3. Verwenden Sie vorübergehend eine weniger strenge CSP während der Entwicklung
```php
// Weniger strenge CSP für Entwicklung
$config->contentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';";
```
#### HSTS-Probleme
Wenn Sie HSTS aktiviert haben und Probleme auftreten:
1. Beginnen Sie mit einer kurzen `max-age` (z.B. 300 Sekunden)
2. Aktivieren Sie `includeSubDomains` erst, wenn Sie sicher sind, dass alle Subdomains HTTPS unterstützen
3. Verwenden Sie `preload` nur, wenn Sie sicher sind, dass Ihre Domain dauerhaft HTTPS unterstützt
#### Frames werden blockiert
Wenn Ihre Anwendung Frames verwenden muss:
```php
// X-Frame-Options anpassen
$config->frameOptions = "SAMEORIGIN"; // Erlaubt Frames auf derselben Domain
```
## Sicherheitsüberlegungen
### Best Practices
1. **Verwenden Sie strenge CSP**: Vermeiden Sie 'unsafe-inline' und 'unsafe-eval' in Produktion
2. **Aktivieren Sie HSTS**: Erzwingen Sie HTTPS für alle Verbindungen
3. **Regelmäßige Überprüfung**: Testen Sie Ihre Security Headers regelmäßig mit Tools wie [securityheaders.com](https://securityheaders.com)
4. **Umgebungsspezifische Konfiguration**: Verwenden Sie unterschiedliche Konfigurationen für Entwicklung und Produktion
5. **CSP-Reporting**: Implementieren Sie CSP-Reporting, um Verstöße zu erkennen
### Bekannte Einschränkungen
- Ältere Browser unterstützen möglicherweise nicht alle Security Headers
- Eine zu strenge CSP kann die Funktionalität von Drittanbieter-Skripten beeinträchtigen
- HSTS kann nicht rückgängig gemacht werden, bis die `max-age` abgelaufen ist
## Weiterführende Informationen
- [Security Features Übersicht](index.md)
- [CSRF-Schutz](csrf-protection.md)
- [Request Signing API](request-signing.md)
- [Sicherheits-Best-Practices](/guides/security-best-practices.md)
- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security)
- [OWASP Security Headers](https://owasp.org/www-project-secure-headers/)

View File

@@ -0,0 +1,424 @@
# Validation Framework Beispiele
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Validation Frameworks korrekt dar.
## Übersicht
Diese Dokumentation enthält praktische Beispiele für die Verwendung des Validation Frameworks in verschiedenen Szenarien. Die Beispiele zeigen, wie Sie Validierungsregeln auf Objekteigenschaften anwenden, Validierungsergebnisse verarbeiten und das Framework in verschiedenen Kontexten integrieren können.
## Grundlegende Verwendung
### Einfache Objektvalidierung
```php
use App\Framework\Validation\Rules\Required;
use App\Framework\Validation\Rules\Email;
use App\Framework\Validation\Rules\StringLength;
// 1. Definieren Sie eine Klasse mit Validierungsregeln
class UserData
{
#[Required]
#[StringLength(min: 3, max: 50)]
public string $name;
#[Required]
#[Email]
public string $email;
#[StringLength(max: 500)]
public ?string $bio = null;
}
// 2. Erstellen Sie eine Instanz der Klasse
$userData = new UserData();
$userData->name = 'Max Mustermann';
$userData->email = 'max@example.com';
// 3. Validieren Sie das Objekt
$validator = $container->get(Validator::class);
$result = $validator->validate($userData);
// 4. Überprüfen Sie das Ergebnis
if ($result->hasErrors()) {
// Fehlerbehandlung
$errors = $result->getAllErrorMessages();
foreach ($errors as $error) {
echo $error . "\n";
}
} else {
// Erfolgreiche Validierung
echo "Validierung erfolgreich!";
}
```
### Validierung mit benutzerdefinierten Fehlermeldungen
```php
class ProductData
{
#[Required(message: "Der Produktname ist erforderlich.")]
#[StringLength(min: 3, max: 100, message: "Der Produktname muss zwischen 3 und 100 Zeichen lang sein.")]
public string $name;
#[Required(message: "Der Preis ist erforderlich.")]
#[Range(min: 0, message: "Der Preis muss größer oder gleich 0 sein.")]
public float $price;
#[Required(message: "Die Kategorie ist erforderlich.")]
#[In(values: ['electronics', 'books', 'clothing'], message: "Ungültige Kategorie.")]
public string $category;
}
```
### Zugriff auf feldspezifische Fehler
```php
$result = $validator->validate($userData);
if ($result->hasErrors()) {
// Alle Fehler für ein bestimmtes Feld abrufen
$emailErrors = $result->getFieldErrors('email');
foreach ($emailErrors as $error) {
echo "Fehler im Feld 'email': $error\n";
}
// Alle Fehler nach Feld gruppiert abrufen
$allErrors = $result->getAll();
foreach ($allErrors as $field => $errors) {
echo "Fehler im Feld '$field':\n";
foreach ($errors as $error) {
echo "- $error\n";
}
}
}
```
## Fortgeschrittene Verwendung
### Validierungsgruppen
Validierungsgruppen ermöglichen es, verschiedene Validierungsszenarien für dasselbe Objekt zu definieren:
```php
use App\Framework\Validation\Rules\Required;
use App\Framework\Validation\Rules\Email;
use App\Framework\Validation\Rules\StringLength;
class UserProfile
{
#[Required(groups: ['registration', 'profile'])]
#[StringLength(min: 3, max: 50)]
public string $name;
#[Required(groups: ['registration'])]
#[Email]
public string $email;
#[Required(groups: ['profile'])]
#[StringLength(max: 500)]
public ?string $bio = null;
#[Required(groups: ['profile'])]
#[Url]
public ?string $website = null;
}
// Validierung mit einer bestimmten Gruppe
$result = $validator->validate($userProfile, 'registration');
// In diesem Fall werden nur die Regeln angewendet, die zur Gruppe 'registration' gehören
// oder keine Gruppe spezifiziert haben
```
### Verschachtelte Validierung
Validierung von Objekten, die andere validierbare Objekte enthalten:
```php
use App\Framework\Validation\Rules\Required;
use App\Framework\Validation\Rules\Email;
class Address
{
#[Required]
#[StringLength(min: 3, max: 100)]
public string $street;
#[Required]
#[StringLength(min: 3, max: 50)]
public string $city;
#[Required]
#[StringLength(min: 5, max: 10)]
public string $zipCode;
}
class Customer
{
#[Required]
#[StringLength(min: 3, max: 50)]
public string $name;
#[Required]
#[Email]
public string $email;
#[Required]
public Address $address;
}
// Validierung eines Objekts mit verschachtelten Objekten
$address = new Address();
$address->street = 'Musterstraße 123';
$address->city = 'Berlin';
$address->zipCode = '10115';
$customer = new Customer();
$customer->name = 'Max Mustermann';
$customer->email = 'max@example.com';
$customer->address = $address;
// Validierung des Hauptobjekts
$result = $validator->validate($customer);
// Manuelle Validierung des verschachtelten Objekts
$addressResult = $validator->validate($customer->address);
$result->merge($addressResult); // Kombinieren der Ergebnisse
```
### Benutzerdefinierte Validierungslogik
Verwendung der `Custom`-Regel für komplexe Validierungsanforderungen:
```php
use App\Framework\Validation\Rules\Custom;
use App\Framework\Validation\Rules\Required;
class PasswordReset
{
#[Required]
public string $email;
#[Required]
public string $password;
#[Required]
#[Custom(callback: 'validatePasswordConfirmation', message: "Die Passwörter stimmen nicht überein.")]
public string $passwordConfirmation;
private function validatePasswordConfirmation($value): bool
{
return $value === $this->password;
}
}
```
## Integration mit Formularen
### Formularvalidierung
Verwendung des Validation Frameworks zur Validierung von Formulardaten:
```php
use App\Framework\Validation\ValidationFormHandler;
use App\Framework\Http\Response;
class UserController
{
public function handleRegistration(
Request $request,
ValidationFormHandler $formHandler,
UserService $userService
): Response {
// Formulardaten abrufen
$formData = $request->getFormData();
// Validierung durchführen
$result = $formHandler->validate(UserRegistration::class, $formData);
if ($result->hasErrors()) {
// Formular mit Fehlern neu rendern
return $this->renderForm('registration', [
'errors' => $result->getAll(),
'data' => $formData
]);
}
// Erfolgreiche Validierung, Benutzer registrieren
$userService->registerUser($formData);
// Weiterleitung zur Erfolgsseite
return $this->redirect('/registration/success');
}
}
```
### Formularvorlage mit Fehleranzeige
```html
<form method="post" action="/register">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" value="<?= htmlspecialchars($data['name'] ?? '') ?>">
<?php if (isset($errors['name'])): ?>
<div class="error">
<?= htmlspecialchars($errors['name'][0]) ?>
</div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="email">E-Mail:</label>
<input type="email" id="email" name="email" value="<?= htmlspecialchars($data['email'] ?? '') ?>">
<?php if (isset($errors['email'])): ?>
<div class="error">
<?= htmlspecialchars($errors['email'][0]) ?>
</div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="password">Passwort:</label>
<input type="password" id="password" name="password">
<?php if (isset($errors['password'])): ?>
<div class="error">
<?= htmlspecialchars($errors['password'][0]) ?>
</div>
<?php endif; ?>
</div>
<button type="submit">Registrieren</button>
</form>
```
## API-Validierung
### Middleware für API-Validierung
Das Framework bietet eine `InputValidationMiddleware` für die automatische Validierung von API-Anfragen:
```php
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(InputValidationMiddleware::class);
```
Konfiguration in `config/validation.php`:
```php
return [
'routes' => [
'/api/users' => [
'POST' => UserCreateData::class,
'PUT' => UserUpdateData::class
],
'/api/products' => [
'POST' => ProductCreateData::class,
'PUT' => ProductUpdateData::class
]
]
];
```
### API-Controller mit Validierung
```php
class ApiController
{
public function createUser(Request $request): Response
{
// Die Validierung wurde bereits durch die Middleware durchgeführt
// Wenn wir hier sind, waren die Daten gültig
$userData = $request->getJsonData();
$user = $this->userService->createUser($userData);
return new Response(201, [], [
'success' => true,
'user' => $user->toArray()
]);
}
}
```
### Fehlerbehandlung für API-Validierung
Die `InputValidationMiddleware` gibt automatisch eine Fehlerantwort zurück, wenn die Validierung fehlschlägt:
```json
{
"error": "Validation failed",
"validation_errors": {
"name": ["Der Name ist erforderlich."],
"email": ["Bitte geben Sie eine gültige E-Mail-Adresse ein."]
}
}
```
## Leistungsoptimierung
### Validierungs-Cache
Für häufig validierte Objekte kann ein Cache verwendet werden, um die Leistung zu verbessern:
```php
use App\Framework\Validation\ValidationCacheDecorator;
// Cache-Decorator erstellen
$cachedValidator = new ValidationCacheDecorator($validator, $cache);
// Validierung mit Cache durchführen
$result = $cachedValidator->validate($userData);
```
### Validierungsgruppen für partielle Validierung
Verwenden Sie Validierungsgruppen, um nur die relevanten Teile eines Objekts zu validieren:
```php
// Nur die für die Aktualisierung relevanten Felder validieren
$result = $validator->validate($userData, 'update');
```
## Fehlerbehebung
### Häufige Probleme und Lösungen
#### Validierungsregeln werden nicht angewendet
Stellen Sie sicher, dass:
- Die Attribute korrekt definiert sind
- Die Eigenschaften für den Validator zugänglich sind (public oder mit Reflection)
- Der Validator korrekt initialisiert wurde
```php
// Korrekte Initialisierung des Validators
$validator = new Validator($reflectionProvider);
```
#### Falsche Fehlermeldungen
Überprüfen Sie die Reihenfolge der Validierungsregeln:
```php
// Korrekte Reihenfolge: Required vor anderen Regeln
#[Required]
#[Email]
public string $email;
```
#### Leistungsprobleme
Verwenden Sie den ValidationCacheDecorator und vermeiden Sie zu komplexe Validierungsregeln:
```php
// Einfache Regeln verwenden
#[StringLength(max: 255)] // Besser als komplexe reguläre Ausdrücke
public string $name;
```
## Weiterführende Informationen
- [Validation Framework Übersicht](index.md)
- [Verfügbare Validierungsregeln](rules.md)
- [API-Validierung](/guides/api-validation.md)

View File

@@ -0,0 +1,338 @@
# Validation Framework
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Validation Frameworks korrekt dar.
## Übersicht
Das Validation Framework ist ein leistungsstarkes System zur Validierung von Objekten und Daten in der Anwendung. Es nutzt moderne PHP-Attribute, um Validierungsregeln direkt an Objekteigenschaften zu definieren, und bietet eine flexible, erweiterbare Architektur für verschiedene Validierungsanforderungen.
## Hauptkomponenten
### Validator-Klasse
Die zentrale Klasse für die Validierungsfunktionalität:
```php
// Klasse initialisieren
$validator = new Validator($reflectionProvider);
// Objekt validieren
$result = $validator->validate($object);
// Validierungsergebnis prüfen
if ($result->hasErrors()) {
// Fehlerbehandlung
$errors = $result->getAllErrorMessages();
}
```
### ValidationRule-Interface
Das Basis-Interface für alle Validierungsregeln:
```php
interface ValidationRule
{
public function validate(mixed $value): bool;
public function getErrorMessages(): array;
}
```
Alle Validierungsregeln implementieren dieses Interface und werden als PHP-Attribute verwendet.
### ValidationResult-Klasse
Speichert und verwaltet Validierungsergebnisse:
- Sammelt Fehlermeldungen für verschiedene Felder
- Bietet Methoden zum Abfragen von Fehlern
- Ermöglicht das Zusammenführen mehrerer Validierungsergebnisse
```php
// Fehler prüfen
if ($result->hasErrors()) {
// Alle Fehlermeldungen abrufen
$allErrors = $result->getAllErrorMessages();
// Fehler für ein bestimmtes Feld abrufen
$fieldErrors = $result->getFieldErrors('email');
}
```
## Validierungsregeln
Das Framework bietet eine Vielzahl vordefinierter Validierungsregeln:
### Grundlegende Regeln
- **Required**: Stellt sicher, dass ein Wert vorhanden ist
- **Email**: Validiert E-Mail-Adressen
- **Url**: Validiert URLs
- **Numeric**: Stellt sicher, dass ein Wert numerisch ist
- **StringLength**: Validiert die Länge eines Strings
### Erweiterte Regeln
- **Pattern**: Validiert Werte gegen reguläre Ausdrücke
- **Range**: Validiert numerische Werte innerhalb eines Bereichs
- **In**: Prüft, ob ein Wert in einer Liste gültiger Werte enthalten ist
- **DateFormat**: Validiert Datumsformate
- **Phone**: Validiert Telefonnummern
- **Ulid**: Validiert ULID-Werte
- **IsTrue**: Prüft, ob ein Wert true ist
### Benutzerdefinierte Regeln
Eigene Validierungsregeln können durch Implementierung des ValidationRule-Interfaces erstellt werden:
```php
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class CustomRule implements ValidationRule
{
public function __construct(
private string $param,
private ?string $message = null
) {
}
public function validate(mixed $value): bool
{
// Validierungslogik implementieren
return true; // oder false
}
public function getErrorMessages(): array
{
return [$this->message ?? 'Standardfehlermeldung'];
}
}
```
## Verwendung
### Objekte mit Attributen validieren
```php
class UserData
{
#[Required]
#[StringLength(min: 3, max: 50)]
public string $name;
#[Required]
#[Email]
public string $email;
#[StringLength(max: 500)]
public ?string $bio = null;
#[Range(min: 18)]
public ?int $age = null;
}
// Validierung durchführen
$userData = new UserData();
$userData->name = 'Max';
$userData->email = 'invalid-email';
$result = $validator->validate($userData);
```
### Validierungsgruppen
Das Framework unterstützt Validierungsgruppen, um verschiedene Validierungsszenarien zu ermöglichen:
```php
class UserData
{
#[Required(groups: ['registration', 'profile'])]
#[StringLength(min: 3, max: 50)]
public string $name;
#[Required(groups: ['registration'])]
#[Email]
public string $email;
#[Required(groups: ['profile'])]
#[StringLength(max: 500)]
public ?string $bio = null;
}
// Validierung mit Gruppe durchführen
$result = $validator->validate($userData, 'registration');
```
### Fehlerbehandlung
```php
if ($result->hasErrors()) {
foreach ($result->getAll() as $field => $errors) {
echo "Fehler im Feld '$field':\n";
foreach ($errors as $error) {
echo "- $error\n";
}
}
}
```
## Integration
### Formular-Validierung
Das Framework bietet eine `ValidationFormHandler`-Klasse für die Validierung von Formulardaten:
```php
// In einem Controller
public function handleForm(Request $request, ValidationFormHandler $formHandler): Response
{
$formData = $request->getFormData();
$result = $formHandler->validate(UserData::class, $formData);
if ($result->hasErrors()) {
return $this->renderForm('user_form', [
'errors' => $result->getAll(),
'data' => $formData
]);
}
// Erfolgreiche Validierung, Daten verarbeiten
$this->userService->createUser($formData);
return $this->redirect('/success');
}
```
### Middleware-Integration
Das Framework bietet eine `InputValidationMiddleware` für die automatische Validierung von API-Anfragen:
```php
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(InputValidationMiddleware::class);
```
Konfiguration in `config/validation.php`:
```php
return [
'routes' => [
'/api/users' => [
'POST' => UserData::class,
'PUT' => UserUpdateData::class
]
]
];
```
## Erweiterbarkeit
### Eigene Validierungsregeln erstellen
1. Interface implementieren:
```php
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class Password implements ValidationRule
{
public function __construct(
private int $minLength = 8,
private bool $requireSpecialChars = true,
private ?string $message = null
) {
}
public function validate(mixed $value): bool
{
if ($value === null || $value === '') {
return true; // Leere Werte werden von Required-Regel behandelt
}
if (!is_string($value) || strlen($value) < $this->minLength) {
return false;
}
if ($this->requireSpecialChars && !preg_match('/[^a-zA-Z0-9]/', $value)) {
return false;
}
return true;
}
public function getErrorMessages(): array
{
return [$this->message ?? "Das Passwort muss mindestens {$this->minLength} Zeichen lang sein und Sonderzeichen enthalten."];
}
}
```
2. Verwendung:
```php
class UserRegistration
{
#[Required]
#[Email]
public string $email;
#[Required]
#[Password(minLength: 10)]
public string $password;
}
```
### Validierungsgruppen implementieren
Für Regeln, die Validierungsgruppen unterstützen sollen, implementieren Sie das `GroupAware`-Interface:
```php
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class Required implements ValidationRule, GroupAware
{
/**
* @param array<string> $groups Validierungsgruppen
*/
public function __construct(
private ?string $message = null,
private array $groups = []
) {
}
public function validate(mixed $value): bool
{
return $value !== null && $value !== '';
}
public function getErrorMessages(): array
{
return [$this->message ?? 'Dieser Wert ist erforderlich.'];
}
public function belongsToGroup(string $group): bool
{
return empty($this->groups) || in_array($group, $this->groups);
}
}
```
## Fehlerbehebung
### Häufige Probleme
1. **Validierungsregeln werden nicht angewendet**:
- Stellen Sie sicher, dass die Attribute korrekt definiert sind
- Überprüfen Sie, ob die Eigenschaften für den Validator zugänglich sind (public oder mit Reflection)
2. **Falsche Fehlermeldungen**:
- Überprüfen Sie die Reihenfolge der Validierungsregeln
- Stellen Sie sicher, dass die Regeln für den richtigen Datentyp verwendet werden
3. **Leistungsprobleme**:
- Verwenden Sie ValidationCacheDecorator für häufig validierte Objekte
- Vermeiden Sie zu komplexe Validierungsregeln
## Weiterführende Informationen
- [Verfügbare Validierungsregeln](rules.md)
- [Formular-Integration](examples.md)
- [API-Validierung](/guides/api-validation.md)

View File

@@ -0,0 +1,451 @@
# Validierungsregeln
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der Validierungsregeln korrekt dar.
## Übersicht
Das Validation Framework bietet eine umfangreiche Sammlung vordefinierter Validierungsregeln, die als PHP-Attribute verwendet werden können. Diese Regeln können auf Objekteigenschaften angewendet werden, um Daten zu validieren und sicherzustellen, dass sie den erwarteten Anforderungen entsprechen.
## Grundlegende Regeln
### Required
Die `Required`-Regel stellt sicher, dass ein Wert vorhanden ist und nicht leer ist:
```php
use App\Framework\Validation\Rules\Required;
class UserData
{
#[Required]
public string $username;
#[Required(message: "Die E-Mail-Adresse ist erforderlich.")]
public string $email;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
- `groups` (optional): Array von Validierungsgruppen, zu denen diese Regel gehört
**Validierungslogik:**
- Gibt `false` zurück, wenn der Wert `null` oder ein leerer String ist
- Gibt `true` zurück für alle anderen Werte, einschließlich `0` und `false`
### Email
Die `Email`-Regel validiert, dass ein Wert eine gültige E-Mail-Adresse ist:
```php
use App\Framework\Validation\Rules\Email;
class UserData
{
#[Email]
public string $email;
#[Email(message: "Bitte geben Sie eine gültige E-Mail-Adresse ein.")]
public string $alternativeEmail;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `filter_var()` mit `FILTER_VALIDATE_EMAIL` zur Validierung
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### StringLength
Die `StringLength`-Regel validiert die Länge eines Strings:
```php
use App\Framework\Validation\Rules\StringLength;
class UserData
{
#[StringLength(min: 3, max: 50)]
public string $username;
#[StringLength(min: 8, message: "Das Passwort muss mindestens 8 Zeichen lang sein.")]
public string $password;
#[StringLength(max: 500)]
public ?string $bio;
}
```
**Parameter:**
- `min` (optional): Minimale Länge des Strings
- `max` (optional): Maximale Länge des Strings
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Mindestens einer der Parameter `min` oder `max` muss gesetzt sein
- Verwendet `mb_strlen()` für korrekte Behandlung von Multibyte-Zeichen
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### Url
Die `Url`-Regel validiert, dass ein Wert eine gültige URL ist:
```php
use App\Framework\Validation\Rules\Url;
class UserData
{
#[Url]
public string $website;
#[Url(message: "Bitte geben Sie eine gültige URL ein.")]
public string $profileUrl;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `filter_var()` mit `FILTER_VALIDATE_URL` zur Validierung
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### Numeric
Die `Numeric`-Regel validiert, dass ein Wert numerisch ist:
```php
use App\Framework\Validation\Rules\Numeric;
class ProductData
{
#[Numeric]
public $price;
#[Numeric(message: "Die Menge muss eine Zahl sein.")]
public $quantity;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `is_numeric()` zur Validierung
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
## Erweiterte Regeln
### Pattern
Die `Pattern`-Regel validiert einen Wert gegen einen regulären Ausdruck:
```php
use App\Framework\Validation\Rules\Pattern;
class UserData
{
#[Pattern(pattern: '/^[a-zA-Z0-9_]+$/', message: "Der Benutzername darf nur Buchstaben, Zahlen und Unterstriche enthalten.")]
public string $username;
}
```
**Parameter:**
- `pattern`: Regulärer Ausdruck für die Validierung
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `preg_match()` zur Validierung gegen den angegebenen regulären Ausdruck
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### Range
Die `Range`-Regel validiert, dass ein numerischer Wert innerhalb eines bestimmten Bereichs liegt:
```php
use App\Framework\Validation\Rules\Range;
class ProductData
{
#[Range(min: 0)]
public float $price;
#[Range(min: 1, max: 100, message: "Die Menge muss zwischen 1 und 100 liegen.")]
public int $quantity;
}
```
**Parameter:**
- `min` (optional): Minimaler Wert
- `max` (optional): Maximaler Wert
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Mindestens einer der Parameter `min` oder `max` muss gesetzt sein
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### In
Die `In`-Regel validiert, dass ein Wert in einer Liste gültiger Werte enthalten ist:
```php
use App\Framework\Validation\Rules\In;
class ProductData
{
#[In(values: ['small', 'medium', 'large'])]
public string $size;
#[In(values: [1, 2, 3, 4, 5], message: "Bitte wählen Sie eine gültige Kategorie.")]
public int $category;
}
```
**Parameter:**
- `values`: Array gültiger Werte
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `in_array()` zur Validierung
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### DateFormat
Die `DateFormat`-Regel validiert, dass ein Wert ein gültiges Datum in einem bestimmten Format ist:
```php
use App\Framework\Validation\Rules\DateFormat;
class EventData
{
#[DateFormat(format: 'Y-m-d')]
public string $date;
#[DateFormat(format: 'Y-m-d H:i:s', message: "Bitte geben Sie ein gültiges Datum und eine gültige Uhrzeit ein.")]
public string $datetime;
}
```
**Parameter:**
- `format`: Das erwartete Datumsformat (PHP date()-Format)
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Verwendet `DateTime::createFromFormat()` zur Validierung
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### Phone
Die `Phone`-Regel validiert, dass ein Wert eine gültige Telefonnummer ist:
```php
use App\Framework\Validation\Rules\Phone;
class ContactData
{
#[Phone]
public string $phoneNumber;
#[Phone(message: "Bitte geben Sie eine gültige Telefonnummer ein.")]
public string $mobileNumber;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Validiert Telefonnummern mit einem flexiblen Muster, das verschiedene Formate unterstützt
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### Ulid
Die `Ulid`-Regel validiert, dass ein Wert ein gültiger ULID (Universally Unique Lexicographically Sortable Identifier) ist:
```php
use App\Framework\Validation\Rules\Ulid;
class EntityData
{
#[Ulid]
public string $id;
#[Ulid(message: "Die ID muss ein gültiger ULID sein.")]
public string $parentId;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Validiert, dass der Wert ein gültiger ULID ist (26 Zeichen, Base32-Kodierung)
- Leere Werte werden als gültig betrachtet (verwenden Sie `Required` in Kombination, um leere Werte zu verhindern)
### IsTrue
Die `IsTrue`-Regel validiert, dass ein Wert `true` ist:
```php
use App\Framework\Validation\Rules\IsTrue;
class RegistrationData
{
#[IsTrue(message: "Sie müssen die Nutzungsbedingungen akzeptieren.")]
public bool $termsAccepted;
}
```
**Parameter:**
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Gibt `true` zurück, wenn der Wert `true` ist
- Gibt `false` zurück für alle anderen Werte
- Leere Werte werden als ungültig betrachtet
## Benutzerdefinierte Regeln
### Custom
Die `Custom`-Regel ermöglicht die Definition einer benutzerdefinierten Validierungslogik mit einer Callback-Funktion:
```php
use App\Framework\Validation\Rules\Custom;
class UserData
{
#[Custom(callback: 'validateUsername', message: "Der Benutzername ist ungültig.")]
public string $username;
private function validateUsername($value): bool
{
// Benutzerdefinierte Validierungslogik
return preg_match('/^[a-zA-Z0-9_]{3,20}$/', $value) === 1;
}
}
```
**Parameter:**
- `callback`: Name der Callback-Methode oder Closure
- `message` (optional): Benutzerdefinierte Fehlermeldung
**Validierungslogik:**
- Ruft die angegebene Callback-Funktion auf und gibt deren Rückgabewert zurück
- Leere Werte werden an die Callback-Funktion übergeben
## Eigene Validierungsregeln erstellen
Sie können eigene Validierungsregeln erstellen, indem Sie das `ValidationRule`-Interface implementieren:
```php
use App\Framework\Validation\ValidationRule;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class Password implements ValidationRule
{
public function __construct(
private int $minLength = 8,
private bool $requireSpecialChars = true,
private ?string $message = null
) {
}
public function validate(mixed $value): bool
{
if ($value === null || $value === '') {
return true; // Leere Werte werden von Required-Regel behandelt
}
if (!is_string($value) || strlen($value) < $this->minLength) {
return false;
}
if ($this->requireSpecialChars && !preg_match('/[^a-zA-Z0-9]/', $value)) {
return false;
}
return true;
}
public function getErrorMessages(): array
{
return [$this->message ?? "Das Passwort muss mindestens {$this->minLength} Zeichen lang sein und Sonderzeichen enthalten."];
}
}
```
## Validierungsgruppen
Für Regeln, die Validierungsgruppen unterstützen sollen, implementieren Sie das `GroupAware`-Interface:
```php
use App\Framework\Validation\ValidationRule;
use App\Framework\Validation\GroupAware;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class Required implements ValidationRule, GroupAware
{
/**
* @param array<string> $groups Validierungsgruppen
*/
public function __construct(
private ?string $message = null,
private array $groups = []
) {
}
public function validate(mixed $value): bool
{
return $value !== null && $value !== '';
}
public function getErrorMessages(): array
{
return [$this->message ?? 'Dieser Wert ist erforderlich.'];
}
public function belongsToGroup(string $group): bool
{
return empty($this->groups) || in_array($group, $this->groups);
}
}
```
## Kombinieren von Regeln
Validierungsregeln können kombiniert werden, um komplexe Validierungsanforderungen zu erfüllen:
```php
class UserData
{
#[Required]
#[StringLength(min: 3, max: 50)]
#[Pattern(pattern: '/^[a-zA-Z0-9_]+$/')]
public string $username;
#[Required]
#[Email]
public string $email;
#[Required]
#[StringLength(min: 8)]
#[Custom(callback: 'validatePassword')]
public string $password;
private function validatePassword($value): bool
{
// Mindestens ein Großbuchstabe, ein Kleinbuchstabe, eine Zahl und ein Sonderzeichen
return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z\d]).+$/', $value) === 1;
}
}
```
## Weiterführende Informationen
- [Validation Framework Übersicht](index.md)
- [Beispiele für die Verwendung von Validierungsregeln](examples.md)
- [API-Validierung](/guides/api-validation.md)

View File

@@ -0,0 +1,279 @@
# WAF Konfiguration
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der WAF-Konfiguration korrekt dar.
## Übersicht
Die Web Application Firewall (WAF) bietet umfangreiche Konfigurationsmöglichkeiten, um das Sicherheitsniveau und die Leistung an die Anforderungen Ihrer Anwendung anzupassen. Diese Dokumentation beschreibt die verfügbaren Konfigurationsoptionen und wie Sie diese anwenden können.
## Konfigurationsklasse
Die zentrale Klasse für die WAF-Konfiguration ist `WafConfig`. Diese Klasse enthält alle Einstellungen, die das Verhalten der WAF steuern:
```php
// Konfiguration erstellen
$config = new WafConfig(
$enabled,
$defaultLayerConfig,
$globalTimeout,
$blockingThreshold,
$alertThreshold,
$parallelProcessing,
$maxParallelLayers,
$detailedLogging,
$metricsEnabled,
$enabledLayers,
$layerConfigs,
$customSettings
);
```
## Vordefinierte Konfigurationen
Die `WafConfig`-Klasse bietet mehrere vordefinierte Konfigurationen für verschiedene Umgebungen:
### Produktionsumgebung
```php
// Produktionskonfiguration verwenden
$config = WafConfig::production();
```
Die Produktionskonfiguration aktiviert alle Sicherheitsfeatures mit strengen Einstellungen:
- Alle Schutzebenen aktiviert
- Niedrige Schwellenwerte für Blockierung
- Parallele Verarbeitung für optimale Leistung
- Detaillierte Metriken für Überwachung
### Entwicklungsumgebung
```php
// Entwicklungskonfiguration verwenden
$config = WafConfig::development();
```
Die Entwicklungskonfiguration ist weniger streng und bietet:
- Höhere Schwellenwerte für Blockierung
- Detailliertes Logging für Debugging
- Alle Schutzebenen aktiviert, aber mit weniger strengen Einstellungen
### Testumgebung
```php
// Testkonfiguration verwenden
$config = WafConfig::testing();
```
Die Testkonfiguration ist für automatisierte Tests optimiert:
- Reduzierte Timeouts
- Deaktivierte parallele Verarbeitung
- Minimales Logging
### Deaktivierte Konfiguration
```php
// WAF deaktivieren
$config = WafConfig::disabled();
```
Diese Konfiguration deaktiviert die WAF vollständig, was für bestimmte Entwicklungs- oder Diagnoseszenarien nützlich sein kann.
## Hauptkonfigurationsoptionen
### Aktivierung/Deaktivierung
```php
// WAF aktivieren
$config = $config->enable();
// WAF deaktivieren
$config = $config->disable();
```
### Timeout-Einstellungen
```php
// Globales Timeout für WAF-Verarbeitung setzen
$config = $config->withGlobalTimeout(Duration::fromMilliseconds(100));
```
### Schwellenwerte
```php
// Schwellenwert für Blockierung setzen
$config = $config->withBlockingThreshold(Percentage::fromFloat(0.75));
```
Der Blockierungsschwellenwert bestimmt, ab welchem Konfidenzwert ein Request blockiert wird. Ein höherer Wert bedeutet weniger Blockierungen (und potenziell mehr falsch negative Ergebnisse), während ein niedrigerer Wert mehr Blockierungen (und potenziell mehr falsch positive Ergebnisse) bedeutet.
## Schutzebenen-Konfiguration
Die WAF verwendet ein mehrschichtiges Schutzsystem. Jede Schutzebene kann individuell konfiguriert werden:
```php
// Schutzebene aktivieren mit benutzerdefinierter Konfiguration
$config = $config->enableLayer(
'statistical',
new LayerConfig(
$enabled = true,
$weight = 0.6,
$threshold = Percentage::fromFloat(0.7),
$timeout = Duration::fromMilliseconds(50)
)
);
// Schutzebene deaktivieren
$config = $config->disableLayer('clustering');
```
### Verfügbare Schutzebenen
- **statistical**: Statistische Anomalieerkennung
- **clustering**: Clustering-basierte Anomalieerkennung
- **signature**: Signaturbasierte Erkennung bekannter Angriffsmuster
- **behavioral**: Verhaltensbasierte Anomalieerkennung
- **ratelimiting**: Ratenbegrenzung für Anfragen
## Benutzerdefinierte Einstellungen
Die WAF unterstützt benutzerdefinierte Einstellungen für spezielle Anwendungsfälle:
```php
// Benutzerdefinierte Einstellung hinzufügen
$config = $config->withCustomSetting('whitelist_ips', ['127.0.0.1', '192.168.1.1']);
// Benutzerdefinierte Einstellung abrufen
$whitelistIps = $config->getCustomSetting('whitelist_ips', []);
```
## Konfigurationsvalidierung
Die WAF-Konfiguration kann validiert werden, um sicherzustellen, dass alle Einstellungen gültig sind:
```php
// Konfiguration validieren
$validationErrors = $config->validate();
// Prüfen, ob die Konfiguration gültig ist
if (!$config->isValid()) {
// Fehlerbehandlung
}
```
## Konfiguration in der Anwendung
### Konfigurationsdatei
Die WAF-Konfiguration kann in einer dedizierten Konfigurationsdatei definiert werden:
```php
// config/waf.php
return [
'enabled' => true,
'learning_mode' => false,
'threshold' => 0.75,
'detectors' => [
'statistical' => true,
'clustering' => true
],
'whitelist' => [
'ips' => ['127.0.0.1'],
'paths' => ['/api/health']
]
];
```
### Laufzeitkonfiguration
Die WAF-Konfiguration kann zur Laufzeit aktualisiert werden:
```php
// WAF-Konfiguration aktualisieren
$waf->updateConfig($newConfig);
```
## Leistungsoptimierung
### Parallele Verarbeitung
Die parallele Verarbeitung kann die Leistung der WAF verbessern, insbesondere bei mehreren aktivierten Schutzebenen:
```php
// Parallele Verarbeitung aktivieren
$config = new WafConfig(
$enabled = true,
$defaultLayerConfig,
$globalTimeout,
$blockingThreshold,
$alertThreshold,
$parallelProcessing = true,
$maxParallelLayers = 4,
$detailedLogging,
$metricsEnabled,
$enabledLayers,
$layerConfigs,
$customSettings
);
```
### Caching
Die WAF unterstützt Caching für wiederholte Anfragen, um die Leistung zu verbessern:
```php
// Benutzerdefinierte Caching-Einstellungen
$config = $config->withCustomSetting('cache_ttl', 300); // 5 Minuten
$config = $config->withCustomSetting('cache_size', 1000); // 1000 Einträge
```
## Fehlerbehebung
### Logging
Detailliertes Logging kann für die Fehlerbehebung aktiviert werden:
```php
// Detailliertes Logging aktivieren
$config = new WafConfig(
$enabled = true,
$defaultLayerConfig,
$globalTimeout,
$blockingThreshold,
$alertThreshold,
$parallelProcessing,
$maxParallelLayers,
$detailedLogging = true,
$metricsEnabled,
$enabledLayers,
$layerConfigs,
$customSettings
);
```
### Metriken
Die WAF kann Metriken zur Leistung und Effektivität sammeln:
```php
// Metriken aktivieren
$config = new WafConfig(
$enabled = true,
$defaultLayerConfig,
$globalTimeout,
$blockingThreshold,
$alertThreshold,
$parallelProcessing,
$maxParallelLayers,
$detailedLogging,
$metricsEnabled = true,
$enabledLayers,
$layerConfigs,
$customSettings
);
```
## Weiterführende Informationen
- [WAF-Übersicht](index.md)
- [Machine Learning Dokumentation](machine-learning.md)
- [Sicherheitsrichtlinien](/guides/security.md)

View File

@@ -0,0 +1,280 @@
# WAF Feedback System
The Web Application Firewall (WAF) Feedback System allows users to provide feedback on WAF detections, helping to improve the accuracy of the security system over time. This document explains how to use the feedback system, how it works, and how to integrate it into your application.
## Table of Contents
1. [User Guide](#user-guide)
- [Submitting Feedback](#submitting-feedback)
- [Types of Feedback](#types-of-feedback)
- [Feedback Dashboard](#feedback-dashboard)
2. [Technical Documentation](#technical-documentation)
- [Architecture](#architecture)
- [Components](#components)
- [Integration](#integration)
3. [Learning Algorithms](#learning-algorithms)
- [False Positive Reduction](#false-positive-reduction)
- [False Negative Reduction](#false-negative-reduction)
- [Severity Adjustment](#severity-adjustment)
4. [Examples](#examples)
- [API Examples](#api-examples)
- [Dashboard Examples](#dashboard-examples)
- [Learning Examples](#learning-examples)
## User Guide
### Submitting Feedback
When the WAF detects a potential security threat, it may block the request or display a warning. Users with appropriate permissions can provide feedback on these detections to help improve the system's accuracy.
To submit feedback:
1. Navigate to the security event in the admin dashboard
2. Click on the "Provide Feedback" button
3. Select the type of feedback (false positive, false negative, correct detection, or severity adjustment)
4. Add an optional comment explaining your feedback
5. Click "Submit"
Alternatively, you can use the API to submit feedback programmatically (see [API Examples](#api-examples)).
### Types of Feedback
The WAF Feedback System supports four types of feedback:
1. **False Positive**: The WAF incorrectly identified a legitimate request as a security threat. This feedback helps reduce false alarms.
2. **False Negative**: The WAF failed to detect a security threat. This feedback helps improve detection coverage.
3. **Correct Detection**: The WAF correctly identified a security threat. This feedback confirms the accuracy of the detection.
4. **Severity Adjustment**: The WAF correctly identified a security threat, but the severity level was incorrect. This feedback helps calibrate the severity assessment.
### Feedback Dashboard
The Feedback Dashboard provides an overview of all feedback submitted to the WAF system, along with analytics and trends. To access the dashboard:
1. Navigate to Admin > Security > WAF > Feedback
2. Use the filters to view specific types of feedback, categories, or time periods
3. View charts and graphs showing feedback trends and detection accuracy
4. Access detailed reports for specific detection categories
## Technical Documentation
### Architecture
The WAF Feedback System consists of several components that work together to collect, store, analyze, and learn from user feedback:
```
+-------------------+ +-------------------+ +-------------------+
| | | | | |
| Feedback API | --> | Feedback Service | --> | Feedback Storage |
| | | | | |
+-------------------+ +-------------------+ +-------------------+
|
v
+-------------------+ +-------------------+ +-------------------+
| | | | | |
| Learning Service | <-- | Analytics | --> | Reporting |
| | | | | |
+-------------------+ +-------------------+ +-------------------+
|
v
+-------------------+
| |
| ML Engine |
| |
+-------------------+
```
### Components
The WAF Feedback System includes the following components:
1. **Feedback API**: Provides endpoints for submitting and retrieving feedback.
- `POST /api/security/waf/feedback`: Submit feedback
- `GET /api/security/waf/feedback/{detectionId}`: Get feedback for a specific detection
- `GET /api/security/waf/feedback/stats`: Get feedback statistics
- `GET /api/security/waf/feedback/recent`: Get recent feedback
2. **Feedback Service**: Handles the business logic for feedback submission and retrieval.
- `FeedbackService`: Core service for handling feedback
- `DetectionFeedback`: Value object representing feedback
- `FeedbackType`: Enum of feedback types
3. **Feedback Storage**: Stores feedback data for later analysis.
- `FeedbackRepositoryInterface`: Interface for feedback storage
- `DatabaseFeedbackRepository`: Database implementation
4. **Learning Service**: Analyzes feedback and adjusts the WAF models.
- `FeedbackLearningService`: Core service for learning from feedback
- `ModelAdjustment`: Value object representing model adjustments
5. **Analytics**: Analyzes feedback data to identify patterns and trends.
- `FeedbackReportGenerator`: Generates reports from feedback data
6. **Reporting**: Provides visualizations and reports on feedback data.
- `WafFeedbackDashboardController`: Controller for the feedback dashboard
7. **ML Engine**: Machine learning engine that uses feedback to improve detection.
- `MachineLearningEngine`: Core ML engine
- `ThresholdAdjustableInterface`: Interface for adjustable thresholds
- `ConfidenceAdjustableInterface`: Interface for adjustable confidence
- `FeatureWeightAdjustableInterface`: Interface for adjustable feature weights
### Integration
To integrate the WAF Feedback System into your application:
1. **Register Services**: Register the feedback services in your dependency injection container:
```php
// Register feedback services
$container->singleton(FeedbackRepositoryInterface::class, DatabaseFeedbackRepository::class);
$container->singleton(FeedbackService::class, FeedbackService::class);
$container->singleton(FeedbackLearningService::class, FeedbackLearningService::class);
$container->singleton(FeedbackReportGenerator::class, FeedbackReportGenerator::class);
```
2. **Register Controllers**: Register the feedback controllers:
```php
// Register feedback controllers
$container->singleton(WafFeedbackController::class, WafFeedbackController::class);
$container->singleton(WafFeedbackDashboardController::class, WafFeedbackDashboardController::class);
```
3. **Schedule Learning**: Schedule the learning process to run periodically:
```php
// Schedule learning process to run daily
$scheduler->daily('waf:learn-from-feedback');
```
4. **Add UI Components**: Add feedback UI components to your application:
```php
// Add feedback button to WAF detection alerts
$alertComponent->addAction('Provide Feedback', '/admin/security/waf/feedback/submit/{detectionId}');
```
## Learning Algorithms
The WAF Feedback System uses several learning algorithms to improve detection accuracy based on user feedback.
### False Positive Reduction
When users report false positives, the system adjusts the detection models to reduce the likelihood of similar false positives in the future:
1. **Threshold Adjustment**: Increases the detection threshold for the affected category, making it less sensitive.
2. **Confidence Reduction**: Decreases the confidence score for similar detections, making them less likely to trigger alerts.
3. **Feature Weight Adjustment**: Reduces the weights of features that contributed to the false positive.
### False Negative Reduction
When users report false negatives, the system adjusts the detection models to improve detection coverage:
1. **Threshold Adjustment**: Decreases the detection threshold for the affected category, making it more sensitive.
2. **Confidence Increase**: Increases the confidence score for similar detections, making them more likely to trigger alerts.
3. **Feature Weight Adjustment**: Increases the weights of features that should have contributed to detection.
### Severity Adjustment
When users report incorrect severity levels, the system adjusts the severity assessment:
1. **Confidence Adjustment**: Adjusts the confidence score based on the severity change.
2. **Category Default Severity**: Updates the default severity for the detection category.
## Examples
### API Examples
#### Submitting Feedback
```javascript
// Example: Submit false positive feedback
fetch('/api/security/waf/feedback', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({
detection_id: 'abc123',
feedback_type: 'false_positive',
category: 'SQL_INJECTION',
severity: 'HIGH',
comment: 'This is a legitimate query used by our reporting system',
context: {
query: 'SELECT * FROM reports WHERE date > ?'
}
})
})
.then(response => response.json())
.then(data => console.log(data));
```
#### Getting Feedback Statistics
```javascript
// Example: Get feedback statistics
fetch('/api/security/waf/feedback/stats')
.then(response => response.json())
.then(data => {
console.log('Total feedback:', data.stats.total_count);
console.log('False positives:', data.stats.by_feedback_type.false_positive);
console.log('False negatives:', data.stats.by_feedback_type.false_negative);
});
```
### Dashboard Examples
#### Viewing Feedback Trends
The Feedback Dashboard provides visualizations of feedback trends over time:
- **Accuracy Trend**: Shows how detection accuracy has improved over time
- **False Positive Rate**: Shows how the false positive rate has decreased
- **False Negative Rate**: Shows how the false negative rate has decreased
- **Category Breakdown**: Shows feedback distribution by detection category
#### Analyzing Detection Categories
The Category Analysis view shows detailed information about each detection category:
- **Accuracy**: Detection accuracy for the category
- **False Positive Rate**: False positive rate for the category
- **False Negative Rate**: False negative rate for the category
- **Severity Distribution**: Distribution of severity levels for the category
- **Common Patterns**: Common patterns in false positives and false negatives
### Learning Examples
#### Scheduled Learning
The learning process can be scheduled to run periodically:
```bash
# Run learning process daily
php console.php waf:learn-from-feedback
```
#### Manual Learning
The learning process can also be triggered manually:
```bash
# Run learning process with custom parameters
php console.php waf:learn-from-feedback --threshold=10 --learning-rate=0.5
```
#### Learning Results
The learning process provides detailed results:
```
Starting WAF feedback learning process...
Processing 25 false positives, 10 false negatives, 5 severity adjustments
Created 3 model adjustments for SQL_INJECTION, XSS, COMMAND_INJECTION
Applied 3 model adjustments
Learning process completed successfully in 0.5 seconds
```

View File

@@ -0,0 +1,135 @@
# WAF (Web Application Firewall)
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der WAF-Komponente korrekt dar.
## Übersicht
Die WAF-Komponente (Web Application Firewall) ist ein fortschrittliches Sicherheitssystem, das Webanwendungen vor verschiedenen Bedrohungen schützt. Es verwendet Machine Learning und statistische Analysen, um Anomalien zu erkennen und potenzielle Angriffe zu blockieren, bevor sie Schaden anrichten können.
## Hauptkomponenten
### WAF-Klasse
Die zentrale Klasse für die WAF-Funktionalität:
```php
// Klasse initialisieren
$waf = new Waf($config, $eventDispatcher);
// Request prüfen
$result = $waf->analyzeRequest($request);
// Entscheidung treffen
if ($result->isBlocked()) {
// Request blockieren
}
```
### MachineLearningEngine
Verarbeitet Requests mit Machine-Learning-Algorithmen:
- Extrahiert Features aus Requests
- Vergleicht mit bekannten Mustern
- Erkennt Anomalien und ungewöhnliches Verhalten
- Klassifiziert potenzielle Bedrohungen
### Detektoren
Verschiedene Detektoren für unterschiedliche Arten von Anomalien:
- `StatisticalAnomalyDetector`: Erkennt statistische Abweichungen
- `ClusteringAnomalyDetector`: Gruppiert ähnliche Requests und identifiziert Ausreißer
- Erweiterbar für zusätzliche Detektoren
### Middleware-System
```php
// In Bootstrap oder Application-Klasse
$app->addMiddleware(WafMiddleware::class);
```
## Feature-Extraktion
Die WAF extrahiert verschiedene Features aus eingehenden Requests:
1. **Request-Metadaten**: URL, HTTP-Methode, Header
2. **Parameter-Analyse**: Anzahl, Länge, Entropie der Parameter
3. **Inhaltsmuster**: Spezielle Zeichen, Skript-Tags, SQL-Fragmente
4. **Verhaltensanalyse**: Anfragehäufigkeit, Sitzungsdauer, Navigationsmuster
## Anomalie-Erkennung
Der Anomalie-Erkennungsprozess umfasst:
1. **Feature-Extraktion** aus dem eingehenden Request
2. **Baseline-Vergleich** mit normalen Verhaltensmustern
3. **Anomalie-Bewertung** durch verschiedene Detektoren
4. **Entscheidungsfindung** basierend auf Schwellenwerten und Regeln
## Konfiguration
Die WAF kann über die Konfigurationsdatei angepasst werden:
```php
// config/waf.php
return [
'enabled' => true,
'learning_mode' => false,
'threshold' => 0.75,
'detectors' => [
'statistical' => true,
'clustering' => true
],
'whitelist' => [
'ips' => ['127.0.0.1'],
'paths' => ['/api/health']
]
];
```
## Integration
### Service-Container
Die WAF wird automatisch registriert und kann per Dependency Injection verwendet werden:
```php
public function __construct(private readonly Waf $waf) {}
```
### Event-Integration
Die WAF löst folgende Events aus:
- `waf.request_analyzed`: Nach der Analyse eines Requests
- `waf.request_blocked`: Wenn ein Request blockiert wird
- `waf.anomaly_detected`: Bei Erkennung einer Anomalie
## Feedback-System (geplant)
Ein Feedback-System für die WAF ist in Planung und wird folgende Funktionen bieten:
- Admin-Interface zur Überprüfung von WAF-Entscheidungen
- Feedback-Mechanismus für falsch positive/negative Ergebnisse
- Kontinuierliches Training der ML-Modelle basierend auf Feedback
## Fehlerbehebung
### Häufige Probleme
1. **Falsch positive Blockierungen**:
- Überprüfen Sie die Whitelist-Konfiguration
- Passen Sie den Schwellenwert an
- Aktivieren Sie den Lernmodus vorübergehend
2. **Leistungsprobleme**:
- Deaktivieren Sie rechenintensive Detektoren
- Implementieren Sie Caching für wiederholte Anfragen
- Optimieren Sie die Feature-Extraktion
## Weiterführende Informationen
- [Machine Learning Dokumentation](machine-learning.md)
- [WAF-Konfiguration](configuration.md)
- [Sicherheitsrichtlinien](/guides/security.md)

View File

@@ -0,0 +1,252 @@
# WAF Machine Learning
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung der Machine-Learning-Komponente der WAF korrekt dar.
## Übersicht
Die Machine-Learning-Komponente ist das Herzstück des WAF-Systems und ermöglicht die intelligente Erkennung von Bedrohungen und Anomalien in Echtzeit. Sie verwendet fortschrittliche Algorithmen, um normales Verhalten zu lernen und Abweichungen zu identifizieren, die auf potenzielle Angriffe hindeuten könnten.
## MachineLearningEngine
Die `MachineLearningEngine`-Klasse ist die zentrale Komponente des Machine-Learning-Systems:
```php
// Initialisierung
$engine = new MachineLearningEngine(
$enabled,
$extractors,
$detectors,
$clock,
$analysisTimeout,
$confidenceThreshold,
$enableParallelProcessing,
$enableFeatureCaching,
$maxFeaturesPerRequest
);
// Analyse eines Requests
$result = $engine->analyzeRequest($requestData, $context);
```
### Hauptfunktionen
- **Request-Analyse**: Analysiert eingehende Requests auf Anomalien
- **Feature-Extraktion**: Extrahiert relevante Features aus Requests
- **Anomalie-Erkennung**: Identifiziert Abweichungen vom normalen Verhalten
- **Baseline-Management**: Verwaltet und aktualisiert Verhaltensbaselines
- **Modell-Aktualisierung**: Passt Modelle kontinuierlich an neue Daten an
- **Leistungsüberwachung**: Überwacht und optimiert die Leistung des Systems
## Prozessablauf
Der Machine-Learning-Prozess umfasst folgende Schritte:
1. **Feature-Extraktion** (`extractFeatures`):
- Extrahiert relevante Features aus dem Request
- Validiert und normalisiert Features
- Wendet Feature-Caching an, wenn aktiviert
2. **Baseline-Abruf** (`getBaselines`):
- Ruft relevante Baselines für die extrahierten Features ab
- Erstellt neue Baselines, wenn keine existieren
- Verwaltet Baseline-Cache für optimale Leistung
3. **Anomalie-Erkennung** (`detectAnomalies`):
- Wendet verschiedene Detektoren auf die Features an
- Vergleicht Features mit Baselines
- Berechnet Anomalie-Scores und Konfidenzwerte
4. **Konfidenzberechnung** (`calculateOverallConfidence`):
- Aggregiert Ergebnisse verschiedener Detektoren
- Berechnet Gesamtkonfidenz basierend auf gewichteten Scores
- Vergleicht mit Schwellenwert für Entscheidungsfindung
5. **Modell-Aktualisierung** (`updateModels`):
- Aktualisiert Modelle mit neuen Daten
- Passt Baselines an sich ändernde Muster an
- Optimiert Detektoren basierend auf Feedback
## Feature-Extraktion
Die Feature-Extraktion ist ein kritischer Schritt im Machine-Learning-Prozess:
```php
$features = $engine->extractFeatures($requestData, $context);
```
### Feature-Typen
- **Request-Features**: URL-Struktur, Parameter, Header
- **Inhalts-Features**: Payload-Struktur, Entropie, Zeichenverteilung
- **Verhaltens-Features**: Anfragemuster, Sitzungsverhalten, Timing
- **Kontext-Features**: IP-Reputation, Geolocation, Benutzeragent
### Feature-Validierung
Alle extrahierten Features werden validiert, um Qualität und Konsistenz zu gewährleisten:
- Überprüfung auf Vollständigkeit und Gültigkeit
- Normalisierung für konsistente Verarbeitung
- Filterung irrelevanter oder redundanter Features
## Anomalie-Detektoren
Das System verwendet verschiedene Detektoren für unterschiedliche Arten von Anomalien:
### StatisticalAnomalyDetector
Erkennt statistische Abweichungen in numerischen Features:
- Berechnet Z-Scores für numerische Features
- Identifiziert Ausreißer basierend auf statistischen Verteilungen
- Erkennt ungewöhnliche Wertekombinationen
### ClusteringAnomalyDetector
Gruppiert ähnliche Requests und identifiziert Ausreißer:
- Verwendet Clustering-Algorithmen zur Gruppierung ähnlicher Requests
- Berechnet Distanz zu Cluster-Zentren
- Identifiziert isolierte Punkte als potenzielle Anomalien
### Erweiterbarkeit
Das System ist erweiterbar für zusätzliche Detektoren:
```php
// Eigenen Detektor registrieren
$config->registerDetector(new CustomAnomalyDetector());
```
## Baselines
Baselines repräsentieren normales Verhalten und dienen als Referenz für die Anomalie-Erkennung:
### Baseline-Typen
- **Statistische Baselines**: Mittelwerte, Standardabweichungen, Verteilungen
- **Verhaltensbaselines**: Typische Anfragemuster und Sequenzen
- **Inhaltsbaselines**: Normale Payload-Strukturen und Charakteristiken
### Baseline-Management
Baselines werden kontinuierlich aktualisiert und optimiert:
- Automatische Erstellung für neue Feature-Kombinationen
- Regelmäßige Aktualisierung basierend auf neuen Daten
- Gewichtete Historisierung für Stabilität und Aktualität
## Leistungsoptimierung
Die Machine-Learning-Komponente enthält verschiedene Optimierungen:
### Feature-Caching
```php
// Konfiguration
$config->setEnableFeatureCaching(true);
```
Speichert extrahierte Features für ähnliche Requests, um Rechenaufwand zu reduzieren.
### Parallele Verarbeitung
```php
// Konfiguration
$config->setEnableParallelProcessing(true);
```
Verarbeitet Features und Detektoren parallel für verbesserte Leistung.
### Leistungsmetriken
Das System sammelt Leistungsmetriken zur Überwachung und Optimierung:
- Verarbeitungszeiten für verschiedene Phasen
- Feature- und Anomaliezahlen
- Cache-Trefferquoten und Speichernutzung
## Konfiguration
Die Machine-Learning-Komponente bietet umfangreiche Konfigurationsmöglichkeiten:
```php
// config/waf_ml.php
return [
'enabled' => true,
'confidence_threshold' => 0.75,
'analysis_timeout' => 100, // ms
'enable_parallel_processing' => true,
'enable_feature_caching' => true,
'max_features_per_request' => 50,
'detectors' => [
'statistical' => [
'enabled' => true,
'weight' => 0.6
],
'clustering' => [
'enabled' => true,
'weight' => 0.4
]
]
];
```
## Integration mit WAF
Die Machine-Learning-Komponente ist nahtlos in das WAF-System integriert:
```php
// In WAF-Klasse
public function analyzeRequest(Request $request): WafResult
{
$requestData = $this->analyzer->analyze($request);
$mlResult = $this->mlEngine->analyzeRequest($requestData, $this->context);
return new WafResult($requestData, $mlResult);
}
```
## Fehlerbehebung
### Häufige Probleme
1. **Hohe Falsch-Positiv-Rate**:
- Erhöhen Sie den Konfidenz-Schwellenwert
- Aktivieren Sie den Lernmodus für einen längeren Zeitraum
- Überprüfen Sie die Gewichtung der Detektoren
2. **Leistungsprobleme**:
- Aktivieren Sie Feature-Caching
- Reduzieren Sie die maximale Anzahl von Features pro Request
- Optimieren Sie die Detektorkonfiguration
3. **Fehlende Erkennung**:
- Senken Sie den Konfidenz-Schwellenwert
- Aktivieren Sie zusätzliche Detektoren
- Überprüfen Sie die Feature-Extraktion
## Weiterentwicklung
### Geplante Erweiterungen
1. **Feedback-System**:
- Integration von Administratorfeedback
- Automatische Anpassung basierend auf Feedback
- Kontinuierliches Lernen aus Fehlklassifikationen
2. **Erweiterte Detektoren**:
- Deep-Learning-basierte Anomalieerkennung
- Sequenzanalyse für komplexe Angriffsmuster
- Verhaltensbasierte Benutzerprofilierung
3. **Verbesserte Visualisierung**:
- Dashboard für Anomalietrends
- Feature-Wichtigkeitsanalyse
- Echtzeit-Monitoring von Bedrohungen
## Weiterführende Informationen
- [WAF-Übersicht](index.md)
- [WAF-Konfiguration](configuration.md)
- [Sicherheitsrichtlinien](/guides/security.md)

View File

@@ -0,0 +1,598 @@
# Coding Standards
Diese Dokumentation beschreibt die Coding Standards, die bei der Entwicklung des Frameworks eingehalten werden sollten. Die Einhaltung dieser Standards gewährleistet einen konsistenten Codestil im gesamten Projekt und erleichtert die Zusammenarbeit zwischen Entwicklern.
## PHP-Standards
### PSR-Standards
Das Framework folgt den [PHP Standards Recommendations (PSR)](https://www.php-fig.org/psr/) des PHP Framework Interop Group (PHP-FIG):
- [PSR-1: Basic Coding Standard](https://www.php-fig.org/psr/psr-1/)
- [PSR-2: Coding Style Guide](https://www.php-fig.org/psr/psr-2/) und [PSR-12: Extended Coding Style](https://www.php-fig.org/psr/psr-12/) (ersetzt PSR-2)
- [PSR-4: Autoloading Standard](https://www.php-fig.org/psr/psr-4/)
### Allgemeine Richtlinien
#### Dateien
- Dateien MÜSSEN die UTF-8-Kodierung ohne BOM verwenden.
- Dateien SOLLTEN entweder Deklarationen (Klassen, Funktionen, Konstanten) ODER Nebeneffekte (z.B. Ausgaben, Änderungen an .ini-Einstellungen) enthalten, aber NICHT beides.
- Dateinamen MÜSSEN `PascalCase` für Klassen verwenden (z.B. `UserController.php`).
- Alle PHP-Dateien MÜSSEN mit einer einzelnen leeren Zeile enden.
#### PHP-Tags
- PHP-Code MUSS die langen Tags `<?php ?>` oder die kurzen Echo-Tags `<?= ?>` verwenden.
- Die schließenden Tags `?>` SOLLTEN bei Dateien, die nur PHP enthalten, weggelassen werden.
#### Zeichenkodierung und Zeilenumbrüche
- Der Code MUSS UTF-8 ohne BOM verwenden.
- Zeilenumbrüche MÜSSEN im Unix-Format (LF) sein.
### Namenskonventionen
#### Namespaces
- Namespaces MÜSSEN `PascalCase` verwenden.
- Der Basis-Namespace für das Framework ist `App\Framework`.
- Der Basis-Namespace für anwendungsspezifischen Code ist `App\Application`.
```php
namespace App\Framework\Http;
namespace App\Application\Controllers;
```
#### Klassen
- Klassennamen MÜSSEN `PascalCase` verwenden.
- Schnittstellen MÜSSEN mit dem Suffix `Interface` enden.
- Abstrakte Klassen SOLLTEN mit dem Präfix `Abstract` beginnen.
- Traits SOLLTEN mit dem Suffix `Trait` enden.
```php
class UserController
interface RepositoryInterface
abstract class AbstractController
trait LoggableTrait
```
#### Methoden und Funktionen
- Methoden- und Funktionsnamen MÜSSEN `camelCase` verwenden.
- Methoden SOLLTEN Verben sein, die ihre Aktion beschreiben.
```php
public function getUserById(int $id): ?User
public function createUser(array $data): User
public function updateUserProfile(User $user, array $data): bool
```
#### Eigenschaften und Variablen
- Eigenschaften und Variablen MÜSSEN `camelCase` verwenden.
- Private und geschützte Eigenschaften SOLLTEN NICHT mit einem Unterstrich beginnen.
```php
private string $firstName;
protected int $itemCount;
public bool $isActive;
```
#### Konstanten
- Klassenkonstanten MÜSSEN in `UPPER_CASE` mit Unterstrichen als Trennzeichen definiert werden.
```php
public const MAX_ATTEMPTS = 5;
private const DEFAULT_TIMEOUT = 30;
```
#### Enums
- Enum-Namen MÜSSEN `PascalCase` verwenden.
- Enum-Werte MÜSSEN `UPPER_CASE` mit Unterstrichen als Trennzeichen verwenden.
```php
enum HttpMethod
{
case GET;
case POST;
case PUT;
case DELETE;
}
enum LogLevel: string
{
case DEBUG = 'debug';
case INFO = 'info';
case WARNING = 'warning';
case ERROR = 'error';
}
```
### Codestruktur
#### Klassen
- Jede Klasse MUSS in einer eigenen Datei definiert werden.
- Die Struktur einer Klasse SOLLTE wie folgt sein:
1. Namespace-Deklaration
2. Verwendete Imports (alphabetisch sortiert)
3. Klassendokumentation (PHPDoc)
4. Klassendeklaration
5. Konstanten (öffentlich, geschützt, privat)
6. Eigenschaften (öffentlich, geschützt, privat)
7. Konstruktor und Destruktor
8. Öffentliche Methoden
9. Geschützte Methoden
10. Private Methoden
```php
<?php
namespace App\Framework\Database;
use App\Framework\Contracts\ConnectionInterface;
use App\Framework\Exceptions\DatabaseException;
/**
* Database connection manager.
*/
class Connection implements ConnectionInterface
{
/**
* Default connection timeout in seconds.
*/
public const DEFAULT_TIMEOUT = 30;
/**
* The active PDO connection.
*/
private ?\PDO $pdo = null;
/**
* The database configuration.
*/
private array $config;
/**
* Create a new database connection instance.
*/
public function __construct(array $config)
{
$this->config = $config;
}
/**
* Get the PDO connection.
*/
public function getPdo(): \PDO
{
if ($this->pdo === null) {
$this->connect();
}
return $this->pdo;
}
/**
* Establish a database connection.
*/
protected function connect(): void
{
// Implementation...
}
/**
* Build the DSN string.
*/
private function buildDsn(): string
{
// Implementation...
}
}
```
#### Methoden
- Methoden SOLLTEN eine einzige Verantwortung haben (Single Responsibility Principle).
- Methoden SOLLTEN kurz sein und eine Sache gut machen.
- Methoden SOLLTEN früh zurückkehren, um die Verschachtelungstiefe zu reduzieren.
```php
// Gut
public function getUserById(int $id): ?User
{
if ($id <= 0) {
return null;
}
return $this->userRepository->find($id);
}
// Schlecht
public function getUserById(int $id): ?User
{
if ($id > 0) {
$user = $this->userRepository->find($id);
if ($user !== null) {
return $user;
} else {
return null;
}
} else {
return null;
}
}
```
### Typisierung
- Der Code MUSS strikte Typisierung verwenden.
- Jede Datei SOLLTE mit `declare(strict_types=1);` beginnen.
- Methoden und Funktionen MÜSSEN Typdeklarationen für Parameter und Rückgabewerte verwenden.
- Eigenschaften MÜSSEN Typdeklarationen verwenden.
```php
<?php
declare(strict_types=1);
namespace App\Framework\Http;
class Request
{
private array $query;
private array $request;
public function __construct(array $query, array $request)
{
$this->query = $query;
$this->request = $request;
}
public function query(string $key, mixed $default = null): mixed
{
return $this->query[$key] ?? $default;
}
public function input(string $key, mixed $default = null): mixed
{
return $this->request[$key] ?? $default;
}
public function has(string $key): bool
{
return isset($this->request[$key]);
}
}
```
### Dokumentation
- Alle Klassen, Methoden, Eigenschaften und Konstanten MÜSSEN mit PHPDoc-Kommentaren dokumentiert werden.
- PHPDoc-Kommentare MÜSSEN eine Beschreibung und alle relevanten Tags enthalten.
- Komplexe Codeabschnitte SOLLTEN mit Inline-Kommentaren erklärt werden.
```php
/**
* Represents an HTTP request.
*/
class Request
{
/**
* The query parameters.
*
* @var array<string, mixed>
*/
private array $query;
/**
* Get a query parameter.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter does not exist
*
* @return mixed The parameter value or the default value
*/
public function query(string $key, mixed $default = null): mixed
{
return $this->query[$key] ?? $default;
}
}
```
### Fehlerbehandlung
- Exceptions SOLLTEN für außergewöhnliche Bedingungen verwendet werden.
- Benutzerdefinierte Exceptions SOLLTEN von einer Basis-Exception-Klasse erben.
- Exception-Nachrichten SOLLTEN klar und informativ sein.
```php
// Definieren einer benutzerdefinierten Exception
class DatabaseException extends \RuntimeException
{
// ...
}
// Werfen einer Exception
if (!$this->isConnected()) {
throw new DatabaseException('Database connection failed: ' . $this->getLastError());
}
// Fangen einer Exception
try {
$user = $this->userRepository->find($id);
} catch (DatabaseException $e) {
$this->logger->error('Database error: ' . $e->getMessage());
throw new ServiceException('Could not retrieve user data', 0, $e);
}
```
## JavaScript-Standards
### Allgemeine Richtlinien
- JavaScript-Code SOLLTE [ESLint](https://eslint.org/) mit der Konfiguration des Projekts verwenden.
- ES6+ Features SOLLTEN verwendet werden.
- Semicolons MÜSSEN verwendet werden.
### Namenskonventionen
- Variablen und Funktionen MÜSSEN `camelCase` verwenden.
- Klassen MÜSSEN `PascalCase` verwenden.
- Konstanten MÜSSEN `UPPER_CASE` mit Unterstrichen als Trennzeichen verwenden.
- Private Eigenschaften und Methoden SOLLTEN mit einem Unterstrich beginnen.
```javascript
// Variablen
const maxItems = 10;
let currentIndex = 0;
// Konstanten
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// Funktionen
function getUserData(userId) {
// ...
}
// Klassen
class UserService {
constructor(apiClient) {
this._apiClient = apiClient;
}
async getUser(id) {
return this._apiClient.get(`/users/${id}`);
}
_handleError(error) {
console.error('API error:', error);
}
}
```
### Codestruktur
- Jede Datei SOLLTE einen einzelnen Export haben.
- Imports SOLLTEN am Anfang der Datei stehen und nach Typ gruppiert werden.
- Funktionen SOLLTEN kurz sein und eine Sache gut machen.
```javascript
// Imports
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
// Eigene Imports
import { UserService } from '../services/UserService';
import { ErrorBoundary } from '../components/ErrorBoundary';
// Komponente
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const userService = new UserService();
const userData = await userService.getUser(userId);
setUser(userData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
UserProfile.propTypes = {
userId: PropTypes.string.isRequired
};
export default UserProfile;
```
## CSS-Standards
### Allgemeine Richtlinien
- CSS-Code SOLLTE [Stylelint](https://stylelint.io/) mit der Konfiguration des Projekts verwenden.
- CSS-Präprozessoren wie SASS oder LESS KÖNNEN verwendet werden.
- CSS-Klassen SOLLTEN nach dem BEM-Muster (Block, Element, Modifier) benannt werden.
### Namenskonventionen
- CSS-Klassen MÜSSEN `kebab-case` verwenden.
- BEM-Notation: `.block__element--modifier`
```css
/* Block */
.user-card {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 16px;
}
/* Element */
.user-card__avatar {
border-radius: 50%;
height: 64px;
width: 64px;
}
/* Element */
.user-card__name {
font-size: 18px;
font-weight: bold;
margin-top: 8px;
}
/* Modifier */
.user-card--premium {
background-color: #f8f8f8;
border: 1px solid #ddd;
}
```
### Codestruktur
- CSS-Regeln SOLLTEN nach Komponenten organisiert werden.
- Medienabfragen SOLLTEN am Ende jeder Komponente stehen.
- Vendor-Präfixe SOLLTEN automatisch mit Tools wie Autoprefixer hinzugefügt werden.
```css
/* Komponente */
.button {
background-color: #007bff;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
font-size: 16px;
padding: 8px 16px;
transition: background-color 0.2s;
}
.button:hover {
background-color: #0069d9;
}
.button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
.button--secondary {
background-color: #6c757d;
}
.button--secondary:hover {
background-color: #5a6268;
}
/* Medienabfragen */
@media (max-width: 768px) {
.button {
font-size: 14px;
padding: 6px 12px;
}
}
```
## Tools und Automatisierung
### Code-Linting
Das Projekt verwendet verschiedene Linting-Tools, um die Einhaltung der Coding Standards zu gewährleisten:
- [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) für PHP
- [ESLint](https://eslint.org/) für JavaScript
- [Stylelint](https://stylelint.io/) für CSS
### Automatische Formatierung
Das Projekt unterstützt automatische Codeformatierung mit:
- [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) für PHP
- [Prettier](https://prettier.io/) für JavaScript und CSS
### Verwendung der Tools
#### PHP_CodeSniffer
```bash
# Überprüfen des Codes
vendor/bin/phpcs src tests
# Automatisches Beheben von Problemen
vendor/bin/phpcbf src tests
```
#### PHP-CS-Fixer
```bash
# Überprüfen des Codes
vendor/bin/php-cs-fixer fix --dry-run --diff src
# Automatisches Beheben von Problemen
vendor/bin/php-cs-fixer fix src
```
#### ESLint
```bash
# Überprüfen des Codes
npm run lint:js
# Automatisches Beheben von Problemen
npm run lint:js:fix
```
#### Stylelint
```bash
# Überprüfen des Codes
npm run lint:css
# Automatisches Beheben von Problemen
npm run lint:css:fix
```
#### Prettier
```bash
# Formatieren von JavaScript und CSS
npm run format
```
## Weitere Informationen
- [Pull Request-Anleitung](pull-requests.md): Erfahren Sie, wie Sie Pull Requests erstellen und überprüfen.
- [Dokumentations-Anleitung](documentation.md): Erfahren Sie, wie Sie zur Dokumentation beitragen können.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

View File

@@ -0,0 +1,345 @@
# Dokumentations-Anleitung
Diese Anleitung beschreibt, wie Sie zur Dokumentation des Frameworks beitragen können. Eine gute Dokumentation ist entscheidend für die Benutzerfreundlichkeit und Wartbarkeit des Frameworks.
## Überblick über die Dokumentationsstruktur
Die Dokumentation des Frameworks ist in mehrere Bereiche unterteilt:
```
docs/
├── README.md # Übersicht und Navigationshilfe
├── getting-started/ # Einstiegsdokumentation
│ ├── installation.md # Installationsanleitung
│ ├── configuration.md # Konfigurationsanleitung
│ └── first-steps.md # Erste Schritte mit dem Framework
├── architecture/ # Architektur-Dokumentation
│ ├── overview.md # Architekturübersicht
│ ├── components.md # Hauptkomponenten
│ └── patterns.md # Verwendete Entwurfsmuster
├── components/ # Komponentendokumentation
│ ├── analytics/ # Analytics-Komponente
│ │ ├── index.md # Übersicht
│ │ ├── configuration.md # Konfiguration
│ │ └── examples.md # Beispiele
│ ├── validation/ # Validierungs-Komponente
│ │ ├── index.md # Übersicht
│ │ ├── rules.md # Validierungsregeln
│ │ └── examples.md # Beispiele
│ ├── security/ # Sicherheits-Komponente
│ │ ├── index.md # Übersicht
│ │ ├── csrf-protection.md # CSRF-Schutz im Detail
│ │ ├── security-headers.md # Security Headers und CSP
│ │ └── request-signing.md # Request Signing API
│ ├── waf/ # WAF-Komponente
│ │ ├── index.md # Übersicht
│ │ ├── machine-learning.md # ML-Funktionalität
│ │ └── configuration.md # Konfiguration
│ └── ... # Weitere Komponenten
├── guides/ # Entwickleranleitungen
│ ├── routing.md # Routing-Anleitung
│ ├── controllers.md # Controller-Anleitung
│ ├── validation.md # Validierungs-Anleitung
│ ├── security.md # Sicherheits-Anleitung
│ └── ... # Weitere Anleitungen
├── api/ # API-Dokumentation
│ ├── index.md # API-Übersicht
│ └── ... # Generierte API-Docs
├── contributing/ # Beitragsrichtlinien
│ ├── code-style.md # Coding-Standards
│ ├── pull-requests.md # PR-Prozess
│ └── documentation.md # Dokumentationsrichtlinien
└── roadmap/ # Projektplanung
├── features.md # Feature-Tracking
├── tasks.md # Task-Tracking
└── milestones.md # Meilensteine
```
## Dokumentationsstandards
### Markdown-Format
Die gesamte Dokumentation wird in Markdown geschrieben. Hier sind die grundlegenden Formatierungsregeln:
#### Überschriften
Verwenden Sie `#` für Überschriften, mit einer Hierarchie von `#` (Hauptüberschrift) bis `######` (Überschrift der sechsten Ebene):
```markdown
# Hauptüberschrift (H1)
## Überschrift der zweiten Ebene (H2)
### Überschrift der dritten Ebene (H3)
#### Überschrift der vierten Ebene (H4)
##### Überschrift der fünften Ebene (H5)
###### Überschrift der sechsten Ebene (H6)
```
#### Textformatierung
```markdown
*Kursiver Text* oder _Kursiver Text_
**Fetter Text** oder __Fetter Text__
***Fett und kursiv*** oder ___Fett und kursiv___
~~Durchgestrichen~~
```
#### Listen
Ungeordnete Listen:
```markdown
- Element 1
- Element 2
- Unterelement 2.1
- Unterelement 2.2
- Element 3
```
Geordnete Listen:
```markdown
1. Erster Schritt
2. Zweiter Schritt
1. Unterschritt 2.1
2. Unterschritt 2.2
3. Dritter Schritt
```
#### Links
```markdown
[Link-Text](URL)
[Link zu einer anderen Dokumentationsseite](../pfad/zur/datei.md)
[Link zu einem Abschnitt in derselben Datei](#abschnitt-id)
```
#### Bilder
```markdown
![Alternativer Text](URL-zum-Bild)
```
#### Codeblöcke
Für Inline-Code:
```markdown
`Inline-Code`
```
Für Codeblöcke:
````markdown
```php
// PHP-Code hier
$variable = 'Wert';
echo $variable;
```
````
Unterstützte Sprachen für Syntax-Highlighting:
- `php` für PHP-Code
- `js` oder `javascript` für JavaScript-Code
- `html` für HTML-Code
- `css` für CSS-Code
- `bash` oder `shell` für Shell-Befehle
- `json` für JSON-Daten
- `xml` für XML-Daten
- `sql` für SQL-Abfragen
#### Tabellen
```markdown
| Spalte 1 | Spalte 2 | Spalte 3 |
|----------|----------|----------|
| Zelle 1 | Zelle 2 | Zelle 3 |
| Zelle 4 | Zelle 5 | Zelle 6 |
```
#### Blockzitate
```markdown
> Dies ist ein Blockzitat.
> Es kann mehrere Zeilen umfassen.
```
#### Horizontale Linien
```markdown
---
```
### Dokumentationsstruktur
Jede Dokumentationsdatei sollte die folgende Struktur haben:
1. **Hauptüberschrift**: Der Titel des Dokuments als H1-Überschrift (`#`).
2. **Einführung**: Eine kurze Einführung, die den Zweck und Umfang des Dokuments beschreibt.
3. **Hauptinhalt**: Der Hauptinhalt des Dokuments, organisiert in Abschnitte mit H2-Überschriften (`##`).
4. **Beispiele**: Praktische Beispiele, die die Verwendung der beschriebenen Funktionalität demonstrieren.
5. **Weitere Informationen**: Links zu verwandten Dokumenten oder externen Ressourcen.
### Schreibstil
- Verwenden Sie eine klare, präzise und konsistente Sprache.
- Schreiben Sie in der zweiten Person ("Sie können..." statt "Man kann...").
- Verwenden Sie die aktive Stimme statt der passiven Stimme.
- Halten Sie Sätze und Absätze kurz und fokussiert.
- Verwenden Sie Aufzählungslisten für Schritte oder Optionen.
- Erklären Sie Fachbegriffe, wenn sie zum ersten Mal verwendet werden.
- Vermeiden Sie Jargon und Abkürzungen, es sei denn, sie sind allgemein bekannt oder wurden erklärt.
### Beispiele
Gute Beispiele sind ein wesentlicher Bestandteil der Dokumentation. Jedes Beispiel sollte:
- Realistisch und praxisnah sein
- Vollständig und funktionsfähig sein
- Gut kommentiert sein, um zu erklären, was passiert
- Die empfohlenen Praktiken und Coding-Standards befolgen
## Beitragen zur Dokumentation
### Neue Dokumentation erstellen
Wenn Sie neue Dokumentation erstellen möchten:
1. Identifizieren Sie den Bereich, in dem die Dokumentation benötigt wird.
2. Erstellen Sie eine neue Markdown-Datei im entsprechenden Verzeichnis.
3. Folgen Sie der oben beschriebenen Dokumentationsstruktur.
4. Fügen Sie die neue Datei in die Navigation ein, indem Sie Links in verwandten Dokumenten hinzufügen.
### Bestehende Dokumentation aktualisieren
Wenn Sie bestehende Dokumentation aktualisieren möchten:
1. Identifizieren Sie die zu aktualisierende Datei.
2. Nehmen Sie die erforderlichen Änderungen vor, wobei Sie die Dokumentationsstandards einhalten.
3. Aktualisieren Sie alle Links oder Verweise, die durch Ihre Änderungen betroffen sein könnten.
### Pull Request-Prozess für Dokumentation
Der Prozess für das Einreichen von Dokumentationsänderungen ist derselbe wie für Code-Änderungen:
1. Erstellen Sie einen Feature-Branch für Ihre Änderungen.
2. Nehmen Sie die Änderungen vor.
3. Reichen Sie einen Pull Request ein.
4. Reagieren Sie auf Feedback und nehmen Sie bei Bedarf weitere Änderungen vor.
Weitere Informationen finden Sie in der [Pull Request-Anleitung](pull-requests.md).
## Dokumentation generieren
### API-Dokumentation
Die API-Dokumentation wird automatisch aus dem Quellcode generiert. Um die API-Dokumentation zu generieren:
```bash
php console.php docs:generate-api
```
Dies generiert die API-Dokumentation im Verzeichnis `docs/api/`.
### Dokumentation lokal anzeigen
Um die Dokumentation lokal anzuzeigen, können Sie einen Markdown-Viewer oder einen lokalen Webserver verwenden:
```bash
# Mit PHP-Webserver
php -S localhost:8000 -t docs
# Mit Node.js und docsify
npm install -g docsify-cli
docsify serve docs
```
## Dokumentations-Checkliste
Verwenden Sie diese Checkliste, um sicherzustellen, dass Ihre Dokumentation vollständig und von hoher Qualität ist:
- [ ] Die Dokumentation folgt der standardisierten Struktur.
- [ ] Die Hauptüberschrift beschreibt klar den Inhalt des Dokuments.
- [ ] Die Einführung erklärt den Zweck und Umfang des Dokuments.
- [ ] Alle Fachbegriffe werden erklärt oder verlinkt.
- [ ] Die Dokumentation enthält praktische Beispiele.
- [ ] Die Beispiele sind vollständig, funktionsfähig und gut kommentiert.
- [ ] Die Dokumentation enthält Links zu verwandten Dokumenten.
- [ ] Die Dokumentation ist frei von Rechtschreib- und Grammatikfehlern.
- [ ] Die Formatierung ist konsistent und folgt den Markdown-Standards.
- [ ] Die Dokumentation ist aktuell und spiegelt den aktuellen Stand des Codes wider.
## Tipps für gute Dokumentation
### Benutzerorientierung
Denken Sie immer an die Benutzer Ihrer Dokumentation:
- Wer sind sie? (Anfänger, erfahrene Entwickler, Mitwirkende)
- Was wollen sie erreichen?
- Welche Vorkenntnisse haben sie?
Passen Sie Ihre Dokumentation entsprechend an.
### Klare Struktur
Eine klare Struktur hilft den Benutzern, die benötigten Informationen schnell zu finden:
- Verwenden Sie aussagekräftige Überschriften.
- Gruppieren Sie verwandte Informationen.
- Verwenden Sie Aufzählungslisten und Tabellen, um Informationen zu organisieren.
- Fügen Sie ein Inhaltsverzeichnis für längere Dokumente hinzu.
### Visuelle Elemente
Visuelle Elemente können die Dokumentation verbessern:
- Verwenden Sie Diagramme, um komplexe Beziehungen zu erklären.
- Fügen Sie Screenshots hinzu, um Benutzeroberflächen zu zeigen.
- Verwenden Sie Codebeispiele, um Konzepte zu demonstrieren.
### Kontinuierliche Verbesserung
Dokumentation ist nie "fertig":
- Überprüfen Sie regelmäßig die Dokumentation auf Aktualität.
- Berücksichtigen Sie Feedback von Benutzern.
- Aktualisieren Sie die Dokumentation, wenn sich der Code ändert.
## Häufige Probleme und Lösungen
### Veraltete Dokumentation
Problem: Die Dokumentation spiegelt nicht den aktuellen Stand des Codes wider.
Lösung:
- Überprüfen Sie die Dokumentation regelmäßig.
- Aktualisieren Sie die Dokumentation als Teil des Entwicklungsprozesses.
- Verwenden Sie automatisierte Tools, um Inkonsistenzen zu erkennen.
### Unvollständige Dokumentation
Problem: Die Dokumentation deckt nicht alle Aspekte der Funktionalität ab.
Lösung:
- Identifizieren Sie fehlende Bereiche durch Benutzerfeedback.
- Erstellen Sie eine Checkliste der zu dokumentierenden Funktionen.
- Priorisieren Sie die Dokumentation basierend auf der Benutzerrelevanz.
### Unklare Dokumentation
Problem: Die Dokumentation ist schwer zu verstehen oder zu technisch.
Lösung:
- Verwenden Sie einfache, klare Sprache.
- Erklären Sie Fachbegriffe.
- Fügen Sie Beispiele hinzu, um Konzepte zu verdeutlichen.
- Lassen Sie die Dokumentation von jemandem überprüfen, der mit dem Thema nicht vertraut ist.
## Weitere Informationen
- [Markdown-Anleitung](https://www.markdownguide.org/): Eine umfassende Anleitung zu Markdown.
- [Technisches Schreiben](https://developers.google.com/tech-writing): Google's Anleitung zum technischen Schreiben.
- [Dokumentationstools](https://docusaurus.io/): Tools für die Erstellung und Verwaltung von Dokumentation.
- [Coding Standards](code-style.md): Erfahren Sie mehr über die Coding Standards des Projekts.
- [Pull Request-Anleitung](pull-requests.md): Erfahren Sie, wie Sie Pull Requests erstellen und überprüfen.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

View File

@@ -0,0 +1,334 @@
# Pull Request-Anleitung
Diese Anleitung beschreibt den Prozess für das Erstellen, Überprüfen und Zusammenführen von Pull Requests im Framework-Projekt. Die Einhaltung dieser Richtlinien gewährleistet einen reibungslosen Entwicklungsprozess und eine hohe Codequalität.
## Überblick über den Pull Request-Prozess
Der Pull Request-Prozess besteht aus den folgenden Schritten:
1. **Vorbereitung**: Erstellen eines Issues und eines Feature-Branches
2. **Entwicklung**: Implementieren der Änderungen und Schreiben von Tests
3. **Einreichen**: Erstellen eines Pull Requests
4. **Überprüfung**: Code-Review und Diskussion
5. **Anpassung**: Vornehmen von Änderungen basierend auf dem Feedback
6. **Zusammenführen**: Zusammenführen des Pull Requests in den Hauptbranch
## 1. Vorbereitung
### Issues erstellen
Bevor Sie mit der Arbeit an einer neuen Funktion oder Fehlerbehebung beginnen, sollten Sie sicherstellen, dass ein entsprechendes Issue existiert:
1. Überprüfen Sie die bestehenden Issues, um Duplikate zu vermeiden.
2. Wenn kein passendes Issue existiert, erstellen Sie ein neues Issue mit einer klaren Beschreibung des Problems oder der Funktion.
3. Warten Sie auf Feedback vom Kernteam, um sicherzustellen, dass Ihre geplante Änderung mit der Projektrichtung übereinstimmt.
### Feature-Branch erstellen
Sobald Sie ein Issue haben, an dem Sie arbeiten möchten, erstellen Sie einen Feature-Branch:
```bash
# Aktualisieren Sie Ihren lokalen main-Branch
git checkout main
git pull origin main
# Erstellen Sie einen Feature-Branch
git checkout -b feature/issue-123-kurze-beschreibung
```
Verwenden Sie eine konsistente Benennungskonvention für Branches:
- `feature/issue-XXX-kurze-beschreibung` für neue Funktionen
- `bugfix/issue-XXX-kurze-beschreibung` für Fehlerbehebungen
- `refactor/issue-XXX-kurze-beschreibung` für Refactoring
- `docs/issue-XXX-kurze-beschreibung` für Dokumentationsänderungen
## 2. Entwicklung
### Coding Standards
Stellen Sie sicher, dass Ihr Code den [Coding Standards](code-style.md) des Projekts entspricht. Verwenden Sie die bereitgestellten Linting-Tools, um die Einhaltung der Standards zu überprüfen:
```bash
# PHP-Code überprüfen
vendor/bin/phpcs src tests
# JavaScript-Code überprüfen
npm run lint:js
# CSS-Code überprüfen
npm run lint:css
```
### Tests schreiben
Für jede Änderung sollten entsprechende Tests geschrieben werden:
- **Unit-Tests** für einzelne Klassen und Methoden
- **Integrationstests** für die Interaktion zwischen Komponenten
- **Funktionstests** für die Überprüfung von Benutzerszenarien
```bash
# Tests ausführen
vendor/bin/phpunit
# Spezifische Testdatei ausführen
vendor/bin/phpunit tests/Unit/Framework/Http/RequestTest.php
# Tests mit Code-Coverage-Bericht ausführen
vendor/bin/phpunit --coverage-html coverage
```
### Commit-Richtlinien
Schreiben Sie klare und aussagekräftige Commit-Nachrichten, die den Zweck des Commits beschreiben:
```
feat(component): Kurze Beschreibung der Änderung
Längere Beschreibung mit Details zur Änderung, Motivation und Kontext.
Mehrere Zeilen sind erlaubt.
Fixes #123
```
Verwenden Sie die folgenden Präfixe für Ihre Commit-Nachrichten:
- `feat`: Neue Funktion
- `fix`: Fehlerbehebung
- `docs`: Dokumentationsänderungen
- `style`: Formatierung, fehlende Semikolons usw. (keine Codeänderungen)
- `refactor`: Code-Refactoring
- `test`: Hinzufügen oder Korrigieren von Tests
- `chore`: Änderungen an Build-Prozessen oder Hilfswerkzeugen
### Regelmäßiges Pushen
Pushen Sie Ihre Änderungen regelmäßig in Ihren Remote-Branch:
```bash
git push origin feature/issue-123-kurze-beschreibung
```
## 3. Einreichen
### Vorbereitung für den Pull Request
Bevor Sie einen Pull Request erstellen, stellen Sie sicher, dass:
1. Alle Tests erfolgreich durchlaufen werden.
2. Der Code den Coding Standards entspricht.
3. Die Dokumentation aktualisiert wurde (falls erforderlich).
4. Der Branch auf dem neuesten Stand mit dem Hauptbranch ist.
```bash
# Aktualisieren Sie Ihren Branch mit dem neuesten Stand des Hauptbranches
git checkout main
git pull origin main
git checkout feature/issue-123-kurze-beschreibung
git merge main
git push origin feature/issue-123-kurze-beschreibung
```
### Pull Request erstellen
Erstellen Sie einen Pull Request über die GitHub-Oberfläche:
1. Navigieren Sie zu Ihrem Branch auf GitHub.
2. Klicken Sie auf "Compare & pull request".
3. Füllen Sie die Pull Request-Vorlage aus:
- Titel: Kurze Beschreibung der Änderung (max. 72 Zeichen)
- Beschreibung: Detaillierte Beschreibung der Änderung, Motivation und Kontext
- Referenzieren Sie das zugehörige Issue mit "Fixes #123" oder "Relates to #123"
4. Klicken Sie auf "Create pull request".
### Pull Request-Vorlage
```markdown
## Beschreibung
[Beschreiben Sie hier Ihre Änderungen und den Kontext]
## Motivation und Kontext
[Warum ist diese Änderung erforderlich? Welches Problem löst sie?]
## Art der Änderung
- [ ] Fehlerbehebung (nicht-breaking change, behebt ein Problem)
- [ ] Neue Funktion (nicht-breaking change, fügt Funktionalität hinzu)
- [ ] Breaking change (Fehlerbehebung oder Funktion, die zu Inkompatibilitäten führt)
- [ ] Diese Änderung erfordert eine Dokumentationsaktualisierung
## Wie wurde getestet?
[Beschreiben Sie die Tests, die Sie durchgeführt haben, um Ihre Änderungen zu überprüfen]
## Checkliste:
- [ ] Mein Code folgt dem Codestil dieses Projekts
- [ ] Ich habe Selbstüberprüfung meines Codes durchgeführt
- [ ] Ich habe Kommentare zu meinem Code hinzugefügt, insbesondere in schwer verständlichen Bereichen
- [ ] Ich habe entsprechende Änderungen an der Dokumentation vorgenommen
- [ ] Meine Änderungen erzeugen keine neuen Warnungen
- [ ] Ich habe Tests hinzugefügt, die meine Änderungen beweisen
- [ ] Neue und bestehende Unit-Tests bestehen lokal mit meinen Änderungen
- [ ] Alle abhängigen Änderungen wurden zusammengeführt und veröffentlicht
## Zugehörige Issues
[Verlinken Sie hier zugehörige Issues, z.B. "Fixes #123"]
```
## 4. Überprüfung
### Code-Review-Prozess
Nach dem Erstellen eines Pull Requests wird er von mindestens einem Mitglied des Kernteams überprüft. Der Reviewer wird:
1. Den Code auf Einhaltung der Coding Standards überprüfen.
2. Die Funktionalität und Korrektheit der Änderungen bewerten.
3. Die Testabdeckung überprüfen.
4. Feedback und Verbesserungsvorschläge geben.
### Automatisierte Checks
Jeder Pull Request durchläuft automatisierte Checks:
- **CI-Pipeline**: Führt Tests und Linting-Checks aus
- **Code-Coverage**: Überprüft die Testabdeckung
- **Dependency-Scanning**: Überprüft auf Sicherheitsprobleme in Abhängigkeiten
Alle automatisierten Checks müssen erfolgreich sein, bevor ein Pull Request zusammengeführt werden kann.
### Feedback erhalten und geben
Beim Geben und Erhalten von Feedback:
- Seien Sie respektvoll und konstruktiv.
- Konzentrieren Sie sich auf den Code, nicht auf die Person.
- Erklären Sie Ihre Gedanken und geben Sie Beispiele.
- Stellen Sie Fragen, anstatt Annahmen zu treffen.
## 5. Anpassung
### Änderungen vornehmen
Basierend auf dem Feedback aus dem Code-Review können Sie Änderungen an Ihrem Branch vornehmen:
```bash
# Änderungen vornehmen
git add .
git commit -m "fix: Adressieren von Feedback aus dem Code-Review"
git push origin feature/issue-123-kurze-beschreibung
```
Die neuen Commits werden automatisch zum Pull Request hinzugefügt.
### Konflikte lösen
Wenn Konflikte mit dem Hauptbranch auftreten, müssen Sie diese lösen:
```bash
git checkout main
git pull origin main
git checkout feature/issue-123-kurze-beschreibung
git merge main
# Konflikte lösen
git add .
git commit -m "chore: Merge main und löse Konflikte"
git push origin feature/issue-123-kurze-beschreibung
```
## 6. Zusammenführen
### Anforderungen für das Zusammenführen
Bevor ein Pull Request zusammengeführt werden kann, muss er:
1. Von mindestens einem Mitglied des Kernteams genehmigt werden.
2. Alle automatisierten Checks bestehen.
3. Keine offenen Diskussionen oder Anfragen nach Änderungen haben.
### Zusammenführungsmethoden
Das Projekt verwendet verschiedene Zusammenführungsmethoden je nach Art der Änderung:
- **Squash and merge**: Für kleine Änderungen oder Fehlerbehebungen, um die Commit-Historie sauber zu halten.
- **Merge commit**: Für größere Funktionen, bei denen die einzelnen Commits wichtig sind.
- **Rebase and merge**: Für Änderungen, die eine lineare Historie erfordern.
Die bevorzugte Methode ist "Squash and merge", es sei denn, es gibt einen guten Grund für eine andere Methode.
### Nach dem Zusammenführen
Nach dem Zusammenführen eines Pull Requests:
1. Der Feature-Branch kann gelöscht werden.
2. Das zugehörige Issue wird automatisch geschlossen (wenn "Fixes #123" verwendet wurde).
3. Die Änderungen werden in der nächsten Version des Frameworks enthalten sein.
## Tipps für erfolgreiche Pull Requests
### Kleine, fokussierte Änderungen
Halten Sie Pull Requests klein und fokussiert auf eine einzelne Änderung. Dies erleichtert die Überprüfung und reduziert das Risiko von Konflikten.
### Klare Dokumentation
Dokumentieren Sie Ihre Änderungen gründlich, sowohl im Code als auch in der Pull Request-Beschreibung. Erklären Sie, warum die Änderung notwendig ist und wie sie implementiert wurde.
### Kommunikation
Kommunizieren Sie aktiv mit Reviewern und anderen Mitwirkenden. Beantworten Sie Fragen zeitnah und bitten Sie um Klärung, wenn etwas unklar ist.
### Geduld
Der Review-Prozess kann Zeit in Anspruch nehmen, besonders bei komplexen Änderungen. Haben Sie Geduld und nutzen Sie die Zeit, um Ihre Änderungen zu verbessern.
## Häufige Probleme und Lösungen
### Mein Branch ist veraltet
Wenn Ihr Branch veraltet ist und Konflikte mit dem Hauptbranch hat:
```bash
git checkout main
git pull origin main
git checkout feature/issue-123-kurze-beschreibung
git merge main
# Konflikte lösen
git add .
git commit -m "chore: Merge main und löse Konflikte"
git push origin feature/issue-123-kurze-beschreibung
```
### Ich habe einen Fehler in meinem letzten Commit gemacht
Wenn Sie einen Fehler in Ihrem letzten Commit gemacht haben und ihn noch nicht gepusht haben:
```bash
# Änderungen vornehmen
git add .
git commit --amend
git push origin feature/issue-123-kurze-beschreibung --force
```
**Hinweis**: Verwenden Sie `--force` mit Vorsicht, besonders wenn andere Personen an demselben Branch arbeiten.
### Ich möchte meine Commits aufräumen, bevor ich einen Pull Request erstelle
Wenn Sie Ihre Commits aufräumen möchten, bevor Sie einen Pull Request erstellen:
```bash
# Interaktives Rebase für die letzten n Commits
git rebase -i HEAD~n
# Pushen Sie die Änderungen
git push origin feature/issue-123-kurze-beschreibung --force
```
## Weitere Informationen
- [Coding Standards](code-style.md): Erfahren Sie mehr über die Coding Standards des Projekts.
- [Dokumentations-Anleitung](documentation.md): Erfahren Sie, wie Sie zur Dokumentation beitragen können.
- [GitHub Flow](https://guides.github.com/introduction/flow/): Eine leichtgewichtige, branchbasierte Workflow-Anleitung.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

View File

@@ -0,0 +1,78 @@
# Database Migration Fix: Column Existence Check
## Issue Description
When running migrations, particularly the `AddSizeToImageVariantsTable` migration, the following error occurred:
```
Running migrations...
Migrating: AddSizeToImageVariantsTable - Add Size to Image Slot Table
❌ Migration failed: Migration AddSizeToImageVariantsTable failed: Failed to execute query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 --- SQL: SHOW COLUMNS FROM image_variants LIKE ? PARAMETERS: {size}
```
## Root Cause
The issue was in the `hasColumn` method of the `Schema` class. When checking if a column exists in a MySQL/MariaDB database, the code was using a parameterized query with a placeholder (`?`) in the `LIKE` clause:
```php
'mysql' => "SHOW COLUMNS FROM {$table} LIKE ?",
```
However, MariaDB doesn't support parameter binding for the `LIKE` clause in this context. The placeholder `?` was being passed directly to the SQL statement instead of being replaced with the actual value.
## Solution
The solution was to modify the `hasColumn` method to use a different query for MySQL/MariaDB that properly supports parameter binding:
```php
public function hasColumn(string $table, string $column): bool
{
$driver = $this->getDriverName();
$query = match($driver) {
'mysql' => "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?",
'pgsql' => "SELECT column_name FROM information_schema.columns WHERE table_name = ? AND column_name = ?",
'sqlite' => "PRAGMA table_info({$table})",
default => throw new \RuntimeException("Unsupported driver: {$driver}")
};
if ($driver === 'pgsql') {
$result = $this->connection->queryScalar($query, [$table, $column]);
} elseif ($driver === 'sqlite') {
$columns = $this->connection->query($query)->fetchAll();
foreach ($columns as $col) {
if ($col['name'] === $column) {
return true;
}
}
return false;
} elseif ($driver === 'mysql') {
$result = $this->connection->queryScalar($query, [$table, $column]);
} else {
throw new \RuntimeException("Unsupported driver: {$driver}");
}
return (bool) $result;
}
```
Key changes:
1. Changed the MySQL query to use `information_schema.COLUMNS` with proper parameter binding
2. Updated the parameter handling for MySQL to pass both table and column parameters
3. Added an explicit condition for the MySQL driver to handle the parameters correctly
## Benefits
This change:
1. Fixes the SQL syntax error when checking if a column exists
2. Makes the code more robust by using parameterized queries throughout
3. Provides better protection against SQL injection
4. Makes the migrations idempotent (can be run multiple times without error)
## Future Considerations
For all database operations, especially in schema manipulation:
1. Always use parameterized queries when possible
2. Test database operations with different database engines
3. Consider adding more comprehensive error handling in database schema operations
4. Add unit tests for database schema operations to catch these issues earlier

View File

@@ -0,0 +1,329 @@
# Database Module New Features
This document provides an overview of the new features added to the Database module.
## Table of Contents
- [Stored Procedures and Functions](#stored-procedures-and-functions)
- [Extended Index Management](#extended-index-management)
- [Enhanced Schema Versioning](#enhanced-schema-versioning)
- [Usage Examples](#usage-examples)
## Stored Procedures and Functions
The Database module now supports defining, executing, and managing stored procedures and functions across different database systems.
### StoredProcedureDefinition
The `StoredProcedureDefinition` class provides a fluent interface for defining stored procedures:
```php
use App\Framework\Database\StoredProcedure\StoredProcedureDefinition;
$procedure = StoredProcedureDefinition::create('get_user_by_id')
->withParameter('user_id', 'INT')
->withBody('SELECT * FROM users WHERE id = user_id')
->returnsType('TABLE');
```
The definition can then be converted to SQL for different database systems:
```php
// Generate MySQL-specific SQL
$mysqlSql = $procedure->toSql('mysql');
// Generate PostgreSQL-specific SQL
$pgsqlSql = $procedure->toSql('pgsql');
```
### StoredProcedureManager
The `StoredProcedureManager` class provides methods for managing stored procedures:
```php
use App\Framework\Database\StoredProcedure\StoredProcedureManager;
// Create a new manager with a database connection
$manager = new StoredProcedureManager($connection);
// Create a stored procedure
$manager->createProcedure($procedure);
// Check if a procedure exists
if ($manager->procedureExists('get_user_by_id')) {
// Execute the procedure with parameters
$result = $manager->executeProcedure('get_user_by_id', [42]);
// Process the results
foreach ($result->fetchAll() as $row) {
// ...
}
}
// Execute a stored function
$value = $manager->executeFunction('calculate_order_total', [123, true]);
// Drop a procedure
$manager->dropProcedure('get_user_by_id');
// List all procedures
$procedures = $manager->listProcedures();
```
## Extended Index Management
The Database module now supports advanced index types and features across different database systems.
### AdvancedIndexDefinition
The `AdvancedIndexDefinition` class provides a fluent interface for defining advanced indexes:
```php
use App\Framework\Database\Schema\Index\AdvancedIndexDefinition;
use App\Framework\Database\Schema\Index\AdvancedIndexType;
// Create a standard index
$index = AdvancedIndexDefinition::create(
'idx_users_email',
['email'],
AdvancedIndexType::INDEX
);
// Create a partial index (only indexes rows that match a condition)
$partialIndex = AdvancedIndexDefinition::partial(
'idx_active_users',
['email'],
AdvancedIndexType::INDEX,
'active = true'
);
// Create a functional index (indexes the result of a function)
$functionalIndex = AdvancedIndexDefinition::functional(
'idx_lower_email',
AdvancedIndexType::INDEX,
['LOWER(email)']
);
// Create a PostgreSQL GIN index (for full-text search, JSON, arrays)
$ginIndex = AdvancedIndexDefinition::gin(
'idx_document_content',
['content']
);
// Create a PostgreSQL GiST index (for geometric data, ranges)
$gistIndex = AdvancedIndexDefinition::gist(
'idx_location_position',
['position']
);
// Create a MySQL BTREE index with options
$btreeIndex = AdvancedIndexDefinition::btree(
'idx_users_name',
['first_name', 'last_name'],
['fillfactor' => 70]
);
```
The index definition can then be converted to SQL for different database systems:
```php
// Generate SQL for PostgreSQL
$sql = $index->toSql('pgsql', 'users');
// Generate SQL for MySQL
$sql = $index->toSql('mysql', 'users');
```
## Enhanced Schema Versioning
The Database module now includes enhanced schema versioning capabilities, including dependency tracking and schema comparison tools.
### Schema Comparison
The schema comparison tools allow you to compare two database schemas and generate migration code to update one schema to match the other.
```php
use App\Framework\Database\Schema\Comparison\SchemaComparator;
// Create a comparator with source and target connections
$comparator = new SchemaComparator($sourceConnection, $targetConnection);
// Compare the schemas
$difference = $comparator->compare();
// Check if there are differences
if ($difference->hasDifferences()) {
// Get a summary of the differences
$summary = $difference->getSummary();
// Get a detailed description of the differences
$description = $difference->getDescription();
// Generate migration code to update the target schema to match the source schema
$migrationCode = $difference->generateMigrationCode('UpdateSchema');
// Save the migration code to a file
file_put_contents('database/migrations/UpdateSchema.php', $migrationCode);
}
```
### Dependent Migrations
The enhanced migration system now supports dependencies between migrations:
```php
use App\Framework\Database\ConnectionInterface;
use App\Framework\Database\Migration\AbstractDependentMigration;
use App\Framework\Database\Migration\MigrationVersion;
use App\Framework\Database\Schema\Schema;
final class CreateCommentsTable extends AbstractDependentMigration
{
public function getVersion(): MigrationVersion
{
return MigrationVersion::fromString('20250805123456');
}
public function getDescription(): string
{
return 'Create comments table';
}
public function getDependencies(): array
{
// This migration depends on the CreateUsersTable and CreatePostsTable migrations
return [
MigrationVersion::fromString('20250805123455'), // CreateUsersTable
MigrationVersion::fromString('20250805123454') // CreatePostsTable
];
}
public function up(ConnectionInterface $connection): void
{
$schema = new Schema($connection);
$schema->create('comments', function ($table) {
$table->id();
$table->text('content');
$table->foreignId('user_id')->references('id')->on('users');
$table->foreignId('post_id')->references('id')->on('posts');
$table->timestamps();
});
$schema->execute();
}
public function down(ConnectionInterface $connection): void
{
$schema = new Schema($connection);
$schema->dropIfExists('comments');
$schema->execute();
}
}
```
The migration runner will ensure that migrations are executed in the correct order based on their dependencies.
## Usage Examples
### Creating and Using a Stored Procedure
```php
use App\Framework\Database\StoredProcedure\StoredProcedureDefinition;
use App\Framework\Database\StoredProcedure\StoredProcedureManager;
// Define a stored procedure to get active users
$procedure = StoredProcedureDefinition::create('get_active_users')
->withParameter('min_login_count', 'INT')
->withBody('
SELECT * FROM users
WHERE active = true AND login_count >= min_login_count
ORDER BY last_login DESC;
')
->returnsType('TABLE');
// Create the procedure in the database
$manager = new StoredProcedureManager($connection);
$manager->createProcedure($procedure);
// Execute the procedure
$result = $manager->executeProcedure('get_active_users', [5]);
// Process the results
foreach ($result->fetchAll() as $user) {
echo "User: {$user['name']} (Last login: {$user['last_login']})\n";
}
```
### Creating Advanced Indexes
```php
use App\Framework\Database\Schema\Index\AdvancedIndexDefinition;
use App\Framework\Database\Schema\Index\AdvancedIndexType;
// In a migration
public function up(ConnectionInterface $connection): void
{
$schema = new Schema($connection);
$schema->create('posts', function ($table) {
$table->id();
$table->string('title');
$table->text('content');
$table->boolean('published')->default(false);
$table->timestamps();
});
$schema->execute();
// Create a partial index on published posts
$partialIndex = AdvancedIndexDefinition::partial(
'idx_published_posts',
['title'],
AdvancedIndexType::INDEX,
'published = true'
);
// Create a functional index for case-insensitive search
$functionalIndex = AdvancedIndexDefinition::functional(
'idx_lower_title',
AdvancedIndexType::INDEX,
['LOWER(title)']
);
// Generate and execute SQL for the current database
$driver = $connection->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME);
$connection->execute($partialIndex->toSql($driver, 'posts'));
$connection->execute($functionalIndex->toSql($driver, 'posts'));
}
```
### Comparing Schemas and Generating Migrations
```php
use App\Framework\Database\Schema\Comparison\SchemaComparator;
// Compare development and production schemas
$comparator = new SchemaComparator($devConnection, $prodConnection);
$difference = $comparator->compare();
if ($difference->hasDifferences()) {
// Print a summary of the differences
$summary = $difference->getSummary();
echo "Found {$summary['total_differences']} differences:\n";
echo " Missing tables: {$summary['missing_tables']}\n";
echo " Extra tables: {$summary['extra_tables']}\n";
echo " Modified tables: {$summary['modified_tables']}\n";
// Generate migration code
$timestamp = date('YmdHis');
$className = "UpdateProductionSchema{$timestamp}";
$migrationCode = $difference->generateMigrationCode($className);
// Save the migration
$migrationPath = "database/migrations/{$className}.php";
file_put_contents($migrationPath, $migrationCode);
echo "Generated migration: {$migrationPath}\n";
}
```

View File

@@ -0,0 +1,296 @@
# Integration von Discovery und Filesystem Modulen
Dieses Dokument beschreibt die Integration des Discovery-Moduls mit dem Filesystem-Modul, um Codeduplizierung zu reduzieren, die Robustheit zu verbessern und erweiterte Funktionen zu nutzen.
## Überblick
Die Integration umfasst folgende Komponenten:
1. **FileMetadata**: Eine erweiterte FileMetadata-Klasse im Filesystem-Modul, die Core Value Objects nutzt
2. **DiscoveryStorage**: Ein spezialisiertes Storage-Interface für Discovery-Operationen
3. **FileSystemDiscoveryStorage**: Eine Implementierung des DiscoveryStorage-Interfaces
4. **FileScannerService**: Der bestehende Service, aktualisiert für die Nutzung des Filesystem-Moduls
5. **FileScannerServiceBootstrapper**: Ein Bootstrapper für den FileScannerService
6. **UnifiedDiscoveryService**: Der bestehende Service, aktualisiert für die Nutzung des FileScannerServiceBootstrapper
## Vorteile der Integration
- **Vermeidung von Code-Duplizierung**: Einheitliche Abstraktion für Dateisystem-Operationen
- **Verbesserte Robustheit**: Konsistente Fehlerbehandlung und Ausnahmen
- **Leistungsoptimierung**: Nutzung von Batch- und Async-Funktionen des Filesystem-Moduls
- **Bessere Testbarkeit**: Einheitliche Mocking-Strategie für Dateisystem-Operationen
- **Erweiterte Funktionalität**: Zugriff auf fortschrittliche Features wie Dateisystem-Events
## Komponenten im Detail
### FileMetadata
Die erweiterte `FileMetadata`-Klasse im Filesystem-Modul vereint die Funktionalität der vorherigen FileMetadata-Klassen und nutzt Core-ValueObjects für eine robustere Implementierung.
```php
namespace App\Framework\Filesystem;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Hash;
use App\Framework\Core\ValueObjects\HashAlgorithm;
use App\Framework\Core\ValueObjects\Timestamp;
final readonly class FileMetadata
{
public function __construct(
public FilePath|string $path = '',
public Byte|int $size = 0,
public Timestamp|int $lastModified = 0,
public ?Hash $checksum = null,
public ?Timestamp $scanTime = null,
public string $mimeType = '',
public bool $isReadable = false,
public bool $isWritable = false,
public array $additionalData = []
) {
}
// Methoden für Erstellung, Konvertierung, Prüfung auf Änderungen, etc.
}
```
### DiscoveryStorage Interface
Das `DiscoveryStorage`-Interface erweitert das Standard-Storage-Interface mit Discovery-spezifischen Methoden.
```php
namespace App\Framework\Discovery\Storage;
use App\Framework\Filesystem\Storage;
use App\Framework\Filesystem\FileMetadata;
use SplFileInfo;
interface DiscoveryStorage extends Storage
{
/**
* Findet geänderte Dateien seit dem letzten Scan
*/
public function findChangedFiles(string $directory, array $fileMetadata): array;
/**
* Führt einen inkrementellen Scan durch
*/
public function incrementalScan(string $directory, array $fileMetadata): array;
/**
* Findet alle Dateien mit einem bestimmten Muster
*/
public function findFiles(string $directory, string $pattern): array;
/**
* Erstellt Metadaten für eine Datei
*/
public function getDiscoveryMetadata(string $filePath, bool $calculateChecksum = true): FileMetadata;
/**
* Erstellt Metadaten für mehrere Dateien parallel
*/
public function getDiscoveryMetadataMultiple(array $filePaths, bool $calculateChecksum = true): array;
/**
* Registriert Dateisystem-Events für Änderungserkennung
*/
public function registerFileSystemEvents(string $directory, callable $callback): bool;
}
```
### FileSystemDiscoveryStorage
Die `FileSystemDiscoveryStorage`-Klasse implementiert das DiscoveryStorage-Interface und delegiert Standard-Storage-Operationen an eine zugrundeliegende Storage-Implementierung.
```php
namespace App\Framework\Discovery\Storage;
use App\Framework\Async\FiberManager;
use App\Framework\Filesystem\File;
use App\Framework\Filesystem\Directory;
use App\Framework\Filesystem\FileMetadata;
use App\Framework\Filesystem\PermissionChecker;
use App\Framework\Filesystem\Storage;
use SplFileInfo;
final class FileSystemDiscoveryStorage implements DiscoveryStorage
{
/**
* @param Storage $storage Basis-Storage-Implementierung für Delegation
* @param PermissionChecker $permissions Permissions-Checker
* @param FiberManager $fiberManager Fiber-Manager für asynchrone Operationen
*/
public function __construct(
private readonly Storage $storage,
public readonly PermissionChecker $permissions = new PermissionChecker(),
public readonly FiberManager $fiberManager = new FiberManager()
) {
}
// Implementierung der Storage-Methoden durch Delegation
/**
* {@inheritdoc}
*/
public function getDiscoveryMetadata(string $filePath, bool $calculateChecksum = true): FileMetadata
{
return FileMetadata::fromFile($filePath, $this, $calculateChecksum);
}
// Weitere Implementierungen der Discovery-spezifischen Methoden
}
```
### FileScannerService
Der `FileScannerService` wurde aktualisiert, um das DiscoveryStorage-Interface zu nutzen, wenn verfügbar, mit Fallback auf die alte Implementierung für Abwärtskompatibilität.
```php
namespace App\Framework\Discovery;
use App\Framework\Discovery\Storage\DiscoveryStorage;
final class FileScannerService
{
public function __construct(
private readonly FileScannerInterface $fileScanner,
private readonly PathProvider $pathProvider,
private readonly Cache $cache,
private readonly bool $useCache = true,
// weitere Parameter
private readonly ?DiscoveryStorage $storage = null
) {
// Initialisierung
}
// Methoden für Scanning, Verarbeitung, Caching, etc.
// mit Nutzung von DiscoveryStorage wenn verfügbar
}
```
### FileScannerServiceBootstrapper
Der `FileScannerServiceBootstrapper` erstellt und konfiguriert den FileScannerService mit den richtigen Abhängigkeiten.
```php
namespace App\Framework\Discovery;
use App\Framework\Filesystem\FilesystemManager;
final class FileScannerServiceBootstrapper
{
public function __construct(
private readonly FilesystemManager $filesystemManager,
// weitere Parameter
) {
}
public function create(
bool $useCache = true,
// weitere Parameter
): FileScannerService {
// Erstelle DiscoveryStorage und FileScannerService
}
public static function createDefault(
FilesystemManager $filesystemManager,
// weitere Parameter
): FileScannerService {
// Factory-Methode für einfache Erstellung
}
}
```
### UnifiedDiscoveryService
Der `UnifiedDiscoveryService` wurde aktualisiert, um den FileScannerServiceBootstrapper zu nutzen.
```php
namespace App\Framework\Discovery;
use App\Framework\Filesystem\FilesystemManager;
final readonly class UnifiedDiscoveryService
{
public function __construct(
FilesystemManager $filesystemManager,
// weitere Parameter
) {
// Erstelle FileScannerService mit Bootstrapper
}
// Methoden für Discovery, Caching, Health-Checks, etc.
}
```
## Verwendung
### Einfache Verwendung mit Standard-Konfiguration
```php
// Container-Konfiguration
$container->singleton(UnifiedDiscoveryService::class, function (Container $container) {
return new UnifiedDiscoveryService(
$container->get(FilesystemManager::class),
$container->get(PathProvider::class),
$container->get(Cache::class),
$container->get(Clock::class),
// weitere Parameter mit Standardwerten
);
});
// Verwendung
$discoveryService = $container->get(UnifiedDiscoveryService::class);
$results = $discoveryService->discover();
```
### Erweiterte Konfiguration
```php
// Manuelle Erstellung mit angepasster Konfiguration
$bootstrapper = new FileScannerServiceBootstrapper(
$filesystemManager,
$pathProvider,
$cache,
$logger
);
$fileScannerService = $bootstrapper->create(
useCache: true,
asyncProcessing: true,
chunkSize: 200,
maxRetries: 5,
enableAdaptiveChunking: true,
storageName: 'custom_storage'
);
// Verwendung des FileScannerService direkt
$fileScannerService->scan(true); // mit Fortschrittsanzeige
```
### Verwendung des DiscoveryStorage direkt
```php
// Erstelle DiscoveryStorage
$storage = new FileSystemDiscoveryStorage(
$filesystemManager->storage('default')
);
// Finde geänderte Dateien
$changedFiles = $storage->findChangedFiles('/path/to/directory', $existingMetadata);
// Hole Metadaten für eine Datei
$metadata = $storage->getDiscoveryMetadata('/path/to/file.php', true);
// Hole Metadaten für mehrere Dateien parallel
$metadataMap = $storage->getDiscoveryMetadataMultiple([
'/path/to/file1.php',
'/path/to/file2.php',
'/path/to/file3.php'
]);
```
## Fazit
Die Integration des Discovery-Moduls mit dem Filesystem-Modul bietet zahlreiche Vorteile in Bezug auf Codeduplizierung, Robustheit, Leistung und Funktionalität. Die Implementierung ist abwärtskompatibel, sodass bestehender Code weiterhin funktioniert, während neue Code die verbesserte Funktionalität nutzen kann.

View File

@@ -1,42 +0,0 @@
# Framework Features
## Core Features
- [ ] Routing mit Unterstützung für PHP-Attribute
- [ ] Dependency Injection Container
- [ ] Request/Response Abstraktion
- [ ] Template-Engine
- [ ] Error/Exception Handling
- [ ] Konfigurationssystem
## Database Features
- [ ] PDO-Wrapper
- [ ] Query Builder
- [ ] Migrations-System
- [ ] Schema Manager
- [ ] Entity-Mapping (optional)
## Security Features
- [ ] CSRF-Schutz
- [ ] XSS-Filtierung
- [ ] Input-Validierung
- [ ] Authentifizierung
- [ ] Autorisierung/Rechtemanagement
## Module: Music
- [ ] Album-Verwaltung
- [ ] Track-Management
- [ ] Playlists
- [ ] Integrationsmöglichkeit mit Spotify/SoundCloud
## Module: Content
- [ ] Blog-System
- [ ] Markdown-Support
- [ ] Medienbibliothek
- [ ] SEO-Optimierung
- [ ] Kommentarsystem
## Admin Interface
- [ ] Dashboard
- [ ] Content-Editor
- [ ] Benutzer-/Rechteverwaltung
- [ ] Statistiken

View File

@@ -1,14 +0,0 @@
# Analytics-Framework
> **Dokumentationshinweis:** Die vollständige Dokumentation für das Analytics-Framework finden Sie im Ordner [/docs/framework/analytics](/docs/framework/analytics/).
## Schnellzugriff
- [Übersicht und Einstieg](/docs/framework/analytics/index.md)
- [Detaillierte Architektur](/docs/framework/analytics/architecture.md)
- [Anwendungsbeispiele](/docs/framework/analytics/usage.md)
- [Migrationsleitfaden](/docs/framework/analytics/migration.md)
## Implementierungsdetails
Die Code-Dokumentation befindet sich in der [README-Datei des Frameworks](/Framework/Analytics1/README.md).

View File

@@ -1,200 +0,0 @@
# Erweiterungsmuster im Framework
## Übersicht
Dieses Dokument beschreibt die verschiedenen Muster und Techniken, um das Framework zu erweitern oder anzupassen, ohne den Kern-Code zu verändern.
## Event-basierte Erweiterungen
### Event-Listener
Die primäre Methode zur Erweiterung des Frameworks ist das Lauschen auf System-Events:
```php
// Event-Listener registrieren
public function __construct(private readonly EventDispatcher $eventDispatcher)
{
$this->eventDispatcher->addHandler(
'App\Framework\Core\Events\ApplicationBooted',
[$this, 'onApplicationBooted']
);
}
// Event-Handler-Methode
public function onApplicationBooted(ApplicationBooted $event): void
{
// Erweiterungslogik implementieren
}
```
### Eigene Events
Benutzerdefinierte Events erstellen:
```php
final readonly class UserRegistered
{
public function __construct(
public string $userId,
public string $email,
public \DateTimeImmutable $timestamp
) {}
}
// Event auslösen
$this->eventDispatcher->dispatch(new UserRegistered(
$user->getId(),
$user->getEmail(),
new \DateTimeImmutable()
));
```
## Middleware
HTTP-Anfragen können durch Middleware-Klassen erweitert werden:
```php
final readonly class CustomMiddleware implements Middleware
{
public function process(Request $request, callable $next): Response
{
// Vor der Anfrageverarbeitung
$modifiedRequest = $this->modifyRequest($request);
// Anfrage weiterleiten
$response = $next($modifiedRequest);
// Nach der Anfrageverarbeitung
return $this->modifyResponse($response);
}
}
// Middleware registrieren
$app->addMiddleware(CustomMiddleware::class);
```
## Service-Erweiterungen
### Service-Ersetzen
Standardimplementierungen durch eigene ersetzen:
```php
#[Initializer]
final readonly class CustomStorageInitializer
{
public function __invoke(Container $container): StorageInterface
{
return new CustomStorage();
}
}
```
### Service-Decorator
Bestehende Services erweitern ohne Änderung der Original-Implementierung:
```php
#[Initializer]
final readonly class LoggingAnalyticsInitializer
{
public function __construct(
private readonly Configuration $config,
private readonly LoggerInterface $logger
) {}
public function __invoke(Container $container): Analytics
{
// Original-Analytics-Service erstellen
$originalAnalytics = new Analytics(
new AnalyticsManager($this->config->get('analytics'), new FileStorage($path)),
$container->get(EventDispatcher::class)
);
// Mit Logging-Decorator umhüllen
return new LoggingAnalyticsDecorator($originalAnalytics, $this->logger);
}
}
// Decorator-Implementierung
final readonly class LoggingAnalyticsDecorator implements AnalyticsInterface
{
public function __construct(
private Analytics $analytics,
private LoggerInterface $logger
) {}
public function track(string $event, array $properties = [], ?string $userId = null): void
{
$this->logger->debug("Tracking event: {$event}", [
'properties' => $properties,
'user_id' => $userId
]);
$this->analytics->track($event, $properties, $userId);
}
// Andere Methoden implementieren
}
```
## Plugin-System
### Plugin-Interface
```php
interface PluginInterface
{
public function register(Application $app): void;
public function boot(Application $app): void;
}
// Plugin-Implementierung
final readonly class CustomPlugin implements PluginInterface
{
public function register(Application $app): void
{
// Services registrieren
}
public function boot(Application $app): void
{
// Nach Initialisierung der Anwendung
}
}
// Plugin registrieren
$app->registerPlugin(new CustomPlugin());
```
## Konfigurationserweiterungen
### Konfigurationsquellen
Benutzerdefinierte Konfigurationsquellen implementieren:
```php
final readonly class EnvironmentConfigSource implements ConfigSourceInterface
{
public function load(string $key, mixed $default = null): mixed
{
$envKey = strtoupper(str_replace('.', '_', $key));
return $_ENV[$envKey] ?? $default;
}
}
// Konfigurationsquelle registrieren
$config->addSource(new EnvironmentConfigSource());
```
## Zusammenfassung
Die bevorzugten Erweiterungsmuster sind:
1. **Event-Listener** für reaktive Erweiterungen
2. **Middleware** für HTTP-Anfrageverarbeitung
3. **Service-Initializer** zum Ersetzen oder Dekorieren von Services
4. **Plugins** für umfassendere Funktionalitätserweiterungen
5. **Konfigurationsquellen** für benutzerdefinierte Konfigurationen
Diese Muster ermöglichen es, das Framework zu erweitern, ohne den Kern zu modifizieren, was zu einer besseren Wartbarkeit und einfacheren Updates führt.

View File

@@ -1,73 +0,0 @@
# Framework-Modul Checkliste
## Übersicht
Diese Checkliste dient als Leitfaden für die Erstellung neuer Module im Framework. Sie hilft sicherzustellen, dass alle Module den Projektstandards entsprechen und konsistent implementiert werden.
## Strukturelle Anforderungen
- [ ] Modul in eigenem Verzeichnis unter `/src/Framework/`
- [ ] Konsistente Namensgebung im PascalCase (z.B. `CacheManager` statt `Cache_manager`)
- [ ] README.md mit Modul-Dokumentation
- [ ] Interface(s) für öffentliche API
- [ ] Implementierungsklassen als `final readonly`
- [ ] Initializer-Klasse mit `#[Initializer]`-Attribut
## Abhängigkeiten
- [ ] Minimale externe Abhängigkeiten (idealerweise keine)
- [ ] Klar definierte Abhängigkeiten zu anderen Framework-Modulen
- [ ] Keine zirkulären Abhängigkeiten
- [ ] Verwendung des DI-Containers für Abhängigkeiten
## Konfiguration
- [ ] Konfigurationsdatei unter `/src/Config/{modul-name}.php`
- [ ] Standardkonfiguration in der Initializer-Klasse
- [ ] Dokumentierte Konfigurationsoptionen
## Code-Qualität
- [ ] Vollständige Typisierung (Parameter, Rückgabewerte, Properties)
- [ ] PHPDoc für öffentliche Methoden und Klassen
- [ ] Keine abstrakten Klassen oder Vererbung (außer Interfaces)
- [ ] Immutable Objekte wo möglich
- [ ] Spezifische Exceptions für Fehlerbehandlung
## Tests
- [ ] Unit-Tests mit Pest für alle öffentlichen Methoden
- [ ] Integrationstests für Modul-Interaktionen
- [ ] Testabdeckung für Fehlerfälle
## Integration
- [ ] Event-Listener für relevante System-Events
- [ ] Erweiterungspunkte für andere Module
- [ ] Keine direkten Abhängigkeiten zu Domain-Klassen
## Dokumentation
- [ ] Beispiele für Verwendung
- [ ] Architektur-Beschreibung
- [ ] API-Dokumentation
- [ ] Konfigurationsreferenz
## Performance
- [ ] Lazy-Loading für ressourcenintensive Operationen
- [ ] Caching-Strategie (falls relevant)
- [ ] Performancekritische Teile identifiziert und optimiert
## Sicherheit
- [ ] Validierung aller externen Eingaben
- [ ] Keine sensiblen Daten in Logs
- [ ] Schutz vor bekannten Sicherheitslücken
## Wartbarkeit
- [ ] Kleine, fokussierte Klassen
- [ ] Klare Trennung von Verantwortlichkeiten
- [ ] Konsistente Fehlerbehandlung
- [ ] Logging an strategischen Stellen

View File

@@ -1,158 +0,0 @@
# Analytics-Modul Dokumentation
## Übersicht
Das Analytics-Modul ist ein internes Tracking- und Analysesystem, das ohne externe Abhängigkeiten Benutzeraktivitäten, Systemereignisse und Leistungsdaten erfasst und analysiert.
## Kernkomponenten
### Analytics (Analytics.php)
Die Hauptklasse, die als zentraler Einstiegspunkt für das Tracking von Events dient.
**Hauptfunktionen:**
- `track()`: Zeichnet ein generisches Event auf
- `page()`: Spezifisch für Seitenaufrufe
- `user()`: Verfolgt Benutzeridentifikation
- `performance()`: Erfasst Leistungsmetriken
- `error()`: Protokolliert Fehler und Ausnahmen
### AnalyticsManager (AnalyticsManager.php)
Verwaltet die Verarbeitung und Speicherung von Events.
**Hauptfunktionen:**
- `track()`: Verarbeitet Events und wendet Middleware an
- `addMiddleware()`: Fügt Verarbeitungsfunktionen hinzu
- `flush()`: Schreibt gepufferte Events in den Speicher
### StorageInterface und FileStorage
Das Interface definiert die Speichermethoden, FileStorage implementiert die Speicherung in Dateien.
**Hauptoperationen:**
- `store()`: Speichert Events
- `retrieve()`: Ruft Events mit Filtern ab
- `clear()`: Löscht alle gespeicherten Daten
### AnalyticsInitializer (AnalyticsInitializer.php)
Konfiguriert und initialisiert den Analytics-Service beim Anwendungsstart.
**Konfigurationsoptionen:**
- Aktivierung/Deaktivierung
- Auto-Flush und Batch-Größe
- Storage-Typ und Pfad
### AnalyticsMiddleware (AnalyticsMiddleware.php)
HTTP-Middleware zum automatischen Tracking von Requests und Responses.
### AnalyticsDashboard (AnalyticsDashboard.php)
Stellt Methoden für Datenanalyse und -aggregation bereit:
- `getEventStats()`: Ereignisstatistiken
- `getTopPages()`: Meistbesuchte Seiten
- `getUserStats()`: Benutzerstatistiken
- `getErrorStats()`: Fehlerstatistiken
- `getPerformanceStats()`: Leistungsmetriken
### Events
Vordefinierte Event-Typen:
- `AnalyticsEvent`: Basis-Event-Klasse
- `PageViewEvent`: Speziell für Seitenaufrufe
### Controllers
`AdminAnalyticsController`: Stellt das Admin-Dashboard bereit mit:
- Übersichtsseite
- Seitenstatistiken
- Fehlerstatistiken
- Leistungsstatistiken
### Console
`AnalyticsClearCommand`: Konsolenbefehl zum Löschen von Analytics-Daten.
## Konfiguration
Die Konfiguration erfolgt in `src/Config/analytics.php` mit folgenden Optionen:
```php
return [
'enabled' => true, // Aktiviert/deaktiviert das Tracking
'auto_flush' => true, // Automatisches Speichern nach Batch-Größe
'batch_size' => 50, // Anzahl Events pro Batch
'storage' => 'file', // Storage-Backend
'storage_path' => '...', // Speicherpfad
'anonymize_ip' => true, // IP-Anonymisierung
'track_events' => [...] // Zu trackende Events
];
```
## Verwendung
### Basis-Tracking
```php
// Event tracken
$analytics->track('button_click', ['button' => 'signup']);
// Seitenaufruf tracken
$analytics->page('/dashboard', ['section' => 'analytics']);
// Benutzer identifizieren
$analytics->user('user123', ['plan' => 'premium']);
```
### Middleware einrichten
```php
$this->addMiddleware(App\Framework\Analytics\AnalyticsMiddleware::class);
```
### Eigene Middleware hinzufügen
```php
$analyticsManager->addMiddleware(function(array $event) {
// Daten verarbeiten oder filtern
return $event;
});
```
## Datenschutz
Das System bietet integrierte Funktionen zur Anonymisierung personenbezogener Daten:
- IP-Adressen-Anonymisierung (letztes Oktett wird entfernt)
- Konfigurierbare Filterung sensibler Daten durch Middleware
## Erweiterbarkeit
### Eigene Storage-Provider
Implementieren Sie das `StorageInterface` für benutzerdefinierte Speicherlösungen:
```php
class CustomStorage implements StorageInterface
{
public function store(array $events): void { /* ... */ }
public function retrieve(array $filters = []): array { /* ... */ }
public function clear(): void { /* ... */ }
}
```
### Event-Typen erweitern
Erstellen Sie benutzerdefinierte Event-Klassen, die von `AnalyticsEvent` erben:
```php
class CustomEvent extends AnalyticsEvent
{
public function __construct(string $customData, array $additionalProps = [])
{
parent::__construct('custom_event',
array_merge(['custom_data' => $customData], $additionalProps));
}
}
```

View File

@@ -1,102 +0,0 @@
# Analytics-Framework: Architektur
## Überblick
Das Analytics-Framework verwendet eine Schichtenarchitektur mit klaren Verantwortlichkeiten:
```
┌─────────────────────────────────────────────────────┐
│ Öffentliche API │
│ (Analytics) │
└───────────────────────┬─────────────────────────────┘
┌───────────────────────▼─────────────────────────────┐
│ Event-Verarbeitung │
│ (AnalyticsManager) │
└───────────────────────┬─────────────────────────────┘
┌──────────────┴──────────────┐
│ │
┌────────▼─────────┐ ┌─────────▼────────┐
│ Middleware │ │ Storage-Layer │
│ (Pipeline) │ │ (StorageInterface)│
└──────────────────┘ └──────────────────┘
```
## Komponenten im Detail
### Analytics (Frontend)
Bietet eine benutzerfreundliche API für Tracking-Operationen. Diese Klasse ist der primäre Einstiegspunkt für Anwendungscode und abstrahiert die Komplexität der Eventverarbeitung.
Verantwortlichkeiten:
- Bereitstellung der öffentlichen API (`track`, `page`, `user`, `error`)
- Integration mit dem Event-Dispatcher des Frameworks
- Typ-Konvertierung zwischen benutzerdefinierten Ereignissen und dem internen Datenformat
### AnalyticsManager (Verarbeitung)
Der Manager ist das Herzstück des Systems und verantwortlich für:
- Anwendung von Middleware-Transformationen auf Events
- Eventpufferung für effiziente Speicherung
- Verwaltung der Konfiguration
- Steuerung des Storage-Layers
Der Manager implementiert einen Event-Buffer, der Daten sammelt und bei Erreichen einer konfigurierbaren Größe automatisch speichert.
### Middleware-System
Eine Kette von Verarbeitungsfunktionen, die auf jedes Event angewendet werden:
- Datenfilterung und -transformation
- Anonymisierung persönlicher Daten
- Validierung und Anreicherung von Events
Jede Middleware kann Events modifizieren oder komplett verwerfen.
### Storage-Layer
Abstraktion für verschiedene Speichermethoden durch das `StorageInterface`:
```php
interface StorageInterface
{
public function store(array $events): void;
public function retrieve(array $filters = []): array;
public function clear(): void;
}
```
Implementierungen:
- `FileStorage`: Speichert Events in JSON-Dateien mit täglicher Rotation
- Erweiterbar für andere Backends (Datenbank, Redis, etc.)
### HTTP-Integration
`AnalyticsMiddleware` integriert Analytics in den HTTP-Request-Lifecycle:
- Tracking von eingehenden Requests
- Erfassung von Antwortzeiten und Statuscodes
- Fehlererfassung bei Exceptions
### Admin-Dashboard
`AnalyticsDashboard` und `AdminAnalyticsController` bieten:
- Datenaggregation und -analyse
- Visualisierung von Metriken
- Filterung nach Zeiträumen
- Verschiedene spezialisierte Ansichten (Seiten, Fehler, Performance)
## Datenfluss
1. Event wird durch `Analytics::track()` oder ähnliche Methoden erstellt
2. `AnalyticsManager` wendet Middleware-Pipeline an
3. Event wird zum Buffer hinzugefügt
4. Bei Buffer-Füllung oder explizitem `flush()` werden Events an Storage übergeben
5. Storage speichert Events im konfigurierten Backend
6. `AnalyticsDashboard` ruft Daten bei Bedarf vom Storage ab und aggregiert sie
## Erweiterungspunkte
- **Storage-Provider**: Neue Implementierungen von `StorageInterface`
- **Middleware**: Funktionen für Filterung/Transformation
- **Event-Typen**: Spezialisierte Event-Klassen für typsicheres Tracking
- **Dashboard-Views**: Zusätzliche Visualisierungen und Berichte

View File

@@ -1,114 +0,0 @@
# Analytics-Framework
> **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Analytics-Frameworks korrekt dar.
## Übersicht
Das Analytics-Framework ist ein eigenständiges Tracking- und Analysesystem, das vollständig in die Anwendung integriert ist und ohne externe Dienste auskommt. Es ermöglicht die Erfassung, Speicherung und Analyse von:
- Benutzeraktivitäten (Seitenaufrufe, Interaktionen)
- Systemereignissen (Anwendungsstart, Fehler)
- Leistungsdaten (Speicherverbrauch, Ausführungszeit, Datenbankabfragen)
## Hauptkomponenten
### Analytics-Klasse
Die zentrale API für Tracking-Operationen:
```php
// Klasse initialisieren
$analytics = new Analytics($analyticsManager, $eventDispatcher);
// Event tracken
$analytics->track('event_name', ['property' => 'value']);
// Seite tracken
$analytics->page('/pfad/zur/seite', ['eigenschaft' => 'wert']);
// Benutzer identifizieren
$analytics->user('user_id', ['eigenschaft' => 'wert']);
// Fehler tracken
$analytics->error($exception);
```
### AnalyticsManager
Verarbeitet und speichert Events:
- Wendet Middleware auf Events an
- Puffert Events für effiziente Speicherung
- Verwaltet die Konfiguration
- Steuert die Speicherung in verschiedenen Backends
### Storage-System
Basierend auf dem `StorageInterface` mit verschiedenen Implementierungen:
- `FileStorage`: Speichert Events in Dateien
- Erweiterbar für Datenbank, Redis oder andere Backends
### Middleware-System
```php
$analyticsManager->addMiddleware(function(array $event) {
// Event verarbeiten oder filtern
return $event; // oder null um zu verwerfen
});
```
### HTTP-Middleware
Automatisches Tracking von HTTP-Requests und -Responses:
```php
// In Bootstrap oder Application-Klasse
$app->addMiddleware(AnalyticsMiddleware::class);
```
### Dashboard und Berichterstattung
Das `AnalyticsDashboard` bietet Methoden zur Datenanalyse:
- `getEventStats()`: Statistiken zu Events
- `getTopPages()`: Meistbesuchte Seiten
- `getUserStats()`: Benutzerstatistiken
- `getErrorStats()`: Fehlerstatistiken
- `getPerformanceStats()`: Leistungsmetriken
Das Admin-Dashboard ist unter `/admin/analytics` verfügbar.
### Konsolen-Befehle
```bash
# Analytics-Daten löschen
php console analytics:clear [--force]
```
## Integration
### Service-Container
Der Analytics-Service wird automatisch registriert und kann per Dependency Injection verwendet werden:
```php
public function __construct(private readonly Analytics $analytics) {}
```
### Event-Integration
Standardmäßig werden folgende Anwendungsereignisse getrackt:
- Anwendungsstart (`application_booted`)
- Fehlerbehandlung (`error_occurred`)
- Request-Verarbeitung (`request_started`, `request_completed`)
## Konfiguration
Detaillierte Konfigurationsoptionen finden Sie in der [Framework-README](/Framework/Analytics1/README.md).
## Weitere Informationen
- [Framework-Erweiterungsmuster](/docs/framework/ERWEITERUNGSPATTERN.md)
- [Modul-Checkliste](/docs/framework/MODUL-CHECKLISTE.md)

View File

@@ -1,160 +0,0 @@
# Analytics-Framework: Migrationsleitfaden
## Von Version 1.x zu 2.x
### Überblick der Änderungen
Die Version 2.x des Analytics-Frameworks führt mehrere wichtige Verbesserungen und Änderungen ein:
- **Typsicherheit**: Neue Event-Klassen statt Arrays
- **Dependency Injection**: Verbesserte Integration mit dem Container
- **Storage-Abstraktion**: Flexiblere Speichermethoden
- **Fehlerbehandlung**: Robustere Exception-Handling
- **Middleware-System**: Standardisierte Middleware-Pipeline
### Notwendige Migrationsschritte
#### 1. Konfiguration aktualisieren
**Alt (1.x):**
```php
return [
'enabled' => true,
'auto_flush' => true,
'batch_size' => 50,
'storage' => 'file',
'storage_path' => '/pfad/zum/speicher',
];
```
**Neu (2.x):**
```php
return [
'enabled' => true,
'auto_flush' => true,
'batch_size' => 50,
'storage_driver' => 'file', // Umbenannt
'storage_config' => [ // Neue Struktur
'path' => '/pfad/zum/speicher',
],
'excluded_paths' => [], // Neue Option
'excluded_user_agents' => [], // Neue Option
'max_file_size' => 10 * 1024 * 1024, // Neue Option
];
```
#### 2. Event-Objekte (falls genutzt)
**Alt (1.x):**
```php
$analytics->track('custom_event', ['property' => 'value']);
```
**Neu (2.x) - Option 1 (abwärtskompatibel):**
```php
// Weiterhin unterstützt
$analytics->track('custom_event', ['property' => 'value']);
```
**Neu (2.x) - Option 2 (typsicher):**
```php
use App\Framework\Analytics\Events\CustomEvent;
$event = new CustomEvent('wert', ['weitere' => 'daten']);
$analytics->trackEvent($event);
```
#### 3. Eigene Storage-Provider
**Alt (1.x):**
```php
class CustomStorage implements StorageInterface
{
public function store(array $events): void
{
// Implementation
}
public function retrieve(array $filters = []): array
{
// Implementation
}
public function clear(): void
{
// Implementation
}
}
```
**Neu (2.x):**
```php
use Psr\Log\LoggerInterface;
class CustomStorage implements StorageInterface
{
public function __construct(
private readonly array $config,
private readonly LoggerInterface $logger
) {}
public function store(array $events): void
{
try {
// Implementation mit Fehlerbehandlung
} catch (\Exception $e) {
$this->logger->error('Storage error', ['exception' => $e]);
throw new StorageException('Failed to store events', 0, $e);
}
}
// Andere Methoden analog
}
```
#### 4. Middleware anpassen
**Alt (1.x):**
```php
$analyticsManager->addMiddleware(function(array $event) {
// Verarbeitung
return $event;
});
```
**Neu (2.x) - Option 1 (abwärtskompatibel):**
```php
// Weiterhin unterstützt
$analyticsManager->addMiddleware(function(array $event) {
// Verarbeitung
return $event;
});
```
**Neu (2.x) - Option 2 (typsicher):**
```php
use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
use App\Framework\Analytics\Events\AnalyticsEvent;
class CustomMiddleware implements AnalyticsMiddleware
{
public function process(AnalyticsEvent $event): ?AnalyticsEvent
{
// Verarbeitung
return $event;
}
}
// Registrierung
$analyticsManager->addMiddleware(new CustomMiddleware());
```
### Automatisierte Tests
Führen Sie die folgenden Tests durch, um sicherzustellen, dass die Migration erfolgreich war:
```bash
php console test:run --group=analytics
```
Weitere Informationen zur Migration finden Sie in den Änderungsprotokollen im Quellcode-Repository.

View File

@@ -1,269 +0,0 @@
# Analytics-Framework: Anwendungsbeispiele
## Grundlegende Verwendung
### Events tracken
```php
// Über Dependency Injection
public function __construct(private readonly Analytics $analytics) {}
// Einfaches Event tracken
$this->analytics->track('login_attempt', [
'success' => true,
'user_type' => 'admin',
'method' => 'password'
]);
// Seitenaufruf tracken
$this->analytics->page('/produkte/kategorie/elektronik', [
'referrer' => 'homepage',
'search_query' => 'smartphones'
]);
// Benutzer identifizieren
$this->analytics->user($user->getId(), [
'email' => $user->getEmail(),
'plan' => $user->getSubscriptionPlan(),
'registered_since' => $user->getCreatedAt()->format('Y-m-d')
]);
```
### Fehler tracken
```php
try {
// Fehleranfälliger Code
$result = $this->riskyOperation();
return $result;
} catch (\Exception $e) {
// Fehler tracken
$this->analytics->error($e);
// Fehler behandeln
$this->logger->error($e->getMessage());
return $this->fallbackOperation();
}
```
### Performance tracken
```php
// Manuelles Performance-Tracking
$startTime = microtime(true);
$startMemory = memory_get_usage();
// Operation durchführen
$result = $this->heavyOperation();
// Performance-Metriken tracken
$this->analytics->performance([
'operation' => 'heavy_operation',
'execution_time' => microtime(true) - $startTime,
'memory_used' => memory_get_usage() - $startMemory,
'result_size' => is_countable($result) ? count($result) : 0
]);
```
## Erweiterte Anwendungsfälle
### Benutzerdefinierte Middleware
```php
// In einem Service Provider oder Initializer
public function initialize(AnalyticsManager $manager): void
{
// DSGVO-Middleware zur Anonymisierung personenbezogener Daten
$manager->addMiddleware(function(array $event) {
// E-Mail-Adressen anonymisieren
if (isset($event['properties']['email'])) {
$parts = explode('@', $event['properties']['email']);
if (count($parts) === 2) {
$event['properties']['email'] = substr($parts[0], 0, 1) .
'***@' . $parts[1];
}
}
// Passwörter und Tokens entfernen
foreach (['password', 'token', 'api_key', 'secret'] as $key) {
if (isset($event['properties'][$key])) {
$event['properties'][$key] = '[redacted]';
}
}
return $event;
});
// Spam-Filter
$manager->addMiddleware(function(array $event) {
// Zu viele Events von einem Benutzer filtern
static $userCounts = [];
$userId = $event['user_id'] ?? $event['session_id'] ?? null;
if ($userId) {
$userCounts[$userId] = ($userCounts[$userId] ?? 0) + 1;
// Mehr als 100 Events pro Session ist verdächtig
if ($userCounts[$userId] > 100) {
return null; // Event verwerfen
}
}
return $event;
});
}
```
### Integration mit dem Domain-Layer
```php
// In einem Domain-Service
namespace App\Domain\Shop\Services;
use App\Framework\Analytics\Analytics;
class ProductService
{
public function __construct(private readonly Analytics $analytics) {}
public function viewProduct(string $productId, ?string $userId): Product
{
$product = $this->productRepository->find($productId);
if (!$product) {
throw new ProductNotFoundException($productId);
}
// Produktansicht tracken
$this->analytics->track('product_view', [
'product_id' => $product->getId(),
'product_name' => $product->getName(),
'product_price' => $product->getPrice(),
'product_category' => $product->getCategory()->getName(),
'in_stock' => $product->isInStock()
], $userId);
return $product;
}
public function addToCart(string $productId, int $quantity, ?string $userId): Cart
{
// Implementation...
// Event tracken
$this->analytics->track('add_to_cart', [
'product_id' => $productId,
'quantity' => $quantity,
'cart_value' => $cart->getTotalValue()
], $userId);
return $cart;
}
}
```
### Verwendung im Controller
```php
namespace App\Application\Controllers;
use App\Framework\Analytics\Analytics;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\Attributes\Route;
class CheckoutController
{
public function __construct(
private readonly Analytics $analytics,
private readonly CheckoutService $checkoutService
) {}
#[Route('/checkout/complete', method: 'POST')]
public function completeCheckout(Request $request): Response
{
$userId = $request->getSession()->get('user_id');
$cartId = $request->getSession()->get('cart_id');
try {
$order = $this->checkoutService->completeCheckout($cartId, $userId);
// Erfolgreichen Checkout tracken
$this->analytics->track('checkout_complete', [
'order_id' => $order->getId(),
'order_value' => $order->getTotalValue(),
'items_count' => count($order->getItems()),
'payment_method' => $order->getPaymentMethod(),
'shipping_method' => $order->getShippingMethod()
], $userId);
return new Response([
'success' => true,
'order_id' => $order->getId()
], 200);
} catch (\Exception $e) {
// Fehler beim Checkout tracken
$this->analytics->track('checkout_error', [
'error' => $e->getMessage(),
'cart_id' => $cartId
], $userId);
// Auch den Exception-Stack tracken
$this->analytics->error($e);
return new Response([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
}
```
## Analyse der Daten
### Dashboard-Controller
```php
namespace App\Application\Controllers;
use App\Framework\Analytics\AnalyticsDashboard;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\View\ViewRenderer;
use App\Framework\Attributes\Route;
class AnalyticsDashboardController
{
public function __construct(
private readonly AnalyticsDashboard $dashboard,
private readonly ViewRenderer $viewRenderer
) {}
#[Route('/admin/analytics/conversion')]
public function conversionReport(Request $request): Response
{
$from = $request->getQueryParam('from');
$to = $request->getQueryParam('to');
// Benutzerdefinierte Analyse für Conversion-Funnel
$pageViews = $this->dashboard->getEventCountByType('page_view', $from, $to);
$productViews = $this->dashboard->getEventCountByType('product_view', $from, $to);
$addToCarts = $this->dashboard->getEventCountByType('add_to_cart', $from, $to);
$checkouts = $this->dashboard->getEventCountByType('checkout_complete', $from, $to);
// Conversion-Raten berechnen
$data = [
'total_visitors' => $pageViews,
'product_view_rate' => $pageViews > 0 ? $productViews / $pageViews : 0,
'add_to_cart_rate' => $productViews > 0 ? $addToCarts / $productViews : 0,
'checkout_rate' => $addToCarts > 0 ? $checkouts / $addToCarts : 0,
'overall_conversion' => $pageViews > 0 ? $checkouts / $pageViews : 0,
'from_date' => $from,
'to_date' => $to
];
return $this->viewRenderer->render('admin/analytics/conversion', $data);
}
}
```

View File

@@ -1,45 +0,0 @@
# Core-Modul Dokumentation
## Übersicht
Das Core-Modul bildet das Herzstück des Frameworks und stellt grundlegende Funktionalitäten bereit, die von anderen Modulen genutzt werden.
## Hauptkomponenten
### Events und EventDispatcher
Das Event-System ermöglicht die Kommunikation zwischen Komponenten über einen zentralen Event-Bus.
**Kernklassen:**
- `EventDispatcher`: Zentraler Service zum Registrieren und Auslösen von Events
- Bekannte Events:
- `ApplicationBooted`
- `ErrorOccurred`
- `BeforeHandleRequest`
- `AfterHandleRequest`
**Beispielverwendung:**
```php
// Event-Handler registrieren
$eventDispatcher->addHandler('App\Framework\Core\Events\ApplicationBooted', function($event) {
// Event verarbeiten
});
```
### PathProvider
Stellt Pfadinformationen für verschiedene Bereiche der Anwendung bereit.
**Hauptfunktionen:**
- `getDataPath()`: Liefert Pfade zu Datenverzeichnissen
## Integration mit anderen Modulen
Das Core-Modul wird von vielen anderen Modulen verwendet, wie z.B.:
- **Analytics-Modul**: Nutzt den EventDispatcher zum Tracking von Systemereignissen
- **DI-Container**: Nutzt Core-Komponenten für die Initialisierung von Services
## Architektur
Das Core-Modul folgt einer ereignisgesteuerten Architektur, bei der Komponenten über Events miteinander kommunizieren können, anstatt direkte Abhängigkeiten zu haben.

View File

@@ -1,89 +0,0 @@
# Dependency Injection Modul
## Übersicht
Das DI-Modul implementiert ein Dependency-Injection-Container-System, das die automatische Auflösung und Verwaltung von Abhängigkeiten ermöglicht.
## Hauptkomponenten
### Container
Der zentrale Service-Container, der Instanzen erstellt und verwaltet.
**Hauptfunktionen:**
- Service-Erstellung und -Auflösung
- Singleton-Verwaltung
- Rekursive Abhängigkeitsauflösung
### Initializer-Attribut
Das `#[Initializer]`-Attribut kennzeichnet Klassen, die Services im Container registrieren können.
**Beispiel:**
```php
#[Initializer]
readonly class AnalyticsInitializer
{
public function __invoke(Container $container): Analytics
{
// Service erstellen und konfigurieren
return $analytics;
}
}
```
## Verwendung
### Service definieren
```php
// Service-Interface
interface MyServiceInterface
{
public function doSomething(): void;
}
// Konkrete Implementierung
class MyService implements MyServiceInterface
{
public function doSomething(): void
{
// Implementierung
}
}
```
### Service registrieren
```php
#[Initializer]
class MyServiceInitializer
{
public function __invoke(Container $container): MyServiceInterface
{
return new MyService();
}
}
```
### Service verwenden
```php
class MyController
{
public function __construct(
private readonly MyServiceInterface $myService
) {}
public function action(): void
{
$this->myService->doSomething();
}
}
```
## Prinzipien
- **Automatische Auflösung**: Abhängigkeiten werden anhand von Typ-Hints automatisch aufgelöst
- **Lazy Loading**: Services werden erst erstellt, wenn sie benötigt werden
- **Singleton-Modus**: Standardmäßig werden Services als Singletons verwaltet

View File

@@ -1,92 +0,0 @@
# HTTP-Modul Dokumentation
## Übersicht
Das HTTP-Modul stellt Komponenten für die Verarbeitung von HTTP-Anfragen und -Antworten bereit.
## Hauptkomponenten
### Request
Repräsentiert eine HTTP-Anfrage mit Methoden zum Zugriff auf:
- HTTP-Methode (`getMethod()`)
- Pfad (`getPath()`)
- Query-Parameter (`getQueryParams()`)
- Request-Body
- Headers
### Response
Repräsentiert eine HTTP-Antwort mit:
- Status-Code (`getStatusCode()`)
- Headers
- Body
### Middleware
Ein Interface für HTTP-Middleware-Komponenten, die die Request-Verarbeitung verändern können:
```php
interface Middleware
{
public function process(Request $request, callable $next): Response;
}
```
**Beispiel-Middleware:**
```php
class AnalyticsMiddleware implements Middleware
{
public function __construct(
private readonly Analytics $analytics
) {}
public function process(Request $request, callable $next): Response
{
// Request tracken
$this->analytics->track('http_request', [
'method' => $request->getMethod(),
'path' => $request->getPath(),
]);
// Request weiterleiten
$response = $next($request);
// Response tracken
$this->analytics->track('http_response', [
'status_code' => $response->getStatusCode(),
]);
return $response;
}
}
```
## Integration mit anderen Modulen
- **Router**: Routing von HTTP-Requests zu Controllers
- **Analytics**: Tracking von HTTP-Requests und -Responses
- **Validation**: Validierung von Request-Daten
## Middlewares registrieren
In der Anwendungsklasse:
```php
$this->addMiddleware(LoggingMiddleware::class);
$this->addMiddleware(AnalyticsMiddleware::class);
$this->addMiddleware(AuthenticationMiddleware::class);
```
## Responses erzeugen
```php
// JSON-Response
return new JsonResponse(['success' => true]);
// HTML-Response
return new HtmlResponse('<html><body>Hello World</body></html>');
// Redirect
return new RedirectResponse('/dashboard');
```

View File

@@ -1,42 +0,0 @@
# Framework-Dokumentation
## Übersicht
Diese Dokumentation beschreibt die Architektur, Komponenten und Verwendung des Framework-Kerns des Projekts.
## Hauptmodule
- [Analytics](/framework/analytics/README.md) - System zur Erfassung und Analyse von Anwendungsdaten
- [Core](/framework/core/README.md) - Kernkomponenten und Event-System
- [DI (Dependency Injection)](/framework/di/README.md) - Container und Service-Management
- [HTTP](/framework/http/README.md) - HTTP-Request/Response-Handling
## Richtlinien und Muster
- [Modul-Checkliste](/framework/MODUL-CHECKLISTE.md) - Leitfaden für die Erstellung neuer Module
- [Erweiterungsmuster](/framework/ERWEITERUNGSPATTERN.md) - Muster zur Erweiterung des Frameworks
## Modulare Architektur
Das Framework ist modular aufgebaut, mit klaren Verantwortlichkeiten für jedes Modul. Module kommunizieren über klar definierte Interfaces und den Event-Dispatcher.
### Neues Modul erstellen
Um ein neues Modul zu erstellen, folgen Sie der [Modul-Checkliste](/framework/MODUL-CHECKLISTE.md) und beachten Sie die folgenden Kernprinzipien:
1. Klare Verantwortlichkeiten definieren
2. Dependency Injection verwenden
3. Interface-basiertes Design umsetzen
4. Event-basierte Kommunikation nutzen
5. Externe Abhängigkeiten minimieren
### Framework erweitern
Es gibt verschiedene Möglichkeiten, das Framework zu erweitern:
1. **Middleware**: HTTP-Request-Pipeline erweitern
2. **Event-Listener**: Auf System-Events reagieren
3. **Service-Provider**: Eigene Services registrieren
4. **Plugin-System**: Umfangreichere Erweiterungen implementieren
Weitere Details finden Sie im Dokument [Erweiterungsmuster](/framework/ERWEITERUNGSPATTERN.md).

View File

@@ -0,0 +1,214 @@
# Konfiguration
Diese Anleitung erklärt, wie Sie das Framework nach der Installation konfigurieren können.
## Umgebungsvariablen
Die Hauptkonfiguration des Frameworks erfolgt über Umgebungsvariablen, die in der `.env`-Datei definiert sind. Wenn Sie das Framework gerade installiert haben, sollten Sie eine Kopie der `.env.example`-Datei erstellt und in `.env` umbenannt haben.
### Wichtige Umgebungsvariablen
Hier sind die wichtigsten Umgebungsvariablen, die Sie konfigurieren sollten:
#### Anwendung
```
APP_NAME="Meine Anwendung"
APP_ENV=development
APP_DEBUG=true
APP_URL=http://localhost:8000
APP_KEY=base64:...
```
- `APP_NAME`: Der Name Ihrer Anwendung
- `APP_ENV`: Die Umgebung, in der die Anwendung läuft (`development`, `testing` oder `production`)
- `APP_DEBUG`: Ob Debug-Informationen angezeigt werden sollen (`true` oder `false`)
- `APP_URL`: Die Basis-URL Ihrer Anwendung
- `APP_KEY`: Der Verschlüsselungsschlüssel für Ihre Anwendung (wird automatisch generiert)
#### Datenbank
```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=framework
DB_USERNAME=root
DB_PASSWORD=
```
- `DB_CONNECTION`: Der Datenbanktyp (`mysql`, `sqlite`, `pgsql` oder `sqlsrv`)
- `DB_HOST`: Der Hostname des Datenbankservers
- `DB_PORT`: Der Port des Datenbankservers
- `DB_DATABASE`: Der Name der Datenbank
- `DB_USERNAME`: Der Benutzername für die Datenbankverbindung
- `DB_PASSWORD`: Das Passwort für die Datenbankverbindung
#### Cache und Sitzungen
```
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
```
- `CACHE_DRIVER`: Der Cache-Treiber (`file`, `redis` oder `memory`)
- `SESSION_DRIVER`: Der Sitzungstreiber (`file`, `database` oder `redis`)
- `SESSION_LIFETIME`: Die Lebensdauer der Sitzung in Minuten
#### E-Mail
```
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
```
- `MAIL_DRIVER`: Der E-Mail-Treiber (`smtp`, `sendmail` oder `log`)
- `MAIL_HOST`: Der Hostname des SMTP-Servers
- `MAIL_PORT`: Der Port des SMTP-Servers
- `MAIL_USERNAME`: Der Benutzername für die SMTP-Verbindung
- `MAIL_PASSWORD`: Das Passwort für die SMTP-Verbindung
- `MAIL_ENCRYPTION`: Die Verschlüsselungsmethode (`tls` oder `ssl`)
- `MAIL_FROM_ADDRESS`: Die Absenderadresse
- `MAIL_FROM_NAME`: Der Absendername
## Konfigurationsdateien
Neben den Umgebungsvariablen verwendet das Framework auch Konfigurationsdateien im Verzeichnis `config/`. Diese Dateien enthalten Konfigurationen, die nicht über Umgebungsvariablen gesteuert werden sollten oder komplexere Strukturen erfordern.
### Wichtige Konfigurationsdateien
#### app.php
Die Datei `config/app.php` enthält allgemeine Anwendungskonfigurationen:
```php
return [
'name' => env('APP_NAME', 'Framework'),
'env' => env('APP_ENV', 'production'),
'debug' => env('APP_DEBUG', false),
'url' => env('APP_URL', 'http://localhost'),
'timezone' => 'UTC',
'locale' => 'de',
'fallback_locale' => 'en',
'key' => env('APP_KEY'),
'cipher' => 'AES-256-CBC',
'providers' => [
// Service-Provider
],
'aliases' => [
// Fassaden
],
];
```
#### database.php
Die Datei `config/database.php` enthält Datenbankkonfigurationen:
```php
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
// Weitere Datenbankverbindungen
],
'migrations' => 'migrations',
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
];
```
#### cache.php
Die Datei `config/cache.php` enthält Cache-Konfigurationen:
```php
return [
'default' => env('CACHE_DRIVER', 'file'),
'stores' => [
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'memory' => [
'driver' => 'memory',
],
],
'prefix' => env('CACHE_PREFIX', 'framework_cache'),
];
```
## Benutzerdefinierte Konfiguration
Sie können auch eigene Konfigurationsdateien erstellen, um anwendungsspezifische Einstellungen zu speichern. Erstellen Sie dazu eine neue Datei im Verzeichnis `config/` und geben Sie ein Array zurück:
```php
// config/myapp.php
return [
'feature_flags' => [
'new_ui' => env('FEATURE_NEW_UI', false),
'api_v2' => env('FEATURE_API_V2', false),
],
'limits' => [
'max_items' => 100,
'max_file_size' => 10 * 1024 * 1024, // 10 MB
],
];
```
Sie können dann auf diese Konfiguration zugreifen mit:
```php
$newUiEnabled = config('myapp.feature_flags.new_ui');
$maxItems = config('myapp.limits.max_items');
```
## Umgebungsspezifische Konfiguration
Das Framework unterstützt umgebungsspezifische Konfigurationen. Sie können verschiedene `.env`-Dateien für verschiedene Umgebungen erstellen:
- `.env` - Standardkonfiguration
- `.env.development` - Entwicklungsumgebung
- `.env.testing` - Testumgebung
- `.env.production` - Produktionsumgebung
Um eine bestimmte Umgebungskonfiguration zu laden, setzen Sie die Umgebungsvariable `APP_ENV` auf den entsprechenden Wert.
## Nächste Schritte
Nachdem Sie das Framework konfiguriert haben, können Sie mit den [ersten Schritten](first-steps.md) fortfahren, um Ihre erste Anwendung zu erstellen.

View File

@@ -0,0 +1,327 @@
# Erste Schritte
Diese Anleitung führt Sie durch die ersten Schritte mit dem Framework, nachdem Sie es [installiert](installation.md) und [konfiguriert](configuration.md) haben.
## Projektstruktur
Zunächst sollten Sie sich mit der Projektstruktur vertraut machen:
```
my-project/
├── bin/ # Ausführbare Skripte
├── config/ # Konfigurationsdateien
├── docs/ # Dokumentation
├── public/ # Öffentlich zugängliche Dateien
│ ├── index.php # Einstiegspunkt für die Anwendung
│ ├── assets/ # Kompilierte Assets (CSS, JS)
│ └── uploads/ # Hochgeladene Dateien
├── resources/ # Quellressourcen
│ ├── css/ # CSS-Dateien
│ ├── js/ # JavaScript-Dateien
│ └── views/ # Template-Dateien
├── src/ # PHP-Quellcode
│ ├── Application/ # Anwendungsspezifischer Code
│ │ ├── Controllers/ # Controller
│ │ ├── Models/ # Modelle
│ │ └── Services/ # Services
│ └── Framework/ # Framework-Code
│ ├── Core/ # Kernkomponenten
│ ├── Database/ # Datenbankabstraktion
│ └── Http/ # HTTP-Komponenten
├── storage/ # Speicher für Anwendungsdaten
│ ├── cache/ # Cache-Dateien
│ ├── logs/ # Log-Dateien
│ └── uploads/ # Hochgeladene Dateien
├── tests/ # Testdateien
├── vendor/ # Composer-Abhängigkeiten
├── .env # Umgebungsvariablen
├── composer.json # Composer-Konfiguration
├── console.php # Kommandozeilen-Interface
└── README.md # Projektdokumentation
```
## Erstellen einer einfachen Seite
Lassen Sie uns eine einfache Seite erstellen, um zu sehen, wie das Framework funktioniert.
### 1. Erstellen eines Controllers
Erstellen Sie eine neue Datei `src/Application/Controllers/WelcomeController.php`:
```php
<?php
namespace App\Application\Controllers;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
class WelcomeController extends Controller
{
public function index(Request $request): Response
{
return $this->view('welcome', [
'title' => 'Willkommen',
'message' => 'Willkommen beim Framework!',
]);
}
}
```
### 2. Erstellen einer View
Erstellen Sie eine neue Datei `resources/views/welcome.php`:
```php
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $title ?></title>
<link rel="stylesheet" href="/assets/css/app.css">
</head>
<body>
<div class="container">
<h1><?= $title ?></h1>
<p><?= $message ?></p>
</div>
<script src="/assets/js/app.js"></script>
</body>
</html>
```
### 3. Definieren einer Route
Öffnen Sie die Datei `config/routes.php` und fügen Sie eine neue Route hinzu:
```php
<?php
use App\Application\Controllers\WelcomeController;
use App\Framework\Routing\Router;
return function (Router $router) {
$router->get('/', [WelcomeController::class, 'index']);
};
```
### 4. Testen der Anwendung
Starten Sie den eingebauten Entwicklungsserver:
```bash
php console.php serve
```
Öffnen Sie dann Ihren Browser und navigieren Sie zu `http://localhost:8000`. Sie sollten Ihre neue Seite sehen.
## Erstellen einer API-Endpunkt
Lassen Sie uns einen einfachen API-Endpunkt erstellen.
### 1. Erstellen eines API-Controllers
Erstellen Sie eine neue Datei `src/Application/Controllers/Api/UserController.php`:
```php
<?php
namespace App\Application\Controllers\Api;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = [
['id' => 1, 'name' => 'Max Mustermann'],
['id' => 2, 'name' => 'Erika Musterfrau'],
];
return $this->json($users);
}
public function show(Request $request, int $id): Response
{
$users = [
1 => ['id' => 1, 'name' => 'Max Mustermann'],
2 => ['id' => 2, 'name' => 'Erika Musterfrau'],
];
if (!isset($users[$id])) {
return $this->json(['error' => 'Benutzer nicht gefunden'], 404);
}
return $this->json($users[$id]);
}
}
```
### 2. Definieren von API-Routen
Fügen Sie in der Datei `config/routes.php` die folgenden Routen hinzu:
```php
$router->group('/api', function (Router $router) {
$router->get('/users', [UserController::class, 'index']);
$router->get('/users/{id}', [UserController::class, 'show']);
});
```
Vergessen Sie nicht, den Controller zu importieren:
```php
use App\Application\Controllers\Api\UserController;
```
### 3. Testen der API
Starten Sie den Entwicklungsserver und testen Sie die API mit einem HTTP-Client wie curl:
```bash
curl http://localhost:8000/api/users
curl http://localhost:8000/api/users/1
```
## Arbeiten mit der Datenbank
Das Framework bietet eine einfache Datenbankabstraktion. Hier ist ein Beispiel für die Arbeit mit der Datenbank:
### 1. Erstellen eines Modells
Erstellen Sie eine neue Datei `src/Application/Models/User.php`:
```php
<?php
namespace App\Application\Models;
use App\Framework\Database\Model;
class User extends Model
{
protected string $table = 'users';
protected array $fillable = ['name', 'email', 'password'];
protected array $hidden = ['password'];
}
```
### 2. Erstellen einer Migration
Erstellen Sie eine neue Migration mit dem Konsolenbefehl:
```bash
php console.php db:migration:create create_users_table
```
Dies erstellt eine neue Datei in `migrations/`. Bearbeiten Sie die Datei:
```php
<?php
use App\Framework\Database\Migration;
use App\Framework\Database\Schema\Blueprint;
class CreateUsersTable extends Migration
{
public function up(): void
{
$this->schema->create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
});
}
public function down(): void
{
$this->schema->dropIfExists('users');
}
}
```
### 3. Ausführen der Migration
Führen Sie die Migration aus:
```bash
php console.php db:migrate
```
### 4. Verwenden des Modells im Controller
Aktualisieren Sie den `UserController`:
```php
<?php
namespace App\Application\Controllers\Api;
use App\Application\Models\User;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = User::all();
return $this->json($users);
}
public function show(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json(['error' => 'Benutzer nicht gefunden'], 404);
}
return $this->json($user);
}
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
$user = User::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => password_hash($request->input('password'), PASSWORD_DEFAULT),
]);
return $this->json($user, 201);
}
}
```
Fügen Sie eine neue Route hinzu:
```php
$router->post('/api/users', [UserController::class, 'store']);
```
## Nächste Schritte
Nachdem Sie die Grundlagen des Frameworks kennengelernt haben, können Sie sich mit den folgenden Themen befassen:
- [Routing](../guides/routing.md) - Erfahren Sie mehr über das Routing-System
- [Controller](../guides/controllers.md) - Lernen Sie, wie Sie Controller effektiv einsetzen
- [Validierung](../guides/validation.md) - Validieren Sie Benutzereingaben
- [Datenbank](../guides/database.md) - Arbeiten Sie mit der Datenbank
- [Authentifizierung](../guides/authentication.md) - Implementieren Sie Benutzerauthentifizierung
- [Sicherheit](../guides/security.md) - Schützen Sie Ihre Anwendung
Oder erkunden Sie die [Komponenten](../components/README.md) des Frameworks, um mehr über die verfügbaren Funktionen zu erfahren.

View File

@@ -0,0 +1,108 @@
# Installation
Diese Anleitung führt Sie durch den Installationsprozess des Frameworks.
## Systemanforderungen
Bevor Sie mit der Installation beginnen, stellen Sie sicher, dass Ihr System die folgenden Anforderungen erfüllt:
- PHP 8.1 oder höher
- Composer 2.0 oder höher
- Node.js 16 oder höher (für Frontend-Assets)
- MySQL 8.0 oder höher (optional, wenn Sie MySQL als Datenbank verwenden)
- SQLite 3 (für Entwicklung und Tests)
## Installation über Composer
Die einfachste Methode zur Installation ist über Composer:
```bash
composer create-project michaelschiemer/framework my-project
cd my-project
```
## Manuelle Installation
Alternativ können Sie das Framework auch manuell installieren:
1. Klonen Sie das Repository:
```bash
git clone https://github.com/michaelschiemer/framework.git my-project
cd my-project
```
2. Installieren Sie die Abhängigkeiten:
```bash
composer install
npm install
```
## Konfiguration nach der Installation
Nach der Installation müssen Sie einige grundlegende Konfigurationen vornehmen:
1. Erstellen Sie eine Kopie der `.env.example`-Datei und benennen Sie sie in `.env` um:
```bash
cp .env.example .env
```
2. Generieren Sie einen Anwendungsschlüssel:
```bash
php console.php app:key-generate
```
3. Konfigurieren Sie Ihre Datenbankverbindung in der `.env`-Datei.
4. Führen Sie die Migrationen aus:
```bash
php console.php db:migrate
```
## Überprüfung der Installation
Um zu überprüfen, ob die Installation erfolgreich war, können Sie den eingebauten Entwicklungsserver starten:
```bash
php console.php serve
```
Öffnen Sie dann Ihren Browser und navigieren Sie zu `http://localhost:8000`. Sie sollten die Startseite des Frameworks sehen.
## Fehlerbehebung
### Häufige Probleme
#### Composer-Fehler
Wenn Sie Probleme mit Composer haben, versuchen Sie, den Cache zu leeren:
```bash
composer clear-cache
```
#### Berechtigungsprobleme
Stellen Sie sicher, dass die folgenden Verzeichnisse für den Webserver beschreibbar sind:
- `storage/`
- `cache/`
- `logs/`
Sie können die Berechtigungen mit dem folgenden Befehl ändern:
```bash
chmod -R 775 storage cache logs
```
#### Datenbank-Verbindungsprobleme
Überprüfen Sie Ihre Datenbankverbindungseinstellungen in der `.env`-Datei. Stellen Sie sicher, dass der Datenbankbenutzer die richtigen Berechtigungen hat.
## Nächste Schritte
Nachdem Sie das Framework erfolgreich installiert haben, können Sie mit der [Konfiguration](configuration.md) fortfahren und dann die [ersten Schritte](first-steps.md) unternehmen, um Ihre erste Anwendung zu erstellen.

387
docs/graphql-examples.md Normal file
View File

@@ -0,0 +1,387 @@
# GraphQL Examples
This framework includes a basic GraphQL implementation with Query and Mutation support.
## GraphQL Endpoints
- **POST /graphql** - GraphQL endpoint for queries and mutations
- **GET /graphql** - GraphQL Playground (interactive editor)
- **GET /graphql/schema** - View schema definition
## Schema Definition
The current schema includes:
```graphql
type User {
id: ID!
name: String!
email: String!
age: Int
active: Boolean!
created_at: String!
}
input UserInput {
name: String!
email: String!
age: Int
active: Boolean
}
type UserStats {
total: Int!
active: Int!
inactive: Int!
average_age: Float!
}
type Query {
users(active: Boolean, limit: Int): [User!]!
user(id: ID!): User
userStats: UserStats!
}
type Mutation {
createUser(input: UserInput!): User!
updateUser(id: ID!, input: UserInput!): User
deleteUser(id: ID!): Boolean!
}
```
## Query Examples
### Get All Users
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { users { id name email active } }"
}'
```
Response:
```json
{
"data": {
"users": [
{
"id": "1",
"name": "John Doe",
"email": "john@example.com",
"active": true
},
{
"id": "2",
"name": "Jane Smith",
"email": "jane@example.com",
"active": true
},
{
"id": "3",
"name": "Bob Wilson",
"email": "bob@example.com",
"active": false
}
]
}
}
```
### Get Active Users Only
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { users(active: true) { id name email } }"
}'
```
### Get Limited Number of Users
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { users(limit: 2) { id name email } }"
}'
```
### Get Single User by ID
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { user(id: \"1\") { id name email age active created_at } }"
}'
```
Response:
```json
{
"data": {
"user": {
"id": "1",
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"active": true,
"created_at": "2024-01-01T00:00:00Z"
}
}
}
```
### Get User Statistics
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { userStats { total active inactive average_age } }"
}'
```
Response:
```json
{
"data": {
"userStats": {
"total": 3,
"active": 2,
"inactive": 1,
"average_age": 30.0
}
}
}
```
## Mutation Examples
### Create New User
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "mutation { createUser(input: { name: \"Alice Johnson\", email: \"alice@example.com\", age: 28, active: true }) { id name email age active created_at } }"
}'
```
Response:
```json
{
"data": {
"createUser": {
"id": "4",
"name": "Alice Johnson",
"email": "alice@example.com",
"age": 28,
"active": true,
"created_at": "2024-08-08T10:30:00Z"
}
}
}
```
### Update Existing User
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "mutation { updateUser(id: \"1\", input: { name: \"John Smith\", age: 31 }) { id name email age } }"
}'
```
Response:
```json
{
"data": {
"updateUser": {
"id": "1",
"name": "John Smith",
"email": "john@example.com",
"age": 31
}
}
}
```
### Delete User
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "mutation { deleteUser(id: \"3\") }"
}'
```
Response:
```json
{
"data": {
"deleteUser": true
}
}
```
## Using Variables
### Query with Variables
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query GetUser($userId: ID!) { user(id: $userId) { id name email } }",
"variables": { "userId": "1" }
}'
```
### Mutation with Variables
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "mutation CreateUser($input: UserInput!) { createUser(input: $input) { id name email } }",
"variables": {
"input": {
"name": "Charlie Brown",
"email": "charlie@example.com",
"age": 22,
"active": true
}
}
}'
```
## Complex Queries
### Multiple Queries in One Request
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { users(active: true) { id name email } userStats { total active } }"
}'
```
Response:
```json
{
"data": {
"users": [
{
"id": "1",
"name": "John Doe",
"email": "john@example.com"
},
{
"id": "2",
"name": "Jane Smith",
"email": "jane@example.com"
}
],
"userStats": {
"total": 3,
"active": 2
}
}
}
```
### Using Aliases
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { activeUsers: users(active: true) { id name } inactiveUsers: users(active: false) { id name } }"
}'
```
## Error Handling
### Invalid Query
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { nonexistentField }"
}'
```
Response:
```json
{
"errors": [
{
"message": "Query field 'nonexistentField' not found",
"extensions": {
"code": "VAL_BUSINESS_RULE_VIOLATION"
}
}
]
}
```
### User Not Found
```bash
curl -X POST https://localhost/graphql \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
-d '{
"query": "query { user(id: \"999\") { id name } }"
}'
```
Response:
```json
{
"data": {
"user": null
}
}
```
## GraphQL Playground
Visit https://localhost/graphql in your browser to access the interactive GraphQL Playground:
- **Query Editor**: Write and test GraphQL queries
- **Variables Panel**: Define query variables
- **Results Panel**: View query results
- **Schema Explorer**: Browse available types and fields
- **Execute Button**: Run queries with Ctrl+Enter
## Best Practices
1. **Use Field Selection**: Only request fields you need
2. **Use Variables**: For dynamic queries and better caching
3. **Handle Errors**: Always check for errors in responses
4. **Batch Operations**: Combine multiple queries when possible
5. **Type Safety**: Use proper types in mutations
6. **Validation**: Validate input data before mutations
7. **Caching**: Consider caching strategies for queries

View File

@@ -1,169 +0,0 @@
# Performance-Richtlinien
## Übersicht
Diese Richtlinien beschreiben Best Practices für die Optimierung der Anwendungsleistung im Framework.
## Grundprinzipien
### 1. Frühe Optimierung vermeiden
- Code zuerst korrekt und lesbar schreiben
- Optimierungen auf Basis von Messungen durchführen
- Performance-Engpässe mit dem Profiler identifizieren
### 2. Caching strategisch einsetzen
- Ergebnisse teurer Operationen cachen
- Geeignete Cache-Invalidierungsstrategien implementieren
- Cache-Hierarchie nutzen (Memory → Filesystem → Datenbank)
```php
// Beispiel: Strategisches Caching
public function getExpensiveData(string $key): array
{
$cacheKey = "data_{$key}";
// Prüfen, ob Daten im Cache sind
if ($this->cache->has($cacheKey)) {
return $this->cache->get($cacheKey);
}
// Teure Operation durchführen
$result = $this->performExpensiveOperation($key);
// Ergebnis cachen mit angemessener TTL
$this->cache->set($cacheKey, $result, 3600);
return $result;
}
```
### 3. Lazy Loading
- Ressourcen erst bei Bedarf laden
- Schwere Abhängigkeiten verzögert initialisieren
```php
// Beispiel: Lazy Loading
private ?ExpensiveService $expensiveService = null;
private function getExpensiveService(): ExpensiveService
{
if ($this->expensiveService === null) {
$this->expensiveService = new ExpensiveService($this->config);
}
return $this->expensiveService;
}
```
### 4. Datenstrukturen optimieren
- Passende Datenstrukturen für den Anwendungsfall wählen
- Große Arrays vermeiden, wenn möglich Iteratoren oder Generatoren nutzen
- Bei großen Datenmengen paginieren
```php
// Beispiel: Generator statt Array
public function processLargeDataset(): Generator
{
$handle = fopen($this->largeFile, 'r');
while (($line = fgets($handle)) !== false) {
yield $this->processLine($line);
}
fclose($handle);
}
```
## Spezifische Optimierungen
### Datenbankzugriffe
- Anzahl der Datenbankabfragen minimieren
- Indizes für häufige Abfragen
- N+1 Problem vermeiden durch Eager Loading
- Datenbankverbindungen poolen
### HTTP-Anfragen
- Statische Assets komprimieren und cachen
- HTTP/2 nutzen, wenn möglich
- Content-Kompression aktivieren
- Browser-Caching durch geeignete Header
### Speichernutzung
- Große Objekte nach Gebrauch freigeben (`unset()`)
- Zirkuläre Referenzen vermeiden
- Bei Dateiberarbeitung auf Streaming-Ansätze setzen
### Autoloading
- Composer-Autoloader in Produktionsumgebung optimieren
- Preloading für häufig verwendete Klassen nutzen
```php
// preload.php Beispiel
<?php
declare(strict_types=1);
// Häufig verwendete Klassen vorladen
require_once __DIR__ . '/Framework/Core/Application.php';
require_once __DIR__ . '/Framework/DI/Container.php';
require_once __DIR__ . '/Framework/Http/Request.php';
require_once __DIR__ . '/Framework/Http/Response.php';
```
## Monitoring und Profiling
### Performance messen
- Kritische Code-Pfade instrumentieren
- End-to-End Zeitmessungen durchführen
```php
// Beispiel: Performance-Messung
$startTime = microtime(true);
// Operation durchführen
$result = $this->performOperation();
$duration = microtime(true) - $startTime;
$this->logger->debug("Operation ausgeführt in {$duration}s");
```
### Automatisiertes Monitoring
- Performance-Regressions automatisch erkennen
- Regelmäßige Lasttests durchführen
- Kritische Pfade überwachen
## Umgebungsspezifische Optimierungen
### Entwicklung
- Debug-Tools aktivieren
- Performance-Optimierungen deaktivieren, die Debugging erschweren
### Produktion
- Opcache aktivieren und optimieren
- Fehlerbehandlung optimieren (keine Stack Traces)
- Logging auf nötige Informationen beschränken
```php
// Umgebungsspezifische Einstellungen
if ($environment === 'production') {
ini_set('opcache.validate_timestamps', 0);
ini_set('display_errors', 0);
error_reporting(E_ERROR | E_WARNING | E_PARSE);
} else {
ini_set('opcache.validate_timestamps', 1);
ini_set('display_errors', 1);
error_reporting(E_ALL);
}
```

View File

@@ -1,181 +0,0 @@
# Testing-Richtlinien
## Übersicht
Diese Richtlinien beschreiben die Standards und Best Practices für Tests im Framework.
## Grundprinzipien
### 1. Testarten
- **Unit Tests**: Testen einzelner Komponenten isoliert
- **Integrationstests**: Testen des Zusammenspiels mehrerer Komponenten
- **Funktionstests**: Testen ganzer Funktionalitäten aus Benutzersicht
### 2. Pest-Framework
Alle Tests werden mit dem Pest-Framework geschrieben:
```php
test('Analytics::track zeichnet Events korrekt auf', function () {
// Arrange
$manager = new AnalyticsManager(['enabled' => true], new InMemoryStorage());
$analytics = new Analytics($manager, new EventDispatcher());
// Act
$analytics->track('test_event', ['key' => 'value']);
// Assert
expect($manager->getStorage()->retrieve())->toHaveCount(1);
expect($manager->getStorage()->retrieve()[0]['event'])->toBe('test_event');
});
```
### 3. Teststruktur
- Jeder Test folgt dem AAA-Prinzip: Arrange, Act, Assert
- Tests sollten unabhängig voneinander sein
- Tests sollten deterministisch sein (keine zufälligen Ergebnisse)
## Best Practices
### 1. Testabdeckung
- Jede öffentliche Methode sollte getestet werden
- Edge Cases und Fehlersituationen explizit testen
- Fokus auf Business-Logik und kritische Pfade
### 2. Mocking
- Externe Abhängigkeiten mocken
- Eigene Test-Implementierungen für Interfaces erstellen
- Mock-Objekte nur für die spezifischen Testfälle konfigurieren
```php
// Beispiel: Test mit Mock
test('Fehlerbehandlung bei Storage-Ausfall', function () {
// Arrange
$storage = new class implements StorageInterface {
public function store(array $events): void
{
throw new \RuntimeException('Storage-Fehler');
}
public function retrieve(array $filters = []): array
{
return [];
}
public function clear(): void
{
}
};
$manager = new AnalyticsManager(['enabled' => true], $storage);
// Act & Assert
expect(fn() => $manager->flush())->toThrow(\RuntimeException::class);
});
```
### 3. Fixtures und Factories
- Testdaten mit Factories erstellen
- Komplexe Objekte über Helpers aufbauen
- Wiederverwendbare Fixtures für ähnliche Tests
```php
// Beispiel: Test-Factory
function createAnalyticsManager(array $config = []): AnalyticsManager
{
$defaultConfig = ['enabled' => true, 'auto_flush' => false];
return new AnalyticsManager(
array_merge($defaultConfig, $config),
new InMemoryStorage()
);
}
test('Auto-Flush funktioniert korrekt', function () {
// Arrange
$manager = createAnalyticsManager(['auto_flush' => true, 'batch_size' => 2]);
// Act
$manager->track('event1', []);
$manager->track('event2', []);
// Assert
expect($manager->getStorage()->retrieve())->toHaveCount(2);
});
```
### 4. Datenbankzugriffe
- In Unit-Tests Datenbankzugriffe vermeiden oder mocken
- In Integrationstests separate Testdatenbank verwenden
- Testdatenbank nach Tests zurücksetzen
### 5. Asynchrone Tests
- Timeouts für asynchrone Tests setzen
- Auf Async-Events warten, statt feste Wartezeiten
## Testorganisation
### 1. Dateistruktur
- Tests in `/tests`-Verzeichnis mit gleicher Struktur wie `/src`
- Dateinamen mit `Test`-Suffix
### 2. Testgruppen
- Tests mit Attributen in Gruppen einteilen
- Langsame Tests markieren
```php
#[Group('analytics')]
#[Group('slow')]
test('große Datenmenge verarbeiten', function () {
// Test mit vielen Daten
});
```
## CI/CD-Integration
- Tests in CI-Pipeline automatisiert ausführen
- Testabdeckung messen und überwachen
- Pull Requests nur mit erfolgreichen Tests mergen
## Fehlersuche
### 1. Debugging-Techniken
- Pest-Debugging aktivieren mit `->dump()`
- PHPUnit-Assertions für detaillierte Fehlermeldungen
```php
test('komplexes Objekt validieren', function () {
$result = processData();
// Bei Fehlern Kontext ausgeben
if (!expect($result->isValid())->toBeTrue()->isSuccess()) {
dump($result->getErrors());
}
});
```
### 2. Problematische Tests
- Flaky Tests identifizieren und beheben
- Tests isolieren mit `only` oder `skip`
```php
test('problematischer Test', function () {
// Test-Code
})->skip('Wird untersucht');
```
## Zusammenfassung
- Tests sind ein integraler Bestandteil der Codebase
- Qualität und Wartbarkeit der Tests sind genauso wichtig wie die des Produktionscodes
- Tests dienen als lebende Dokumentation der Funktionalität

View File

@@ -1,43 +0,0 @@
# Entwicklungsrichtlinien
## Übersicht
Diese Richtlinien bieten Best Practices und Standards für die Entwicklung innerhalb des Projekts. Sie helfen, qualitativ hochwertigen, wartbaren und leistungsfähigen Code zu schreiben.
## Verfügbare Richtlinien
- [Performance-Richtlinien](/guidelines/PERFORMANCE-GUIDELINES.md) - Optimierung der Anwendungsleistung
- [Testing-Richtlinien](/guidelines/TESTING-GUIDELINES.md) - Standards und Best Practices für Tests
## Performance-Optimierung
Leistungsoptimierung ist ein wichtiger Aspekt der Anwendungsentwicklung. Die [Performance-Richtlinien](/guidelines/PERFORMANCE-GUIDELINES.md) bieten Einblicke in:
- Strategisches Caching
- Lazy Loading
- Optimierung von Datenbankabfragen
- Effiziente Datenstrukturen
- Speichernutzung
## Teststrategien
Testen ist ein integraler Bestandteil des Entwicklungsprozesses. Die [Testing-Richtlinien](/guidelines/TESTING-GUIDELINES.md) decken folgende Themen ab:
- Unit Tests mit Pest-Framework
- Integrationstests
- Test-Fixtures und Factories
- Mocking-Strategien
- Testorganisation und -struktur
## Anwendung der Richtlinien
Diese Richtlinien sollten in allen Phasen der Entwicklung berücksichtigt werden:
1. **Planungsphase**: Frühzeitige Berücksichtigung von Performance und Testbarkeit
2. **Implementierungsphase**: Anwendung der Best Practices während der Entwicklung
3. **Review-Phase**: Überprüfung des Codes anhand der Richtlinien
4. **Refactoring**: Verbesserung bestehenden Codes gemäß den Richtlinien
## Continuous Improvement
Diese Richtlinien werden kontinuierlich verbessert und aktualisiert. Wenn Sie Vorschläge zur Verbesserung haben, zögern Sie nicht, diese einzubringen.

727
docs/guides/controllers.md Normal file
View File

@@ -0,0 +1,727 @@
# Controller-Anleitung
Diese Anleitung erklärt, wie Controller im Framework funktionieren und wie Sie sie effektiv nutzen können.
## Was sind Controller?
Controller sind Klassen, die für die Verarbeitung von HTTP-Anfragen verantwortlich sind. Sie nehmen Anfragen entgegen, führen die erforderliche Geschäftslogik aus und geben Antworten zurück. Controller dienen als Vermittler zwischen den Modellen (Daten und Geschäftslogik) und den Views (Präsentationsschicht).
## Grundlegende Controller
### Erstellen eines Controllers
Controller werden im Verzeichnis `src/Application/Controllers` gespeichert. Ein einfacher Controller sieht wie folgt aus:
```php
<?php
namespace App\Application\Controllers;
use App\Framework\Http\Controller;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
class UserController extends Controller
{
public function index(Request $request): Response
{
return $this->view('users.index', [
'users' => User::all()
]);
}
public function show(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->notFound('Benutzer nicht gefunden');
}
return $this->view('users.show', [
'user' => $user
]);
}
}
```
### Controller-Basisklasse
Alle Controller sollten von der `App\Framework\Http\Controller`-Klasse erben, die nützliche Methoden für die Erstellung von Antworten bereitstellt:
```php
// Gibt eine View zurück
$this->view('users.index', ['users' => $users]);
// Gibt JSON zurück
$this->json(['name' => 'John', 'email' => 'john@example.com']);
// Leitet zu einer anderen URL um
$this->redirect('/users');
// Leitet zurück zur vorherigen Seite um
$this->back();
// Gibt einen Fehler zurück
$this->error('Ein Fehler ist aufgetreten', 500);
// Gibt einen 404-Fehler zurück
$this->notFound('Seite nicht gefunden');
// Gibt einen 403-Fehler zurück
$this->forbidden('Zugriff verweigert');
// Gibt eine leere Antwort zurück
$this->noContent();
```
## Anfragen verarbeiten
### Zugriff auf Anfragedaten
Sie können auf die Daten einer Anfrage über das `Request`-Objekt zugreifen:
```php
public function store(Request $request): Response
{
// Zugriff auf Formulardaten
$name = $request->input('name');
$email = $request->input('email');
// Zugriff auf Formulardaten mit Standardwert
$age = $request->input('age', 18);
// Prüfen, ob ein Feld vorhanden ist
if ($request->has('address')) {
// ...
}
// Zugriff auf alle Formulardaten
$data = $request->all();
// Zugriff auf bestimmte Formulardaten
$userData = $request->only(['name', 'email']);
$nonUserData = $request->except(['name', 'email']);
// Zugriff auf URL-Parameter
$page = $request->query('page', 1);
// Zugriff auf Dateien
$file = $request->file('avatar');
// Zugriff auf Header
$token = $request->header('Authorization');
// Zugriff auf Cookies
$remember = $request->cookie('remember', false);
// Zugriff auf die Anfragemethode
$method = $request->method();
// Prüfen, ob die Anfrage eine AJAX-Anfrage ist
if ($request->isAjax()) {
// ...
}
// Prüfen, ob die Anfrage eine bestimmte Methode verwendet
if ($request->isMethod('POST')) {
// ...
}
// Zugriff auf die Anfrage-URL
$url = $request->url();
// Zugriff auf die vollständige Anfrage-URL mit Abfrageparametern
$fullUrl = $request->fullUrl();
// Zugriff auf den Pfad der Anfrage
$path = $request->path();
}
```
### Validierung von Anfragedaten
Sie können Anfragedaten direkt im Controller validieren:
```php
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
]);
// Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
$user = User::create($request->only(['name', 'email', 'password']));
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
Wenn die Validierung fehlschlägt, wird automatisch eine Antwort mit den Validierungsfehlern zurückgegeben. Bei einer regulären Anfrage wird der Benutzer zur vorherigen Seite umgeleitet, bei einer AJAX-Anfrage wird eine JSON-Antwort mit den Fehlern zurückgegeben.
Weitere Informationen zur Validierung finden Sie in der [Validierungs-Anleitung](validation.md).
## Antworten erstellen
### HTML-Antworten
Um eine HTML-Antwort zu erstellen, verwenden Sie die `view`-Methode:
```php
public function index(): Response
{
$users = User::all();
return $this->view('users.index', [
'users' => $users
]);
}
```
Die `view`-Methode akzeptiert den Namen der View und ein Array mit Daten, die an die View übergeben werden sollen. Der Name der View entspricht dem Pfad der View-Datei relativ zum Verzeichnis `resources/views`, wobei Punkte als Verzeichnistrennzeichen verwendet werden. Im obigen Beispiel wird die Datei `resources/views/users/index.php` gerendert.
### JSON-Antworten
Um eine JSON-Antwort zu erstellen, verwenden Sie die `json`-Methode:
```php
public function index(): Response
{
$users = User::all();
return $this->json([
'users' => $users
]);
}
```
Die `json`-Methode akzeptiert ein Array oder ein Objekt, das in JSON konvertiert werden soll, und einen optionalen HTTP-Statuscode:
```php
return $this->json(['error' => 'Nicht gefunden'], 404);
```
### Weiterleitungen
Um eine Weiterleitung zu erstellen, verwenden Sie die `redirect`-Methode:
```php
public function store(Request $request): Response
{
// Benutzer erstellen
return $this->redirect('/users');
}
```
Sie können auch zur vorherigen Seite umleiten:
```php
public function store(Request $request): Response
{
// Validierungsfehler
return $this->back();
}
```
Sie können Flash-Daten mit der Weiterleitung senden:
```php
return $this->redirect('/users')
->with('success', 'Benutzer erstellt');
```
Diese Flash-Daten sind in der nächsten Anfrage über die Session verfügbar:
```php
$message = $request->session()->get('success');
```
### Fehlerantworten
Um eine Fehlerantwort zu erstellen, verwenden Sie eine der Fehlermethoden:
```php
// 404 Not Found
return $this->notFound('Benutzer nicht gefunden');
// 403 Forbidden
return $this->forbidden('Sie haben keine Berechtigung, diesen Benutzer zu bearbeiten');
// 401 Unauthorized
return $this->unauthorized('Bitte melden Sie sich an');
// 400 Bad Request
return $this->badRequest('Ungültige Anfrage');
// 500 Internal Server Error
return $this->error('Ein Fehler ist aufgetreten');
```
### Datei-Downloads
Um eine Datei zum Download anzubieten, verwenden Sie die `download`-Methode:
```php
public function download(int $id): Response
{
$file = File::find($id);
return $this->download($file->path, $file->name);
}
```
### Datei-Streams
Um eine Datei zu streamen, verwenden Sie die `stream`-Methode:
```php
public function stream(int $id): Response
{
$video = Video::find($id);
return $this->stream($video->path, $video->mime_type);
}
```
## Dependency Injection
Das Framework unterstützt Dependency Injection in Controller-Konstruktoren und -Methoden:
```php
class UserController extends Controller
{
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function index(Request $request, Logger $logger): Response
{
$logger->info('Benutzerindex aufgerufen');
$users = $this->userRepository->all();
return $this->view('users.index', [
'users' => $users
]);
}
}
```
## Middleware
Sie können Middleware auf Controller-Ebene anwenden, indem Sie die `middleware`-Methode im Konstruktor aufrufen:
```php
class AdminController extends Controller
{
public function __construct()
{
$this->middleware(AuthMiddleware::class);
$this->middleware(AdminMiddleware::class);
}
// ...
}
```
Sie können die Middleware auch auf bestimmte Methoden beschränken:
```php
public function __construct()
{
$this->middleware(AuthMiddleware::class)->only(['index', 'show']);
$this->middleware(AdminMiddleware::class)->except(['index', 'show']);
}
```
## Ressourcen-Controller
Ressourcen-Controller bieten eine bequeme Möglichkeit, CRUD-Operationen für eine Ressource zu implementieren. Ein Ressourcen-Controller enthält die folgenden Methoden:
- `index`: Zeigt eine Liste aller Ressourcen an
- `create`: Zeigt ein Formular zum Erstellen einer neuen Ressource an
- `store`: Speichert eine neu erstellte Ressource
- `show`: Zeigt eine bestimmte Ressource an
- `edit`: Zeigt ein Formular zum Bearbeiten einer Ressource an
- `update`: Aktualisiert eine bestimmte Ressource
- `destroy`: Löscht eine bestimmte Ressource
Hier ist ein Beispiel für einen Ressourcen-Controller:
```php
class PhotoController extends Controller
{
public function index(): Response
{
$photos = Photo::all();
return $this->view('photos.index', [
'photos' => $photos
]);
}
public function create(): Response
{
return $this->view('photos.create');
}
public function store(Request $request): Response
{
$this->validate($request, [
'title' => 'required|string|max:255',
'image' => 'required|image|max:2048',
]);
$photo = new Photo();
$photo->title = $request->input('title');
$photo->path = $request->file('image')->store('photos');
$photo->save();
return $this->redirect('/photos')->with('success', 'Foto hochgeladen');
}
public function show(int $id): Response
{
$photo = Photo::find($id);
if (!$photo) {
return $this->notFound('Foto nicht gefunden');
}
return $this->view('photos.show', [
'photo' => $photo
]);
}
public function edit(int $id): Response
{
$photo = Photo::find($id);
if (!$photo) {
return $this->notFound('Foto nicht gefunden');
}
return $this->view('photos.edit', [
'photo' => $photo
]);
}
public function update(Request $request, int $id): Response
{
$photo = Photo::find($id);
if (!$photo) {
return $this->notFound('Foto nicht gefunden');
}
$this->validate($request, [
'title' => 'required|string|max:255',
]);
$photo->title = $request->input('title');
$photo->save();
return $this->redirect('/photos')->with('success', 'Foto aktualisiert');
}
public function destroy(int $id): Response
{
$photo = Photo::find($id);
if (!$photo) {
return $this->notFound('Foto nicht gefunden');
}
$photo->delete();
return $this->redirect('/photos')->with('success', 'Foto gelöscht');
}
}
```
Um einen Ressourcen-Controller zu registrieren, verwenden Sie die `resource`-Methode des Routers:
```php
$router->resource('photos', PhotoController::class);
```
## API-Controller
API-Controller sind ähnlich wie reguläre Controller, geben jedoch in der Regel JSON-Antworten zurück:
```php
class ApiUserController extends Controller
{
public function index(): Response
{
$users = User::all();
return $this->json([
'data' => $users
]);
}
public function show(int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
return $this->json([
'data' => $user
]);
}
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
$user = User::create($request->only(['name', 'email', 'password']));
return $this->json([
'data' => $user,
'message' => 'Benutzer erstellt'
], 201);
}
public function update(Request $request, int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
$this->validate($request, [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $id,
]);
$user->fill($request->only(['name', 'email']));
$user->save();
return $this->json([
'data' => $user,
'message' => 'Benutzer aktualisiert'
]);
}
public function destroy(int $id): Response
{
$user = User::find($id);
if (!$user) {
return $this->json([
'error' => 'Benutzer nicht gefunden'
], 404);
}
$user->delete();
return $this->json([
'message' => 'Benutzer gelöscht'
]);
}
}
```
## Single Action Controller
Wenn ein Controller nur eine einzige Aktion ausführt, können Sie einen Single Action Controller erstellen, der die `__invoke`-Methode implementiert:
```php
class ShowDashboardController extends Controller
{
public function __invoke(Request $request): Response
{
$stats = [
'users' => User::count(),
'posts' => Post::count(),
'comments' => Comment::count(),
];
return $this->view('dashboard', [
'stats' => $stats
]);
}
}
```
Um einen Single Action Controller zu registrieren, geben Sie einfach die Controller-Klasse an:
```php
$router->get('/dashboard', ShowDashboardController::class);
```
## Controller-Organisation
### Namensräume
Sie können Controller in Namensräumen organisieren, um sie besser zu strukturieren:
```php
namespace App\Application\Controllers\Admin;
class UserController extends Controller
{
// ...
}
```
### Controller-Gruppen
Sie können Controller in Gruppen organisieren, indem Sie Routengruppen mit einem Namensraum verwenden:
```php
$router->group('/admin', function (Router $router) {
$router->get('/users', [UserController::class, 'index']);
$router->get('/posts', [PostController::class, 'index']);
})->namespace('App\\Application\\Controllers\\Admin');
```
## Beste Praktiken
### Schlanke Controller
Controller sollten schlank sein und sich auf die Verarbeitung von HTTP-Anfragen konzentrieren. Komplexe Geschäftslogik sollte in Service-Klassen oder Modelle ausgelagert werden:
```php
class UserController extends Controller
{
private UserService $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
]);
$user = $this->userService->createUser(
$request->input('name'),
$request->input('email'),
$request->input('password')
);
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
}
```
### Wiederverwendung von Validierungsregeln
Wenn Sie dieselben Validierungsregeln in mehreren Controllern verwenden, sollten Sie sie in eine separate Klasse auslagern:
```php
class UserValidationRules
{
public static function forCreation(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
];
}
public static function forUpdate(int $userId): array
{
return [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $userId,
];
}
}
```
Dann können Sie diese Regeln in Ihren Controllern verwenden:
```php
public function store(Request $request): Response
{
$this->validate($request, UserValidationRules::forCreation());
// ...
}
public function update(Request $request, int $id): Response
{
$this->validate($request, UserValidationRules::forUpdate($id));
// ...
}
```
### Verwendung von Form Requests
Für komplexe Validierungslogik können Sie Form Request-Klassen erstellen:
```php
class CreateUserRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
];
}
public function messages(): array
{
return [
'name.required' => 'Der Name ist erforderlich',
'email.unique' => 'Diese E-Mail-Adresse wird bereits verwendet',
];
}
public function authorize(): bool
{
return $this->user()->hasPermission('create-users');
}
}
```
Dann können Sie die Form Request-Klasse in Ihrem Controller verwenden:
```php
public function store(CreateUserRequest $request): Response
{
// Die Validierung wurde bereits durchgeführt
$user = User::create($request->validated());
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
## Weitere Informationen
- [Routing-Anleitung](routing.md): Erfahren Sie mehr über das Routing-System und wie es mit Controllern interagiert.
- [Validierungs-Anleitung](validation.md): Erfahren Sie mehr über die Validierung von Benutzereingaben.
- [Middleware-Anleitung](middleware.md): Erfahren Sie mehr über Middleware und wie sie mit Controllern interagiert.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

370
docs/guides/routing.md Normal file
View File

@@ -0,0 +1,370 @@
# Routing-Anleitung
Diese Anleitung erklärt, wie das Routing-System des Frameworks funktioniert und wie Sie es effektiv nutzen können.
## Grundlagen des Routings
Das Routing-System ist verantwortlich für das Mapping von HTTP-Anfragen zu Controller-Aktionen. Es ermöglicht Ihnen, URLs zu definieren und festzulegen, welcher Code ausgeführt werden soll, wenn diese URLs aufgerufen werden.
### Routing-Konfiguration
Die Routing-Konfiguration befindet sich in der Datei `config/routes.php`. Diese Datei gibt eine Funktion zurück, die einen Router als Parameter erhält:
```php
<?php
use App\Framework\Routing\Router;
use App\Application\Controllers\HomeController;
use App\Application\Controllers\UserController;
return function (Router $router) {
// Hier werden Routen definiert
$router->get('/', [HomeController::class, 'index']);
$router->get('/users', [UserController::class, 'index']);
$router->get('/users/{id}', [UserController::class, 'show']);
};
```
## Definieren von Routen
### Grundlegende Routen
Sie können Routen für verschiedene HTTP-Methoden definieren:
```php
// GET-Route
$router->get('/users', [UserController::class, 'index']);
// POST-Route
$router->post('/users', [UserController::class, 'store']);
// PUT-Route
$router->put('/users/{id}', [UserController::class, 'update']);
// PATCH-Route
$router->patch('/users/{id}', [UserController::class, 'update']);
// DELETE-Route
$router->delete('/users/{id}', [UserController::class, 'destroy']);
// Mehrere HTTP-Methoden
$router->match(['GET', 'POST'], '/users/search', [UserController::class, 'search']);
// Alle HTTP-Methoden
$router->any('/users/all', [UserController::class, 'all']);
```
### Routenparameter
Sie können dynamische Segmente in Ihren Routen definieren, indem Sie geschweifte Klammern verwenden:
```php
$router->get('/users/{id}', [UserController::class, 'show']);
$router->get('/posts/{post}/comments/{comment}', [CommentController::class, 'show']);
```
Diese Parameter werden automatisch an die Controller-Methode übergeben:
```php
public function show(Request $request, int $id): Response
{
$user = User::find($id);
// ...
}
public function show(Request $request, int $post, int $comment): Response
{
$post = Post::find($post);
$comment = Comment::find($comment);
// ...
}
```
### Optionale Parameter
Sie können optionale Parameter definieren, indem Sie ein Fragezeichen nach dem Parameternamen hinzufügen:
```php
$router->get('/users/{id?}', [UserController::class, 'show']);
```
In diesem Fall müssen Sie in Ihrer Controller-Methode einen Standardwert für den Parameter angeben:
```php
public function show(Request $request, int $id = null): Response
{
if ($id === null) {
// Alle Benutzer anzeigen
} else {
// Einen bestimmten Benutzer anzeigen
}
// ...
}
```
### Parametereinschränkungen
Sie können Einschränkungen für Routenparameter definieren, um sicherzustellen, dass sie einem bestimmten Muster entsprechen:
```php
$router->get('/users/{id}', [UserController::class, 'show'])
->where('id', '[0-9]+');
$router->get('/posts/{slug}', [PostController::class, 'show'])
->where('slug', '[a-z0-9-]+');
$router->get('/categories/{category}/posts/{post}', [PostController::class, 'showInCategory'])
->where(['category' => '[a-z0-9-]+', 'post' => '[0-9]+']);
```
### Benannte Routen
Sie können Routen benennen, um später einfacher auf sie verweisen zu können:
```php
$router->get('/users/{id}', [UserController::class, 'show'])
->name('users.show');
```
Sie können dann URLs für benannte Routen generieren:
```php
$url = route('users.show', ['id' => 1]); // /users/1
```
## Routengruppen
Routengruppen ermöglichen es Ihnen, gemeinsame Attribute auf mehrere Routen anzuwenden, ohne sie für jede Route einzeln definieren zu müssen.
### Präfixe
Sie können ein Präfix für eine Gruppe von Routen definieren:
```php
$router->group('/admin', function (Router $router) {
$router->get('/dashboard', [AdminController::class, 'dashboard']);
$router->get('/users', [AdminController::class, 'users']);
$router->get('/settings', [AdminController::class, 'settings']);
});
```
Dies definiert die folgenden Routen:
- `/admin/dashboard`
- `/admin/users`
- `/admin/settings`
### Middleware
Sie können Middleware für eine Gruppe von Routen definieren:
```php
$router->group('', function (Router $router) {
$router->get('/dashboard', [AdminController::class, 'dashboard']);
$router->get('/users', [AdminController::class, 'users']);
$router->get('/settings', [AdminController::class, 'settings']);
})->middleware(AuthMiddleware::class);
```
Sie können auch mehrere Middleware-Klassen angeben:
```php
$router->group('', function (Router $router) {
// Routen
})->middleware([AuthMiddleware::class, AdminMiddleware::class]);
```
### Namensräume
Sie können einen Namensraum für eine Gruppe von Routen definieren:
```php
$router->group('', function (Router $router) {
$router->get('/users', ['UserController', 'index']);
$router->get('/posts', ['PostController', 'index']);
})->namespace('App\\Application\\Controllers\\Admin');
```
In diesem Fall werden die Controller-Klassen im Namensraum `App\Application\Controllers\Admin` gesucht, also `App\Application\Controllers\Admin\UserController` und `App\Application\Controllers\Admin\PostController`.
### Kombinierte Attribute
Sie können mehrere Attribute für eine Gruppe von Routen kombinieren:
```php
$router->group('/admin', function (Router $router) {
$router->get('/dashboard', ['DashboardController', 'index']);
$router->get('/users', ['UserController', 'index']);
})
->namespace('App\\Application\\Controllers\\Admin')
->middleware([AuthMiddleware::class, AdminMiddleware::class])
->name('admin.');
```
Dies definiert die folgenden Routen:
- `/admin/dashboard` mit dem Namen `admin.dashboard`
- `/admin/users` mit dem Namen `admin.users`
Beide Routen verwenden die Controller im Namensraum `App\Application\Controllers\Admin` und durchlaufen die `AuthMiddleware` und `AdminMiddleware`.
## Verschachtelte Gruppen
Sie können Routengruppen verschachteln, um komplexere Strukturen zu erstellen:
```php
$router->group('/admin', function (Router $router) {
$router->get('/dashboard', [AdminController::class, 'dashboard']);
$router->group('/users', function (Router $router) {
$router->get('/', [AdminUserController::class, 'index']);
$router->get('/{id}', [AdminUserController::class, 'show']);
$router->put('/{id}', [AdminUserController::class, 'update']);
$router->delete('/{id}', [AdminUserController::class, 'destroy']);
});
$router->group('/settings', function (Router $router) {
$router->get('/', [AdminSettingsController::class, 'index']);
$router->put('/general', [AdminSettingsController::class, 'updateGeneral']);
$router->put('/security', [AdminSettingsController::class, 'updateSecurity']);
});
});
```
## Fallback-Routen
Sie können eine Fallback-Route definieren, die verwendet wird, wenn keine andere Route übereinstimmt:
```php
$router->fallback([NotFoundController::class, 'index']);
```
## Middleware für einzelne Routen
Sie können Middleware auch für einzelne Routen definieren:
```php
$router->get('/profile', [ProfileController::class, 'index'])
->middleware(AuthMiddleware::class);
$router->get('/admin/dashboard', [AdminController::class, 'dashboard'])
->middleware([AuthMiddleware::class, AdminMiddleware::class]);
```
## Routen-Caching
Um die Leistung zu verbessern, können Sie die Routing-Konfiguration cachen:
```bash
php console.php route:cache
```
Dies erstellt eine Cache-Datei, die vom Framework verwendet wird, anstatt die Routen bei jeder Anfrage neu zu analysieren.
Um den Cache zu löschen:
```bash
php console.php route:clear
```
## Routen auflisten
Sie können alle registrierten Routen auflisten:
```bash
php console.php route:list
```
Dies zeigt eine Tabelle mit allen Routen, ihren HTTP-Methoden, URLs, Controller-Aktionen und Namen an.
## Routen-Modell-Binding
Das Framework unterstützt Routen-Modell-Binding, das automatisch Modellinstanzen aus Routenparametern auflöst:
```php
$router->get('/users/{user}', [UserController::class, 'show']);
```
In Ihrem Controller:
```php
public function show(Request $request, User $user): Response
{
// $user ist bereits eine Instanz des User-Modells
return $this->view('users.show', ['user' => $user]);
}
```
Standardmäßig wird der Parameter `{user}` als ID verwendet, um das Modell zu finden. Sie können dieses Verhalten anpassen, indem Sie die Methode `resolveRouteBinding` in Ihrem Modell überschreiben:
```php
public function resolveRouteBinding(string $value): ?static
{
return static::where('username', $value)->first();
}
```
## Ressourcen-Routen
Das Framework bietet eine Möglichkeit, schnell Ressourcen-Routen für CRUD-Operationen zu definieren:
```php
$router->resource('photos', PhotoController::class);
```
Dies erstellt die folgenden Routen:
| HTTP-Methode | URI | Aktion | Routenname |
|--------------|-------------------|----------|----------------|
| GET | /photos | index | photos.index |
| GET | /photos/create | create | photos.create |
| POST | /photos | store | photos.store |
| GET | /photos/{photo} | show | photos.show |
| GET | /photos/{photo}/edit | edit | photos.edit |
| PUT/PATCH | /photos/{photo} | update | photos.update |
| DELETE | /photos/{photo} | destroy | photos.destroy |
Sie können die generierten Routen einschränken:
```php
$router->resource('photos', PhotoController::class)
->only(['index', 'show']);
$router->resource('photos', PhotoController::class)
->except(['create', 'store', 'update', 'destroy']);
```
## API-Ressourcen-Routen
Für APIs können Sie API-Ressourcen-Routen definieren, die keine `create` und `edit` Routen enthalten:
```php
$router->apiResource('photos', PhotoApiController::class);
```
Dies erstellt die folgenden Routen:
| HTTP-Methode | URI | Aktion | Routenname |
|--------------|------------------|----------|----------------|
| GET | /photos | index | photos.index |
| POST | /photos | store | photos.store |
| GET | /photos/{photo} | show | photos.show |
| PUT/PATCH | /photos/{photo} | update | photos.update |
| DELETE | /photos/{photo} | destroy | photos.destroy |
## Verschachtelte Ressourcen
Sie können auch verschachtelte Ressourcen definieren:
```php
$router->resource('photos.comments', PhotoCommentController::class);
```
Dies erstellt Routen wie:
- `/photos/{photo}/comments`
- `/photos/{photo}/comments/{comment}`
## Weitere Informationen
- [Controller-Anleitung](controllers.md): Erfahren Sie mehr über Controller und wie sie mit Routen interagieren.
- [Middleware-Anleitung](middleware.md): Erfahren Sie mehr über Middleware und wie sie im Routing-System verwendet werden.
- [Validierungs-Anleitung](validation.md): Erfahren Sie, wie Sie Benutzereingaben validieren können.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

585
docs/guides/security.md Normal file
View File

@@ -0,0 +1,585 @@
# Sicherheits-Anleitung
Diese Anleitung erklärt die Sicherheitsfunktionen des Frameworks und wie Sie sie effektiv nutzen können, um Ihre Anwendung zu schützen.
## Überblick über die Sicherheitsarchitektur
Das Framework bietet eine mehrschichtige Sicherheitsarchitektur, die verschiedene Schutzmaßnahmen auf verschiedenen Ebenen implementiert:
1. **Eingabevalidierung**: Validierung aller Benutzereingaben, um Injection-Angriffe zu verhindern.
2. **Ausgabebereinigung**: Automatische Bereinigung von Ausgaben, um Cross-Site Scripting (XSS) zu verhindern.
3. **CSRF-Schutz**: Schutz vor Cross-Site Request Forgery.
4. **Authentifizierung**: Flexible Authentifizierungsmechanismen.
5. **Autorisierung**: Rollenbasierte und fähigkeitsbasierte Zugriffskontrolle.
6. **Web Application Firewall (WAF)**: Integrierte WAF zum Schutz vor gängigen Angriffen.
7. **Sicherheitsheader**: Automatische Konfiguration von Sicherheitsheadern.
8. **Sichere Konfiguration**: Sichere Standardeinstellungen und Best Practices.
## Eingabevalidierung
Die Eingabevalidierung ist die erste Verteidigungslinie gegen Injection-Angriffe. Das Framework bietet ein leistungsstarkes Validierungssystem, das in der [Validierungs-Anleitung](validation.md) ausführlich beschrieben wird.
### Beispiel für die Validierung von Benutzereingaben
```php
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
'website' => 'nullable|url',
'age' => 'nullable|integer|min:18',
]);
// Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
$user = User::create($request->only(['name', 'email', 'password']));
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
### Schutz vor SQL-Injection
Das Framework verwendet parametrisierte Abfragen und Prepared Statements, um SQL-Injection-Angriffe zu verhindern:
```php
// Sicher: Verwendung von parametrisierten Abfragen
$users = DB::table('users')
->where('email', $request->input('email'))
->get();
// Sicher: Verwendung des Query Builders
$users = User::where('email', $request->input('email'))->get();
// Sicher: Verwendung von Prepared Statements
$statement = DB::prepare('SELECT * FROM users WHERE email = ?');
$statement->execute([$request->input('email')]);
$users = $statement->fetchAll();
```
## Ausgabebereinigung
### Automatische Bereinigung in Views
Das Framework bereinigt automatisch alle Ausgaben in Views, um XSS-Angriffe zu verhindern:
```php
<!-- Sicher: Automatische Bereinigung -->
<div><?= $user->name ?></div>
<!-- Unsicher: Rohe Ausgabe ohne Bereinigung (nur verwenden, wenn Sie sicher sind, dass der Inhalt vertrauenswürdig ist) -->
<div><?= raw($user->html_content) ?></div>
```
### Manuelle Bereinigung
Sie können auch manuell Daten bereinigen:
```php
use App\Framework\Security\Sanitizer;
// Text bereinigen
$cleanText = Sanitizer::clean($input);
// HTML bereinigen (entfernt gefährliche Tags und Attribute)
$cleanHtml = Sanitizer::cleanHtml($input);
// URL bereinigen
$cleanUrl = Sanitizer::cleanUrl($input);
```
## CSRF-Schutz
Das Framework bietet automatischen Schutz vor Cross-Site Request Forgery (CSRF) für alle Formulare und AJAX-Anfragen.
### CSRF-Token in Formularen
```php
<form method="POST" action="/users">
<?= csrf_field() ?>
<input type="text" name="name">
<button type="submit">Speichern</button>
</form>
```
Die `csrf_field()`-Funktion generiert ein verstecktes Eingabefeld mit einem CSRF-Token:
```html
<input type="hidden" name="_token" value="random-token-here">
```
### CSRF-Token in AJAX-Anfragen
```javascript
// Mit jQuery
$.ajax({
url: '/users',
type: 'POST',
data: {
name: 'John Doe',
_token: '<?= csrf_token() ?>'
}
});
// Mit Fetch API
fetch('/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '<?= csrf_token() ?>'
},
body: JSON.stringify({
name: 'John Doe'
})
});
```
### CSRF-Schutz deaktivieren
In einigen Fällen, wie z.B. bei API-Endpunkten, möchten Sie möglicherweise den CSRF-Schutz deaktivieren:
```php
// In der Middleware-Konfiguration
$middleware->except([
CsrfMiddleware::class => [
'/api/*'
]
]);
```
## Authentifizierung
Das Framework bietet ein flexibles Authentifizierungssystem, das verschiedene Authentifizierungsmethoden unterstützt.
### Benutzerauthentifizierung
```php
use App\Framework\Auth\Auth;
class LoginController extends Controller
{
public function login(Request $request): Response
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|string',
]);
$credentials = $request->only(['email', 'password']);
$remember = $request->input('remember', false);
if (Auth::attempt($credentials, $remember)) {
return $this->redirect('/dashboard');
}
return $this->back()->withErrors([
'email' => 'Die angegebenen Anmeldeinformationen sind ungültig.',
]);
}
public function logout(): Response
{
Auth::logout();
return $this->redirect('/');
}
}
```
### Zugriff auf den authentifizierten Benutzer
```php
// Prüfen, ob ein Benutzer angemeldet ist
if (Auth::check()) {
// Benutzer ist angemeldet
}
// Aktuellen Benutzer abrufen
$user = Auth::user();
// Benutzer-ID abrufen
$userId = Auth::id();
```
### Passwort-Hashing
Das Framework verwendet automatisch sichere Passwort-Hashing-Algorithmen:
```php
use App\Framework\Security\Hash;
// Passwort hashen
$hashedPassword = Hash::make('password');
// Passwort überprüfen
if (Hash::check('password', $hashedPassword)) {
// Passwort ist korrekt
}
// Prüfen, ob ein Passwort neu gehasht werden muss
if (Hash::needsRehash($hashedPassword)) {
$hashedPassword = Hash::make('password');
}
```
### Passwort-Zurücksetzung
Das Framework bietet auch Unterstützung für die Passwort-Zurücksetzung:
```php
use App\Framework\Auth\Password;
// Token für die Passwort-Zurücksetzung erstellen
$token = Password::createToken($user);
// E-Mail mit dem Token senden
Mail::send('emails.reset-password', [
'token' => $token,
'user' => $user
], function ($message) use ($user) {
$message->to($user->email);
$message->subject('Passwort zurücksetzen');
});
// Token überprüfen und Passwort zurücksetzen
$status = Password::reset($request->only(
'email', 'password', 'password_confirmation', 'token'
), function ($user, $password) {
$user->password = Hash::make($password);
$user->save();
});
```
## Autorisierung
Das Framework bietet ein leistungsstarkes Autorisierungssystem, das rollenbasierte und fähigkeitsbasierte Zugriffskontrolle unterstützt.
### Rollenbasierte Zugriffskontrolle
```php
use App\Framework\Auth\Auth;
// Prüfen, ob der Benutzer eine bestimmte Rolle hat
if (Auth::user()->hasRole('admin')) {
// Benutzer ist ein Administrator
}
// Prüfen, ob der Benutzer eine von mehreren Rollen hat
if (Auth::user()->hasAnyRole(['admin', 'editor'])) {
// Benutzer ist entweder Administrator oder Editor
}
// Prüfen, ob der Benutzer alle angegebenen Rollen hat
if (Auth::user()->hasAllRoles(['admin', 'editor'])) {
// Benutzer ist sowohl Administrator als auch Editor
}
```
### Fähigkeitsbasierte Zugriffskontrolle
```php
use App\Framework\Auth\Auth;
// Prüfen, ob der Benutzer eine bestimmte Fähigkeit hat
if (Auth::user()->can('edit-post', $post)) {
// Benutzer kann den Beitrag bearbeiten
}
// Prüfen, ob der Benutzer eine Fähigkeit nicht hat
if (Auth::user()->cannot('delete-post', $post)) {
// Benutzer kann den Beitrag nicht löschen
}
// Autorisierung erzwingen (wirft eine Exception, wenn nicht autorisiert)
Auth::user()->authorize('edit-post', $post);
```
### Richtlinien definieren
Sie können Autorisierungsrichtlinien definieren, um komplexe Autorisierungslogik zu kapseln:
```php
use App\Framework\Auth\Policy;
class PostPolicy extends Policy
{
public function view(User $user, Post $post): bool
{
return true; // Jeder kann Beiträge sehen
}
public function create(User $user): bool
{
return $user->hasRole('writer');
}
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->hasRole('editor');
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->hasRole('admin');
}
}
```
Registrieren Sie die Richtlinie:
```php
use App\Framework\Auth\Gate;
// In der Bootstrap-Datei
Gate::policy(Post::class, PostPolicy::class);
```
Verwenden Sie die Richtlinie:
```php
if (Auth::user()->can('update', $post)) {
// Benutzer kann den Beitrag aktualisieren
}
```
### Autorisierung in Controllern
Sie können die Autorisierung auch direkt in Controllern verwenden:
```php
public function update(Request $request, int $id): Response
{
$post = Post::find($id);
if (!$post) {
return $this->notFound('Beitrag nicht gefunden');
}
$this->authorize('update', $post);
// Beitrag aktualisieren
return $this->redirect('/posts')->with('success', 'Beitrag aktualisiert');
}
```
## Web Application Firewall (WAF)
Das Framework enthält eine integrierte Web Application Firewall (WAF), die Ihre Anwendung vor gängigen Angriffen schützt.
### WAF-Konfiguration
Die WAF ist standardmäßig aktiviert und kann in der Konfigurationsdatei `config/security.php` konfiguriert werden:
```php
return [
'waf' => [
'enabled' => true,
'rules' => [
'sql_injection' => true,
'xss' => true,
'command_injection' => true,
'path_traversal' => true,
'request_validation' => true,
],
'whitelist' => [
'ip' => [
'127.0.0.1',
'::1',
],
'paths' => [
'/api/webhook',
],
],
'blacklist' => [
'ip' => [
// Blockierte IP-Adressen
],
'user_agents' => [
'Bad Bot',
],
],
'rate_limiting' => [
'enabled' => true,
'max_requests' => 100,
'time_window' => 60, // Sekunden
],
],
];
```
### Maschinelles Lernen für die Angriffserkennung
Die WAF verwendet auch maschinelles Lernen, um Anomalien zu erkennen und potenzielle Angriffe zu identifizieren:
```php
use App\Framework\Waf\MachineLearning\MachineLearningEngine;
// In einem Controller oder Service
$mlEngine = $this->container->get(MachineLearningEngine::class);
$anomalyScore = $mlEngine->detectAnomalies($request);
if ($anomalyScore > 0.8) {
// Verdächtige Anfrage protokollieren oder blockieren
$this->logger->warning('Verdächtige Anfrage erkannt', [
'ip' => $request->ip(),
'path' => $request->path(),
'score' => $anomalyScore,
]);
}
```
## Sicherheitsheader
Das Framework konfiguriert automatisch wichtige Sicherheitsheader, um Ihre Anwendung zu schützen.
### Content Security Policy (CSP)
Die Content Security Policy schützt vor XSS-Angriffen, indem sie kontrolliert, welche Ressourcen geladen werden dürfen:
```php
use App\Framework\Security\ContentSecurityPolicy;
// In einem Middleware oder Controller
$csp = new ContentSecurityPolicy();
$csp->setDefaultSrc(['self'])
->setScriptSrc(['self', 'trusted-scripts.com'])
->setStyleSrc(['self', 'trusted-styles.com'])
->setImgSrc(['self', 'trusted-images.com'])
->setFontSrc(['self', 'trusted-fonts.com'])
->setConnectSrc(['self', 'api.trusted-domain.com'])
->setFrameSrc(['none'])
->setObjectSrc(['none'])
->setReportUri('/csp-report');
$response->headers->set('Content-Security-Policy', $csp->compile());
```
### Andere Sicherheitsheader
Das Framework setzt auch andere wichtige Sicherheitsheader:
```php
// In einem Middleware oder Controller
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
```
## Sichere Konfiguration
### HTTPS erzwingen
Sie können HTTPS für Ihre Anwendung erzwingen:
```php
// In der Middleware-Konfiguration
$middleware->add(HttpsMiddleware::class);
```
### Sichere Cookies
Das Framework konfiguriert automatisch sichere Cookies:
```php
// In der Konfigurationsdatei config/session.php
return [
'cookie' => [
'secure' => true,
'http_only' => true,
'same_site' => 'lax',
],
];
```
### Sichere Datei-Uploads
Das Framework bietet Funktionen für sichere Datei-Uploads:
```php
use App\Framework\Security\FileValidator;
// In einem Controller
$this->validate($request, [
'document' => 'required|file|mimes:pdf,doc,docx|max:10240',
]);
$file = $request->file('document');
// Zusätzliche Sicherheitsvalidierung
$validator = new FileValidator();
if (!$validator->isSafe($file)) {
return $this->back()->withErrors([
'document' => 'Die Datei ist möglicherweise schädlich.',
]);
}
// Datei speichern
$path = $file->store('documents');
```
## Sicherheitsprotokollierung und -überwachung
Das Framework bietet umfangreiche Protokollierung für Sicherheitsereignisse:
```php
use App\Framework\Security\SecurityLogger;
// In einem Controller oder Service
$securityLogger = $this->container->get(SecurityLogger::class);
// Sicherheitsereignis protokollieren
$securityLogger->log('authentication_failure', [
'user_id' => $user->id,
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
]);
```
### Sicherheitsbenachrichtigungen
Sie können auch Benachrichtigungen für wichtige Sicherheitsereignisse konfigurieren:
```php
use App\Framework\Security\SecurityNotifier;
// In einem Controller oder Service
$securityNotifier = $this->container->get(SecurityNotifier::class);
// Benachrichtigung senden
$securityNotifier->notify('suspicious_login', [
'user_id' => $user->id,
'ip' => $request->ip(),
'location' => $geoip->getLocation($request->ip()),
'time' => now(),
]);
```
## Sicherheits-Checkliste
Hier ist eine Checkliste, um sicherzustellen, dass Ihre Anwendung sicher ist:
1. **Eingabevalidierung**: Validieren Sie alle Benutzereingaben.
2. **Ausgabebereinigung**: Bereinigen Sie alle Ausgaben, um XSS zu verhindern.
3. **CSRF-Schutz**: Verwenden Sie CSRF-Token in allen Formularen und AJAX-Anfragen.
4. **Authentifizierung**: Implementieren Sie sichere Authentifizierungsmechanismen.
5. **Autorisierung**: Implementieren Sie rollenbasierte und fähigkeitsbasierte Zugriffskontrolle.
6. **Sichere Passwörter**: Verwenden Sie sichere Passwort-Hashing-Algorithmen.
7. **HTTPS**: Erzwingen Sie HTTPS für Ihre Anwendung.
8. **Sichere Cookies**: Konfigurieren Sie sichere Cookies.
9. **Sicherheitsheader**: Setzen Sie wichtige Sicherheitsheader.
10. **Datei-Uploads**: Validieren Sie Datei-Uploads sorgfältig.
11. **Fehlerbehandlung**: Zeigen Sie keine sensiblen Informationen in Fehlermeldungen an.
12. **Protokollierung**: Protokollieren Sie Sicherheitsereignisse.
13. **Aktualisierungen**: Halten Sie das Framework und alle Abhängigkeiten aktuell.
## Weitere Informationen
- [Authentifizierungs-Anleitung](authentication.md): Erfahren Sie mehr über die Authentifizierungsfunktionen des Frameworks.
- [Autorisierungs-Anleitung](authorization.md): Erfahren Sie mehr über die Autorisierungsfunktionen des Frameworks.
- [WAF-Anleitung](../components/waf/index.md): Erfahren Sie mehr über die Web Application Firewall des Frameworks.
- [Validierungs-Anleitung](validation.md): Erfahren Sie mehr über die Validierungsfunktionen des Frameworks.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

539
docs/guides/validation.md Normal file
View File

@@ -0,0 +1,539 @@
# Validierungs-Anleitung
Diese Anleitung erklärt, wie das Validierungssystem des Frameworks funktioniert und wie Sie es effektiv nutzen können.
## Grundlagen der Validierung
Die Validierung ist ein wichtiger Teil jeder Webanwendung, da sie sicherstellt, dass die Daten, die von Benutzern eingegeben werden, den erwarteten Regeln entsprechen. Das Framework bietet ein leistungsstarkes und flexibles Validierungssystem, das einfach zu verwenden ist.
### Validierung in Controllern
Die einfachste Möglichkeit, Daten zu validieren, ist die Verwendung der `validate`-Methode in Controllern:
```php
public function store(Request $request): Response
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
'age' => 'integer|min:18',
]);
// Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
$user = User::create($request->only(['name', 'email', 'password']));
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
Wenn die Validierung fehlschlägt, wird automatisch eine Antwort mit den Validierungsfehlern zurückgegeben:
- Bei einer regulären Anfrage wird der Benutzer zur vorherigen Seite umgeleitet, und die Validierungsfehler werden in der Session gespeichert.
- Bei einer AJAX-Anfrage wird eine JSON-Antwort mit den Validierungsfehlern und dem HTTP-Statuscode 422 zurückgegeben.
### Manuelle Validierung
Sie können auch den Validator direkt verwenden, um mehr Kontrolle über den Validierungsprozess zu haben:
```php
use App\Framework\Validation\Validator;
public function store(Request $request): Response
{
$validator = new Validator($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
]);
if ($validator->fails()) {
$errors = $validator->errors();
// Fehler behandeln
return $this->back()->withErrors($errors);
}
// Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
$user = User::create($request->only(['name', 'email', 'password']));
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
## Validierungsregeln
Das Framework bietet eine Vielzahl von Validierungsregeln, die Sie verwenden können, um Ihre Daten zu validieren.
### Grundlegende Regeln
- `required`: Das Feld muss vorhanden sein und darf nicht leer sein.
- `string`: Das Feld muss ein String sein.
- `integer`: Das Feld muss eine Ganzzahl sein.
- `numeric`: Das Feld muss eine Zahl sein (Ganzzahl oder Dezimalzahl).
- `boolean`: Das Feld muss ein Boolean sein (`true`, `false`, `1`, `0`, `"1"`, `"0"`).
- `array`: Das Feld muss ein Array sein.
- `date`: Das Feld muss ein gültiges Datum sein.
- `email`: Das Feld muss eine gültige E-Mail-Adresse sein.
- `url`: Das Feld muss eine gültige URL sein.
- `ip`: Das Feld muss eine gültige IP-Adresse sein.
- `json`: Das Feld muss ein gültiger JSON-String sein.
- `alpha`: Das Feld darf nur Buchstaben enthalten.
- `alpha_num`: Das Feld darf nur Buchstaben und Zahlen enthalten.
- `alpha_dash`: Das Feld darf nur Buchstaben, Zahlen, Bindestriche und Unterstriche enthalten.
### Größenregeln
- `min:value`: Das Feld muss mindestens `value` groß sein.
- Für Strings: Die Anzahl der Zeichen.
- Für Zahlen: Der Mindestwert.
- Für Arrays: Die Mindestanzahl der Elemente.
- Für Dateien: Die Mindestgröße in Kilobyte.
- `max:value`: Das Feld darf höchstens `value` groß sein.
- `size:value`: Das Feld muss genau `value` groß sein.
- `between:min,max`: Das Feld muss zwischen `min` und `max` liegen.
### Vergleichsregeln
- `same:field`: Das Feld muss den gleichen Wert wie `field` haben.
- `different:field`: Das Feld muss einen anderen Wert als `field` haben.
- `gt:field`: Das Feld muss größer als `field` sein.
- `gte:field`: Das Feld muss größer oder gleich `field` sein.
- `lt:field`: Das Feld muss kleiner als `field` sein.
- `lte:field`: Das Feld muss kleiner oder gleich `field` sein.
### Datenbankregeln
- `unique:table,column,except,idColumn`: Das Feld muss in der angegebenen Tabelle und Spalte einzigartig sein.
- `table`: Der Name der Tabelle.
- `column`: Der Name der Spalte (standardmäßig der Feldname).
- `except`: Die ID des Datensatzes, der bei der Überprüfung ignoriert werden soll (optional).
- `idColumn`: Der Name der ID-Spalte (standardmäßig `id`).
- `exists:table,column`: Das Feld muss in der angegebenen Tabelle und Spalte existieren.
### Dateiregeln
- `file`: Das Feld muss eine erfolgreich hochgeladene Datei sein.
- `image`: Das Feld muss ein Bild sein (jpeg, png, bmp, gif, svg).
- `mimes:jpeg,png,...`: Das Feld muss eine Datei mit einem der angegebenen MIME-Typen sein.
- `mimetypes:text/plain,...`: Das Feld muss eine Datei mit einem der angegebenen MIME-Typen sein.
- `dimensions:min_width=100,max_width=1000,min_height=100,max_height=1000,width=100,height=100,ratio=1/1`: Das Feld muss ein Bild sein, das den angegebenen Dimensionen entspricht.
### Bedingte Regeln
- `required_if:anotherfield,value,...`: Das Feld ist erforderlich, wenn `anotherfield` einen der angegebenen Werte hat.
- `required_unless:anotherfield,value,...`: Das Feld ist erforderlich, es sei denn, `anotherfield` hat einen der angegebenen Werte.
- `required_with:foo,bar,...`: Das Feld ist erforderlich, wenn eines der anderen angegebenen Felder vorhanden ist.
- `required_with_all:foo,bar,...`: Das Feld ist erforderlich, wenn alle anderen angegebenen Felder vorhanden sind.
- `required_without:foo,bar,...`: Das Feld ist erforderlich, wenn eines der anderen angegebenen Felder nicht vorhanden ist.
- `required_without_all:foo,bar,...`: Das Feld ist erforderlich, wenn alle anderen angegebenen Felder nicht vorhanden sind.
### Formatregeln
- `date_format:format`: Das Feld muss dem angegebenen Datumsformat entsprechen.
- `regex:pattern`: Das Feld muss dem angegebenen regulären Ausdruck entsprechen.
- `not_regex:pattern`: Das Feld darf nicht dem angegebenen regulären Ausdruck entsprechen.
### Bestätigungsregeln
- `confirmed`: Das Feld muss ein Bestätigungsfeld haben (z.B. `password_confirmation` für das Feld `password`).
- `accepted`: Das Feld muss akzeptiert werden (yes, on, 1, true).
### Spezielle Regeln
- `nullable`: Das Feld darf `null` sein.
- `present`: Das Feld muss im Eingabedaten vorhanden sein, kann aber leer sein.
- `sometimes`: Die Regel wird nur angewendet, wenn das Feld vorhanden ist.
## Benutzerdefinierte Validierungsnachrichten
Sie können benutzerdefinierte Validierungsnachrichten angeben, um die Standardnachrichten zu überschreiben:
```php
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
], [
'name.required' => 'Der Name ist erforderlich',
'email.unique' => 'Diese E-Mail-Adresse wird bereits verwendet',
'password.min' => 'Das Passwort muss mindestens 8 Zeichen lang sein',
]);
```
Sie können auch Platzhalter in Ihren Nachrichten verwenden:
- `:attribute`: Der Name des Feldes.
- `:min`: Der Mindestwert.
- `:max`: Der Maximalwert.
- `:size`: Die erforderliche Größe.
- `:values`: Die gültigen Werte.
- `:other`: Der Name des anderen Feldes.
```php
'min' => 'Das Feld :attribute muss mindestens :min Zeichen enthalten',
```
## Validierung von Arrays
Sie können auch verschachtelte Arrays validieren:
```php
$this->validate($request, [
'user.name' => 'required|string|max:255',
'user.email' => 'required|email|unique:users,email',
'addresses.*.street' => 'required|string|max:255',
'addresses.*.city' => 'required|string|max:255',
'addresses.*.country' => 'required|string|max:255',
]);
```
In diesem Beispiel wird erwartet, dass `user` ein Array mit den Schlüsseln `name` und `email` ist, und `addresses` ein Array von Arrays ist, wobei jedes innere Array die Schlüssel `street`, `city` und `country` hat.
## Benutzerdefinierte Validierungsregeln
### Erstellen einer benutzerdefinierten Regel
Sie können benutzerdefinierte Validierungsregeln erstellen, indem Sie die `Rule`-Schnittstelle implementieren:
```php
use App\Framework\Validation\Rule;
class StrongPassword implements Rule
{
public function passes($attribute, $value): bool
{
// Überprüfen, ob das Passwort stark ist
return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $value) === 1;
}
public function message(): string
{
return 'Das Passwort muss mindestens 8 Zeichen lang sein und mindestens einen Großbuchstaben, einen Kleinbuchstaben, eine Zahl und ein Sonderzeichen enthalten.';
}
}
```
### Verwenden einer benutzerdefinierten Regel
Sie können Ihre benutzerdefinierte Regel wie folgt verwenden:
```php
use App\Framework\Validation\Validator;
$validator = new Validator($request->all(), [
'password' => ['required', 'string', new StrongPassword()],
]);
```
Oder in einem Controller:
```php
$this->validate($request, [
'password' => ['required', 'string', new StrongPassword()],
]);
```
## Validierung mit Form Requests
Für komplexe Validierungslogik können Sie Form Request-Klassen erstellen:
```php
use App\Framework\Http\FormRequest;
class CreateUserRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
];
}
public function messages(): array
{
return [
'name.required' => 'Der Name ist erforderlich',
'email.unique' => 'Diese E-Mail-Adresse wird bereits verwendet',
'password.min' => 'Das Passwort muss mindestens 8 Zeichen lang sein',
];
}
public function authorize(): bool
{
return $this->user()->hasPermission('create-users');
}
}
```
Dann können Sie die Form Request-Klasse in Ihrem Controller verwenden:
```php
public function store(CreateUserRequest $request): Response
{
// Die Validierung wurde bereits durchgeführt
$user = User::create($request->validated());
return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```
Die `validated`-Methode gibt nur die validierten Felder zurück, was nützlich ist, um Massenänderungen zu verhindern.
## Validierung von Dateien
Das Framework bietet spezielle Regeln für die Validierung von Dateien:
```php
$this->validate($request, [
'avatar' => 'required|file|image|max:2048', // max in Kilobyte
'document' => 'required|file|mimes:pdf,doc,docx|max:10240',
]);
```
## Validierung von Daten außerhalb von Requests
Sie können den Validator auch verwenden, um Daten zu validieren, die nicht aus einer HTTP-Anfrage stammen:
```php
use App\Framework\Validation\Validator;
$data = [
'name' => 'John Doe',
'email' => 'john@example.com',
];
$validator = new Validator($data, [
'name' => 'required|string|max:255',
'email' => 'required|email',
]);
if ($validator->fails()) {
$errors = $validator->errors();
// Fehler behandeln
} else {
$validatedData = $validator->validated();
// Mit validierten Daten fortfahren
}
```
## Validierung in JavaScript
Das Framework bietet auch eine Möglichkeit, Validierungsregeln in JavaScript zu verwenden, um clientseitige Validierung zu ermöglichen:
```php
// In Ihrer View
<script>
const rules = <?= json_encode($validator->jsRules()) ?>;
const messages = <?= json_encode($validator->jsMessages()) ?>;
// Verwenden Sie die Regeln mit Ihrer bevorzugten JavaScript-Validierungsbibliothek
</script>
```
## Validierung von Abhängigkeiten
Manchmal hängt die Validierung eines Feldes vom Wert eines anderen Feldes ab. Sie können benutzerdefinierte Regeln verwenden, um diese Art von Validierung zu implementieren:
```php
$this->validate($request, [
'payment_type' => 'required|in:credit_card,paypal',
'card_number' => 'required_if:payment_type,credit_card|string|size:16',
'card_expiry' => 'required_if:payment_type,credit_card|date_format:m/y',
'card_cvv' => 'required_if:payment_type,credit_card|string|size:3',
'paypal_email' => 'required_if:payment_type,paypal|email',
]);
```
## Validierung mit Bedingungen
Sie können auch komplexere Bedingungen für die Validierung definieren:
```php
$validator = new Validator($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|email',
]);
$validator->sometimes('phone', 'required|string|size:10', function ($input) {
return $input->contact_method === 'phone';
});
$validator->sometimes('address', 'required|string|max:255', function ($input) {
return $input->requires_shipping === true;
});
```
## Validierung von Datenbanken
Das Framework bietet Regeln für die Validierung von Datenbanken:
```php
$this->validate($request, [
'email' => 'required|email|unique:users,email',
'username' => 'required|string|unique:users,username',
'category_id' => 'required|integer|exists:categories,id',
]);
```
Bei der Aktualisierung eines Datensatzes möchten Sie möglicherweise den aktuellen Datensatz von der Einzigartigkeit ausschließen:
```php
$this->validate($request, [
'email' => 'required|email|unique:users,email,' . $userId,
'username' => 'required|string|unique:users,username,' . $userId,
]);
```
## Fehlerbehandlung
### Zugriff auf Validierungsfehler
Wenn die Validierung fehlschlägt, können Sie auf die Fehler zugreifen:
```php
$validator = new Validator($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
]);
if ($validator->fails()) {
$errors = $validator->errors();
// Alle Fehler abrufen
$allErrors = $errors->all();
// Fehler für ein bestimmtes Feld abrufen
$nameErrors = $errors->get('name');
// Ersten Fehler für ein bestimmtes Feld abrufen
$firstNameError = $errors->first('name');
// Prüfen, ob ein Feld Fehler hat
$hasNameErrors = $errors->has('name');
}
```
### Anzeigen von Validierungsfehlern in Views
In Ihren Views können Sie die Validierungsfehler wie folgt anzeigen:
```php
<?php if ($errors->has('name')): ?>
<div class="error"><?= $errors->first('name') ?></div>
<?php endif; ?>
```
Oder alle Fehler anzeigen:
```php
<?php if ($errors->any()): ?>
<div class="alert alert-danger">
<ul>
<?php foreach ($errors->all() as $error): ?>
<li><?= $error ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
```
## Beste Praktiken
### Wiederverwendung von Validierungsregeln
Wenn Sie dieselben Validierungsregeln in mehreren Controllern verwenden, sollten Sie sie in eine separate Klasse auslagern:
```php
class UserValidationRules
{
public static function forCreation(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
];
}
public static function forUpdate(int $userId): array
{
return [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $userId,
];
}
}
```
Dann können Sie diese Regeln in Ihren Controllern verwenden:
```php
public function store(Request $request): Response
{
$this->validate($request, UserValidationRules::forCreation());
// ...
}
public function update(Request $request, int $id): Response
{
$this->validate($request, UserValidationRules::forUpdate($id));
// ...
}
```
### Validierung in Modellen
Sie können Validierungsregeln auch in Ihren Modellen definieren:
```php
class User extends Model
{
public static function validationRules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8',
];
}
public static function updateValidationRules(int $userId): array
{
return [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $userId,
];
}
}
```
Dann können Sie diese Regeln in Ihren Controllern verwenden:
```php
public function store(Request $request): Response
{
$this->validate($request, User::validationRules());
// ...
}
public function update(Request $request, int $id): Response
{
$this->validate($request, User::updateValidationRules($id));
// ...
}
```
## Weitere Informationen
- [Controller-Anleitung](controllers.md): Erfahren Sie mehr über Controller und wie sie mit der Validierung interagieren.
- [Form Request-Anleitung](form-requests.md): Erfahren Sie mehr über Form Requests und wie sie die Validierung vereinfachen können.
- [Datenbank-Anleitung](database.md): Erfahren Sie mehr über Datenbankoperationen und wie sie mit der Validierung interagieren.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.

View File

@@ -1,35 +0,0 @@
# Projekt-Dokumentation
## Willkommen zur Projektdokumentation
Diese Dokumentation bietet umfassende Informationen zu Coding-Standards, Architektur, Best Practices und Framework-Komponenten des Projekts.
## Schnellzugriff
- [Coding-Guidelines](/standards/CODING-GUIDELINES.md)
- [Sicherheitsrichtlinien](/standards/SICHERHEITS-GUIDELINES.md)
- [Projektstruktur](/architecture/STRUKTUR-DOKUMENTATION.md)
- [Performance-Optimierung](/guidelines/PERFORMANCE-GUIDELINES.md)
- [KI-Assistent Einrichtung](/ai/EINRICHTUNG-PHPSTORM.md)
## Dokumentationsstruktur
Die Dokumentation ist in verschiedene Bereiche unterteilt:
- **Standards und Guidelines**: Grundlegende Prinzipien und Richtlinien für die Entwicklung
- **Framework-Module**: Dokumentation zu den einzelnen Framework-Komponenten
- **Entwicklungsrichtlinien**: Detaillierte Anleitungen zu Performance, Testing und mehr
- **Architektur**: Übersicht und Details zur Systemarchitektur
- **KI-Assistent-Integration**: Anleitung zur Verwendung des KI-Assistenten
## Für neue Entwickler
Wenn Sie neu im Projekt sind, empfehlen wir Ihnen, mit folgenden Dokumenten zu beginnen:
1. [Projektstruktur](/architecture/STRUKTUR-DOKUMENTATION.md) - Um einen Überblick zu bekommen
2. [Coding-Guidelines](/standards/CODING-GUIDELINES.md) - Um die Coding-Standards zu verstehen
3. [Modul-Checkliste](/framework/MODUL-CHECKLISTE.md) - Um die Modularisierung zu verstehen
## Beitragen zur Dokumentation
Die Dokumentation ist ein lebendiges Dokument. Wenn Sie Fehler finden oder Verbesserungen vorschlagen möchten, erstellen Sie bitte einen Pull Request mit Ihren Änderungen.

185
docs/logging-module.md Normal file
View File

@@ -0,0 +1,185 @@
# Logging-Modul Dokumentation
## Übersicht
Das Logging-Modul wurde überarbeitet, um eine konsistente Pfadverwaltung zu gewährleisten und die Konfiguration zu zentralisieren. Die Hauptverbesserungen umfassen:
1. Zentrale Konfiguration für Logpfade mit `LogConfig`
2. Integration des `PathProvider` für konsistente Pfadauflösung
3. Einheitliche Verzeichnisstruktur für verschiedene Logtypen
4. Automatische Erstellung von Logverzeichnissen
## Komponenten
### LogConfig
Die neue `LogConfig`-Klasse dient als zentrale Konfiguration für alle Logpfade:
```php
final class LogConfig
{
public function __construct(PathProvider $pathProvider)
{
// Initialisierung der Logpfade
}
public function getLogPath(string $type): string
{
// Gibt den Pfad für einen bestimmten Log-Typ zurück
}
public function getAllLogPaths(): array
{
// Gibt alle konfigurierten Logpfade zurück
}
public function ensureLogDirectoriesExist(): void
{
// Stellt sicher, dass alle Logverzeichnisse existieren
}
}
```
### FileHandler und JsonFileHandler
Die Handler wurden aktualisiert, um den `PathProvider` zu verwenden:
```php
public function __construct(
string $logFile,
LogLevel|int $minLevel = LogLevel::DEBUG,
string $outputFormat = '[{timestamp}] [{level_name}] {request_id}{channel}{message}',
int $fileMode = 0644,
?LogRotator $rotator = null,
?PathProvider $pathProvider = null
) {
// Pfad auflösen, falls PathProvider vorhanden
if ($this->pathProvider !== null && !str_starts_with($logFile, '/')) {
$logFile = $this->pathProvider->resolvePath($logFile);
}
// ...
}
```
### LoggerInitializer
Der `LoggerInitializer` wurde aktualisiert, um `PathProvider` und `LogConfig` zu verwenden:
```php
#[Initializer]
public function __invoke(TypedConfiguration $config, PathProvider $pathProvider): Logger
{
// Erstelle LogConfig für zentrale Pfadverwaltung
$logConfig = new LogConfig($pathProvider);
// Stelle sicher, dass alle Logverzeichnisse existieren
$logConfig->ensureLogDirectoriesExist();
// ...
$handlers[] = new FileHandler(
$logConfig->getLogPath('app'),
$minLevel,
'[{timestamp}] [{level_name}] {request_id}{channel}{message}',
0644,
null,
$pathProvider
);
// ...
}
```
### LogViewerInitializer
Der `LogViewerInitializer` wurde aktualisiert, um `PathProvider` und `LogConfig` zu verwenden:
```php
#[Initializer]
public function __invoke(PathProvider $pathProvider): LogViewer
{
// Erstelle LogConfig für zentrale Pfadverwaltung
$logConfig = new LogConfig($pathProvider);
// Stelle sicher, dass alle Logverzeichnisse existieren
$logConfig->ensureLogDirectoriesExist();
// Verwende die konfigurierten Logpfade aus LogConfig
$logPaths = $logConfig->getAllLogPaths();
return new LogViewer($logPaths);
}
```
## Verzeichnisstruktur
Die Logs werden in einer einheitlichen Verzeichnisstruktur organisiert:
```
logs/
├── app/
│ ├── app.log
│ └── error.log
├── security/
│ └── security.log
└── debug/
├── framework.log
├── cache.log
└── database.log
```
## Konfiguration
Die Logpfade können über Umgebungsvariablen konfiguriert werden:
- `LOG_BASE_PATH`: Basis-Verzeichnis für Logs (Standard: `logs`)
- `LOG_PATH`: Pfad für die Haupt-Logdatei (überschreibt `app.log`)
- `PHP_ERROR_LOG`: Pfad für PHP-Fehler (überschreibt `error.log`)
- `NGINX_ACCESS_LOG`: Pfad für Nginx-Access-Logs
- `NGINX_ERROR_LOG`: Pfad für Nginx-Error-Logs
## Verwendung
### Logger verwenden
```php
// Logger wird automatisch über Dependency Injection bereitgestellt
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function someMethod()
{
$this->logger->info("Eine Informationsmeldung");
$this->logger->error("Ein Fehler ist aufgetreten", ['context' => 'additional data']);
}
```
### LogViewer verwenden
```php
// LogViewer wird automatisch über Dependency Injection bereitgestellt
public function __construct(LogViewer $logViewer)
{
$this->logViewer = $logViewer;
}
public function viewLogs()
{
// Alle verfügbaren Logs anzeigen
$availableLogs = $this->logViewer->getAvailableLogs();
// Inhalt eines bestimmten Logs abrufen
$appLogContent = $this->logViewer->getLogContent('app');
}
```
## Vorteile der neuen Implementierung
1. **Konsistente Pfadverwaltung**: Alle Logpfade werden einheitlich über den `PathProvider` aufgelöst
2. **Zentrale Konfiguration**: Alle Logpfade sind an einem Ort definiert und können einfach geändert werden
3. **Automatische Verzeichniserstellung**: Logverzeichnisse werden automatisch erstellt, wenn sie nicht existieren
4. **Umgebungsvariablen-Support**: Logpfade können über Umgebungsvariablen konfiguriert werden
5. **Strukturierte Logs**: Klare Verzeichnisstruktur für verschiedene Logtypen

View File

@@ -0,0 +1,130 @@
# Middleware System Robustness Improvements
This document describes the improvements made to the middleware system to make it more robust and provides guidelines for developing robust middlewares.
## Improvements Implemented
### 1. Exception Handling
The `ExceptionHandlingMiddleware` has been positioned as the first middleware in the chain to ensure it can catch exceptions from all other middlewares. This ensures that any exception thrown by a middleware will be properly handled and converted to an appropriate HTTP response.
### 2. Timeout Mechanism
A timeout mechanism has been added to the `MiddlewareInvoker` to prevent long-running middlewares from blocking requests indefinitely. If a middleware exceeds its configured timeout, a `MiddlewareTimeoutException` is thrown, which is then caught by the `ExceptionHandlingMiddleware`.
Timeouts can be configured:
- Globally via the `MIDDLEWARE_TIMEOUT` environment variable (default: 5 seconds)
- Per middleware class via the `$middlewareTimeouts` parameter in the `MiddlewareInvoker` constructor
### 3. Circuit Breaker Pattern
A circuit breaker pattern has been implemented to prevent repeatedly failing middlewares from being executed. The `MiddlewareCircuitBreaker` class uses the existing `CircuitBreaker` module to track middleware failures and temporarily disable middlewares that fail too often.
The circuit breaker has three states:
- **Closed**: Normal operation, middleware is allowed to execute
- **Open**: Too many failures, middleware is not allowed to execute
- **Half-Open**: After a cooldown period, allows one execution to test if the middleware is working again
The integration with the existing `CircuitBreaker` module provides several benefits:
- Consistent circuit breaker behavior across the application
- Shared configuration and monitoring capabilities
- Improved reliability through a well-tested implementation
### 4. Enhanced Logging and Monitoring
A metrics collection system has been implemented to track middleware execution performance and failures. The `MiddlewareMetricsCollector` class collects and reports metrics about middleware execution, including:
- Execution time (min, max, average, total)
- Success/failure counts and rates
- Error types and counts
- Last execution time
## Guidelines for Developing Robust Middlewares
### 1. Error Handling
- Always catch and handle exceptions specific to your middleware's functionality
- Let unexpected exceptions propagate to be caught by the `ExceptionHandlingMiddleware`
- Use appropriate HTTP status codes for different error conditions
### 2. Performance Considerations
- Keep middleware execution time as short as possible
- For long-running operations, consider using asynchronous processing
- Be aware of the configured timeout for your middleware
### 3. Resource Management
- Properly manage resources (file handles, database connections, etc.)
- Use try-finally blocks to ensure resources are released even if an exception occurs
- Be mindful of memory usage, especially when processing large requests
### 4. Middleware Dependencies
- Keep dependencies between middlewares to a minimum
- Document required middleware execution order in code comments
- Use the `MiddlewarePriorityAttribute` to specify the desired execution order
### 5. Testing
- Write unit tests for your middleware
- Test both success and failure scenarios
- Test with various input data, including edge cases
- Test timeout scenarios
## Monitoring and Troubleshooting
### Metrics
The middleware system now collects detailed metrics about middleware execution. These metrics can be accessed via the `MiddlewareMetricsCollector` class:
```php
// Get metrics for a specific middleware
$metrics = $metricsCollector->getMetrics(MyMiddleware::class);
// Get metrics for all middlewares
$allMetrics = $metricsCollector->getAllMetrics();
```
### Circuit Breaker Status
You can interact with the circuit breaker for middlewares using the following methods:
```php
// Check if a middleware is allowed to execute
$isAllowed = $circuitBreaker->isAllowed(MyMiddleware::class);
// Get the current state of the circuit for a middleware
$state = $circuitBreaker->getState(MyMiddleware::class); // Returns CircuitState enum
// Reset the circuit for a middleware
$circuitBreaker->reset(MyMiddleware::class);
// Get metrics for a middleware
$metrics = $circuitBreaker->getMetrics(MyMiddleware::class);
```
The circuit breaker state can be one of the following:
- `CircuitState::CLOSED`: Normal operation, middleware is allowed to execute
- `CircuitState::OPEN`: Too many failures, middleware is not allowed to execute
- `CircuitState::HALF_OPEN`: Testing if the middleware is working again
### Logging
The middleware system logs detailed information about middleware execution, including:
- Start and end of middleware execution
- Execution time
- Errors and exceptions
- Circuit breaker state changes
Check the application logs for entries with the middleware name to troubleshoot issues.
## Conclusion
These improvements make the middleware system more robust by:
- Ensuring exceptions are properly handled
- Preventing long-running middlewares from blocking requests
- Preventing repeatedly failing middlewares from being executed
- Providing detailed metrics for monitoring and troubleshooting
By following the guidelines in this document, you can develop robust middlewares that contribute to a stable and reliable application.

67
docs/next-steps.md Normal file
View File

@@ -0,0 +1,67 @@
# Nächste Schritte (Kurzplan)
Dieser Kurzplan macht die Top-Prioritäten aus `docs/tasks.md` sofort umsetzbar. Er ist so geschrieben, dass du ihn Schritt für Schritt abarbeiten kannst. Jeder Schritt verweist auf die detaillierten Aufgaben in `docs/tasks.md`.
Hinweis: Befehle lokal ausführen; Projekt nutzt Docker. Siehe auch „Project Guidelines“ im Repository.
## Heute (Setup & Checks)
- [ ] Abhängigkeiten installieren und Basis-Checks ausführen
- [ ] Composer-Install: `composer install`
- [ ] Docker Images bauen: `./build.sh`
- [ ] Stack starten: `docker-compose up -d`
- [ ] Healthcheck: App erreichbar unter http://localhost:${APP_PORT:-8000}
- [ ] Grundchecks lokal laufen lassen
- [ ] Linter (sofern konfiguriert): `composer cs`
- [ ] PHPStan: `composer phpstan`
- [ ] Tests: `./vendor/bin/pest`
Siehe: tasks.md → 1 (Baseline), 2 (CI/CD), 3 (Static Analysis), 15 (Testing)
## Als Nächstes (Kurzzyklus, 12 Tage)
- [ ] Static Analysis schärfen (tasks.md → Punkt 3)
- [ ] Selektiv `declare(strict_types=1);` in Hot-Paths ergänzen (z. B. src/Framework/Http/*, src/Framework/Config/*)
- [ ] PHPStan auf aktueller Codebasis „sauber“ bekommen (Fehler beheben statt pauschal ignorieren)
- [ ] Baseline überprüfen und ggf. reduzieren
- [ ] Kritische Tests ergänzen (tasks.md → Punkte 10, 11, 14, 15)
- [ ] HTTP: Tests für HttpRequest/Query, Fehlerpfade, Middleware-Kette
- [ ] Feature Flags: Tests für CacheFeatureFlagRepository inkl. Negative Caching Verhalten
- [ ] WAF/Rate Limiting: Basisfälle & Fehlerszenarien abdecken
## Diese Woche (35 Tage)
- [ ] CI/CD-Pipeline aufsetzen/härten (tasks.md → Punkt 2)
- [ ] Jobs: Lint, PHPStan, Pest, `composer audit`
- [ ] Optional: Coverage (XDEBUG_MODE=coverage) mit Minimal-Schwelle
- [ ] Pre-commit Hooks (z. B. CaptainHook) lokal aktivieren
- [ ] Konfiguration & Secrets zentralisieren (tasks.md → Punkt 5)
- [ ] `.env.example` prüfen/ergänzen (fehlende Keys, Defaults)
- [ ] Boot-time Validierung sicherstellen (ConfigValidator bereits integriert)
- [ ] Secrets über ENV/Secret Store, nicht im Repo
- [ ] Observability-Basis (tasks.md → Punkte 6, 8)
- [ ] Strukturierte Logs & Metriken-Events (Cache Hit/Miss/Errors) definieren
- [ ] Einfache Zähler/Timer an kritischen Stellen einhängen
## Konkrete, kleine Fixes (Schnelle Gewinne)
- [ ] Feature Flags Negative-Caching absichern (tasks.md → 20)
- [ ] Prüfen, dass der Marker (`NOT_FOUND`) nicht mit echten Werten kollidiert; ggf. Sentinel-ValueObject einführen
- [ ] View Cache nicht einchecken (tasks.md → 13, 20)
- [ ] Sicherstellen, dass `src/Framework/View/cache/*` in `.gitignore` ausgeschlossen ist
## Validierung nach Umsetzung
- [ ] Alle Checks lokal: `composer cs && composer phpstan && ./vendor/bin/pest && composer audit`
- [ ] Docker-Stack Neustart: `docker-compose restart`
- [ ] Manuelle Smoke-Tests der wichtigsten Endpunkte
## Entscheidungspunkte (bitte festlegen)
- [ ] Bevorzugtes CI-System (GitHub Actions, GitLab CI, …)?
- [ ] Minimal abzudeckende Coverage-Schwelle (z. B. 40% initial)?
- [ ] Ziel-PHPStan-Level kurzfristig (8 → 9)?
---
Kurzlinke Referenzen:
- CI/CD → tasks.md §2
- Static Analysis → tasks.md §3
- HTTP Layer → tasks.md §10
- Feature Flags → tasks.md §11 & §20
- WAF/Rate Limiting → tasks.md §7
- Konfiguration/Secrets → tasks.md §5
- Observability → tasks.md §6 & §8

252
docs/plan.md Normal file
View File

@@ -0,0 +1,252 @@
# Improvement Plan for michaelschiemer.de
This document outlines a comprehensive improvement plan for the michaelschiemer.de website project. The plan is based on an analysis of the current project state, documentation, and requirements. It is organized by theme or system area, with each section containing specific improvements and their rationale.
## 1. Architecture and Structure
### 1.1 Complete Plugin Architecture Implementation
**Current State**: The framework has implemented a module system to organize and encapsulate related components, but the plugin architecture for extending core functionality is still pending as indicated in the roadmap tasks.
**Proposed Changes**:
- Implement the plugin architecture to allow for easier extension of core functionality
- Create standardized extension points for all major framework components
- Develop a plugin discovery and registration system
- Provide documentation and examples for plugin development
**Rationale**: Completing the plugin architecture aligns with the framework's core principle of extensibility and is a key component of Milestone 4 (Extensibility and Ecosystem). This will enable developers to extend the framework without modifying core code, improving maintainability and flexibility.
### 1.2 Standardize Language Usage
**Current State**: The codebase and documentation use a mix of German and English, creating inconsistency and potential confusion. This is identified as an incomplete task in the improvement tasks list.
**Proposed Changes**:
- Choose English as the primary language for code (class names, method names, variables, comments)
- Maintain German for user-facing content and documentation where appropriate
- Create a language style guide for contributors
- Gradually migrate existing code to follow the new standards
**Rationale**: Consistent language usage improves readability and reduces cognitive load for developers. English is the standard language for programming and will make the codebase more accessible to a wider range of contributors.
### 1.3 Optimize Dependency Injection Configuration
**Current State**: While significant work has been done to optimize the DI container (marked as completed in roadmap tasks), there are still opportunities for improvement in service organization and documentation.
**Proposed Changes**:
- Implement service tagging for better organization of related services
- Create comprehensive documentation for DI container configuration patterns and best practices
- Add performance metrics for container initialization
- Develop examples for common DI container usage patterns
**Rationale**: Optimized DI configuration will improve application bootstrap time and overall performance. Better documentation will help developers understand and use the DI container effectively, which is essential for the framework's extensibility goals.
## 2. Code Quality
### 2.1 Complete TODO Items in Codebase
**Current State**: Several TODO items remain in the codebase, particularly in the migration system, as noted in the roadmap tasks document.
**Proposed Changes**:
- Implement migration logic in `MigrationGenerator.php`
- Implement rollback functionality in `MigrationGenerator.php`
- Review and address any remaining TODO items throughout the codebase
- Create a process for tracking and prioritizing TODO items
**Rationale**: Completing TODO items will improve code completeness and reliability. The migration system is particularly important as it's a key component for database management and deployment, which is essential for the project's stability and maintainability.
### 2.2 Improve Documentation Coverage
**Current State**: Many public methods and classes lack comprehensive PHPDoc comments, as indicated in the roadmap tasks document.
**Proposed Changes**:
- Add comprehensive PHPDoc comments to all public methods and classes
- Ensure documentation follows PSR standards
- Include examples in documentation for complex methods
- Add return type information and parameter descriptions
**Rationale**: Comprehensive code documentation improves developer experience, makes the codebase more maintainable, and helps new contributors understand the system more quickly. This aligns with the project's focus on developer experience and supports the upcoming Milestone 4 (Extensibility and Ecosystem).
### 2.3 Implement Mutation Testing
**Current State**: While the project has good test coverage, mutation testing to verify test quality is not yet implemented, as noted in the roadmap tasks.
**Proposed Changes**:
- Implement mutation testing framework (such as Infection PHP)
- Configure mutation testing to run on critical components
- Add mutation testing to CI/CD pipeline
- Create guidelines for writing mutation-resistant tests
**Rationale**: Mutation testing helps identify weaknesses in test suites by modifying code and checking if tests fail as expected. This improves overall test quality and code reliability, supporting the testability principle in the architecture documentation.
## 3. Testing
### 3.1 Complete Test Coverage for Remaining Components
**Current State**: Several components still lack adequate test coverage, including Analytics, API, Attributes, and Auth, as detailed in the roadmap tasks document.
**Proposed Changes**:
- Add unit tests for Analytics components
- Create tests for API components
- Implement tests for Attributes system
- Develop comprehensive tests for Auth components
- Ensure all new tests follow the project's testing standards
**Rationale**: Comprehensive test coverage ensures reliability and makes it easier to refactor code with confidence. The identified components are critical to the system's functionality and security, making their testing essential for the project's overall quality.
### 3.2 Enhance Testing Infrastructure
**Current State**: The testing infrastructure could be improved to support more advanced testing scenarios, particularly for canary releases as mentioned in the roadmap tasks.
**Proposed Changes**:
- Implement canary testing for critical features
- Add more sophisticated mocking capabilities for external dependencies
- Create testing utilities for common testing scenarios
- Improve test data generation and management
**Rationale**: Enhanced testing infrastructure will make it easier to write comprehensive tests and improve the overall quality of the test suite. This supports the testability principle in the architecture documentation and prepares the project for more advanced deployment strategies.
## 4. Performance Optimization
### 4.1 Implement Advanced Caching Strategies
**Current State**: While basic caching is implemented (marked as completed in the features list), there are opportunities for more advanced caching strategies as the project moves toward Milestone 3 (Security and Performance).
**Proposed Changes**:
- Implement hierarchical cache tags for more precise invalidation
- Add cache warming for critical data during deployment
- Implement content-aware caching based on data change frequency
- Create cache analytics to identify cache efficiency
**Rationale**: Advanced caching strategies will further improve application performance and reduce server load, particularly for high-traffic scenarios. This aligns with the performance principle in the architecture documentation and supports the goals of Milestone 3.
### 4.2 Optimize HTTP Request Processing
**Current State**: The HTTP request processing pipeline could be further optimized to support the performance goals of Milestone 3.
**Proposed Changes**:
- Implement request batching for API endpoints where appropriate
- Optimize middleware pipeline execution
- Add conditional processing based on request characteristics
- Implement HTTP/2 server push for critical resources
**Rationale**: Efficient HTTP request processing is crucial for good user experience. Optimizations in this area will benefit every request to the application and support the performance principle in the architecture documentation.
## 5. Documentation
### 5.1 Create Comprehensive API Documentation
**Current State**: API documentation is incomplete or missing for some components, as noted in the roadmap tasks document.
**Proposed Changes**:
- Document all public APIs with examples and explanations
- Create an interactive API explorer using OpenAPI/Swagger
- Add versioning information to API documentation
- Include authentication and authorization requirements
**Rationale**: Comprehensive API documentation makes it easier for developers to use the framework correctly and efficiently. This is especially important as the project moves toward Milestone 4 (Extensibility and Ecosystem) and supports the project's goal of improving developer experience.
### 5.2 Develop User and Developer Guides
**Current State**: User guides for key features and developer onboarding documentation are incomplete, as indicated in the roadmap tasks.
**Proposed Changes**:
- Create user guides for all key features
- Develop comprehensive developer onboarding documentation
- Add troubleshooting guides for common issues
- Create a glossary of project-specific terms
**Rationale**: Better documentation reduces the time it takes for new users and developers to become productive and reduces the burden on existing team members for support. This supports the project's goal of improving developer experience and is essential for the success of Milestone 4.
### 5.3 Document Architecture and Design Decisions
**Current State**: While some architecture documentation exists, it could be enhanced with more details on design decisions, as noted in the roadmap tasks.
**Proposed Changes**:
- Create architectural decision records (ADRs) for major design choices
- Document the rationale behind architectural patterns used
- Add diagrams illustrating component interactions
- Create documentation on how to extend the architecture
**Rationale**: Documenting architecture and design decisions helps maintain architectural integrity as the project evolves and helps new developers understand why certain approaches were chosen. This supports the project's modularity and extensibility principles.
## 6. Security Enhancements
### 6.1 Implement Feedback System for WAF
**Current State**: The Web Application Firewall (WAF) has been implemented with machine learning-based anomaly detection, but the feedback system is still planned, as indicated in the features list.
**Proposed Changes**:
- Implement the planned feedback system for the WAF
- Create a mechanism for reporting false positives and false negatives
- Develop a learning system to improve detection accuracy over time
- Add analytics for WAF performance and effectiveness
**Rationale**: A feedback system for the WAF will improve its accuracy and effectiveness over time, enhancing the security of the application. This aligns with the security principle in the architecture documentation and supports the goals of Milestone 3 (Security and Performance).
### 6.2 Implement Canary Releases for Critical Features
**Current State**: While blue-green deployments are implemented, canary releases for critical features are not yet available, as noted in the roadmap tasks.
**Proposed Changes**:
- Implement canary release infrastructure
- Create monitoring and rollback mechanisms for canary deployments
- Develop traffic routing for canary releases
- Add analytics for canary deployment performance
**Rationale**: Canary releases allow for safer deployment of critical features by gradually exposing them to a subset of users. This reduces the risk of security or performance issues affecting all users and supports the project's goals for reliability and quality.
## 7. DevOps and Infrastructure
### 7.1 Enhance Monitoring and Observability
**Current State**: While basic monitoring is in place (marked as completed in the roadmap tasks), there are opportunities to enhance observability for better system insights.
**Proposed Changes**:
- Implement distributed tracing across all components
- Add business metrics monitoring
- Create custom dashboards for different stakeholder needs
- Implement anomaly detection for system metrics
**Rationale**: Enhanced monitoring and observability will help detect and resolve issues more quickly, improving overall system reliability and performance. This supports the project's goals for reliability and quality and prepares for the enterprise features planned in Milestone 5.
### 7.2 Optimize Deployment Pipeline
**Current State**: The deployment pipeline is functional (marked as completed in the roadmap tasks) but could be optimized for efficiency and reliability.
**Proposed Changes**:
- Implement parallel testing to reduce pipeline execution time
- Add deployment verification tests
- Create deployment impact analysis
- Implement automated environment scaling based on deployment needs
**Rationale**: An optimized deployment pipeline reduces deployment time and risk, allowing for more frequent and reliable releases. This supports the project's goals for quality and developer experience.
## Implementation Timeline and Priorities
The improvements outlined above should be prioritized based on their impact and alignment with the project's milestones:
### Short-term (1-3 months)
- Complete TODO items in codebase (2.1)
- Complete test coverage for remaining components (3.1)
- Implement advanced caching strategies (4.1)
- Implement feedback system for WAF (6.1)
### Medium-term (3-6 months)
- Complete plugin architecture implementation (1.1)
- Improve documentation coverage (2.2)
- Create comprehensive API documentation (5.1)
- Enhance monitoring and observability (7.1)
### Long-term (6-12 months)
- Standardize language usage (1.2)
- Implement mutation testing (2.3)
- Document architecture and design decisions (5.3)
- Implement canary releases for critical features (6.2)
## Conclusion
This improvement plan addresses the key areas identified in the project documentation and aligns with the architectural principles and milestone planning. By implementing these changes, the project will become more maintainable, secure, performant, and developer-friendly.
The plan is designed to be flexible, allowing for adjustments based on changing priorities and new requirements. Regular reviews of the plan's progress will help ensure that the project continues to move in the right direction.
The plan focuses particularly on completing the remaining tasks for Milestone 2 (Extended Feature Set) and preparing for Milestone 3 (Security and Performance), while also laying groundwork for future milestones. The emphasis on documentation, testing, and architecture will ensure the project remains maintainable and extensible as it grows in complexity and scope.

83
docs/roadmap/features.md Normal file
View File

@@ -0,0 +1,83 @@
# Framework Features
## Core Features
- [x] Routing mit Unterstützung für PHP-Attribute
- [x] Dependency Injection Container
- [x] Request/Response Abstraktion
- [x] Template-Engine
- [x] Error/Exception Handling
- [x] Konfigurationssystem
## Database Features
- [x] PDO-Wrapper
- [x] Query Builder
- [x] Migrations-System
- [x] Schema Manager
- [ ] Entity-Mapping (optional)
## Security Features
- [x] CSRF-Schutz
- [x] XSS-Filtierung
- [x] Input-Validierung
- [x] Authentifizierung
- [x] Autorisierung/Rechtemanagement
- [x] Security Headers
- [x] Request Signing
- [x] Session-Sicherheit
- [x] Sicherheits-Ereignisbehandlung
## Web Application Firewall (WAF)
- [x] Machine Learning basierte Anomalieerkennung
- [x] Feature-Extraktion aus Requests
- [x] Statistische Anomaliedetektion
- [x] Clustering-basierte Anomaliedetektion
- [x] Baseline-Management
- [x] Leistungsoptimierung
- [ ] Feedback-System (geplant)
## Validation Framework
- [x] Attribut-basierte Validierung
- [x] Umfangreiche Validierungsregeln
- [x] Validierungsgruppen
- [x] Formular-Integration
- [x] API-Validierung
- [x] Benutzerdefinierte Validierungsregeln
## Module: Analytics
- [x] Event-Tracking
- [x] Benutzer-Tracking
- [x] Seiten-Tracking
- [x] Fehler-Tracking
- [x] Leistungsmetriken
- [x] Dashboard
- [x] Speicherung in verschiedenen Backends
- [x] Middleware-System
## Module: Content
- [x] Blog-System
- [x] Markdown-Support
- [x] Medienbibliothek
- [x] SEO-Optimierung
- [ ] Kommentarsystem
## Admin Interface
- [x] Dashboard
- [x] Content-Editor
- [x] Benutzer-/Rechteverwaltung
- [x] Statistiken
## Performance
- [x] Caching-System
- [x] Lazy Loading
- [x] Asynchrone Verarbeitung
- [x] Leistungsüberwachung
- [x] Optimierte Bootstrapping
## Developer Experience
- [x] Umfangreiche Logging-Funktionen
- [x] Debugging-Tools
- [x] Fehlerberichterstattung
- [x] Entwicklermodus
- [x] Konsolen-Befehle
- [x] Code-Generatoren
- [x] Testunterstützung

289
docs/roadmap/milestones.md Normal file
View File

@@ -0,0 +1,289 @@
# Meilensteine
Diese Dokumentation beschreibt die geplanten Meilensteine für die Entwicklung des Frameworks. Meilensteine sind wichtige Punkte in der Entwicklung, die einen signifikanten Fortschritt oder eine Version markieren.
## Überblick über die Meilensteinplanung
Die Meilensteinplanung hilft dabei, die Entwicklung des Frameworks zu strukturieren und zu priorisieren. Jeder Meilenstein repräsentiert einen Satz von Funktionen und Verbesserungen, die zusammen einen bedeutenden Schritt in der Evolution des Frameworks darstellen.
## Aktuelle Meilensteine
### Meilenstein 1: Grundlegende Framework-Struktur (Abgeschlossen)
**Zeitraum:** Q1 2023
**Beschreibung:** Etablierung der grundlegenden Architektur und Kernkomponenten des Frameworks.
**Hauptfunktionen:**
- Dependency Injection Container
- Routing-System
- MVC-Struktur
- Grundlegende HTTP-Abstraktion
- Einfache Datenbank-Abstraktion
- Konfigurationssystem
**Status:** Abgeschlossen
### Meilenstein 2: Erweitertes Feature-Set (Aktuell)
**Zeitraum:** Q2-Q3 2023
**Beschreibung:** Erweiterung des Frameworks um fortgeschrittene Funktionen und Verbesserung der Benutzerfreundlichkeit.
**Hauptfunktionen:**
- Erweiterte Validierung
- Formular-Handling
- Authentifizierung und Autorisierung
- Caching-System
- Erweiterte Datenbankfunktionen
- Migrations-System
- Kommandozeilen-Interface
- Ereignissystem
**Status:** In Bearbeitung (80% abgeschlossen)
### Meilenstein 3: Sicherheit und Leistung
**Zeitraum:** Q4 2023 - Q1 2024
**Beschreibung:** Fokus auf Sicherheitsverbesserungen und Leistungsoptimierungen.
**Hauptfunktionen:**
- Web Application Firewall (WAF)
- CSRF-Schutz
- XSS-Schutz
- Content Security Policy
- Rate Limiting
- Leistungsoptimierungen
- Caching-Verbesserungen
- Lazy Loading
- Profilierung und Benchmarking
**Status:** Geplant
### Meilenstein 4: Erweiterbarkeit und Ökosystem
**Zeitraum:** Q2-Q3 2024
**Beschreibung:** Verbesserung der Erweiterbarkeit des Frameworks und Aufbau eines Ökosystems.
**Hauptfunktionen:**
- Plugin-System
- Modulares Design
- Paket-Manager
- Erweiterungspunkte
- Community-Beitragsrichtlinien
- Dokumentationsverbesserungen
- Beispielanwendungen
- Starter-Kits
**Status:** Geplant
### Meilenstein 5: Enterprise-Features
**Zeitraum:** Q4 2024 - Q1 2025
**Beschreibung:** Implementierung von Funktionen für Enterprise-Anwendungen.
**Hauptfunktionen:**
- Horizontale Skalierbarkeit
- Verteilte Caches
- Message Queues
- Batch-Verarbeitung
- Reporting und Analytics
- Multi-Tenancy
- LDAP/Active Directory-Integration
- Single Sign-On (SSO)
**Status:** Geplant
## Detaillierte Meilensteinpläne
### Meilenstein 2: Erweitertes Feature-Set (Aktuell)
#### Validierung (Abgeschlossen)
- Implementierung eines umfassenden Validierungssystems
- Unterstützung für verschiedene Validierungsregeln
- Benutzerdefinierte Validierungsregeln
- Validierung von Arrays und verschachtelten Daten
- Validierungsnachrichten und -lokalisierung
#### Formular-Handling (Abgeschlossen)
- Formular-Klassen
- CSRF-Schutz für Formulare
- Formular-Validierung
- Datei-Uploads
- Formular-Rendering
#### Authentifizierung und Autorisierung (In Bearbeitung)
- Benutzerauthentifizierung
- Sitzungsverwaltung
- Rollenbasierte Zugriffskontrolle
- Fähigkeitsbasierte Zugriffskontrolle
- Richtlinien für die Autorisierung
- Passwort-Hashing und -Verifizierung
- Passwort-Zurücksetzung
#### Caching-System (In Bearbeitung)
- Cache-Abstraktionsschicht
- Verschiedene Cache-Backends (Datei, Redis, Memcached)
- Cache-Tags
- Cache-Invalidierung
- Cache-Middleware
#### Erweiterte Datenbankfunktionen (Geplant)
- Beziehungen zwischen Modellen
- Eager Loading
- Query Builder-Verbesserungen
- Transaktionen
- Ereignisse für Modelle
- Soft Deletes
- Timestamps
#### Migrations-System (Geplant)
- Datenbank-Migrationen
- Schema Builder
- Seeding
- Rollbacks
- Migration-Status
#### Kommandozeilen-Interface (Abgeschlossen)
- Befehlsregistrierung
- Eingabe/Ausgabe-Abstraktion
- Interaktive Befehle
- Fortschrittsanzeige
- Farbige Ausgabe
#### Ereignissystem (Abgeschlossen)
- Ereignisregistrierung
- Ereignislistener
- Ereignisabonnenten
- Asynchrone Ereignisse
- Ereignispriorisierung
### Meilenstein 3: Sicherheit und Leistung
#### Web Application Firewall (WAF) (In Bearbeitung)
- Erkennung und Blockierung von SQL-Injection
- Erkennung und Blockierung von XSS
- Erkennung und Blockierung von Command Injection
- Erkennung und Blockierung von Path Traversal
- Maschinelles Lernen zur Erkennung von Anomalien
#### CSRF-Schutz (Abgeschlossen)
- CSRF-Token-Generierung
- CSRF-Token-Validierung
- CSRF-Middleware
- CSRF-Schutz für AJAX-Anfragen
#### XSS-Schutz (In Bearbeitung)
- Automatische Ausgabebereinigung
- HTML-Purifier
- Content Security Policy
- X-XSS-Protection-Header
#### Content Security Policy (Geplant)
- CSP-Header-Generierung
- CSP-Richtlinien
- CSP-Reporting
- CSP-Nonce
- CSP-Hashes
#### Rate Limiting (Geplant)
- Rate Limiting-Middleware
- Verschiedene Strategien (IP, Benutzer, Route)
- Konfigurierbare Limits
- Response-Header für Rate Limiting
- Speicherung von Rate Limiting-Daten
#### Leistungsoptimierungen (Geplant)
- Code-Optimierungen
- Lazy Loading
- Eager Loading
- Caching-Verbesserungen
- Datenbankoptimierungen
- Komprimierung
- Minifizierung
#### Caching-Verbesserungen (Geplant)
- Verbesserte Cache-Tags
- Cache-Invalidierung
- Cache-Warming
- Cache-Prefetching
- Verteilte Caches
#### Profilierung und Benchmarking (Geplant)
- Leistungsprofilierung
- Datenbankabfrage-Protokollierung
- Speicherverbrauch-Tracking
- Ausführungszeit-Tracking
- Benchmarking-Tools
## Versionsplanung
Die Meilensteine sind mit der Versionsplanung des Frameworks verknüpft:
### Version 1.0 (Meilenstein 2)
- Erste stabile Version
- Vollständiges Feature-Set für die meisten Webanwendungen
- Gut dokumentiert und getestet
- Erwartetes Veröffentlichungsdatum: Q3 2023
### Version 2.0 (Meilenstein 3)
- Fokus auf Sicherheit und Leistung
- Verbesserte Entwicklererfahrung
- Erweiterte Dokumentation
- Erwartetes Veröffentlichungsdatum: Q1 2024
### Version 3.0 (Meilenstein 4)
- Erweiterbarkeit und Ökosystem
- Plugin-System
- Community-Beiträge
- Erwartetes Veröffentlichungsdatum: Q3 2024
### Version 4.0 (Meilenstein 5)
- Enterprise-Features
- Skalierbarkeit
- Integration mit Unternehmensumgebungen
- Erwartetes Veröffentlichungsdatum: Q1 2025
## Priorisierung und Entscheidungsfindung
Die Priorisierung von Funktionen und Verbesserungen basiert auf den folgenden Kriterien:
1. **Benutzerbedarf**: Funktionen, die von vielen Benutzern benötigt werden, haben Priorität.
2. **Sicherheit**: Sicherheitsverbesserungen haben immer hohe Priorität.
3. **Leistung**: Leistungsverbesserungen sind wichtig für die Benutzererfahrung.
4. **Entwicklererfahrung**: Funktionen, die die Entwicklung erleichtern, sind wichtig.
5. **Wartbarkeit**: Verbesserungen, die die Wartbarkeit des Frameworks erhöhen, sind langfristig wichtig.
## Beitrag zu Meilensteinen
Wenn Sie zu einem Meilenstein beitragen möchten:
1. Überprüfen Sie den aktuellen Status des Meilensteins.
2. Identifizieren Sie Funktionen oder Verbesserungen, an denen Sie arbeiten möchten.
3. Erstellen Sie ein Issue, das beschreibt, woran Sie arbeiten möchten.
4. Diskutieren Sie Ihren Ansatz mit dem Kernteam.
5. Erstellen Sie einen Pull Request mit Ihrer Implementierung.
Weitere Informationen finden Sie in der [Pull Request-Anleitung](../contributing/pull-requests.md).
## Meilenstein-Tracking
Der Fortschritt der Meilensteine wird in den folgenden Quellen verfolgt:
1. **GitHub Issues**: Jeder Meilenstein hat ein entsprechendes GitHub-Milestone, dem Issues zugeordnet sind.
2. **Projektboard**: Ein Projektboard zeigt den Fortschritt der Aufgaben für jeden Meilenstein.
3. **Dokumentation**: Diese Dokumentation wird regelmäßig aktualisiert, um den aktuellen Status der Meilensteine widerzuspiegeln.
## Änderungen an Meilensteinen
Meilensteine können sich im Laufe der Zeit ändern, basierend auf Feedback, neuen Anforderungen und Ressourcenverfügbarkeit. Änderungen an Meilensteinen werden dokumentiert und kommuniziert, um Transparenz zu gewährleisten.
## Weitere Informationen
- [Features](features.md): Detaillierte Beschreibung der geplanten Features.
- [Tasks](tasks.md): Aufgaben, die für die Implementierung der Features erforderlich sind.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.
- [Contributing](../contributing/documentation.md): Informationen zum Beitragen zum Framework.

138
docs/roadmap/tasks.md Normal file
View File

@@ -0,0 +1,138 @@
# Improvement Tasks
This document contains a comprehensive list of actionable improvement tasks for the project. Each task is specific, actionable, and can be checked off when completed.
## Architecture
1. [x] Evaluate and optimize the dependency graph in the DI container to reduce initialization time
2. [x] Implement a service locator pattern for non-critical services to reduce container complexity
3. [x] Create a unified configuration system that consolidates the various config approaches (env files, JSON configs, code-based configs)
4. [x] Refactor the bootstrapping process to support lazy-loading of non-essential services
5. [x] Implement a module system to better organize and encapsulate related components
6. [x] Standardize error handling across all framework components
7. [x] Create a comprehensive application lifecycle documentation with sequence diagrams
8. [ ] Implement a plugin architecture to allow for easier extension of core functionality
## Code Quality
9. [ ] Complete all TODO items in the codebase:
- [ ] Implement migration logic in `MigrationGenerator.php`
- [ ] Implement rollback in `MigrationGenerator.php`
- [x] Return proper responses in various handlers
- [x] Implement actual login logic in `LoginUserHandler.php`
- [x] Use Clock instead of date() in `ShowImageUpload.php`
- [x] Implement Size for ImageVariant in `ImageVariant.php`
- [x] Remove TTL in RedisCache
- [x] Get RequestData from Request Object in Container
- [x] Integrate McpInitializer with the discovery system
10. [x] Implement consistent error handling and logging across all components
11. [ ] Add comprehensive PHPDoc comments to all public methods and classes
12. [x] Standardize naming conventions across the codebase
13. [x] Refactor large classes (>200 lines) into smaller, more focused components
14. [x] Implement strict type checking across all files
15. [x] Remove commented-out code and unused imports
16. [x] Apply consistent code formatting using PHP-CS-Fixer or similar tool
## Performance
17. [x] Implement caching for frequently accessed data and expensive operations
18. [x] Optimize database queries by adding appropriate indexes and query analysis
19. [x] Implement lazy loading for non-critical components
20. [x] Add performance benchmarks for critical paths in the application
21. [x] Optimize the discovery service to reduce bootstrap time
22. [x] Implement resource pooling for database connections and other expensive resources
23. [x] Add memory usage optimization for large data processing
24. [x] Implement asynchronous processing for non-blocking operations
25. [x] Optimize the dependency injection container initialization
26. [x] Add performance monitoring for production environments
## Security
27. [x] Implement comprehensive input validation for all user inputs
28. [x] Add Content Security Policy (CSP) headers
29. [x] Implement rate limiting for all public endpoints
30. [x] Add security headers (X-Content-Type-Options, X-Frame-Options, etc.)
31. [x] Implement proper password hashing and storage
32. [x] Add CSRF protection to all forms
33. [x] Implement proper session management with secure cookies
34. [x] Add security scanning in the CI/CD pipeline
35. [x] Implement proper error handling that doesn't expose sensitive information
36. [x] Add security audit logging for sensitive operations
## Testing
37. [ ] Add unit tests for components without test coverage:
- [ ] Analytics
- [ ] Api
- [ ] Attributes
- [ ] Auth
- [x] CircuitBreaker
- [x] Config
- [x] Console
- [x] Context
- [x] Debug
- [x] Encryption
- [x] ErrorAggregation
- [x] ErrorBoundaries
- [x] ErrorHandling
- [x] ErrorReporting
- [x] EventBus
- [x] Exception
- [x] Firewall
- [x] Health
- [x] HttpClient
- [x] Logging
- [x] Markdown
- [x] Meta
- [x] OpenApi
- [x] Performance
- [x] Quality
- [x] QueryBus
- [x] Queue
- [x] Random
- [x] RateLimit
- [x] Redis
- [x] Reflection
- [x] Sitemap
- [x] Smartlinks
- [x] SyntaxHighlighter
- [x] Tracing
- [x] Ulid
- [x] UserAgent
- [x] Waf
- [x] Worker
38. [x] Implement integration tests for critical workflows
39. [x] Add end-to-end tests for key user journeys
40. [x] Implement performance tests for critical paths
41. [x] Add security tests for authentication and authorization
42. [ ] Implement mutation testing to verify test quality
43. [x] Add code coverage reporting to CI/CD pipeline
44. [x] Implement contract tests for API endpoints
45. [x] Add load testing for high-traffic endpoints
46. [x] Implement snapshot testing for UI components
## Documentation
47. [ ] Create comprehensive API documentation
48. [ ] Add inline code documentation for complex algorithms
49. [ ] Create user guides for key features
50. [ ] Document the architecture and design decisions
51. [x] Add setup and installation instructions
52. [ ] Create troubleshooting guides
53. [ ] Document performance optimization strategies
54. [ ] Add security best practices documentation
55. [ ] Create developer onboarding documentation
56. [ ] Document testing strategies and approaches
## DevOps
57. [x] Implement automated deployment pipelines
58. [x] Add infrastructure as code for all environments
59. [x] Implement comprehensive monitoring and alerting
60. [x] Add automated database migrations
61. [x] Implement blue-green deployments
62. [ ] Add canary releases for critical features
63. [x] Implement feature flags for gradual rollouts
64. [x] Add automated rollback mechanisms
65. [x] Implement comprehensive logging and log aggregation
66. [x] Add performance monitoring and profiling in production

472
docs/search-api-examples.md Normal file
View File

@@ -0,0 +1,472 @@
# Search API Examples
This framework provides a comprehensive RESTful API for full-text search functionality.
## Base URL
All search endpoints are available under `/api/search/`
## Authentication
Search endpoints require a valid User-Agent header to avoid triggering firewall rules:
```bash
curl -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
https://localhost/api/search/...
```
## API Endpoints
### 1. Search Documents
**GET** `/api/search/{entityType}`
Search for documents of a specific entity type.
#### Parameters
| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `q` | string | Search query | `*` |
| `limit` | integer | Results per page (1-100) | `20` |
| `offset` | integer | Results offset | `0` |
| `page` | integer | Page number (alternative to offset) | `1` |
| `per_page` | integer | Results per page when using page | `20` |
| `fields` | string/array | Comma-separated fields to return | all |
| `highlight` | string/array | Fields to highlight | `title,content,description` |
| `sort_by` | string | Field to sort by | - |
| `sort_direction` | string | `asc` or `desc` | `asc` |
| `sort_by_relevance` | boolean | Sort by relevance score | `true` |
| `enable_highlighting` | boolean | Enable result highlighting | `true` |
| `enable_fuzzy` | boolean | Enable fuzzy matching | `false` |
| `min_score` | float | Minimum relevance score | `0.0` |
#### Examples
**Basic Search:**
```bash
curl -H "User-Agent: Mozilla/5.0" \
"https://localhost/api/search/products?q=iPhone"
```
**Advanced Search with Filters:**
```bash
curl -H "User-Agent: Mozilla/5.0" \
"https://localhost/api/search/products?q=smartphone&filter[category][type]=equals&filter[category][value]=electronics&filter[price][type]=range&filter[price][value][min]=500&filter[price][value][max]=1500"
```
**Search with JSON Filters:**
```bash
curl -H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
"https://localhost/api/search/products?q=laptop&filters=%7B%22category%22%3A%7B%22type%22%3A%22equals%22%2C%22value%22%3A%22computers%22%7D%2C%22price%22%3A%7B%22type%22%3A%22range%22%2C%22value%22%3A%7B%22min%22%3A800%2C%22max%22%3A2000%7D%7D%7D"
```
**Pagination:**
```bash
curl -H "User-Agent: Mozilla/5.0" \
"https://localhost/api/search/articles?q=technology&page=2&per_page=10"
```
**Field Boosting:**
```bash
curl -H "User-Agent: Mozilla/5.0" \
"https://localhost/api/search/articles?q=artificial intelligence&boosts=%7B%22title%22%3A2.0%2C%22tags%22%3A1.5%7D"
```
#### Response Format
```json
{
"success": true,
"data": {
"hits": [
{
"id": "1",
"entity_type": "products",
"score": 1.2345,
"source": {
"title": "iPhone 15 Pro Max",
"description": "Latest iPhone with advanced features",
"category": "smartphones",
"price": 1199
},
"highlight": {
"title": ["<em>iPhone</em> 15 Pro Max"],
"description": ["Latest <em>iPhone</em> with advanced features"]
}
}
],
"total": 145,
"max_score": 2.5432,
"took": 23.45,
"has_more": true,
"page": 1,
"per_page": 20,
"total_pages": 8
},
"aggregations": {}
}
```
### 2. Index Document
**POST** `/api/search/{entityType}/{id}`
Index a single document for searching.
```bash
curl -X POST \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{
"title": "iPhone 15 Pro Max",
"description": "Latest iPhone with advanced camera and A17 Pro chip",
"category": "smartphones",
"brand": "Apple",
"price": 1199,
"tags": ["phone", "apple", "premium"],
"created_at": "2024-08-08T10:00:00Z"
}' \
https://localhost/api/search/products/iphone-15-pro-max
```
#### Response
```json
{
"success": true,
"data": {
"entity_type": "products",
"id": "iphone-15-pro-max",
"indexed": true,
"message": "Document indexed successfully"
}
}
```
### 3. Bulk Index Documents
**POST** `/api/search/{entityType}/bulk`
Index multiple documents at once.
```bash
curl -X POST \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{
"id": "product-1",
"data": {
"title": "MacBook Pro 14",
"description": "Professional laptop with M3 chip",
"category": "laptops",
"price": 1999
}
},
{
"id": "product-2",
"data": {
"title": "iPad Air",
"description": "Versatile tablet for work and play",
"category": "tablets",
"price": 599
},
"metadata": {
"priority": "high"
}
}
]
}' \
https://localhost/api/search/products/bulk
```
#### Response
```json
{
"success": true,
"data": {
"entity_type": "products",
"bulk_result": {
"total": 2,
"successful": 2,
"failed": 0,
"successful_ids": ["product-1", "product-2"],
"failed_ids": [],
"errors": {},
"started_at": "2024-08-08T10:00:00Z",
"finished_at": "2024-08-08T10:00:01Z",
"duration_ms": 1234.56,
"success_rate": 100
}
}
}
```
### 4. Update Document
**PUT** `/api/search/{entityType}/{id}`
Update an existing document in the search index.
```bash
curl -X PUT \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{
"title": "iPhone 15 Pro Max - Updated",
"description": "Latest iPhone with enhanced features and longer battery life",
"price": 1099
}' \
https://localhost/api/search/products/iphone-15-pro-max
```
### 5. Delete Document
**DELETE** `/api/search/{entityType}/{id}`
Remove a document from the search index.
```bash
curl -X DELETE \
-H "User-Agent: Mozilla/5.0" \
https://localhost/api/search/products/iphone-15-pro-max
```
## Index Management
### 6. Get Engine Statistics
**GET** `/api/search/_stats`
Get overall search engine statistics.
```bash
curl -H "User-Agent: Mozilla/5.0" \
https://localhost/api/search/_stats
```
#### Response
```json
{
"success": true,
"data": {
"engine_stats": {
"engine_name": "Database",
"version": "8.0.33",
"is_healthy": true,
"total_documents": 1250,
"index_counts": {
"products": 450,
"articles": 800
},
"disk_usage_mb": 128.5,
"memory_usage_mb": 45.2,
"last_updated": "2024-08-08T10:00:00Z"
},
"available": true
}
}
```
### 7. Get Index Statistics
**GET** `/api/search/{entityType}/_stats`
Get statistics for a specific index.
```bash
curl -H "User-Agent: Mozilla/5.0" \
https://localhost/api/search/products/_stats
```
#### Response
```json
{
"success": true,
"data": {
"index_stats": {
"entity_type": "products",
"document_count": 450,
"index_size_mb": 67.3,
"query_count": 0,
"average_query_time_ms": 0.0,
"last_indexed": "2024-08-08T09:30:00Z",
"created_at": "2024-08-01T12:00:00Z"
},
"entity_type": "products"
}
}
```
### 8. Create Index
**PUT** `/api/search/{entityType}/_index`
Create or update a search index with specific field configurations.
```bash
curl -X PUT \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"title": {
"type": "text",
"searchable": true,
"highlightable": true,
"boost": 2.0
},
"description": {
"type": "text",
"searchable": true,
"highlightable": true,
"boost": 1.0
},
"category": {
"type": "keyword",
"searchable": false,
"filterable": true,
"sortable": true
},
"price": {
"type": "float",
"searchable": false,
"filterable": true,
"sortable": true
},
"created_at": {
"type": "datetime",
"searchable": false,
"filterable": true,
"sortable": true
}
},
"settings": {
"min_score_threshold": 0.1
}
}' \
https://localhost/api/search/products/_index
```
### 9. Delete Index
**DELETE** `/api/search/{entityType}/_index`
Delete a search index and all its documents.
```bash
curl -X DELETE \
-H "User-Agent: Mozilla/5.0" \
https://localhost/api/search/products/_index
```
## Filter Types
The search API supports various filter types:
### Equals
```json
{
"category": {
"type": "equals",
"value": "smartphones"
}
}
```
### In (Array)
```json
{
"category": {
"type": "in",
"value": ["smartphones", "tablets", "laptops"]
}
}
```
### Range
```json
{
"price": {
"type": "range",
"value": {
"min": 500,
"max": 1500
}
}
}
```
### Greater/Less Than
```json
{
"price": {
"type": "greater_than",
"value": 1000
},
"stock": {
"type": "less_than",
"value": 10
}
}
```
### Contains (Text Search)
```json
{
"description": {
"type": "contains",
"value": "wireless"
}
}
```
### Exists/Not Exists
```json
{
"discount": {
"type": "exists"
},
"legacy_field": {
"type": "not_exists"
}
}
```
## Error Handling
All endpoints return consistent error responses:
```json
{
"success": false,
"error": {
"message": "Search query cannot be empty",
"code": "VAL_BUSINESS_RULE_VIOLATION",
"details": {
"field": "query",
"provided_value": ""
}
}
}
```
## Common HTTP Status Codes
- `200 OK` - Successful search/get operation
- `201 Created` - Document indexed successfully
- `202 Accepted` - Bulk operation partially successful
- `400 Bad Request` - Invalid request parameters
- `404 Not Found` - Index or document not found
- `500 Internal Server Error` - Server error
## Performance Tips
1. **Use Field Restrictions**: Only request fields you need with the `fields` parameter
2. **Limit Results**: Use reasonable `limit` values (20-50 for UI, 100 max)
3. **Filter Before Search**: Use filters to narrow down results before full-text search
4. **Boost Important Fields**: Use field boosting for better relevance
5. **Batch Operations**: Use bulk indexing for multiple documents
6. **Index Only Searchable Data**: Don't index fields you'll never search

View File

@@ -0,0 +1,256 @@
# External Entity Mapping für Search System
**Suchfunktionalität ohne Entity-Änderungen** - Komplette Integration über externe Konfiguration.
## 1. Basic Mapping Configuration
```php
// In einem Service Provider oder Initializer
final class SearchMappingProvider
{
public static function registerMappings(SearchableMappingRegistry $registry): void
{
// User Entity Mapping
$userMapping = SearchableMapping::for(User::class)
->entityType('users')
->idField('id')
->field('name', 'name')
->field('email', 'email')
->field('bio', 'biography')
->field('created', 'createdAt', fn($date) => $date->format('Y-m-d'))
->boost('name', 2.0)
->boost('email', 1.5)
->autoIndex(true)
->build();
$registry->register($userMapping);
// Product Entity Mapping
$productMapping = SearchableMapping::for(Product::class)
->entityType('products')
->field('title', 'name')
->field('description', 'description')
->field('category', 'category.name') // Nested field access
->field('price', 'price', fn($price) => $price->getCents() / 100) // Transform Money object
->field('tags', 'getTags', fn($tags) => implode(' ', $tags)) // Method call + transform
->boost('title', 3.0)
->boost('description', 1.0)
->build();
$registry->register($productMapping);
}
}
```
## 2. Configuration-Based Mapping
```php
// config/search_mappings.php
return [
User::class => [
'entity_type' => 'users',
'id_field' => 'id',
'auto_index' => true,
'fields' => [
'name' => 'name',
'email' => 'email',
'bio' => 'biography',
'created' => [
'field' => 'createdAt',
'transformer' => fn($date) => $date->format('Y-m-d')
]
],
'boosts' => [
'name' => 2.0,
'email' => 1.5
]
],
Product::class => [
'entity_type' => 'products',
'fields' => [
'title' => 'name',
'description' => 'description',
'category' => 'category.name', // Nested access
'price' => [
'field' => 'price',
'transformer' => fn($price) => $price->toFloat()
]
],
'boosts' => [
'title' => 3.0
]
]
];
// Load configuration
$config = require 'config/search_mappings.php';
$registry->registerFromConfig($config);
```
## 3. Repository Integration (No Entity Changes)
```php
final class UserRepository
{
public function __construct(
private EntityManager $entityManager,
private SearchIndexingService $searchIndexing
) {
}
public function create(array $userData): User
{
$user = new User($userData);
$this->entityManager->persist($user);
$this->entityManager->flush();
// Auto-index after creation (if enabled)
$this->searchIndexing->indexEntity($user);
return $user;
}
public function update(User $user, array $changes): void
{
// Apply changes to user
foreach ($changes as $field => $value) {
$user->{"set" . ucfirst($field)}($value);
}
$this->entityManager->flush();
// Update search index
$this->searchIndexing->updateEntity($user);
}
public function delete(User $user): void
{
// Remove from search first
$this->searchIndexing->removeEntity($user);
$this->entityManager->remove($user);
$this->entityManager->flush();
}
public function reindexAll(): BulkIndexResult
{
return $this->searchIndexing->reindexEntityType('users', function() {
return $this->entityManager->findAll(User::class);
});
}
}
```
## 4. Service Usage Without Entity Knowledge
```php
final class ProductSearchService
{
public function __construct(
private SearchService $searchService,
private SearchableMappingRegistry $mappingRegistry
) {
}
public function makeProductSearchable(Product $product): bool
{
// Check if product is configured as searchable
if (!$this->mappingRegistry->isSearchable($product)) {
return false;
}
// Create adapter automatically
$adapter = $this->mappingRegistry->createAdapter($product);
if (!$adapter) {
return false;
}
// Index using the mapped fields
return $this->searchService->index(
$adapter->getEntityType(),
$adapter->getId(),
$adapter->toSearchDocument()
);
}
public function searchProducts(string $query): SearchResult
{
return $this->searchService
->for('products')
->query($query)
->boost('title', 3.0) // Use configured boosts
->limit(20)
->search();
}
}
```
## 5. Event-Driven Auto-Indexing
```php
// Events werden automatisch von Entity Operations gefeuert
$eventDispatcher->dispatch(new EntityCreatedEvent($user)); // Auto-indexes
$eventDispatcher->dispatch(new EntityUpdatedEvent($product)); // Auto-updates
$eventDispatcher->dispatch(new EntityDeletedEvent($order)); // Auto-removes
```
## 6. Advanced Field Transformations
```php
$mapping = SearchableMapping::for(Article::class)
->field('title', 'title')
->field('content', 'body')
->field('author', 'user.name') // Nested object access
->field('tags', 'tags', fn($tags) => implode(' ', array_column($tags, 'name')))
->field('published_date', 'publishedAt', fn($date) => $date?->format('Y-m-d'))
->field('word_count', 'body', fn($content) => str_word_count(strip_tags($content)))
->field('reading_time', 'body', fn($content) => ceil(str_word_count($content) / 200))
->build();
```
## 7. Conditional Indexing
```php
final class ConditionalSearchListener
{
#[EventListener(event: 'entity.updated')]
public function onEntityUpdated(EntityUpdatedEvent $event): void
{
$entity = $event->getEntity();
// Only index published articles
if ($entity instanceof Article && $entity->isPublished()) {
$this->indexingService->updateEntity($entity);
} elseif ($entity instanceof Article && !$entity->isPublished()) {
// Remove from index if unpublished
$this->indexingService->removeEntity($entity);
}
}
}
```
## Vorteile dieses Ansatzes:
**Keine Entity-Änderungen erforderlich**
**Zentrale Konfiguration** aller Mappings
**Flexible Field-Transformationen**
**Automatische Indexierung** über Events
**Repository-Integration** ohne Abhängigkeiten
**Conditional Indexing** möglich
**Backward Compatible** mit bestehenden Entities
## Integration:
```php
// Container Registration
$container->singleton(SearchableMappingRegistry::class);
$container->singleton(SearchIndexingService::class);
// Register mappings at startup
$registry = $container->get(SearchableMappingRegistry::class);
SearchMappingProvider::registerMappings($registry);
```
Dieser Ansatz ermöglicht **vollständige Suchfunktionalität ohne jegliche Änderungen an bestehenden Entity-Klassen**.

View File

@@ -0,0 +1,126 @@
# SPA Router Backend Integration
Das SPA Router System benötigt Backend-Unterstützung, um nur den `<main>` Content für AJAX-Requests zu liefern.
## HTTP Headers
Das SPA System sendet diese Headers bei Navigation:
```http
X-Requested-With: XMLHttpRequest
X-SPA-Request: true
Accept: text/html
```
## Backend Implementation
### Option 1: Separate SPA Views
```php
// In your controller
public function showContact(HttpRequest $request): HttpResponse
{
$data = [
'title' => 'Kontakt',
// ... other data
];
// Check if this is an SPA request
if ($request->headers->get('X-SPA-Request') === 'true') {
// Return only the main content
return new ViewResult('contact-spa.view.php', $data);
}
// Return full page
return new ViewResult('contact.view.php', $data);
}
```
### Option 2: Template Fragments
```php
// Create a partial template system
public function showContact(HttpRequest $request): HttpResponse
{
$data = [
'title' => 'Kontakt',
'content' => $this->renderPartial('contact-main.view.php')
];
if ($request->headers->get('X-SPA-Request') === 'true') {
// Return only main content as JSON
return new JsonResult([
'title' => $data['title'],
'content' => $data['content']
]);
}
return new ViewResult('contact.view.php', $data);
}
```
### Option 3: Layout Conditional (Recommended)
Modify your main layout to conditionally include header/footer:
```php
// main.view.php layout
<?php
$isSPARequest = $request->headers->get('X-SPA-Request') === 'true';
?>
<?php if (!$isSPARequest): ?>
<!DOCTYPE html>
<html>
<head>
<title><?= $title ?></title>
<!-- head content -->
</head>
<body>
<header>
<!-- header content -->
</header>
<?php endif; ?>
<main>
<!-- This is what gets sent for SPA requests -->
<?= $content ?>
</main>
<?php if (!$isSPARequest): ?>
<footer>
<!-- footer content -->
</footer>
<!-- scripts -->
</body>
</html>
<?php endif; ?>
```
## Testing
Test SPA requests with curl:
```bash
# Normal request (full page)
curl https://localhost/kontakt
# SPA request (only main content)
curl -H "X-SPA-Request: true" -H "X-Requested-With: XMLHttpRequest" https://localhost/kontakt
```
## Error Handling
Das Frontend fällt automatisch auf normale Navigation zurück wenn:
- HTTP Status >= 400
- Network Fehler
- Parse Fehler
- Timeout
## Performance Considerations
- SPA Requests sind ~70% kleiner (nur Content, kein Header/Footer/Scripts)
- Reduzierte Server-Last durch weniger Asset-Requests
- Schnellere Navigation durch weniger DOM-Updates
- Browser-Cache wird optimal genutzt

View File

@@ -1,234 +0,0 @@
# Coding Guidelines
## Allgemeine Prinzipien
Diese Guidelines definieren die Standards für die Entwicklung und Wartung des Projekts. Sie sorgen für Konsistenz, Lesbarkeit und Wartbarkeit des Codes.
## PHP-Version
- **PHP 8.4**: Die Codebase nutzt stets die neueste stabile PHP-Version (aktuell PHP 8.4)
- Alle neuen PHP-Sprachfeatures sollten, wo sinnvoll, genutzt werden
## Abhängigkeiten
- **Externe Abhängigkeiten vermeiden**: Das Projekt soll möglichst ohne externe Bibliotheken auskommen
- **Eigene Implementierungen bevorzugen**: Anstatt externe Pakete einzubinden, sollten eigene Lösungen entwickelt werden
- **Erlaubte Abhängigkeiten**: Nur die bereits in composer.json definierten Pakete dürfen verwendet werden
- **Neue Abhängigkeiten**: Müssen explizit genehmigt werden und sollten nur in Ausnahmefällen hinzugefügt werden
## Klassenstruktur
### Klassen
- **Alle Klassen müssen `final` sein**, es sei denn, es gibt einen zwingenden Grund für Vererbung
- **Keine abstrakten Klassen** - bevorzuge Interfaces und Kompositionen
- **Klassen sollten `readonly` sein**, wann immer möglich
- Interfaces verwenden, um Verträge zwischen Komponenten zu definieren
```php
// Gut
final readonly class AnalyticsManager
{
// ...
}
// Vermeiden
abstract class BaseManager
{
// ...
}
```
### Properties
- **Properties sollten `readonly` sein**, wann immer möglich
- Private Visibility für alle Properties, es sei denn, es gibt einen zwingenden Grund
- Typisierung ist obligatorisch für alle Properties
```php
// Gut
private readonly StorageInterface $storage;
// Vermeiden
public array $config;
```
## Methoden und Funktionen
- Typisierung ist obligatorisch für alle Parameter und Rückgabewerte
- Methoden sollten klein und fokussiert sein (Single Responsibility)
- Verwende named arguments für bessere Lesbarkeit
```php
// Gut
public function track(string $event, array $properties = [], ?string $userId = null): void
{
// ...
}
// Vermeiden
public function process($data)
{
// ...
}
```
## Dependency Injection
- Constructor Injection für alle Abhängigkeiten
- Keine Service Locator oder globale Zustände
- Verwende das `#[Initializer]`-Attribut für Service-Registrierung
```php
// Gut
public function __construct(
private readonly Configuration $config,
private readonly StorageInterface $storage
) {}
// Vermeiden
public function __construct()
{
$this->config = Container::get(Configuration::class);
}
```
## Moderne PHP-Features
### Nullable Types und Union Types
```php
public function findUser(?int $id): ?User
public function process(int|string $identifier): void
```
### Match Expression statt Switch
```php
// Gut
return match($storageType) {
'file' => new FileStorage($path),
'redis' => new RedisStorage($connection),
default => throw new \InvalidArgumentException("Nicht unterstützter Storage-Typ: {$storageType}")
};
// Vermeiden
switch ($storageType) {
case 'file':
return new FileStorage($path);
// ...
}
```
### Named Arguments
```php
$this->createUser(
email: 'user@example.com',
role: 'admin',
sendWelcomeEmail: true
);
```
### Constructor Property Promotion
```php
public function __construct(
private readonly Configuration $config,
private readonly PathProvider $pathProvider
) {}
```
## Fehlerbehandlung
- Spezifische Exceptions werfen
- Typed Exceptions verwenden
- Early Return Pattern bevorzugen
```php
// Gut
if (!$this->isValid()) {
throw new ValidationException('Ungültige Daten');
}
// Vermeiden
if ($this->isValid()) {
// Lange Verarbeitung...
} else {
throw new Exception('Fehler');
}
```
## Testing
- Tests mit Pest-Framework schreiben
- Für jede öffentliche Methode sollte mindestens ein Test existieren
- Mocking nur für externe Abhängigkeiten verwenden
```php
test('track method records events correctly', function () {
$analytics = new Analytics($manager, $dispatcher);
$analytics->track('test_event', ['key' => 'value']);
expect($manager->getEvents())->toHaveCount(1);
});
```
## Dokumentation
- PHPDoc für alle öffentlichen Methoden und Klassen
- Typen in PHPDoc sollten den tatsächlichen Typen entsprechen
- Klare, beschreibende Kommentare für komplexe Logik
```php
/**
* Zeichnet ein Event auf und wendet Middleware an
*
* @param string $event Event-Name
* @param array $properties Event-Eigenschaften
* @param string|null $userId Benutzer-ID (optional)
*/
public function track(string $event, array $properties = [], ?string $userId = null): void
```
## Namenskonventionen
- **Klassen**: PascalCase (`AnalyticsManager`)
- **Methoden/Funktionen**: camelCase (`getEventStats()`)
- **Variablen**: camelCase (`$eventData`)
- **Konstanten**: SNAKE_CASE (`MAX_BATCH_SIZE`)
- **Dateien**: Klassenname.php (`AnalyticsManager.php`)
## Architektur
- Dependency Inversion Principle befolgen
- Interfaces für alle externen Abhängigkeiten
- Vermeide zirkuläre Abhängigkeiten zwischen Modulen
- Services sollten eine klare, fokussierte Verantwortung haben
## Performance
- Lazy Loading für ressourcenintensive Operationen
- Caching wo sinnvoll
- Datenstrukturen sorgfältig auswählen
## Security
- Alle Benutzereingaben validieren und bereinigen
- Prepared Statements für Datenbankabfragen
- Vermeidung von `eval()` und ähnlichen unsicheren Funktionen
- Sensible Daten niemals in Logs schreiben
## Best Practices
- **Immutability**: Bevorzuge unveränderliche Objekte
- **Pure Functions**: Bevorzuge reine Funktionen ohne Seiteneffekte
- **Enums**: Verwende Enums statt String-Konstanten für feste Optionssätze
- **DTOs**: Verwende Data Transfer Objects für Datentransport
- **Value Objects**: Verwende Value Objects für semantisch reiche Datentypen
## Refactoring
- Code, der diese Guidelines nicht erfüllt, sollte beim Bearbeiten aktualisiert werden
- Tests müssen vor und nach dem Refactoring bestehen
- Große Refactorings sollten in kleinen, separaten Commits erfolgen

View File

@@ -1,187 +0,0 @@
# Sicherheitsrichtlinien
## Übersicht
Diese Richtlinien definieren Standards und Best Practices für sichere Softwareentwicklung im Projekt.
## Grundprinzipien
### 1. Defense in Depth
- Mehrere Sicherheitsschichten implementieren
- Nicht auf eine einzelne Sicherheitsmaßnahme vertrauen
- Fail-Safe-Mechanismen einbauen
### 2. Least Privilege
- Minimale Berechtigungen für Funktionen und Benutzer
- Ressourcenzugriff nur bei Bedarf gewähren
- Temporäre Berechtigungen nach Gebrauch entziehen
### 3. Input-Validierung
- Alle Benutzereingaben validieren und bereinigen
- Whitelist-Ansatz bevorzugen (erlaubte Eingaben definieren)
- Typprüfung und Formatvalidierung durchführen
```php
// Beispiel: Sichere Input-Validierung
public function processUserInput(string $input): string
{
// Länge prüfen
if (strlen($input) > 100) {
throw new ValidationException('Input zu lang (max 100 Zeichen)');
}
// Inhalt validieren (Whitelist-Ansatz)
if (!preg_match('/^[a-zA-Z0-9\s\-_]+$/', $input)) {
throw new ValidationException('Input enthält ungültige Zeichen');
}
// Bereinigung
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
}
```
## Spezifische Sicherheitsmaßnahmen
### 1. SQL-Injection-Prävention
- Prepared Statements für alle Datenbankabfragen
- Keine dynamischen SQL-Queries
- ORM-Framework bevorzugen
```php
// Sicher
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
// Unsicher - NIEMALS SO MACHEN
$query = "SELECT * FROM users WHERE email = '{$email}'";
```
### 2. Cross-Site Scripting (XSS) Prävention
- Output-Escaping für alle benutzergenerierten Inhalte
- Content-Security-Policy (CSP) implementieren
- HttpOnly und Secure Flags für Cookies
```php
// Ausgabe in HTML
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// Ausgabe in JavaScript
echo json_encode($userInput, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
```
### 3. Cross-Site Request Forgery (CSRF) Schutz
- CSRF-Token für alle ändernden Anfragen
- SameSite-Attribut für Cookies
```php
// CSRF-Token generieren
public function generateCsrfToken(): string
{
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
return $token;
}
// CSRF-Token validieren
public function validateCsrfToken(string $token): bool
{
return hash_equals($_SESSION['csrf_token'] ?? '', $token);
}
```
### 4. Sichere Authentifizierung
- Passwörter mit starken Algorithmen hashen (Argon2id)
- Multi-Faktor-Authentifizierung anbieten
- Ratelimiting für Login-Versuche
```php
// Passwort hashen
public function hashPassword(string $password): string
{
return password_hash($password, PASSWORD_ARGON2ID);
}
// Passwort verifizieren
public function verifyPassword(string $password, string $hash): bool
{
return password_verify($password, $hash);
}
```
### 5. Sichere Datenspeicherung
- Sensible Daten verschlüsseln
- Separate Schlüssel für unterschiedliche Daten
- Schlüsselrotation implementieren
```php
// Daten verschlüsseln
public function encrypt(string $data, string $purpose): string
{
$key = $this->getEncryptionKey($purpose);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = sodium_crypto_secretbox(
$data,
$nonce,
$key
);
return base64_encode($nonce . $cipher);
}
// Daten entschlüsseln
public function decrypt(string $encrypted, string $purpose): string
{
$key = $this->getEncryptionKey($purpose);
$decoded = base64_decode($encrypted);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$cipher = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
return sodium_crypto_secretbox_open(
$cipher,
$nonce,
$key
);
}
```
## Sicherheitstests
### 1. Automatisierte Sicherheitstests
- Static Application Security Testing (SAST)
- Dynamic Application Security Testing (DAST)
- Dependency-Scanning für bekannte Schwachstellen
### 2. Penetrationstests
- Regelmäßige Sicherheitsaudits
- Manuelle Penetrationstests
- Bug-Bounty-Programme
## Sicherheitskultur
### 1. Entwicklerschulungen
- Regelmäßige Sicherheitsschulungen
- Code-Reviews mit Sicherheitsfokus
- Sicherheits-Champions im Team
### 2. Incident Response
- Sicherheitsvorfälle dokumentieren
- Prozess für Sicherheitsmeldungen
- Notfallpläne für Sicherheitsvorfälle
## Zusammenfassung
Sicherheit ist ein kontinuierlicher Prozess, keine einmalige Aufgabe. Diese Richtlinien sollten regelmäßig überprüft und aktualisiert werden, um neuen Bedrohungen zu begegnen.

View File

@@ -1,50 +0,0 @@
# Coding-Standards und Richtlinien
## Übersicht
Diese Standards und Richtlinien definieren die grundlegenden Prinzipien für die Codierung und Sicherheit im Projekt. Sie gewährleisten Konsistenz, Wartbarkeit und Sicherheit des Codes.
## Verfügbare Standards
- [Coding Guidelines](/standards/CODING-GUIDELINES.md) - Allgemeine Coding-Standards für das Projekt
- [Sicherheitsrichtlinien](/standards/SICHERHEITS-GUIDELINES.md) - Standards für sichere Softwareentwicklung
## Coding Guidelines
Die [Coding Guidelines](/standards/CODING-GUIDELINES.md) definieren die technischen Standards für die Codeentwicklung, einschließlich:
- Klassenstruktur und -design
- Property- und Methodendefinitionen
- Nutzung moderner PHP-Features
- Fehlerbehandlung
- Dokumentation
- Namenskonventionen
## Sicherheitsrichtlinien
Die [Sicherheitsrichtlinien](/standards/SICHERHEITS-GUIDELINES.md) bieten umfassende Anleitungen zur sicheren Softwareentwicklung:
- Input-Validierung
- SQL-Injection-Prävention
- XSS-Schutz
- CSRF-Schutz
- Sichere Authentifizierung
- Sichere Datenspeicherung
- Session-Management
## Anwendung der Standards
Alle Teammitglieder sind verpflichtet, diese Standards in ihrer Arbeit anzuwenden. Sie dienen als Grundlage für Code-Reviews und Qualitätssicherung.
## Abweichungen von Standards
In Ausnahmefällen können Abweichungen von diesen Standards erforderlich sein. Solche Abweichungen sollten:
1. Dokumentiert werden
2. Begründet werden
3. Im Team besprochen werden
4. Auf ein Minimum beschränkt werden
## Aktualisierungen
Diese Standards werden regelmäßig überprüft und aktualisiert, um sicherzustellen, dass sie den neuesten Best Practices und Technologien entsprechen.

Some files were not shown because too many files have changed in this diff Show More