open($z, ZipArchive::CREATE); $zip->addFromString('theme.css', "/*\n * Version: 1.0.0\n */\na{}"); $zip->close(); // Webseite: Vorschau-Adresse im Katalog nur bei Einträgen mit Bild $check(site_publish('theme', $z, ['slug' => 'mitbild', 'name' => 'Mit Bild'], $pngFile, 'vorschau.png')['ok'], 'Theme mit Vorschaubild wird veröffentlicht'); $zip2 = tempnam(sys_get_temp_dir(), 'pk') . '.zip'; $zz = new ZipArchive(); $zz->open($zip2, ZipArchive::CREATE); $zz->addFromString('theme.css', "/*\n * Version: 1.0.0\n */\nb{}"); $zz->close(); $check(site_publish('theme', $zip2, ['slug' => 'ohnebild', 'name' => 'Ohne Bild'])['ok'], 'Theme ohne Vorschaubild wird veröffentlicht'); $cat = site_catalog('theme'); $byslug = array_column($cat['themes'], null, 'slug'); $check(isset($byslug['mitbild']['previewUrl']) && str_starts_with($byslug['mitbild']['previewUrl'], 'https://plugins.example.test/preview.php?file=') && !isset($byslug['ohnebild']['previewUrl']), 'Katalog nennt die Vorschau-Adresse nur für Einträge mit Bild'); // DeskHub: Adresse prüfen $base = 'https://plugins.example.test/catalog.php?type=themes'; $check(catalog_preview_url($base, 'https://plugins.example.test/preview.php?file=a.png') !== '', 'Vorschau auf derselben Domain wird übernommen'); $check(catalog_preview_url($base, 'https://anderer.example.test/a.png') === '', 'Vorschau auf einer anderen Domain wird verworfen'); $check(catalog_preview_url($base, 'http://plugins.example.test/a.png') === '' && catalog_preview_url($base, '') === '', 'http und leere Adressen werden verworfen'); // DeskHub: Katalog lesen, Bild laden, prüfen, zwischenspeichern set_setting('theme_catalog_url', $base); $requests = []; $serve = ['body' => $png]; $GLOBALS['deskhub_http_get'] = function (string $url, int $max) use ($cat, &$requests, &$serve): array { $requests[] = $url; if (str_contains($url, 'catalog.php')) return [200, json_encode($cat), null]; if (str_contains($url, 'preview.php')) return [200, $serve['body'], null]; return [404, null, 'HTTP 404']; }; $tc = theme_catalog_fetch(); $by = array_column($tc['themes'], null, 'slug'); $check(($by['mitbild']['preview'] ?? '') !== '' && ($by['ohnebild']['preview'] ?? 'x') === '', 'DeskHub übernimmt die Vorschau-Adresse aus dem Theme-Katalog'); foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) @unlink($f); $img = catalog_preview_image('theme', 'mitbild'); $check($img !== null && $img['mime'] === 'image/png' && $img['data'] === $png, 'Vorschaubild wird geladen und mit dem richtigen Typ geliefert'); $n = count($requests); $img2 = catalog_preview_image('theme', 'mitbild'); $check($img2 !== null && count($requests) === $n, 'zweiter Aufruf kommt aus dem Zwischenspeicher (kein neuer Abruf)'); $check(catalog_preview_image('theme', 'ohnebild') === null, 'Eintrag ohne Vorschau liefert kein Bild'); $check(catalog_preview_image('theme', 'gibtesnicht') === null && catalog_preview_image('theme', '../x') === null && catalog_preview_image('auto', 'mitbild') === null, 'unbekannte Einträge, Pfadtricks und falsche Arten liefern nichts'); foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) @unlink($f); $serve['body'] = ''; $check(catalog_preview_image('theme', 'mitbild') === null, 'eine Datei, die kein Bild ist, wird nicht ausgeliefert'); foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) @unlink($f); $serve['body'] = "GIF89a" . str_repeat("\0", 30); $check(catalog_preview_image('theme', 'mitbild') === null, 'andere Bildtypen (z. B. GIF) werden nicht ausgeliefert'); // Ein fehlgeschlagener Abruf wird nur 5 Minuten gemerkt (früher einen Tag): Sobald das Bild da ist, erscheint es foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) @unlink($f); $serve['body'] = 'kein Bild'; $check(catalog_preview_image('theme', 'mitbild') === null, 'Abruf ohne gültiges Bild liefert nichts'); $serve['body'] = $png; $check(catalog_preview_image('theme', 'mitbild') === null, 'der Fehlschlag wird kurz gemerkt (kein Dauerabruf bei kaputtem Bild)'); foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) touch($f, time() - 400); $check(catalog_preview_image('theme', 'mitbild') !== null, 'nach 5 Minuten wird erneut geladen und das Bild erscheint'); foreach (glob(sys_get_temp_dir() . '/deskhub_preview_*.bin') ?: [] as $f) touch($f, time() - 400); $check(catalog_preview_image('theme', 'mitbild') !== null, 'ein erfolgreich geladenes Bild bleibt länger als 5 Minuten im Zwischenspeicher'); // Installierte Themes: Vorschau aus dem Katalog (gleicher Name) oder aus preview.png im Theme-Ordner $themesDir = sys_get_temp_dir() . '/dh-thumb-themes-' . bin2hex(random_bytes(3)); mkdir($themesDir, 0755, true); putenv('DESKHUB_THEMES_DIR=' . $themesDir); $zt = tempnam(sys_get_temp_dir(), 'th') . '.zip'; $q = new ZipArchive(); $q->open($zt, ZipArchive::CREATE); $q->addFromString('theme.css', "/* * Version: 1.0.0 */ a{}"); $q->addFromString('preview.png', $png); $q->close(); $inst = install_custom_theme_archive($zt, 'Mit Bild'); $ohne = tempnam(sys_get_temp_dir(), 'th') . '.zip'; $q = new ZipArchive(); $q->open($ohne, ZipArchive::CREATE); $q->addFromString('theme.css', "/* * Version: 1.0.0 */ c{}"); $q->close(); $inst2 = install_custom_theme_archive($ohne, 'Ganz Ohne'); $catThemes = [['slug' => 'mitbild', 'name' => 'Mit-Bild', 'preview' => 'https://plugins.example.test/preview.php?file=a.png']]; $p1 = theme_installed_preview(['id' => $inst['id'], 'name' => 'Mit Bild'], $catThemes); $check($p1 && $p1['kind'] === 'catalog' && $p1['slug'] === 'mitbild', 'installiertes Theme bekommt die Vorschau aus dem Katalog (Name "Mit Bild" = "Mit-Bild")'); $p2 = theme_installed_preview(['id' => $inst['id'], 'name' => 'Mit Bild'], []); $check($p2 && $p2['kind'] === 'file' && str_ends_with($p2['url'], '/preview.png'), 'ohne Katalog gilt die preview.png aus dem Theme-Ordner'); $check(theme_installed_preview(['id' => $inst2['id'], 'name' => 'Ganz Ohne'], $catThemes) === null, 'ohne Katalogbild und ohne preview.png gibt es keine Vorschau'); $check(str_contains(installed_theme_thumb(['id' => $inst2['id'], 'name' => 'Ganz Ohne'], []), '>G<'), 'Platzhalter zeigt den Anfangsbuchstaben'); $check(str_contains(installed_theme_thumb(['id' => $inst['id'], 'name' => 'Mit Bild'], $catThemes), 'catalog_preview.php?kind=theme&slug=mitbild'), 'Mini-Vorschau verweist auf die Auslieferung durch DeskHub'); $rmT = function (string $d) use (&$rmT) { foreach (scandir($d) ?: [] as $e) { if ($e === '.' || $e === '..') continue; is_dir("$d/$e") ? $rmT("$d/$e") : @unlink("$d/$e"); } @rmdir($d); }; $rmT($themesDir); putenv('DESKHUB_THEMES_DIR'); // Platzhalter und Bild-Markup $check(str_contains(catalog_thumb('theme', ['slug' => 'mitbild', 'name' => 'Mit Bild', 'preview' => 'https://x']), 'catalog_preview.php?kind=theme&slug=mitbild'), 'Mini-Vorschau zeigt das Bild über die DeskHub-Adresse'); $ph = catalog_thumb('plugin', ['slug' => 'x', 'name' => '