Plan: apply() darf den Wert nicht als Regex-Ersatz behandeln

preg_replace deutet $1, \1 und \\ im ERSATZ als Rueckverweise, auch ohne
Gruppen im Muster. Der Wert kommt von der Befehlszeile, das Ziel ist die Datei
mit allen Zugangsdaten, und das Ergebnis waere still verstuemmelt statt
abgelehnt — isValidLine() sieht weiterhin ein gueltiges KEY=value.

Jetzt zeilenweise, ohne Regex auf dem Schreibweg. Dazu faengt der Befehl
InvalidEnvContentException ab, statt dem Betreiber einen Stapelabzug zu zeigen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat/versandtakt
nexxo 2026-08-04 15:20:19 +02:00
parent d90676632e
commit 5c9ee2c6d5
1 changed files with 33 additions and 8 deletions

View File

@ -729,6 +729,7 @@ Datei `app/Console/Commands/BindHosts.php`:
namespace App\Console\Commands;
use App\Services\Env\EnvFileEditor;
use App\Services\Env\InvalidEnvContentException;
use Illuminate\Console\Command;
/**
@ -821,7 +822,16 @@ class BindHosts extends Command
return self::FAILURE;
}
$backup = $env->write($this->apply($content, $missing));
try {
$backup = $env->write($this->apply($content, $missing));
} catch (InvalidEnvContentException $e) {
// Abgelehnt heißt hier: NICHTS geschrieben, und die Sicherung ist
// erst gar nicht angelegt worden — der Editor prüft vor beidem.
// Der Betreiber soll das als Satz erfahren, nicht als Stapelabzug.
$this->error('Die Datei wurde nicht geschrieben: '.$e->getMessage());
return self::FAILURE;
}
$this->info('Geschrieben. Die vorherige Fassung liegt unter '.$backup);
$this->line('Danach: php artisan config:cache && php artisan route:cache');
@ -850,6 +860,12 @@ class BindHosts extends Command
/**
* Vorhandene Zeile ersetzen, sonst anhängen.
*
* Zeilenweise und ohne `preg_replace`: der Wert kommt von der Befehlszeile,
* und `preg_replace` deutet `$1`, `\1` und `\\` im ERSATZ als Rückverweise.
* Aus `--site 'www.example.test$1'` würde still `SITE_HOST=www.example.test`
* — und diese Datei hält jedes Geheimnis dieser Installation. Ein leise
* verstümmelter Wert darin ist schlimmer als eine Fehlermeldung.
*
* Ersetzen und nicht nur anhängen, weil ein leerer Schlüssel als fehlend
* gilt: `APP_HOST=` steht dann schon da, und ein zweites `APP_HOST=…`
* darunter wäre eine Datei mit zwei Antworten auf dieselbe Frage.
@ -858,16 +874,25 @@ class BindHosts extends Command
*/
private function apply(string $content, array $values): string
{
foreach ($values as $key => $value) {
$line = $key.'='.$value;
$pattern = '/^'.preg_quote($key, '/').'=.*$/m';
$lines = preg_split('/\R/', rtrim($content, "\r\n"));
$content = preg_match($pattern, $content) === 1
? preg_replace($pattern, $line, $content, 1)
: rtrim($content, "\n")."\n".$line."\n";
foreach ($values as $key => $value) {
$replaced = false;
foreach ($lines as $index => $line) {
if (str_starts_with($line, $key.'=')) {
$lines[$index] = $key.'='.$value;
$replaced = true;
break;
}
}
if (! $replaced) {
$lines[] = $key.'='.$value;
}
}
return $content;
return implode("\n", $lines)."\n";
}
}
```