Files
urlshort-qr-gen/templates/setup/index.php
T
florian.wilde c65c02cda5 feat(setup): Systemcheck und Upload-Paket fuer klassisches Webhosting
Auf Shared Hosting gibt es keine Kommandozeile - ohne Anzeige laesst
sich dort nicht feststellen, ob etwa gd fehlt, die PHP-Version zu alt
ist oder data/ nicht beschreibbar ist. Der Setup-Assistent prueft das
jetzt und listet es auf; im Dashboard meldet sich die Pruefung spaeter
nur noch, wenn etwas nicht stimmt. Fehlende Pflichtbausteine sind
Fehler, fehlende Kuer (intl, imagick, cURL) nur Hinweise mit Angabe,
was dadurch entfaellt.

build-release.sh erzeugt das Upload-Paket: Abhaengigkeiten ohne
Entwicklungspakete, ohne Tests und Docker-Dateien. Dabei faellt eine
16 MB grosse Schriftart aus endroid/qr-code weg, die ausschliesslich
fuer Beschriftungen unter dem QR-Code gebraucht wird - die erzeugt
diese Anwendung nicht. Das Paket schrumpft damit von 18 MB auf 1 MB.
Sollte spaeter doch eine Beschriftung dazukommen, erkennt das Skript
das und behaelt die Datei.

Die Variante ohne eigenen Webroot (alles liegt im Domainverzeichnis,
die .htaccess im Stammverzeichnis leitet nach public/ um) war bisher
gebaut, aber nie erprobt. Sie ist jetzt gegen eine Hoster-Simulation
getestet: Ersteinrichtung, Kurzlinks, Weiterleitung, QR-Codes,
Statistik und die Sperren fuer src/, vendor/, data/ und .env.
2026-08-10 15:32:13 +02:00

126 lines
5.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* @var App\Security\Csrf $csrf
* @var string $username
* @var array<string,string> $errors
* @var int $minLength
* @var string $tokenPath
* @var list<array{label:string,status:string,text:string,required:bool}> $systemChecks
* @var string $systemStatus
*/
use App\Service\SystemCheck;
$symbol = static fn (string $status): string => match ($status) {
SystemCheck::OK => '✓',
SystemCheck::WARNING => '!',
default => '×',
};
$cssClass = static fn (string $status): string => match ($status) {
SystemCheck::OK => 'ok',
SystemCheck::WARNING => 'warn',
default => 'error',
};
?>
<div class="card card--narrow">
<div class="card__head">
<span class="brand__mark brand__mark--lg" aria-hidden="true"></span>
<h1>Ersteinrichtung</h1>
<p class="muted">
Es ist noch kein Administrator-Konto vorhanden. Lege jetzt Benutzername und Passwort fest –
danach ist diese Seite gesperrt.
</p>
</div>
<form method="post" action="<?= $e($url('/setup')) ?>" class="form">
<?= $csrf->field() ?>
<div class="field <?= isset($errors['token']) ? 'field--error' : '' ?>">
<label for="setup_token">Einrichtungs-Token <span class="req">*</span></label>
<input type="text" id="setup_token" name="setup_token" required autofocus
spellcheck="false" autocapitalize="characters" autocomplete="off"
class="mono" placeholder="z. B. 3F9A1C0E7B2D4856">
<p class="field__hint">
Damit niemand anderes diese Installation übernimmt, steht das Token auf dem Server:
</p>
<details>
<summary>Wo finde ich das Token?</summary>
<ul class="checklist small muted">
<li><strong>Per FTP/SFTP oder Dateimanager:</strong> in der Datei
<code><?= $e($tokenPath) ?></code></li>
<li><strong>Docker:</strong> <code>docker compose logs app | grep Einrichtungs-Token</code>
oder <code>docker compose exec app cat data/setup-token.txt</code></li>
<li><strong>Mit Shell-Zugang:</strong> <code>cat <?= $e($tokenPath) ?></code></li>
</ul>
<p class="muted small">
Nach abgeschlossener Einrichtung wird die Datei automatisch gelöscht.
</p>
</details>
<?php if (isset($errors['token'])): ?>
<p class="field__error"><?= $e($errors['token']) ?></p>
<?php endif; ?>
</div>
<div class="field <?= isset($errors['username']) ? 'field--error' : '' ?>">
<label for="username">Benutzername</label>
<input type="text" id="username" name="username" value="<?= $e($username) ?>"
autocomplete="username" required>
<?php if (isset($errors['username'])): ?>
<p class="field__error"><?= $e($errors['username']) ?></p>
<?php endif; ?>
</div>
<div class="field <?= isset($errors['password']) ? 'field--error' : '' ?>">
<label for="password">Passwort</label>
<input type="password" id="password" name="password" autocomplete="new-password" required
minlength="<?= (int) $minLength ?>">
<p class="field__hint">Mindestens <?= (int) $minLength ?> Zeichen.</p>
<?php if (isset($errors['password'])): ?>
<p class="field__error"><?= $e($errors['password']) ?></p>
<?php endif; ?>
</div>
<div class="field <?= isset($errors['password_confirm']) ? 'field--error' : '' ?>">
<label for="password_confirm">Passwort wiederholen</label>
<input type="password" id="password_confirm" name="password_confirm" autocomplete="new-password" required>
<?php if (isset($errors['password_confirm'])): ?>
<p class="field__error"><?= $e($errors['password_confirm']) ?></p>
<?php endif; ?>
</div>
<button type="submit" class="btn btn--primary btn--block">Konto anlegen und anmelden</button>
</form>
<p class="muted small">
Alternativ kann das Konto auch fest in der <code>.env</code> hinterlegt werden
(<code>ADMIN_USER</code> und <code>ADMIN_PASSWORD_HASH</code>). Details stehen in der README.
</p>
</div>
<section class="card check-result check-result--<?= $e($cssClass($systemStatus)) ?>">
<details <?= $systemStatus === SystemCheck::OK ? '' : 'open' ?>>
<summary>
Systemvoraussetzungen –
<?= $systemStatus === SystemCheck::OK
? 'alles vorhanden'
: ($systemStatus === SystemCheck::WARNING ? 'mit Einschränkungen nutzbar' : 'es fehlt etwas') ?>
</summary>
<ul class="check-list">
<?php foreach ($systemChecks as $check): ?>
<li class="check-list__item check-list__item--<?= $e($cssClass($check['status'])) ?>">
<span class="check-list__icon" aria-hidden="true"><?= $e($symbol($check['status'])) ?></span>
<span class="check-list__label"><?= $e($check['label']) ?></span>
<span class="check-list__text"><?= $e($check['text']) ?></span>
</li>
<?php endforeach; ?>
</ul>
<p class="muted small">
Dass diese Seite überhaupt erscheint, belegt bereits, dass <code>mod_rewrite</code> arbeitet
und die <code>.htaccess</code> ausgewertet wird.
</p>
</details>
</section>