Upload via GUI (338 Dateien)

This commit is contained in:
2026-10-25 17:47:01 +00:00
parent b38f5b34ad
commit 63561d259f
4 changed files with 57 additions and 16 deletions
+24 -2
View File
@@ -3,7 +3,12 @@
require_once __DIR__ . '/../includes/bootstrap.php';
$staff = require_staff_login();
$info = app_download_info((string) ($_GET['platform'] ?? ''));
$platform = (string) ($_GET['platform'] ?? '');
if ($platform === 'minecraft' && !app_minecraft_enabled()) {
http_response_code(404);
exit('Diese App ist nicht hinterlegt.');
}
$info = app_publisher_info($platform);
if (!$info) {
http_response_code(404);
exit('Diese App ist nicht hinterlegt.');
@@ -18,4 +23,21 @@ header('Content-Disposition: attachment; filename="' . $info['filename'] . '"');
header('Content-Length: ' . $info['size']);
header('X-Content-Type-Options: nosniff');
header('Cache-Control: private, no-store');
readfile($info['path']);
if (($info['source'] ?? '') === 'publisher') {
session_write_close();
@set_time_limit(0);
$url = app_publisher_endpoint($platform, true);
$headers = function_exists('catalog_access_headers') ? catalog_access_headers($url) : [];
if (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_FOLLOWLOCATION => false, CURLOPT_CONNECTTIMEOUT => 8, CURLOPT_TIMEOUT => 0, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => false, CURLOPT_WRITEFUNCTION => static function ($curl, $chunk) { echo $chunk; return strlen($chunk); }]);
curl_exec($ch);
curl_close($ch);
} else {
$context = stream_context_create(['http' => ['timeout' => 0, 'header' => implode("\r\n", $headers)]]);
$remote = @fopen($url, 'rb', false, $context);
if ($remote) { fpassthru($remote); fclose($remote); }
}
} else {
readfile($info['path']);
}
+16 -13
View File
@@ -4,10 +4,9 @@ require_once __DIR__ . '/_ui.php';
$staff = require_staff_login();
$isAdmin = ($staff['role'] ?? '') === 'admin';
if ($isAdmin) app_downloads_prepare_dir(); // Ordner anlegen und Direktzugriff sperren
$apps = [];
foreach (array_keys(app_platforms()) as $key) $apps[$key] = app_download_info($key);
$visiblePlatforms = array_filter(app_platforms(), fn($k) => $k !== 'minecraft' || app_minecraft_enabled(), ARRAY_FILTER_USE_KEY);
foreach (array_keys($visiblePlatforms) as $key) $apps[$key] = app_publisher_info($key);
$serverUrl = base_url();
$pageTitle = 'Apps';
@@ -27,20 +26,21 @@ require __DIR__ . '/_header.php';
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px">
<?php foreach (app_platforms() as $key => $p): $a = $apps[$key]; ?>
<?php foreach ($visiblePlatforms as $key => $p): $a = $apps[$key]; $noun = $key === "minecraft" ? "Plugin" : "App"; ?>
<div class="card" style="margin:0">
<div style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-bottom:8px"><?= e($p['label']) ?></div>
<?php if ($a): ?>
<div style="font-size:1.3rem;font-weight:800"><?= e($p['label']) ?>-App</div>
<div style="font-size:1.3rem;font-weight:800"><?= e($p['label']) ?>-<?= $noun ?><?= !empty($a['version']) ? ' · ' . e($a['version']) : '' ?></div>
<div class="muted" style="font-size:.82rem;margin:4px 0 12px">
<?= e(app_format_size($a['size'])) ?> · Stand <?= e(ui_date($a['modified_at'])) ?>
</div>
<a class="btn" href="/staff/app_download.php?platform=<?= e($key) ?>">⬇ <?= e($p['label']) ?>-App herunterladen</a>
<a class="btn" href="/staff/app_download.php?platform=<?= e($key) ?>">⬇ <?= e($p['label']) ?>-<?= $noun ?> herunterladen</a>
<div class="muted" style="font-size:.72rem;margin-top:10px;word-break:break-all">SHA-256: <?= e($a['sha256']) ?></div>
<?php if (!empty($a['notes'])): ?><div class="muted" style="font-size:.82rem;margin-top:8px"><?= nl2br(e($a['notes'])) ?></div><?php endif; ?>
<?php else: ?>
<div class="muted">Hier ist noch keine <?= e($p['label']) ?>-App hinterlegt.<?= $isAdmin ? '' : ' Bitte einen Administrator fragen.' ?></div>
<div class="muted">Für <?= e($p['label']) ?> ist noch keine Version auf der Plugin-Website veröffentlicht.<?= $isAdmin ? '' : ' Bitte einen Administrator fragen.' ?></div>
<?php if ($isAdmin): ?>
<div style="font-size:.85rem;margin-top:8px">Datei per FTP in den Ordner <code>app_downloads/</code> legen und genau so benennen: <code><?= e($p['stored']) ?></code></div>
<div style="font-size:.85rem;margin-top:8px">Veröffentliche die Version im Administrationsbereich der Plugin-Website.</div>
<?php endif; ?>
<?php endif; ?>
@@ -52,6 +52,13 @@ require __DIR__ . '/_header.php';
<li>Falls Windows warnt („Der Computer wurde geschützt“): <em>Weitere Informationen → Trotzdem ausführen</em>.</li>
<li>App öffnen, Serveradresse eingeben und anmelden.</li>
</ol>
<?php elseif ($key === 'minecraft'): ?>
<ol style="padding-left:18px;margin:6px 0 0;line-height:1.7">
<li>Jar herunterladen und in den Ordner <code>plugins</code> deines Spigot-, Paper- oder BungeeCord-Servers legen.</li>
<li>Server einmal starten, dann <code>plugins/DeskHub-Minecraft/config.yml</code> ausfüllen: Serveradresse (oben), API-Schlüssel und Absender-E-Mail.</li>
<li>API-Schlüssel mit dem Recht „Tickets anlegen“ erzeugst du unter Verwalten → API-Schlüssel.</li>
<li>Mit <code>/deskhubmc test</code> ein Testticket anlegen. Bei einem Ausfall des Servers legt das Plugin selbst ein Ticket an.</li>
</ol>
<?php else: ?>
<ol style="padding-left:18px;margin:6px 0 0;line-height:1.7">
<li>Datei auf dem Handy herunterladen und öffnen.</li>
@@ -65,9 +72,5 @@ require __DIR__ . '/_header.php';
<?php endforeach; ?>
</div>
<?php if ($isAdmin): ?>
<p class="muted" style="font-size:.82rem;margin-top:18px">
Hinweis für Administratoren: Zum Aktualisieren einer App die neue Datei per FTP in <code>app_downloads/</code> hochladen und die alte ersetzen (Namen: <code>DeskHub-Setup.exe</code> und <code>DeskHub.apk</code>). Die Seite zeigt automatisch Größe, Datum und Prüfsumme der neuen Datei. Die Dateien sind nur für angemeldete Mitarbeiter abrufbar.
</p>
<?php endif; ?>
<?php if ($isAdmin): ?><p class="muted" style="font-size:.82rem;margin-top:18px">Neue App-Versionen veröffentlichst du in der Plugin-Website unter „DeskHub-Apps veröffentlichen“. Downloads hier bleiben auf angemeldete Mitarbeiter beschränkt.</p><?php endif; ?>
<?php require __DIR__ . '/_footer.php'; ?>
+15 -1
View File
@@ -29,7 +29,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'create_backup') {
$result = create_backup();
// Lange Aufgabe: Sitzungssperre freigeben (sonst blockiert sie jede weitere Seite dieses Mitarbeiters) und bei Abbruch des Browsers weiterlaufen
@ignore_user_abort(true);
@set_time_limit(600);
if (!backup_lock_acquire($pdo)) {
flash('error', 'Es läuft bereits ein Backup (automatisch oder von jemand anderem gestartet). Bitte warte, bis es fertig ist, und prüfe dann die Liste.');
redirect('/staff/backup.php');
}
session_write_close();
try {
$result = create_backup();
} finally {
backup_lock_release($pdo);
}
if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); }
if ($result['ok']) {
// FTP-Upload wenn konfiguriert
$ftpHost = bget('ftp_host');
@@ -42,6 +55,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($ftpHost && $ftpUser && function_exists('ftp_connect')) {
$ftp = $ftpTls ? @ftp_ssl_connect($ftpHost, $ftpPort, 10) : @ftp_connect($ftpHost, $ftpPort, 10);
if ($ftp && @ftp_login($ftp, $ftpUser, $ftpPass)) {
@ftp_set_option($ftp, FTP_TIMEOUT_SEC, 120); // sonst wartet die Seite bei hängender Verbindung bis zu 90 s je Schritt
ftp_pasv($ftp, true);
$remote = rtrim($ftpPath, '/') . '/' . $result['filename'];
$ftpMsg = ftp_put($ftp, $remote, $result['path'], FTP_BINARY)
+2
View File
@@ -73,6 +73,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$errors[] = 'Erlaubte Bildformate: JPG, PNG, GIF, WEBP.';
} elseif ($_FILES['avatar']['size'] > 2 * 1024 * 1024) {
$errors[] = 'Maximale Dateigröße: 2 MB.';
} elseif (($imgErr = favicon_validate_file($_FILES['avatar']['tmp_name'], $ext)) !== null) {
$errors[] = $imgErr;
} else {
$dir = __DIR__ . '/../assets/avatars/';
if (!is_dir($dir)) mkdir($dir, 0755, true);