109 lines
5.4 KiB
PHP
109 lines
5.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file db.php
|
|
* @brief Enthält grundlegende Funktionen und Initialisierungen für die Datenbankinteraktion.
|
|
*
|
|
* @details Diese Datei kapselt den gesamten Prozess des Verbindungsaufbaus zur MySQL/MariaDB-Datenbank.
|
|
* Sie nutzt die zentralen Konfigurationseinstellungen (wie Host, Benutzer, Passwort, Datenbankname und Port),
|
|
* die in der Datei config.php hinterlegt sind. Durch die Auslagerung in diese Datei wird eine einheitliche
|
|
* und zentrale Stelle für das Verbindungsmanagement geschaffen, was die Wartbarkeit, Sicherheit und
|
|
* Erweiterbarkeit des Gesamtsystems signifikant verbessert.
|
|
*
|
|
* Besonderes Augenmerk liegt auf der Fehlerbehandlung beim Verbindungsaufbau: Schlägt dieser fehl,
|
|
* so wird der Ausführungskontext sicher terminiert und ein HTTP-Statuscode 500 generiert. Zudem wird
|
|
* der Zeichensatz streng konfiguriert (meist utf8mb4), was für die fehlerfreie Verarbeitung von
|
|
* Sonderzeichen und Emojis essenziell ist und Schutz vor bestimmten SQL-Injection-Vektoren bietet.
|
|
*
|
|
* @author Geizkragen Entwicklerteam
|
|
* @version 1.1
|
|
* @date 2026-04-04
|
|
*/
|
|
|
|
declare(strict_types=1); ///< Erzwingt auf Sprachebene strikte Typenprüfung für Parameter und Rückgabewerte dieses Skripts. Dies verhindert fehleranfällige, implizite automatische Typenumwandlungen.
|
|
|
|
/**
|
|
* @brief Baut eine MySQLi-Datenbankverbindung anhand der zentralen Konfiguration auf und liefert diese zurück.
|
|
*
|
|
* @details Diese essenzielle Funktion greift auf die zentrale Konfigurationsdatei (config.php) zu,
|
|
* lädt deren Parameterstruktur und initialisiert eine neue Instanz der Klasse mysqli, sofern dies
|
|
* für den aktuellen Ausführungskontext notwendig ist. Um Performance zu optimieren, nutzt sie
|
|
* das Singleton-ähnliche Konzept mittels einer statischen Variablen, sodass die Konfiguration
|
|
* (und die Datei-Lese-Operation) nur genau einmal pro Skriptlauf ausgeführt wird.
|
|
*
|
|
* @attention Bei einem Verbindungsfehler bricht das System das Skript mittels die() hart ab.
|
|
* Sensible Datenbankfehler (wie falsche Zugangsdaten) werden dabei absichtlich nicht ausgegeben,
|
|
* um so genannte Information Disclosure-Vulnerabilities zu vermeiden. Stattdessen wird lediglich
|
|
* der neutrale Text "Datenbankfehler" gezeigt und der HTTP Header auf Status 500 gesetzt.
|
|
*
|
|
* @b Anwendungsbeispiel:
|
|
* @code
|
|
* // Verbindung zur Datenbank aufbauen
|
|
* $mysqli_connection = db_connect();
|
|
*
|
|
* // Abfrage ausführen
|
|
* $result = $mysqli_connection->query("SELECT * FROM users");
|
|
* @endcode
|
|
*
|
|
* @return mysqli Das erfolgreich aufgebaute und vollständig konfigurierte Datenbankverbindungs-Objekt.
|
|
*
|
|
* @throws Exception Löst im Hintergrund potenziell Ausnahmen aus, fängt diese durch manuelle Fehlerabfragen ($conn->connect_error) aber sauber ab.
|
|
*/
|
|
function db_connect(): mysqli
|
|
{
|
|
/**
|
|
* @var array|null $cfg Statische Variable zur Wiederverwendung der Systemkonfiguration.
|
|
* Durch das Schlüsselwort 'static' behält diese Variable ihren Wert auch über
|
|
* multiple Funktionsaufrufe hinweg und verhindert mehrfaches Einlesen der config.php.
|
|
*/
|
|
static $cfg;
|
|
|
|
/// Prüft, ob die Konfiguration im aktuellen Skriptlauf bereits geladen und im Speicher abgelegt wurde.
|
|
if ($cfg === null)
|
|
{
|
|
/**
|
|
* @var array{db: array{host:string,port:int,user:string,pass:string,name:string,charset:string}} $cfg
|
|
* @brief Bindet die Konfigurationsdaten ein und lädt das rückgegebene Array in die statische Variable $cfg.
|
|
* Der Dateipfad wird hierbei relativ und sicher über die magische Konstante __DIR__ dynamisch aufgelöst.
|
|
*/
|
|
$cfg = require __DIR__ . '/config.php';
|
|
}
|
|
|
|
/// Extrahiert aus Leistungs- und Lesbarkeitsgründen den spezifischen Datenbankbereich der geladenen Gesamt-Konfiguration in die lokale Variable $db.
|
|
$db = $cfg['db'];
|
|
|
|
/// Initialisiert direkt eine neue, native mysqli-Verbindung mit den extrahierten Zugangsdaten (Host, Benutzer, Passwort, DB-Name, Port).
|
|
$conn = new mysqli($db['host'], $db['user'], $db['pass'], $db['name'], $db['port']);
|
|
|
|
/**
|
|
* @brief Überprüft unmittelbar, ob beim Versuch des Verbindungsaufbaus durch die MySQLi-Extension ein Fehler aufgetreten ist.
|
|
* Wenn der Wert von $conn->connect_error einen String enthält (und somit nicht null ist), war der Verbindungsversuch erfolglos.
|
|
*/
|
|
if ($conn->connect_error)
|
|
{
|
|
/**
|
|
* @brief Ein fataler Fehler ist aufgetreten: Setzt den HTTP-Response-Statuscode auf 500 (Internal Server Error).
|
|
* Dies teilt dem Browser oder API-Konsumenten strukturiert mit, dass der Server ein internes Problem hat.
|
|
*/
|
|
http_response_code(500);
|
|
|
|
/**
|
|
* @brief Bricht die Ausführung des gesamten PHP-Skripts unwiderruflich ab.
|
|
* Aus Sicherheitsgründen wird dem Client lediglich eine maskierte, generelle String-Fehlermeldung ("Datenbankfehler") ausgegeben.
|
|
*/
|
|
die('Datenbankfehler');
|
|
}
|
|
|
|
/**
|
|
* @brief Setzt für die nun erfolgreich initiierte Verbindung ein einheitliches, konfiguriertes Charset.
|
|
* Dies ist (insbesondere bei utf8mb4) aus Sicherheits- und Stabilitätsgründen äußerst wichtig, um Encoding-Probleme,
|
|
* abgeschnittene Texte und potenzielle SQL-Sicherheitslücken beim Escaping vollständig auszuschließen.
|
|
*/
|
|
$conn->set_charset($db['charset']);
|
|
|
|
/// Der Aufbau war erfolgreich. Gibt die einsatzbereite und abgesicherte MySQLi-Klasseninstanz an den aufrufenden Kontext zurück.
|
|
return $conn;
|
|
}
|
|
|
|
?>
|