Fassung 1.7.0: verlässliche Installation, übersichtliche Verwaltung und bedienbare Bewegung
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

This commit is contained in:
kantarci committed 2026-09-14 10:49:54 +02:00
1 parent b164c4edfe
commit 495b26896e
55 files changed
+1632 -423

No files matched your search

+8 -27
View File
@@ -22,7 +22,7 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
* Everything the browser installer does, without a browser.
*
* The order is the order of the screens, and every step writes its result immediately instead of
* collecting answers in a session: after the database step there is a `.env.local`, after the
* collecting answers in a session: after the database step there is a `.env`, after the
* migration step there are tables, after the website step there is content. That way a reload, a
* timeout or a closed tab never loses a half filled form - the installer simply sees what is
* already there and continues at the next missing thing.
@@ -123,7 +123,7 @@ final class Installation
$checks[] = $this->check('ZIP-Erweiterung', class_exists(\ZipArchive::class), 'Wird für Sicherungen als Archiv gebraucht. Ohne sie bleibt die Sicherung ein Verzeichnis.', false);
$checks[] = $this->check('proc_open', \function_exists('proc_open') && !\in_array('proc_open', array_map('trim', explode(',', (string) ini_get('disable_functions'))), true), 'Ohne proc_open kann das Update im Browser nicht laufen. Ein Update über das Releasearchiv geht trotzdem.', false);
foreach ([$this->root => 'Projektstamm (für .env.local)', $this->root.'/var' => 'var/ (Datenbank, Cache, Sicherungen)', $this->mediaDirectory => 'Medienordner'] as $path => $label) {
foreach ([$this->root => 'Projektstamm (für .env)', $this->root.'/var' => 'var/ (Datenbank, Cache, Sicherungen)', $this->mediaDirectory => 'Medienordner'] as $path => $label) {
$checks[] = $this->check('Schreibrecht: '.$label, $this->writable($path), sprintf('%s ist nicht beschreibbar. Im FTP-Programm die Rechte auf 0775 setzen (oder 0755, wenn PHP als Eigentümer läuft).', $path), true, $path);
}
@@ -138,7 +138,7 @@ final class Installation
false,
$documentRoot ?: null,
);
$checks[] = $this->check('Geheimnis (APP_SECRET)', '' !== $this->secret && !str_contains($this->secret, 'nicht-gespeichert'), 'Das Geheimnis konnte nicht in .env.local geschrieben werden. Ohne Schreibrecht im Projektstamm bleibt jede Anmeldung nach einem Neustart ungültig.');
$checks[] = $this->check('Geheimnis (APP_SECRET)', '' !== $this->secret && !str_contains($this->secret, 'nicht-gespeichert'), 'Das Geheimnis konnte nicht in .env geschrieben werden. Ohne Schreibrecht im Projektstamm bleibt jede Anmeldung nach einem Neustart ungültig.');
return $checks;
}
@@ -151,7 +151,7 @@ final class Installation
public function environmentWritten(): bool
{
return is_file($this->root.'/.env.local') && str_contains((string) file_get_contents($this->root.'/.env.local'), 'DATABASE_URL=');
return is_file($this->root.'/.env') && str_contains((string) file_get_contents($this->root.'/.env'), 'KANT_DATABASE_CONFIGURED="1"');
}
public function schemaReady(): bool
@@ -206,32 +206,13 @@ final class Installation
return ['url' => $url, 'error' => null];
}
/**
* Writes `.env.local`, never `.env`.
*
* `.env` belongs to the release and is replaced by the next update; `.env.local` belongs to
* this installation and survives. Values that are already there stay unless they are given
* again, so the website step can add the address without losing the database.
*/
/** Save installation settings in the single persistent configuration file. */
public function writeEnvironment(array $values): void
{
$file = $this->root.'/.env.local';
$lines = [];
foreach (is_file($file) ? (preg_split('/\R/', (string) file_get_contents($file)) ?: []) : [] as $line) {
if ('' !== trim($line) && 1 === preg_match('/^([A-Z_]+)=/', $line, $match) && !\array_key_exists($match[1], $values)) {
$lines[$match[1]] = $line;
}
if (isset($values['DATABASE_URL'])) {
$values['KANT_DATABASE_CONFIGURED'] = '1';
}
foreach ($values as $key => $value) {
$lines[$key] = $key.'="'.str_replace(['\\', '"', "\n"], ['\\\\', '\"', ''], (string) $value).'"';
}
$content = "# Diese Datei gehört zu dieser Installation und wird von keinem Update überschrieben.\n".implode("\n", $lines)."\n";
$temporary = $file.'.'.bin2hex(random_bytes(4));
if (false === file_put_contents($temporary, $content) || !rename($temporary, $file)) {
@unlink($temporary);
throw new \RuntimeException('.env.local ließ sich nicht schreiben. Bitte das Schreibrecht im Projektstamm prüfen.');
}
@chmod($file, 0o600);
Environment::write($this->root, $values);
}
/**