diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e17c2c..8209fef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - The backend controller, Web Services API controller, and legacy `cli/mokosuitebackup.php` now run backups through the shared `BackupRunner` (gaining the normalized complete/warning/fail status) instead of instantiating `BackupEngine` directly. ### Fixed +- Archive names for **CLI/console-triggered backups** no longer come out as `joomla.invalid_…`. The `[HOST]` placeholder took `$_SERVER['HTTP_HOST']` verbatim, but Joomla's console fills that with the reserved sentinel host `joomla.invalid`; the resolver now treats that (like empty/`localhost`) as unusable and falls back to the configured `live_site` host, then the system hostname. (Set the site's *live_site* to get the exact domain in CLI-built names.) - Standalone restore script generation no longer aborts backups with `str_replace() expects at least 3 arguments, 2 given`. `MokoRestore::generateStandaloneScript()` had a `str_replace()` call (the "Backup Archive" pre-check rewrite) that was missing its `$php` subject argument, so **every** standalone-mode backup fatally errored while "Generating standalone restore.php…" — the archive still finalized and uploaded, but no `restore.php` was ever produced (the true root cause behind #226). (#226) - Remote upload: the standalone restore script upload is no longer silent — its result is now checked and logged, and a failed restore-script upload marks the backup as `warning` (previously the result was discarded, so a missing restore script on the remote went unreported while the archive still showed success). (#226) diff --git a/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php b/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php index 2d6b5486..cccbb0aa 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php +++ b/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php @@ -52,15 +52,25 @@ class PlaceholderResolver { $now = new \DateTimeImmutable('now'); - /* Resolve hostname: prefer HTTP_HOST (web), then try Joomla config (CLI), then system hostname */ - $rawHost = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? ''; + /* Resolve hostname: prefer the real request host (web), then the + configured live_site (CLI), then the system hostname. Joomla's console + fills the request host with the placeholder 'joomla.invalid' (an + RFC 6761 reserved TLD used as a CLI sentinel), so treat that — along + with empty/localhost — as unusable and fall through; otherwise every + CLI-triggered backup would be named 'joomla.invalid_…'. */ + $unusable = static function (string $h): bool { + $h = strtolower(trim($h)); - if (empty($rawHost) || $rawHost === 'localhost') { + return $h === '' || $h === 'localhost' || $h === 'joomla.invalid'; + }; + + $rawHost = (string) ($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? ''); + + if ($unusable($rawHost)) { try { - $app = Factory::getApplication(); - $liveSite = $app->get('live_site', ''); + $liveSite = (string) Factory::getApplication()->get('live_site', ''); - if (!empty($liveSite)) { + if ($liveSite !== '') { $parsed = parse_url($liveSite, PHP_URL_HOST); if (!empty($parsed)) { @@ -68,12 +78,13 @@ class PlaceholderResolver } } } catch (\Throwable $e) { - /* fallback */ + /* fall through to system hostname */ } } - if (empty($rawHost)) { - $rawHost = php_uname('n'); + if ($unusable($rawHost)) { + $sysHost = php_uname('n'); + $rawHost = $sysHost !== '' ? $sysHost : 'site'; } $hostname = preg_replace('/[^a-zA-Z0-9._-]/', '', $rawHost);