* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved. * @license GNU General Public License version 3 or later; see LICENSE * * Resolves placeholders like [host], [date], [profile_name] in backup * directory paths and archive filename formats. */ namespace Joomla\Component\MokoJoomBackup\Administrator\Engine; defined('_JEXEC') or die; use Joomla\CMS\Factory; class PlaceholderResolver { /** * Supported placeholders and their descriptions (for documentation). */ public const PLACEHOLDERS = [ '[host]' => 'Server hostname', '[date]' => 'Date as Ymd (e.g. 20260604)', '[time]' => 'Time as His (e.g. 143025)', '[datetime]' => 'Date and time as Ymd_His', '[year]' => 'Four-digit year', '[month]' => 'Two-digit month', '[day]' => 'Two-digit day', '[hour]' => 'Two-digit hour (24h)', '[minute]' => 'Two-digit minute', '[second]' => 'Two-digit second', '[profile_id]' => 'Backup profile ID', '[profile_name]' => 'Profile title (sanitized)', '[site_name]' => 'Joomla site name (sanitized)', '[type]' => 'Backup type (full, database, files, differential)', '[random]' => 'Random 6-character hex string', '[DEFAULT_DIR]' => 'Default backup directory (administrator/components/com_mokojoombackup/backups)', ]; private array $replacements; /** * @param object $profile The backup profile object */ public function __construct(object $profile) { $now = new \DateTimeImmutable('now'); $hostname = preg_replace('/[^a-zA-Z0-9._-]/', '', $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? php_uname('n')); $siteName = ''; try { $siteName = Factory::getApplication()->get('sitename', ''); } catch (\Throwable $e) { // Fallback: not critical } $this->replacements = [ '[host]' => $hostname, '[date]' => $now->format('Ymd'), '[time]' => $now->format('His'), '[datetime]' => $now->format('Ymd_His'), '[year]' => $now->format('Y'), '[month]' => $now->format('m'), '[day]' => $now->format('d'), '[hour]' => $now->format('H'), '[minute]' => $now->format('i'), '[second]' => $now->format('s'), '[profile_id]' => (string) ($profile->id ?? '0'), '[profile_name]' => $this->sanitize($profile->title ?? 'default'), '[site_name]' => $this->sanitize($siteName ?: 'joomla'), '[type]' => $profile->backup_type ?? 'full', '[random]' => bin2hex(random_bytes(3)), '[DEFAULT_DIR]' => JPATH_ADMINISTRATOR . '/components/com_mokojoombackup/backups', ]; } /** * Replace all placeholders in a string. * * @param string $template String containing [placeholder] tokens * * @return string Resolved string */ public function resolve(string $template): string { return str_replace( array_keys($this->replacements), array_values($this->replacements), $template ); } /** * Get the raw hostname value (for backward compatibility). */ public function getHostname(): string { return $this->replacements['[host]']; } /** * Get the datetime tag value (for backward compatibility). */ public function getTag(): string { return $this->replacements['[datetime]']; } /** * Sanitize a string for use in filenames/paths. * Keeps alphanumerics, dots, hyphens, underscores. Replaces spaces with hyphens. */ private function sanitize(string $value): string { $value = str_replace(' ', '-', trim($value)); return preg_replace('/[^a-zA-Z0-9._-]/', '', $value); } }