Skip to content

Latest commit

 

History

70 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PowerPHPBoard

PHP Bootstrap tests lighthouse license

Ein sicheres, leichtgewichtiges PHP-Forum-System für PHP 8.4+ mit modernem Bootstrap-5-Frontend. Ursprünglich entwickelt 2001-2009 von Stefan "BFG" Kramer, modernisiert 2026.


Schnellstart (Docker, empfohlen)

Du brauchst nur Git, Composer und Docker Desktop (oder docker compose v2).

# 1. Repository klonen
git clone https://github.com/schubertnico/PowerPHPBoard.git
cd PowerPHPBoard

# 2. Dev-Dependencies für Tests/Tooling installieren
composer install

# 3. Container starten (Forum + MySQL + Mailpit + phpMyAdmin)
cd .docker
docker compose up -d --build
cd ..

# 4. Im Browser öffnen
#    http://localhost:8085  -> Forum

Beim ersten Start lädt MySQL automatisch das Schema aus install.sql und danach die Testkonten aus .docker/dev-seed.sql. install.sql selbst legt seit 2.3.0 keinen Administrator mehr an – im Docker-Stack übernimmt das der Dev-Seed, auf echten Servern der Web-Installer.

Service URL Zweck
Forum http://localhost:8085 Hauptanwendung
phpMyAdmin http://localhost:8088 DB-Verwaltung
Mailpit (UI) http://localhost:8032 E-Mails von Registrierung/Reset
Mailpit SMTP mailpit:1025 (intern) SMTP-Ziel der App
MySQL localhost:3315 Direkter DB-Zugriff (Dev)

Test-Accounts (Dev-Stack, nur lokal)

Nach dem ersten Start sind folgende Test-Accounts vorhanden. Sie stammen aus .docker/dev-seed.sql (Argon2id-Hashes) und sind ausschließlich für die lokale Entwicklung gedacht – die Datei gehört nie auf einen Live-Server und ist per .gitattributes aus dem Release-Paket ausgeschlossen:

Benutzer Rolle E-Mail Passwort
RalphAdmin Administrator ralphadmin@example.com Test1234!
RalphUser Normal user ralphuser@example.com Test1234!

Stoppen, Aktualisieren, Zurücksetzen

# Container stoppen
docker compose -f .docker/docker-compose.yml down

# Neu bauen (z. B. nach PHP-Version-Upgrade)
docker compose -f .docker/docker-compose.yml up -d --build

# Komplett zurücksetzen (alle Daten löschen!)
docker compose -f .docker/docker-compose.yml down -v

Schnellstart ohne Docker (Web-Installer)

Seit Version 2.3.0 richtet ein Web-Installer das Forum ein – ohne Kommandozeile und ohne Zugangsdaten im PHP-Code. Das passt auch für Shared Hosting:

  1. Dateien hochladen – das Release-Paket entpacken und per FTP/SFTP in das gewünschte Verzeichnis kopieren (versteckte .htaccess-Dateien mit übertragen).
  2. Leere Datenbank anlegen – im Kundenmenü des Hosters (MySQL 8 oder MariaDB 10.5+, Zeichensatz utf8mb4). Server, Name, Benutzer und Passwort notieren, ebenso Postausgangsserver (SMTP), Benutzername und Passwort eines E-Mail-Postfachs für den Versand der Forum-Mails.
  3. Installer aufrufen – https://ihre-domain.de/forum/install/ im Browser öffnen (wer die Startseite des noch leeren Forums aufruft, landet automatisch dort). Der Assistent führt durch fünf Schritte: Systemprüfung, Datenbank, Forum, Administrator, Abschluss. Er legt die Tabellen an, erstellt Ihr Administrator-Konto (Argon2id) und schreibt die Zugangsdaten in config.local.php.
  4. install/ löschen – danach ist der Installer ohnehin gesperrt, gehört aber nicht auf ein laufendes Forum.

Details, Schritt-für-Schritt-Anleitung und Sonderfälle (Verzeichnis nicht beschreibbar, bestehende Tabellen, Neuinstallation) stehen in INSTALLATION.md.

Lokal zum Ausprobieren ohne Docker:

git clone https://github.com/schubertnico/PowerPHPBoard.git
cd PowerPHPBoard
composer install          # nur für Tests und Analyse-Werkzeuge nötig

mysql -u root -p -e "CREATE DATABASE PowerPHPBoard_v2 CHARACTER SET utf8mb4;"
php -S localhost:8085     # dann http://localhost:8085/install/ aufrufen

Der PHP-Entwicklungsserver wertet keine .htaccess-Dateien aus – für einen öffentlich erreichbaren Server immer Apache (oder nginx mit den Regeln aus INSTALLATION.md) verwenden.

Notfall-Werkzeug: Hat kein Administrator mehr Zugang, legt php bin/create-admin.php --user=Name --email=adresse@example.com auf der Kommandozeile einen neuen an (das Passwort wird abgefragt, unter Linux/macOS verdeckt; --update macht ein bestehendes Konto zum Administrator). Über das Web ist das Skript gesperrt.

Update von 2.2.x auf 2.3.0

Der Installer ist für ein Update nicht nötig – Datenbank und Zugangsdaten bleiben gültig, eine Datenbank-Migration ist nicht nötig. Wer Zugangsdaten direkt in config.inc.php eingetragen hatte, überträgt sie vor dem Hochladen der neuen Dateien in eine config.local.php (die neue config.inc.php wird überschrieben). Umgebungsvariablen funktionieren unverändert; ist PPB_MAIL_FROM bzw. from gesetzt, ist diese Adresse jetzt der Absender aller Mails (Antworten gehen an die Admin-E-Mail). Das Verzeichnis install/ beim Update nicht hochladen bzw. danach löschen. Anleitung: INSTALLATION.md.

Bugfix-Migration einspielen (für bestehende Installationen)

Wenn du eine ältere Version updatest, führe zusätzlich die Migration aus:

mysql -u <user> -p <dbname> < install_bugfix_2026-04-23.sql

Sie legt neue Tabellen für Password-Reset-Tokens und Rate-Limits an und setzt UNIQUE auf username.

Deploy-Paket für den Live-Server

Die .gitattributes ist so konfiguriert, dass Dev-Artefakte (Tests, Docker, CI, Dokumentation, statische Analyse-Configs, Setup-Skripte) beim git archive automatisch ausgeschlossen werden. Ein sauberes Deploy-Paket erstellst du mit:

# Tarball für den Live-Server bauen (ohne Tests, Docker, Docs, CI ...)
git archive --format=tar.gz --prefix=powerphpboard/ HEAD > deploy.tar.gz

# Oder direkt ins Zielverzeichnis packen
git archive --format=tar HEAD | tar -C /var/www/html -xf -

# Auf dem Live-Server: nur Produktions-Dependencies installieren
composer install --no-dev --optimize-autoloader

Bei einem "dummen" Upload (FTP/SFTP) bitte die in .gitattributes mit export-ignore markierten Verzeichnisse manuell NICHT mit hochladen.


Inhaltsverzeichnis

  1. Features
  2. Frontend (Bootstrap 5)
  3. Voraussetzungen
  4. Konfiguration
  5. Projektstruktur
  6. Core-Klassen
  7. Sicherheit
  8. Adminbereich
  9. Accessibility
  10. BBCode-Referenz
  11. Testing
  12. Entwicklung
  13. Changelog
  14. Lizenz
  15. Kontakt

Features

Forum-Funktionen

  • Foren mit Kategorien, Boards, Threads und Posts
  • Benutzerregistrierung, Profilverwaltung, Signaturen, Biografie
  • Moderatoren pro Board, Admin-Rolle
  • Private Boards mit Passwortschutz
  • BBCode, Smilies, optional HTML
  • E-Mail-Versand (Registrierung, Passwort-Reset, User-zu-User)
  • Mehrsprachig: Deutsch (Sie/Du), Englisch

Sicherheit

  • CSRF-Schutz auf allen POST-Formularen
  • Prepared Statements (PDO) durchgängig
  • XSS-Prävention (htmlspecialchars, Whitelist-strip_tags für Signaturen)
  • Argon2id Passwort-Hashing mit Legacy-Migration
  • HttpOnly Session-Cookies, SameSite=Strict, Secure-fertig
  • Rate-Limiting gegen Brute-Force (Login, Passwort-Reset)
  • Token-basierter Passwort-Reset (einmalige, zeitlich begrenzte Tokens)
  • Unified Error Messages (keine User-Enumeration)
  • Username-UNIQUE Constraint auf DB-Ebene
  • Admin-Guard im Adminbereich (Early-Return mit Bootstrap-Alert)

Technische Features

  • PHP 8.4 Strict Types, Match Expressions, Named Arguments, readonly
  • PSR-4 Autoloading, modulare includes/-Klassen
  • 647 PHPUnit-Tests (585 Unit + 62 Feature)
  • PHPStan Level 8, Psalm, PHP-CS-Fixer, Rector, Infection
  • Docker-Compose Dev-Stack mit Mailpit und phpMyAdmin
  • GitHub Actions CI

Frontend (Bootstrap 5)

Seit Version 2.2.0 nutzt PowerPHPBoard ein durchgängiges Bootstrap-5.3.3-Frontend:

Layout

  • HTML5 (<!DOCTYPE html>, <html lang="de">, Viewport-Meta, Meta-Description)
  • Responsives Layout über container-xl, row, col-*, d-flex, gap-*
  • Dunkle Navbar für das Forum (navbar-dark bg-dark)
  • Rote Admin-Navbar (navbar-dark bg-danger) zur klaren visuellen Trennung
  • Footer mit bg-dark text-light und link-light für Kontrast

Komponenten

  • Cards (card, card-header, card-body, card-footer) für jede Section
  • Bootstrap-Tabellen (table, table-hover, table-striped, table-responsive)
  • Bootstrap-Forms (form-label, form-control, form-select, form-check, invalid-feedback, form-text)
  • Bootstrap-Alerts (alert alert-success/danger/warning/info) für alle Status- und Fehlermeldungen
  • Bootstrap-Buttons (btn-primary, btn-success, btn-danger, btn-outline-secondary, btn-link)
  • Bootstrap-Pagination für Thread-Seiten
  • Bootstrap-Breadcrumbs für Navigationspfade
  • Bootstrap-Badges für Status (Administrator, Privat, Geschlossen, …)
  • Bootstrap-Icons (bi-*) statt Legacy-GIF-Icons für Status-Anzeigen

Validierung

  • Server-seitige Validierung bleibt führend (Validator-Klasse)
  • Bootstrap-Client-Validierung als Ergänzung (needs-validation/was-validated)
  • Hilfetexte (form-text) bei jedem nicht-trivialen Eingabefeld
  • Pflichtfelder mit * markiert, Beschreibung über aria-describedby

CDN + ppb.css

  • Bootstrap 5.3.3 + Bootstrap Icons 1.11.3 via jsdelivr CDN mit SRI-Hashes
  • Schlanke ppb.css für projektspezifische Anpassungen (Link-Kontrast für WCAG-AA, BBCode-Quote-Styling, Wortumbruch in Posts)

Voraussetzungen

Komponente Version Hinweis
PHP 8.4+ mit pdo_mysql, mbstring, openssl
MySQL 8.0+ oder MariaDB 10.5+
Composer 2.0+ Autoloader und Dev-Tooling
Browser modern Bootstrap 5.3 unterstützt alle aktuellen Browser
SMTP - Mailpit im Dev-Setup, produktiv das Postfach des Hosters (STARTTLS/SSL mit Anmeldung)

Konfiguration

Zugangsdaten für Datenbank und Mailversand werden in dieser Rangfolge gelesen (höchste zuerst):

  1. config.local.php – schreibt der Web-Installer; kann auch von Hand angelegt werden. Nicht versioniert (.gitignore), per .htaccess gesperrt.
  2. Umgebungsvariablen PPB_DB_* / PPB_MAIL_* – für Docker, SetEnv oder PHP-FPM.
  3. Vorgaben aus LocalConfig::DEFAULT_MYSQL / DEFAULT_MAIL.

Die Datei config.local.php gewinnt, weil sie die ausdrückliche Einstellung genau dieser Installation ist; im Docker-Stack gibt es sie nicht, dort greifen die Umgebungsvariablen. Einzelne Schlüssel dürfen fehlen – dann gilt der Wert der nächsten Stufe.

config.local.php

<?php

declare(strict_types=1);

return [
    'mysql' => [
        'server' => 'localhost',
        'port' => 3306,
        'user' => 'forum_user',
        'password' => 'GEHEIMES_PASSWORT',
        'database' => 'forum_db',
    ],
    'mail' => [            // optional
        'host' => 'smtp.example.com',
        'port' => 587,
        'from' => 'forum@example.com',   // Absender (From); leer = Admin-E-Mail
        'user' => 'forum@example.com',   // leer = ohne Anmeldung
        'password' => 'PASSWORT_DES_POSTFACHS',
        'encryption' => 'starttls',      // none, starttls oder ssl
    ],
];

Die Datei liefert nur ein Array zurück und setzt keine Variablen. Rechte möglichst auf 640 (bzw. 600) setzen.

Mailversand: Die meisten Hoster verlangen eine Anmeldung mit einem E-Mail-Postfach und eine verschlüsselte Verbindung – starttls (meist Port 587) oder ssl (meist Port 465). Die Angaben stehen im Kundenmenü des Hosters beim E-Mail-Postfach. Das Zertifikat des Mailservers wird immer geprüft; ohne Verschlüsselung (none) meldet sich der Mailer nur an, wenn das ausdrücklich so eingestellt ist. Details, typische Werte und Fehlermeldungen: INSTALLATION.md – E-Mail-Versand.

Absender: Ist from (bzw. PPB_MAIL_FROM oder im Installer die „Absenderadresse“) gesetzt, steht diese Adresse im From aller Mails – passend zum SMTP-Postfach, wie es viele Hoster und SPF/DMARC verlangen. Die Admin-E-Mail aus den Einstellungen geht dann als Reply-To mit, bei Mails von Mitglied zu Mitglied die Adresse des schreibenden Mitglieds. Ohne eigenen Absender ist die Admin-E-Mail der Absender.

Environment-Variablen

Variable Beschreibung Standard
PPB_DB_HOST Datenbank-Host localhost
PPB_DB_PORT Datenbank-Port 3306
PPB_DB_USER Datenbank-Benutzer root
PPB_DB_PASS Datenbank-Passwort (leer)
PPB_DB_NAME Datenbank-Name PowerPHPBoard_v2
PPB_MAIL_HOST SMTP-Host mailpit
PPB_MAIL_PORT SMTP-Port 1025
PPB_MAIL_FROM Absender (From) aller Mails; Antworten gehen an die Admin-E-Mail (leer: Admin-E-Mail)
PPB_MAIL_USER SMTP-Benutzer (leer = ohne Anmeldung) (leer)
PPB_MAIL_PASS SMTP-Passwort (leer)
PPB_MAIL_ENCRYPTION Verschlüsselung: none, starttls oder ssl none
PPB_DEBUG Debug-Modus false

config.inc.php

<?php
declare(strict_types=1);

use PowerPHPBoard\Installer\LocalConfig;

$mysql = [
    'server'   => getenv('PPB_DB_HOST') ?: LocalConfig::DEFAULT_MYSQL['server'],
    'port'     => (int) (getenv('PPB_DB_PORT') ?: LocalConfig::DEFAULT_MYSQL['port']),
    'user'     => getenv('PPB_DB_USER') ?: LocalConfig::DEFAULT_MYSQL['user'],
    'password' => getenv('PPB_DB_PASS') ?: LocalConfig::DEFAULT_MYSQL['password'],
    'database' => getenv('PPB_DB_NAME') ?: LocalConfig::DEFAULT_MYSQL['database'],
];
// PPB_MAIL_HOST, _PORT, _FROM, _USER, _PASS, _ENCRYPTION, sonst LocalConfig::DEFAULT_MAIL
$mail = LocalConfig::mailFromEnvironment(static fn (string $name): string|false => getenv($name));

// config.local.php hat Vorrang
if (is_file(__DIR__ . '/config.local.php')) {
    ['mysql' => $mysql, 'mail' => $mail] = LocalConfig::apply($mysql, $mail, require __DIR__ . '/config.local.php');
}

config.inc.php selbst enthält keine Zugangsdaten mehr und wird bei jedem Update überschrieben – eigene Werte gehören in config.local.php oder in Umgebungsvariablen.

Sprache

Die UI-Sprache wird in der Datenbank gesetzt: Tabelle ppb_config, Spalte language. Möglich sind English, Deutsch-Sie, Deutsch-Du. Default seit dem Bootstrap-Refactor ist Deutsch-Du.

UPDATE ppb_config SET language = 'Deutsch-Du' WHERE id = 1;

Projektstruktur

PowerPHPBoard/
├── .docker/                       # Dev-Stack (Apache+PHP, MySQL, Mailpit, phpMyAdmin)
│   └── dev-seed.sql               # Testkonten für den Docker-Stack (nur lokal)
├── .github/workflows/             # CI
├── admin/                         # Admin-Panel (Bootstrap, eigene Navbar)
│   ├── header.inc.php             # Bootstrap-Layout mit bg-danger Navbar + Admin-Guard
│   ├── footer.inc.php
│   ├── index.php                  # Dashboard mit Stats-Tiles
│   ├── general.php                # Allgemeine Einstellungen
│   ├── boards.php / addboard.php / editboard.php
│   ├── addboardcategory.php / editboardcategory.php
│   ├── boarddesign.php
│   └── user.php / adduser.php / edituser.php
├── bin/
│   └── create-admin.php           # CLI-Notfallwerkzeug: Administrator anlegen/befördern
├── docs/                          # Audit-Berichte, Pläne, Dokumentation
├── images/                        # Smilies, UI-Grafiken (Icons jetzt via Bootstrap Icons CDN)
├── inc/                           # HTML5-Layout-Templates (öffnen/schließen Body+Bootstrap-CSS/JS)
│   ├── header.ppb                 # <!DOCTYPE> + <head> mit Bootstrap-CDN
│   └── footer.ppb                 # Bootstrap-JS + needs-validation-Init
├── includes/                      # Core-Klassen (PSR-4, Namespace PowerPHPBoard\)
│   ├── CSRF.php                   # CSRF-Tokens
│   ├── Database.php               # PDO-Wrapper (Singleton)
│   ├── DatabaseRateLimitStorage.php
│   ├── ErrorHandler.php           # Error + Security-Logging
│   ├── Mailer.php                 # SMTP-Versand mit STARTTLS/SSL und AUTH PLAIN/LOGIN
│   ├── PostDeletion.php           # Themen/Antworten löschen, „Letzter Beitrag“ neu berechnen
│   ├── RateLimiter.php            # Fenster/Lock-basiertes Rate-Limit
│   ├── RateLimiterStorage.php     # Interface für verschiedene Backends
│   ├── Security.php               # escape, hashPassword, verifyPassword, isValidEmail …
│   ├── Session.php                # Session-Verwaltung (login/logout, regenerate)
│   ├── SmtpConnection.php         # SMTP-Verbindung: Zeilen, Antworten, TLS (für Mailer)
│   ├── TextFormatter.php          # BBCode + Smilies
│   ├── ThreadPages.php            # Seite eines Beitrags für Sprung-Links (25 je Seite)
│   ├── Validator.php              # Username-, Längen-, Passwortregeln
│   └── Installer/                 # Web-Installer: LocalConfig, Schema, FormValidator,
│                                  # Requirements, DatabaseSetup, AdminAccount,
│                                  # InstallState (Sperre), Wizard, Html, SmtpCheck
├── install/                       # Web-Installer (nach der Installation löschen)
│   ├── index.php                  # Einstieg mit PHP-Versionsprüfung
│   ├── installer.php              # Ablaufsteuerung der fünf Schritte
│   └── templates/                 # Seitenvorlagen (per .htaccess gesperrt)
├── logs/                          # PHP- und Security-Logs (nicht versioniert)
├── tests/
│   ├── Unit/                      # 585 Unit-Tests
│   └── Feature/                   # 62 Feature-/Integrations-Tests
├── config.inc.php                 # Zentrale Konfiguration (DB, Mail, Konstanten)
├── config.local.php               # Zugangsdaten aus dem Web-Installer (nicht versioniert)
├── header.inc.php / footer.inc.php
│                                  # Bootstrap-Wrapper für jedes Frontend-Skript
├── functions.inc.php              # default_error (Bootstrap-Card-Alert), getrank,
│                                  # getpages (Bootstrap-Pagination), ppb_alert,
│                                  # ppb_onoff_label, render_action_button
├── ppb.css                        # Schlanke projektspezifische Styles (Link-Kontrast etc.)
├── index.php                      # Startseite, Boardliste (Bootstrap-Tabelle)
├── login.php / logout.php
├── register.php                   # Registrierung (CSRF, Validator, Mailer)
├── profile.php                    # Profil-Edit (Re-Auth für sensible Änderungen)
├── sendpassword.php               # Reset-Link anfordern (Token-Flow)
├── resetpassword.php              # Reset via Token einlösen
├── showboard.php / showthread.php
├── newthread.php / newpost.php / editpost.php  # Posting (nur Session)
├── showprofile.php / showip.php / sendmail.php / statistics.php
├── bbcode.php / smilies.php       # Referenz-Seiten
├── english.inc.php                # Sprachdateien
├── deutsch-sie.inc.php
├── deutsch-du.inc.php
├── install.sql                    # DB-Schema + Forum-Einstellungen (ohne Admin-Konto)
├── install_bugfix_2026-04-23.sql  # Migration für bestehende Installationen
├── composer.json / composer.lock
└── phpunit.xml / phpstan.neon / psalm.xml / rector.php / infection.json5

Core-Klassen

Database (Singleton PDO-Wrapper)

use PowerPHPBoard\Database;

$db   = Database::getInstance($mysql);
$user = $db->fetchOne('SELECT * FROM ppb_users WHERE id = ?', [$id]);
$rows = $db->fetchAll('SELECT * FROM ppb_posts WHERE boardid = ?', [$boardId]);
$db->query('UPDATE ppb_users SET username = ? WHERE id = ?', [$name, $id]);
$db->beginTransaction();
$db->commit();
$db->rollBack();

Security (Escape, Hashing, Validierung)

use PowerPHPBoard\Security;

Security::escape($input);                // htmlspecialchars wrapper
Security::isValidEmail($email);          // RFC-konforme Prüfung
Security::hashPassword($pw);             // Argon2id (mit bcrypt-Fallback)
Security::verifyPassword($pw, $hash);    // stützt Legacy-Base64 (Migration)
Security::needsRehash($hash);            // true = alter Hash, re-hashen
Security::getString($key, 'POST');       // sicherer Zugriff auf $_POST / $_GET / $_REQUEST
Security::getInt($key, 'REQUEST', 0);

⚠️ Wichtig: $lang_*-Strings dürfen nicht durch Security::escape() umschlossen werden. Sie enthalten beabsichtigtes HTML (<b>, <small>, &uuml; etc.) und kommen aus den vertrauenswürdigen Sprachdateien. Doppeltes Escapen führt zu sichtbaren &lt;b&gt;-Tags im Browser.

CSRF

use PowerPHPBoard\CSRF;

echo CSRF::getTokenField();              // <input type="hidden" name="csrf_token" ...>
if (!CSRF::validateFromPost()) { /* 400 */ }
CSRF::regenerate();                      // nach Login/sensiblem Change

Session

use PowerPHPBoard\Session;

Session::start();
Session::login((int) $userId);
if (Session::isLoggedIn()) { $uid = Session::getUserId(); }
Session::set('theme', 'dark');
Session::get('theme', 'light');
Session::logout();

Validator

use PowerPHPBoard\Validator;

Validator::isValidUsername('alice');       // [A-Za-z0-9._-], 2-50 Zeichen
Validator::isStrongPassword('Passw0rd!');  // min. 8 Zeichen
Validator::withinLength($bio, Validator::BIOGRAPHY_MAX); // 1000
Validator::withinLength($sig, Validator::SIGNATURE_MAX); // 500
Validator::withinLength($post, Validator::POST_MAX);     // 65000

Web-Installer (PowerPHPBoard\Installer\*)

Die Logik des Installers liegt testbar in includes/Installer/, die Oberfläche in install/:

Klasse Aufgabe
LocalConfig config.local.php erzeugen (var_export, sicher für Sonderzeichen), einlesen, Vorgaben
Schema install.sql in Anweisungen zerlegen – eine Schemaquelle für Installer und mysql < install.sql
FormValidator Eingaben der Schritte 2–4 prüfen (gleiche Regeln wie Validator/Registrierung)
Requirements Systemprüfung (PHP, Erweiterungen, Schreibrechte, HTTPS)
DatabaseSetup Verbindungstest, verständliche Fehlermeldungen, Schema + Admin einspielen mit Aufräumen bei Fehlern
InstallState Sperre des Installers und Weiterleitung der Startseite
Wizard Fortschritt in der Session (Admin-Passwort nur als Hash)
AdminAccount Administrator anlegen/befördern (auch für bin/create-admin.php)
SmtpCheck „Test-Mail senden“ in Schritt 3: Text, Zusammenfassung ohne Passwort, ehrliche Meldung

RateLimiter

use PowerPHPBoard\{RateLimiter, DatabaseRateLimitStorage};

$rl = new RateLimiter(
    new DatabaseRateLimitStorage($db),
    maxAttempts: 10,    // nach 10 Fehlversuchen …
    windowSeconds: 900, // … innerhalb von 15 Minuten …
    lockSeconds: 900    // … für 15 Minuten sperren.
);
$ident = $_SERVER['REMOTE_ADDR'] ?? 'unknown';

if (!$rl->check('login', $ident)) { /* blockiert */ }
$rl->recordFailure('login', $ident);
$rl->recordSuccess('login', $ident);

Das Interface RateLimiterStorage erlaubt das Austauschen des Backends (z. B. Redis).

Mailer

Schlanker SMTP-Client ohne externe Abhängigkeiten – verbindet sich per stream_socket_client mit einem SMTP-Server (in Dev: Mailpit auf Port 1025). Die Socket-Ebene steckt in SmtpConnection.

  • Verschlüsselung none, starttls (nach EHLO per stream_socket_enable_crypto) oder ssl (ssl://host:465), nur TLS 1.2/1.3, Zertifikatsprüfung immer an
  • Anmeldung per AUTH PLAIN, sonst AUTH LOGIN – nur mit Benutzer; ohne Verschlüsselung nur bei ausdrücklich none
  • EHLO mit Hostname bzw. eigener IP als Adressliteral, HELO für alte Server, Zeitlimit auch beim Lesen, SMTP-Punktverdopplung
use PowerPHPBoard\Mailer;

// Aus der Konfiguration ($mail in config.inc.php) …
$mailer = Mailer::fromConfig($mail);

// … oder direkt
$mailer = new Mailer(
    smtpHost: 'smtp.example.com',
    smtpPort: 587,
    encryption: Mailer::ENCRYPTION_STARTTLS,
    username: 'forum@example.com',
    password: 'PASSWORT_DES_POSTFACHS',
);

if (!$mailer->send(
    to:      'alice@example.com',
    from:    'forum@example.com',
    subject: 'Willkommen!',
    body:    "Hallo Alice,\n\ndein Account wurde angelegt."
)) {
    echo $mailer->lastError(); // z. B. "Anmeldung (AUTH PLAIN): Server antwortet 535 …"
}

Versand schlägt nicht stumm fehl – Fehler landen mit Arbeitsschritt, Antwortcode und Kurztext im error_log, Passwort und Anmeldezeilen nie. Für einen Mailserver mit eigener Zertifizierungsstelle (Testumgebung) ergänzt $mailer->withTlsOptions(['cafile' => '/pfad/ca.pem']) die SSL-Optionen, ohne die Prüfung abzuschalten.

TextFormatter (BBCode + Smilies)

use PowerPHPBoard\TextFormatter;

echo TextFormatter::formatPost(
    $text,
    $settings['bbcode']   ?? 'ON',
    $settings['smilies']  ?? 'ON',
    $settings['htmlcode'] ?? 'OFF' // in Signaturen hart auf OFF erzwungen!
);

Helper-Funktionen in functions.inc.php

// Bootstrap-Card-Alert für Fehler-Seiten (legacy-API mit Bootstrap-Output)
default_error($message, $backUrl, $backText);

// Generischer Bootstrap-Alert (success/info/warning/danger)
echo ppb_alert('Profil gespeichert.', 'success', 'Status');

// Bootstrap-Pagination für Thread-Seiten
echo getpages($threadId, $db, $currentOffset);

// ON/OFF/YES/NO-Setting in deutsche "an"/"aus"-Anzeige
echo ppb_onoff_label($settings['htmlcode'] ?? 'OFF'); // → "an" oder "aus"

Sicherheit

Siehe docs/SECURITY.md für Details. Kurzfassung:

  • Passwörter: Argon2id (mit Pfeffer durch globale Konstante, falls konfiguriert), automatische Migration aus altem Base64.
  • CSRF: Token pro Session, regeneriert bei Login und sensiblen Änderungen.
  • XSS: htmlspecialchars + Whitelist-strip_tags für Signaturen, Post-Rendering über TextFormatter::formatPost; Signaturen immer mit htmlcode=OFF.
  • SQL-Injection: Ausschließlich Prepared Statements. Keine dynamischen Queries.
  • Session: HttpOnly + SameSite=Strict + strict_mode, Regenerate bei Login/Logout.
  • Rate-Limits: Login (10 / 15 min / 15 min Lock), Passwort-Reset (5 / 1 h / 1 h Lock).
  • Passwort-Reset: Token (32 Byte random, SHA-256 gehasht in DB), 1 h Gültigkeit, einmalig einlösbar. Keine Preisgabe, ob eine E-Mail existiert.
  • Logout: nur per POST mit CSRF-Token (keine GET-CSRF-Angriffe mehr).
  • Adminbereich: Eigener Guard mit Early-Return-Bootstrap-Alert.
  • Installation: Kein Standard-Administrator mit bekanntem Passwort mehr. Der Web-Installer ist CSRF-geschützt, schreibt nur per POST und sperrt sich nach Abschluss (Sperrdatei install/.installed, vorhandene config.local.php oder eingerichtete Datenbank). Fällt die Datenbank eines eingerichteten Forums aus, bleibt er ebenfalls gesperrt. Zugangsdaten erscheinen weder in Logs noch in Fehlermeldungen; HTML in Beiträgen ist nach der Installation ausgeschaltet.
  • Lösch-Funktionen (Boards, Kategorien): Mehrstufige Bestätigung im "Gefahrenzone"-Card. Kategorien können nur gelöscht werden, wenn sie keine Boards mehr enthalten. Boards mit Threads erfordern eine separate zweite Bestätigungs-Checkbox, bevor alle Beiträge unwiderruflich entfernt werden.

Adminbereich

  • Erreichbar unter /admin/ für Nutzer mit status='Administrator'.
  • Eingeloggte Administratoren sehen im Frontend-Header zusätzlich einen "Adminbereich"-Link mit Schild-Icon (link-warning).
  • Nicht-Administratoren erhalten beim Aufruf eine alert alert-danger-Card und werden zum Login geschickt.

Funktionen

Bereich Beschreibung
Übersicht Stats-Tiles (Nutzer / Boards / Threads / Beiträge), Schnellzugriffe
Allgemein Boardtitel, URL, Admin-E-Mail, Sprache, Feature-Schalter (HTML/BBCode/Smilies)
Boards Kategorien + Boards anlegen, bearbeiten, löschen mit Bestätigung
Nutzer Komplette Liste mit Filter-Tabs (Alle / Administratoren / Normale Nutzer / Deaktiviert), Pagination (25 / Seite), Volltext-Suche per LIKE

Test-Accounts

Im Dev-Stack sind nach dem ersten Start folgende Accounts verfügbar (aus .docker/dev-seed.sql, nur lokal):

Benutzer Rolle E-Mail Passwort
RalphAdmin Administrator ralphadmin@example.com Test1234!
RalphUser Normal user ralphuser@example.com Test1234!

Für Produktion: löschen oder Passwörter ändern.


Accessibility

Lighthouse-Audit (Desktop) für /showthread.php mit Bootstrap-Refactor:

Kategorie Score
Accessibility 100
Best Practices 100
SEO 100
Agentic Browsing 100

Was wir dafür gemacht haben:

  • Semantisches HTML5: ein <h1> pro Seite, <h2> für Untertitel, <nav> mit aria-label, <main>, <header>, <footer>, <aside>.
  • <label for> an jedem Eingabefeld; aria-describedby für Hilfetexte.
  • <fieldset>/<legend> für Radio-Gruppen.
  • visually-hidden Texte für Icon-only-Status, sichtbare title-Attribute.
  • <dl class="row"> mit Bootstrap-Spalten statt inline-<dt>/<dd>-Gemurkse.
  • Kontrast-Optimierungen in ppb.css:
    • Breadcrumb- und Card-Body-Links: #0a58ca (Bootstrap-Hover-Blau, ~5.6:1 Kontrast auf bg-body-tertiary) statt Default-#0d6efd (~4.26:1).
    • Admin-Status: text-danger-emphasis statt text-danger.
  • Meta-Description in inc/header.ppb für SEO/Agentic Browsing.
  • Form-Validation client-seitig (Bootstrap was-validated), serverseitig immer Validator-Klasse.

BBCode-Referenz

Tag Ergebnis
[b]fett[/b] fett
[i]kursiv[/i] kursiv
[u]unterstrichen[/u] unterstrichen
[url]https://...[/url] Link
[url=https://...]Text[/url] Link mit Text
[img]https://.../img.png[/img] Bild
[quote]Text[/quote] Zitat
[code]... [/code] Code-Block
[color=#ff0000]rot[/color] Farbiger Text

Smilies: :) :P ;) :D :( :o :cool: :eek: :mad: :confused: :rolleyes:

Siehe auch /bbcode.php und /smilies.php im laufenden Forum.


Testing

# Alle Tests
composer test

# Nur Unit
vendor/bin/phpunit --testsuite Unit

# Nur Feature (braucht DB)
vendor/bin/phpunit --testsuite Feature

# Coverage (Xdebug erforderlich)
composer test-coverage

Aktueller Stand: 647 Tests (585 Unit + 62 Feature), 3224 Assertions, 0 Failures.

Statische Analyse:

composer phpstan   # PHPStan Level 8
composer psalm     # Psalm
composer phpmd     # PHP Mess Detector
composer cs-check  # PHP-CS-Fixer (dry-run)
composer cs-fix    # PHP-CS-Fixer (apply)
composer rector-dry
composer qa        # alles in Folge

Entwicklung

Docker-Workflow

cd .docker
docker compose up -d            # starten
docker compose logs -f web      # Logs beobachten
docker compose exec web bash    # Shell im Container
docker compose down             # stoppen (Daten bleiben)
docker compose down -v          # stoppen + alle Daten löschen

Git-Workflow

# Branch für neue Arbeit
git checkout -b feature/xyz

# Lokal testen
composer qa

# Pushen + PR
git push -u origin feature/xyz
gh pr create --title "..." --body "..."

PHP-CLI im Container

docker compose exec web php -v
docker compose exec web php -l includes/Validator.php
docker compose exec web composer test

Frontend anpassen

Das gesamte Layout liegt in inc/header.ppb (Doctype + <head> mit Bootstrap-CDN) und inc/footer.ppb (Bootstrap-JS + needs-validation-Init). Page-spezifischer Wrapper kommt aus header.inc.php / footer.inc.php (Navbar, Breadcrumb, Board-Header, Footer).

Eigene CSS-Anpassungen nur in ppb.css machen (klein und dokumentiert). Keine globalen a { color: ... }-Regeln, weil sonst die Navbar-Linkfarben auf dunklem Hintergrund unleserlich werden.


Changelog

Version 2.3.0 – 2026-09-25

Web-Installer

  • Neuer Web-Installer unter install/ in fünf Schritten (Systemprüfung, Datenbank, Forum, Administrator, Abschluss) mit Bootstrap-5-Oberfläche, CSRF-Schutz und Post/Redirect/Get – schreibende Aktionen nur per POST
  • Verbindungstest mit verständlichen Fehlermeldungen ohne Zugangsdaten; vorhandene ppb_-Tabellen werden gemeldet statt still überschrieben; schlägt die Installation fehl, entfernt der Installer die in diesem Lauf angelegten Tabellen wieder
  • Board-URL wird aus der Anfrage vorbelegt, muss aber bestätigt werden und eine http(s)-Adresse sein; HTML in Beiträgen ist nach der Installation ausgeschaltet
  • Administrator-Konto nach denselben Regeln wie die Registrierung, Passwort als Argon2id-Hash
  • Zugangsdaten landen in config.local.php (Werte per var_export, sicher für Sonderzeichen in Passwörtern); ist das Forumverzeichnis nicht beschreibbar, bietet der Installer die Datei zum Herunterladen an
  • Sperre nach der Installation: install/.installed, vorhandene config.local.php oder eingerichtete Datenbank; auch bei ausgefallener Datenbank eines konfigurierten Forums startet der Installer nicht
  • Startseite leitet ein noch nicht installiertes Forum auf install/ weiter statt einen Datenbankfehler zu zeigen
  • config.inc.php: Rangfolge config.local.php > Umgebungsvariablen > Vorgaben, neuer Datenbank-Port (PPB_DB_PORT bzw. 'port'); config.local.php per .htaccess gesperrt
  • install.sql: kein Standard-Administrator „Gott“ mit bekanntem Passwort mehr, Kommentare in sauberem UTF-8, Forum-Einstellungen mit sicheren Vorgaben (HTML aus, BBCode und Smilies an, Farben wie im Adminbereich)
  • Docker-Stack: .docker/dev-seed.sql legt die Testkonten RalphAdmin und RalphUser an (nur lokal, nicht im Release-Paket)
  • bin/create-admin.php: CLI-Notfallwerkzeug mit Argumenten statt Code-Änderung (--user, --email, --update, --password-stdin), ersetzt das alte create-admin.php
  • 212 neue Unit-Tests für Validierung, Erzeugung von config.local.php inklusive Sonderzeichen, Sperrlogik, Schema-Aufteilung und Datenbank-Einrichtung

Sicherheit

  • Gespeichertes XSS geschlossen: Beiträge werden immer escaped, bei „HTML an“ nur attributlose Formatierungs-Tags; Links und Bilder nur mit http(s), auch [url=…] und die Homepage im Profil
  • Passwort-Reset-Link nur noch aus der konfigurierten Board-URL, nie aus dem Host-Header
  • Deaktivierte Konten können sich nicht mehr anmelden, offene Sitzungen werden beendet
  • Private Boards: Passwörter als Argon2id-Hash (alte Werte werden beim ersten richtigen Passwort umgestellt), Zugangsnachweis statt Passwortkopie in ppb_visits, Zitatfunktion und Brotkrumen ohne Zugang gesperrt, Sperre nach Fehlversuchen
  • SMTP-Punktverdopplung gegen das Einschleusen weiterer Empfänger, IP-Anzeige nur für Moderatoren des betroffenen Boards, Header-/Footer-Templates nur aus inc/, „Design anwenden“ nur per POST mit CSRF-Schutz

Mailversand

  • SMTP-Anmeldung per AUTH PLAIN bzw. AUTH LOGIN und Verschlüsselung per STARTTLS (meist Port 587) oder SSL/TLS (meist Port 465), nur TLS 1.2/1.3, Zertifikatsprüfung immer an; ohne Verschlüsselung meldet sich der Mailer nur bei ausdrücklich none an
  • Neue Einstellungen user, password und encryption in $mail bzw. config.local.php, Umgebungsvariablen PPB_MAIL_USER, PPB_MAIL_PASS und PPB_MAIL_ENCRYPTION; unbekannte Verschlüsselungswerte werden nie stillschweigend unverschlüsselt versendet
  • Web-Installer, Schritt 3: Verschlüsselung, Benutzername und Passwort des Postfachs, Port-Vorschlag passend zur Verschlüsselung und „Test-Mail senden“ an die E-Mail-Adresse des Forums mit ehrlicher Erfolgs- bzw. Fehlermeldung
  • Fehlerprotokoll mit Arbeitsschritt, SMTP-Antwortcode und Kurztext – ohne Passwort und Anmeldezeilen; EHLO mit Hostname bzw. Adressliteral, Zeitlimit auch beim Lesen
  • Systemprüfung des Installers weist auf die PHP-Erweiterung openssl hin
  • Ein eingestellter Absender (from bzw. PPB_MAIL_FROM, im Installer die „Absenderadresse“) ist jetzt der From aller Mails und der Absender gegenüber dem SMTP-Server; die Admin-E-Mail geht als Reply-To mit, bei Mails von Mitglied zu Mitglied die Adresse des schreibenden Mitglieds. Ohne eigenen Absender bleibt die Admin-E-Mail der Absender. Die Test-Mail des Installers folgt derselben Regel

Fehlerbehebungen

  • Registrierungs-, Reset- und Benutzer-Mails kamen bei Hostern, deren Mailserver eine Anmeldung verlangt, nie an – der Mailer beherrscht jetzt Anmeldung und Verschlüsselung
  • Eine fehlende Antwort auf QUIT meldet eine bereits angenommene Mail nicht mehr als gescheitert
  • Registrierung und „Benutzer anlegen“ nicht mehr durch ein vorbelegtes „https://“ blockiert
  • Alle Mails über den SMTP-Mailer, Fehlschläge werden gemeldet, kein Klartext-Passwort mehr per Mail
  • Eingaben bleiben nach Fehlern erhalten, Design-Felder sind optional, ein falsches Board-Passwort wird gemeldet
  • Letzter Administrator und eigener Status sind geschützt; Benutzernamen und Passwörter werden auch im Adminbereich geprüft
  • Themen-Symbole werden angezeigt; Bearbeiten und IP-Anzeige nur für Berechtigte
  • PPB_VERSION stimmt wieder mit dem Release überein
  • „Zum letzten Beitrag springen“ und „Zum ersten ungelesenen Beitrag springen“ führten bei genau 25, 50 … Beiträgen auf eine leere Seite; nach einer Antwort springt „Zurück zum Thema“ jetzt auf die Seite der neuen Antwort
  • [code]-Blöcke bekamen nach jeder Zeile eine zusätzliche Leerzeile
  • Nach dem Löschen eines Themas oder einer Antwort zeigten Startseite und Themenliste weiter den gelöschten Beitrag als letzten an (Pfeil ins Leere)
  • Geschlossene Boards waren auch für Administratoren gesperrt: Administratoren und die Moderatoren des Boards schreiben dort und in geschlossenen Themen weiterhin, etwa in einem Ankündigungsboard; alle anderen sehen „Forum geschlossen“ bzw. „Thema geschlossen“
  • Ein richtiges Board-Passwort setzt den Fehlversuchszähler zurück (Zähler je IP-Adresse und Board)

Sprache & Oberfläche

  • Drei synchrone Sprachdateien in UTF-8 ohne HTML-Entitäten, einheitliches Siezen bzw. Duzen, Adminbereich vollständig übersetzt
  • Neutrale Forenränge („Neuling“ bis „Legende“) statt Marine-Rängen, gleiche Schwellen
  • BBCode-Hilfe zeigt die tatsächlich unterstützten Tags, gerendert mit dem TextFormatter
  • Neues Thema ohne Antworten: „Letzte Antwort“ zeigt „Keine Antworten“ statt Datum und Autor des Starterbeitrags
  • „E-Mail-Adresse verbergen?“ ist bei Registrierung und „Benutzer anlegen“ auf „ja“ voreingestellt (Privacy by Default)
  • Kontaktformular einheitlich: Briefumschlag im Beitragskopf und „E-Mail senden“ im Profil bei allen Mitgliedern, die Adresse selbst nur bei „nicht verbergen“
  • Die wirkungslose Option „Anmeldung merken?“ entfällt in Registrierung, Profil und Adminbereich (die Spalte logincookie bleibt aus Kompatibilitätsgründen)
  • Hinweis „Forum geschlossen – Sie schreiben mit Moderationsrechten.“ bzw. „Thema geschlossen – …“ für Administratoren und Moderatoren
  • Board-Passwort im Adminbereich als verdecktes Feld mit dem sachlich richtigen Hinweis „Wird nur als Hash gespeichert und kann nicht wieder angezeigt werden.“
  • INSTALLATION.md auf 2.3.0 aktualisiert und mit echten Umlauten; die veraltete README.html (Stand 2.1.0, ohne Generator, nicht im Release-Paket) ist entfallen – maßgeblich ist diese README.md

Video-Anleitungen

  • Vertonte Schritt-für-Schritt-Videos zu Installation, Einstellungen, Forenstruktur, privaten Boards, Registrierung, Beiträgen, Moderation und Passwort-Reset auf powerscripts.org

Version 2.2.1 – 2026-05-10 (i18n + CI)

Sprachdateien synchronisiert und Pipeline gehärtet.

Bug-Fixes

  • english.inc.php: Tippfehler-Variable $lang_opentrhead (toter Code) entfernt
  • english.inc.php: 3 doppelte Definitionen entfernt ($lang_closethread, $lang_title, $lang_nopostwithid)
  • english.inc.php: HTML-Bug BBCode</a> is und Smilies</a> are (Schließtag ohne öffnendes <a>) – war im Frontend auf Edit-/New-Post/ New-Thread/Profile/Register-Seite sichtbar
  • editpost.php: PHPStan Level-8 assert($post !== null) für Null-Guard
  • deutsch-du.inc.php / deutsch-sie.inc.php: Tippfehler kansnt, Korrektniss, Passworterinnerumg, unterstichen

Modernisierung Englisch

  • adress → address (9× im Datenbestand)
  • eMail → email (10×)
  • successfull → successful, loggin in → logging in, replys → replies, updateing → updating, autmatic generated → automatically generated, can not → cannot

Sonstiges

  • BBCode-Beispiele in allen drei Sprachdateien: alte Domain ps-powerscripts.de → https://www.powerscripts.org
  • Default-Boardtitel: PowerPHPBoard 2.2.1
  • 21 Files mit php-cs-fixer fix formatiert (Indents in Inline-PHP)
  • CI grün: PHPStan Level 8 (0 Errors), PHP-CS-Fixer (0 Findings), PHPMD clean, alle PHPUnit-Tests grün

Validierung

  • $lang_*-Schlüssel: 199 in deutsch-du.inc.php und english.inc.php identisch (vorher Drift durch opentrhead-Tippfehler)

Version 2.2.0 – 2026-05-10 (Bootstrap-5-Frontend)

Komplettes Frontend-Refactoring – die gesamte HTML-Ausgabe wurde in ein konsistentes Bootstrap-5.3.3-Template überführt (siehe .ralph-loop/ für das Audit-Protokoll).

Neue Features

  • HTML5 + Bootstrap 5.3.3 + Bootstrap Icons via CDN mit SRI
  • Komplette Sprachvereinheitlichung auf Deutsch (Default Deutsch-Du)
  • Test-Accounts RalphAdmin / RalphUser (passwort Test1234!)
  • Helper-Funktion ppb_onoff_label() für deutsche an/aus-Anzeige
  • Helper-Funktion ppb_alert() für Bootstrap-Alerts
  • Bootstrap-Setup-Layout für create-admin.php (Setup-Skript)
  • Adminbereich mit eigener bg-danger-Navbar und Admin-Guard
  • Adminbereich-Link im Frontend-Header (gelb, Schild-Icon) – nur für eingeloggte Administratoren sichtbar
  • Komplette Nutzerliste in admin/user.php mit Filter-Tabs (Alle / Administratoren / Normale Nutzer / Deaktiviert), Pagination und Volltext-Suche
  • Lösch-Funktion für Boards und Kategorien: "Gefahrenzone"-Card mit kontextueller Bestätigung, Cascade-Delete für Threads/Posts/Visits beim Board-Löschen, Schutz vor Kategorie-Löschung wenn Boards drin sind
  • Klare Beschriftungen + Info-Alerts für Legacy-Design-Felder (Hg 1/2/3 → "Tabelle Hintergrund 1/2/3" + Erklärung "Helle Zeile" etc.; Header-Datei → "Eigenes Header-Template" + Hilfetext; Button "Neuer Thread" → "Bild für 'Neuer Thread'-Button" + Größenhinweis)
  • Color-Preview-Squares neben jedem Hex-Farb-Input
  • Footer auf https://www.powerscripts.org verlinkt (statt GitHub + MIT-Link)
  • Default-Boardtitel: PowerPHPBoard 2.2.1 (statt 1.0 BETA)

Refactor

  • 18 Forum-PHP-Dateien (index, showboard, showthread, login, logout, register, profile, showprofile, newthread, newpost, editpost, sendpassword, resetpassword, sendmail, showip, bbcode, smilies, statistics)
  • 13 Admin-Dateien (alle in admin/)
  • header.inc.php, footer.inc.php, functions.inc.php
  • HTML5-Templates in inc/header.ppb/inc/footer.ppb
  • ppb.css schlank, ohne Legacy-Link-Color-Override

Sicherheits-Fixes

  • editpost.php: editpost-Parameter wird aus REQUEST gelesen (war fälschlich POST), Edit-Submit funktioniert jetzt
  • Doppeltes HTML-Escapen von Lang-Strings entfernt (zeigte <b> als Text)
  • Operator-Präzedenz-Bug in 5 Stellen behoben (('<a>' . $lang_x ?? 'Y' . '</a>') produzierte offene <a>-Tags)

Sprache & Lesbarkeit

  • Alle Transliterationen (ae/oe/ue/ss) durch echte Umlaute ersetzt (ä/ö/ü/ß) – konsequent in allen geänderten Dateien und Sprachfiles
  • "eMail Adresse" → "E-Mail-Adresse" (alle Sprachfiles)
  • "Forumpasswort" → "Forum-Passwort"
  • "Letzer Beitrag" → "Letzter Beitrag" (Tippfehler-Fix)
  • "Anzeigen" (Spalte für Views) → "Aufrufe"
  • ON/OFF in Forms → an/aus
  • yes/no-Fallbacks → ja/nein
  • "Zurücksetzten" → "Zurücksetzen" ($lang_reset)

Accessibility & SEO

  • Lighthouse Desktop: 100/100/100/100
  • WCAG-AA-Kontrast überall (Breadcrumb-Links, Admin-Badges)
  • Korrekte Heading-Hierarchie (<h1> einmal pro Seite, <h2> für Sektionen)
  • <dl class="row"> mit semantisch sauberen <dt>/<dd>-Paaren
  • Meta-Description ergänzt
  • Mobile responsive (Hamburger-Navbar, responsive Tabellen)

Tests

  • 5 vorbestehende PHPUnit-Failures (Test-Fixture-Bugs in FeatureTestCase::createTestUser – falsche Spaltennamen) gefixt
  • 198/198 Tests grün (137 Unit + 61 Feature, 362 Assertions)

Version 2.1.0 – 2026-04-24 (Bugfix-Release)

Basierend auf dem Userbereich-Audit vom 2026-04-23 (siehe docs/2026-04-23-Userbereichs-bugs.md). Alle 18 dokumentierten Bugs behoben.

Neue Features

  • Validator-Klasse (Username-Regex, Passwortregeln, Length-Checks)
  • RateLimiter + DatabaseRateLimitStorage (Login- und Reset-Bruteforce-Schutz)
  • Mailer-Klasse (SMTP direkt, ersetzt stummes @mail())
  • resetpassword.php (Token-basierter Passwort-Reset)
  • install_bugfix_2026-04-23.sql (Migration für Username-UNIQUE, Tokens, Rate-Limits)

Sicherheits-Fixes

  • Stored XSS via Signatur verhindert (Whitelist-strip_tags + htmlcode=OFF im Rendering)
  • Passwort-Reset überschreibt Passwörter nicht mehr sofort – Token-Flow
  • Logout nur noch per POST mit CSRF-Token
  • Login/Reset liefern vereinheitlichte Fehlermeldungen (keine User-Enumeration)
  • Brute-Force-Schutz auf Login (10/15min) und Reset (5/1h)
  • Re-Authentifizierung per aktuellem Passwort bei E-Mail-/Passwort-Wechsel
  • UNIQUE-Index auf ppb_users.username

UX / Workflow

  • Registrierungsformular liest acception aus REQUEST (nicht mehr nur GET) – Registrierung funktioniert jetzt ohne Workaround
  • Profilseite: Passwortfelder optional (leer = keine Änderung), ICQ-Default-0 wird leer angezeigt
  • Posting: nur per Session (kein paralleler E-Mail+Password-Auth-Pfad mehr)
  • Längen-Checks mit klaren Fehlermeldungen (statt stummen PDO-Exceptions)
  • Login-Erfolgstext entfernt Legacy-"360-Tage-Cookie"-Hinweis

Version 2.0.0 – 2026-01 (PHP 8.4 Migration)

  • Komplette Modernisierung auf PHP 8.4
  • PHPUnit-Testsuite eingeführt
  • PHPStan Level 8, Psalm, PHP-CS-Fixer, Rector, Infection
  • GitHub Actions CI/CD
  • Zentrales Error-Handling, Security-Event-Logging
  • PSR-4 Autoloading
  • Session-basierte Authentifizierung statt Cookie mit Passwort

Version 1.x – 2001-2009

  • Ursprüngliche Entwicklung von Stefan "BFG" Kramer
  • PHP 4/5, mysql_*-Funktionen, Basis-Forum

Lizenz

MIT License

Copyright (c) 2001-2009 Stefan "BFG" Kramer (PowerScripts) Copyright (c) 2026 Nico Schubert / PowerScripts

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Kontakt

SchubertMedia Inhaber: Nico Schubert Stauffenbergallee 57 D-99085 Erfurt

  • Telefon: +49 (0) 3612 3002247 (Mo.–Fr. 9–12 und 13–18 Uhr)
  • Telefax: +49 (0) 3612 3004636
  • E-Mail: info@schubertmedia.de

Projekte:

Bug-Reports und Feature-Requests bitte über die GitHub-Issues: https://github.com/schubertnico/PowerPHPBoard/issues

About

PowerPHPBoard - Sicheres, leichtgewichtiges PHP 8.4 Forum-System

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages