'jpg', 'image/png' => 'png', ]; /** * @var finfo $finfo PHP finfo-Instanz zur Bestimmung des tatsächlichen MIME-Types der Datei. */ $finfo = new finfo(FILEINFO_MIME_TYPE); /** * @var string|false $mime Der ausgelesene MIME-Type der temporären Datei. */ $mime = $finfo->file($tmp); /** * @brief Validiert den MIME-Type. * * @details Erlaubt sind nur die in $allowedMimeToExt definierten Dateitypen (JPEG, PNG). */ if (!$mime || !isset($allowedMimeToExt[$mime])) { // Mime loggen ist ok (kein Secret), hilft bei Support error_log('Upload: invalid mime=' . (string)$mime); header('Location: account.php?upload=err&code=mime'); exit(); } /** * @var string $ext Die zur validierten Datei passende Dateiendung. */ $ext = $allowedMimeToExt[$mime]; /** * @var string $relativeTargetDir Relativer Pfad zum Verzeichnis der Profilbilder. */ // Zielordner: assets/images/profilePictures relativ zum Projekt (upload.php liegt im Webroot) $relativeTargetDir = 'assets/images/profilePictures'; /** * @var string $dirTargetDir Absoluter Pfad zum Zielordner, basierend auf der aktuellen Datei (__DIR__). */ // Kandidat 1: relativ zu __DIR__ (robust gegen VHost/Alias) $dirTargetDir = rtrim(__DIR__, "\\/") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativeTargetDir); /** * @var string $documentRoot Dokumentenwurzel des Webservers (falls gesetzt). */ // Kandidat 2: relativ zu DOCUMENT_ROOT (nur wenn gesetzt) $documentRoot = isset($_SERVER['DOCUMENT_ROOT']) ? (string)$_SERVER['DOCUMENT_ROOT'] : ''; /** * @var string $docRootTrim Formatierter Dokumenten-Root-Pfad (ohne abschließende Slashes). */ $docRootTrim = rtrim($documentRoot, "\\/"); /** * @var string $docTargetDir Absoluter Zielordner aus der Server-Variablen (DOCUMENT_ROOT). */ $docTargetDir = ($docRootTrim !== '') ? $docRootTrim . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativeTargetDir) : ''; /** * @var string $targetDir Finaler Pfad, in den die Datei verschoben wird. * @details Bevorzugt wird __DIR__. Falls dieses aus Systemgründen fehlschlägt und DOCUMENT_ROOT zur Verfügung steht, wird dieser verwendet. */ // Bevorzugt __DIR__. Falls __DIR__ aus irgendeinem Grund nicht ins Projekt zeigt, und DOCUMENT_ROOT plausibel ist, nutze DOCUMENT_ROOT. $targetDir = $dirTargetDir; if ($docTargetDir !== '' && !is_dir($dirTargetDir) && is_dir($docTargetDir)) { $targetDir = $docTargetDir; } /** * @brief Prüft, ob das Zielverzeichnis existiert und erstellt es gegebenenfalls. * * @details Nutzt mkdir() rekursiv, um fehlende Ordnerstrukturen zu generieren. */ if (!is_dir($targetDir)) { $mkOk = @mkdir($targetDir, 0755, true); if (!$mkOk) { $lastErr = error_get_last(); $lastErrMsg = (is_array($lastErr) && isset($lastErr['message'])) ? (string)$lastErr['message'] : 'unknown'; error_log('Upload: mkdir failed for ' . $targetDir . ' - ' . $lastErrMsg); header('Location: account.php?upload=err&code=mkdir'); exit(); } } /** * @brief Prüft, ob in den Zielordner geschrieben werden darf. */ if (!is_writable($targetDir)) { error_log('Upload: targetDir not writable: ' . $targetDir); header('Location: account.php?upload=err&code=perm'); exit(); } /** * @var string $timestamp Ein Zeitstempel zur Vergabe einmaliger Dateinamen. */ // Dateiname: user__. // Format ist dateisystem-sicher (keine Doppelpunkte) und eindeutig genug. $timestamp = gmdate('Ymd-His'); /** * @var string $filename Der zu verwendende neue Name für die hochgeladene Datei. */ $filename = 'user_' . $userId . '_' . $timestamp . '.' . $ext; /** * @var string $targetPath Der genaue finale Pfad (inkl. Dateiname). */ $targetPath = rtrim($targetDir, "\\/") . DIRECTORY_SEPARATOR . $filename; /** * @brief Verschiebt die hochgeladene Datei aus dem temporären Verzeichnis in den endgültigen Pfad. * * @details Schlägt dieser Vorgang fehl, wird ein serverseitiges Error-Log geschrieben und eine Weiterleitung durchgeführt. */ if (!move_uploaded_file($tmp, $targetPath)) { $lastErr = error_get_last(); $lastErrMsg = (is_array($lastErr) && isset($lastErr['message'])) ? (string)$lastErr['message'] : 'unknown'; error_log('Upload: move_uploaded_file failed to ' . $targetPath . ' - ' . $lastErrMsg); header('Location: account.php?upload=err&code=move'); exit(); } /** * @var string $publicPath Öffentlich zugänglicher URL-Pfad relativ zum Webroot. * Dies ist der Pfad, der in der Datenbank gespeichert wird. */ // Pfad, der in HTML genutzt wird (URL relativ zur Webroot) $publicPath = 'assets/images/profilePictures/' . $filename; /** * @var string $servername Adresse des Datenbankservers (veraltet in diesem Skript, aber vorhanden). */ $servername = "localhost"; /** * @var int $port Portadresse der Datenbank (ebenfalls ungenutzt im direkten Setup hier). */ $port = 3306; /** * @var mysqli|bool $conn Die per db_connect (aus lib/db.php) aufgebaute Verbindung zur Datenbank. */ $conn = db_connect(); /** * @var mysqli_stmt|false $stmt Das vorbereitete Statement zur Aktualisierung des Benutzer-Profilbilds. */ $stmt = mysqli_prepare($conn, "UPDATE users SET profilePicture = ? WHERE userID = ?"); /** * @brief Bricht ab, wenn das Prepared Statement nicht erstellt werden konnte. */ if (!$stmt) { mysqli_close($conn); header('Location: account.php?upload=err'); exit(); } /** * @brief Bindet Parameter, führt das Statement aus und schließt anschließend Verbindung und Statement. */ mysqli_stmt_bind_param($stmt, 'si', $publicPath, $userId); $ok = mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); $conn->close(); /** * @brief Leitet bei einem fehlgeschlagenen Datenbankupdate zur Error-Variante der account.php weiter. */ if (!$ok) { header('Location: account.php?upload=err'); exit(); } /** * @brief Der Upload war erfolgreich; Umleitung zur Account-Seite mit Erfolgsmeldung. */ header('Location: account.php?upload=ok'); exit();