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.
- Projekt-Website: https://www.powerscripts.org
- Projektübersicht: https://www.powerscripts.org/projects-3.html
- Repository: https://github.com/schubertnico/PowerPHPBoard
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 -> ForumBeim 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) |
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 | Passwort | |
|---|---|---|---|
RalphAdmin |
Administrator | ralphadmin@example.com |
Test1234! |
RalphUser |
Normal user | ralphuser@example.com |
Test1234! |
# 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 -vSeit 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:
- Dateien hochladen – das Release-Paket entpacken und per FTP/SFTP in das
gewünschte Verzeichnis kopieren (versteckte
.htaccess-Dateien mit übertragen). - 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. - 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 inconfig.local.php. 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/ aufrufenDer 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.
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.
Wenn du eine ältere Version updatest, führe zusätzlich die Migration aus:
mysql -u <user> -p <dbname> < install_bugfix_2026-04-23.sqlSie legt neue Tabellen für Password-Reset-Tokens und Rate-Limits an und setzt UNIQUE auf username.
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-autoloaderBei einem "dummen" Upload (FTP/SFTP) bitte die in .gitattributes mit
export-ignore markierten Verzeichnisse manuell NICHT mit hochladen.
- Features
- Frontend (Bootstrap 5)
- Voraussetzungen
- Konfiguration
- Projektstruktur
- Core-Klassen
- Sicherheit
- Adminbereich
- Accessibility
- BBCode-Referenz
- Testing
- Entwicklung
- Changelog
- Lizenz
- Kontakt
- 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
- 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)
- 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
Seit Version 2.2.0 nutzt PowerPHPBoard ein durchgängiges Bootstrap-5.3.3-Frontend:
- 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-lightundlink-lightfür Kontrast
- 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
- 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 überaria-describedby
- Bootstrap 5.3.3 + Bootstrap Icons 1.11.3 via jsdelivr CDN mit SRI-Hashes
- Schlanke
ppb.cssfür projektspezifische Anpassungen (Link-Kontrast für WCAG-AA, BBCode-Quote-Styling, Wortumbruch in Posts)
| 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) |
Zugangsdaten für Datenbank und Mailversand werden in dieser Rangfolge gelesen (höchste zuerst):
config.local.php– schreibt der Web-Installer; kann auch von Hand angelegt werden. Nicht versioniert (.gitignore), per.htaccessgesperrt.- Umgebungsvariablen
PPB_DB_*/PPB_MAIL_*– für Docker,SetEnvoder PHP-FPM. - 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.
<?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.
| 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 |
<?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.
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;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
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();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 durchSecurity::escape()umschlossen werden. Sie enthalten beabsichtigtes HTML (<b>,<small>,üetc.) und kommen aus den vertrauenswürdigen Sprachdateien. Doppeltes Escapen führt zu sichtbaren<b>-Tags im Browser.
use PowerPHPBoard\CSRF;
echo CSRF::getTokenField(); // <input type="hidden" name="csrf_token" ...>
if (!CSRF::validateFromPost()) { /* 400 */ }
CSRF::regenerate(); // nach Login/sensiblem Changeuse PowerPHPBoard\Session;
Session::start();
Session::login((int) $userId);
if (Session::isLoggedIn()) { $uid = Session::getUserId(); }
Session::set('theme', 'dark');
Session::get('theme', 'light');
Session::logout();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); // 65000Die 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 |
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).
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(nachEHLOperstream_socket_enable_crypto) oderssl(ssl://host:465), nur TLS 1.2/1.3, Zertifikatsprüfung immer an - Anmeldung per
AUTH PLAIN, sonstAUTH LOGIN– nur mit Benutzer; ohne Verschlüsselung nur bei ausdrücklichnone EHLOmit Hostname bzw. eigener IP als Adressliteral,HELOfü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.
use PowerPHPBoard\TextFormatter;
echo TextFormatter::formatPost(
$text,
$settings['bbcode'] ?? 'ON',
$settings['smilies'] ?? 'ON',
$settings['htmlcode'] ?? 'OFF' // in Signaturen hart auf OFF erzwungen!
);// 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"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_tagsfür Signaturen, Post-Rendering überTextFormatter::formatPost; Signaturen immer mithtmlcode=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, vorhandeneconfig.local.phpoder 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.
- Erreichbar unter
/admin/für Nutzer mitstatus='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.
| 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 |
Im Dev-Stack sind nach dem ersten Start folgende Accounts verfügbar
(aus .docker/dev-seed.sql, nur lokal):
| Benutzer | Rolle | Passwort | |
|---|---|---|---|
RalphAdmin |
Administrator | ralphadmin@example.com |
Test1234! |
RalphUser |
Normal user | ralphuser@example.com |
Test1234! |
Für Produktion: löschen oder Passwörter ändern.
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>mitaria-label,<main>,<header>,<footer>,<aside>. <label for>an jedem Eingabefeld;aria-describedbyfür Hilfetexte.<fieldset>/<legend>für Radio-Gruppen.visually-hiddenTexte für Icon-only-Status, sichtbaretitle-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 aufbg-body-tertiary) statt Default-#0d6efd(~4.26:1). - Admin-Status:
text-danger-emphasisstatttext-danger.
- Breadcrumb- und Card-Body-Links:
- Meta-Description in
inc/header.ppbfür SEO/Agentic Browsing. - Form-Validation client-seitig (Bootstrap
was-validated), serverseitig immer Validator-Klasse.
| 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.
# 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-coverageAktueller 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 Folgecd .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# 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 "..."docker compose exec web php -v
docker compose exec web php -l includes/Validator.php
docker compose exec web composer testDas 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.
- 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 pervar_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, vorhandeneconfig.local.phpoder 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: Rangfolgeconfig.local.php> Umgebungsvariablen > Vorgaben, neuer Datenbank-Port (PPB_DB_PORTbzw.'port');config.local.phpper.htaccessgesperrtinstall.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.sqllegt die TestkontenRalphAdminundRalphUseran (nur lokal, nicht im Release-Paket) bin/create-admin.php: CLI-Notfallwerkzeug mit Argumenten statt Code-Änderung (--user,--email,--update,--password-stdin), ersetzt das altecreate-admin.php- 212 neue Unit-Tests für Validierung, Erzeugung von
config.local.phpinklusive Sonderzeichen, Sperrlogik, Schema-Aufteilung und Datenbank-Einrichtung
- 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
- SMTP-Anmeldung per
AUTH PLAINbzw.AUTH LOGINund 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ücklichnonean - Neue Einstellungen
user,passwordundencryptionin$mailbzw.config.local.php, UmgebungsvariablenPPB_MAIL_USER,PPB_MAIL_PASSundPPB_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;
EHLOmit Hostname bzw. Adressliteral, Zeitlimit auch beim Lesen - Systemprüfung des Installers weist auf die PHP-Erweiterung
opensslhin - Ein eingestellter Absender (
frombzw.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 alsReply-Tomit, 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
- 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
QUITmeldet 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_VERSIONstimmt 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)
- 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
logincookiebleibt 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.mdauf 2.3.0 aktualisiert und mit echten Umlauten; die veralteteREADME.html(Stand 2.1.0, ohne Generator, nicht im Release-Paket) ist entfallen – maßgeblich ist dieseREADME.md
- Vertonte Schritt-für-Schritt-Videos zu Installation, Einstellungen, Forenstruktur, privaten Boards, Registrierung, Beiträgen, Moderation und Passwort-Reset auf powerscripts.org
Sprachdateien synchronisiert und Pipeline gehärtet.
english.inc.php: Tippfehler-Variable$lang_opentrhead(toter Code) entferntenglish.inc.php: 3 doppelte Definitionen entfernt ($lang_closethread,$lang_title,$lang_nopostwithid)english.inc.php: HTML-BugBBCode</a> isundSmilies</a> are(Schließtag ohne öffnendes<a>) – war im Frontend auf Edit-/New-Post/ New-Thread/Profile/Register-Seite sichtbareditpost.php: PHPStan Level-8assert($post !== null)für Null-Guarddeutsch-du.inc.php/deutsch-sie.inc.php: Tippfehlerkansnt,Korrektniss,Passworterinnerumg,unterstichen
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
- 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 fixformatiert (Indents in Inline-PHP) - CI grün: PHPStan Level 8 (0 Errors), PHP-CS-Fixer (0 Findings), PHPMD clean, alle PHPUnit-Tests grün
$lang_*-Schlüssel: 199 indeutsch-du.inc.phpundenglish.inc.phpidentisch (vorher Drift durchopentrhead-Tippfehler)
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).
- HTML5 + Bootstrap 5.3.3 + Bootstrap Icons via CDN mit SRI
- Komplette Sprachvereinheitlichung auf Deutsch (Default
Deutsch-Du) - Test-Accounts
RalphAdmin/RalphUser(passwortTest1234!) - 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.phpmit 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(statt1.0 BETA)
- 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.cssschlank, ohne Legacy-Link-Color-Override
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)
- 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)
- 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)
- 5 vorbestehende PHPUnit-Failures (Test-Fixture-Bugs in
FeatureTestCase::createTestUser– falsche Spaltennamen) gefixt - 198/198 Tests grün (137 Unit + 61 Feature, 362 Assertions)
Basierend auf dem Userbereich-Audit vom 2026-04-23 (siehe docs/2026-04-23-Userbereichs-bugs.md).
Alle 18 dokumentierten Bugs behoben.
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)
- Stored XSS via Signatur verhindert (Whitelist-
strip_tags+htmlcode=OFFim 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
- Registrierungsformular liest
acceptionaus REQUEST (nicht mehr nur GET) – Registrierung funktioniert jetzt ohne Workaround - Profilseite: Passwortfelder optional (leer = keine Änderung),
ICQ-Default-
0wird 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
- 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
- Ursprüngliche Entwicklung von Stefan "BFG" Kramer
- PHP 4/5,
mysql_*-Funktionen, Basis-Forum
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.
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:
- https://www.powerscripts.org – PowerScripts Hauptseite
- https://www.powerscripts.org/projects-3.html – Alle Projekte
- https://github.com/schubertnico/PowerPHPBoard – Quellcode
Bug-Reports und Feature-Requests bitte über die GitHub-Issues: https://github.com/schubertnico/PowerPHPBoard/issues