diff --git a/common.php b/common.php index a455a7de2..e62800df7 100644 --- a/common.php +++ b/common.php @@ -86,6 +86,19 @@ if (is_file(BB_PATH . '/library/config.local.php')) { require_once BB_PATH . '/library/config.local.php'; } +// Initialize Config singleton +$config = \TorrentPier\Config::init($bb_cfg); + +/** + * Get the Config instance + * + * @return \TorrentPier\Config + */ +function config(): \TorrentPier\Config +{ + return \TorrentPier\Config::getInstance(); +} + /** * Initialize debug */ @@ -100,16 +113,16 @@ if (APP_ENV === 'local') { /** * Server variables initialize */ -$server_protocol = $bb_cfg['cookie_secure'] ? 'https://' : 'http://'; -$server_port = in_array((int)$bb_cfg['server_port'], [80, 443], true) ? '' : ':' . $bb_cfg['server_port']; -define('FORUM_PATH', $bb_cfg['script_path']); -define('FULL_URL', $server_protocol . $bb_cfg['server_name'] . $server_port . $bb_cfg['script_path']); +$server_protocol = config()->get('cookie_secure') ? 'https://' : 'http://'; +$server_port = in_array((int)config()->get('server_port'), [80, 443], true) ? '' : ':' . config()->get('server_port'); +define('FORUM_PATH', config()->get('script_path')); +define('FULL_URL', $server_protocol . config()->get('server_name') . $server_port . config()->get('script_path')); unset($server_protocol, $server_port); /** * Database */ -$DBS = new TorrentPier\Legacy\Dbs($bb_cfg); +$DBS = new TorrentPier\Legacy\Dbs(config()->all()); function DB(string $db_alias = 'db') { @@ -120,7 +133,7 @@ function DB(string $db_alias = 'db') /** * Cache */ -$CACHES = new TorrentPier\Legacy\Caches($bb_cfg); +$CACHES = new TorrentPier\Legacy\Caches(config()->all()); function CACHE(string $cache_name) { @@ -131,22 +144,22 @@ function CACHE(string $cache_name) /** * Datastore */ -switch ($bb_cfg['datastore_type']) { +switch (config()->get('datastore_type')) { case 'apcu': - $datastore = new TorrentPier\Legacy\Datastore\APCu($bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\APCu(config()->get('cache.prefix')); break; case 'memcached': - $datastore = new TorrentPier\Legacy\Datastore\Memcached($bb_cfg['cache']['memcached'], $bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\Memcached(config()->get('cache.memcached'), config()->get('cache.prefix')); break; case 'sqlite': - $datastore = new TorrentPier\Legacy\Datastore\Sqlite($bb_cfg['cache']['db_dir'] . 'datastore', $bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\Sqlite(config()->get('cache.db_dir') . 'datastore', config()->get('cache.prefix')); break; case 'redis': - $datastore = new TorrentPier\Legacy\Datastore\Redis($bb_cfg['cache']['redis'], $bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\Redis(config()->get('cache.redis'), config()->get('cache.prefix')); break; case 'filecache': default: - $datastore = new TorrentPier\Legacy\Datastore\File($bb_cfg['cache']['db_dir'] . 'datastore/', $bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\File(config()->get('cache.db_dir') . 'datastore/', config()->get('cache.prefix')); } // Functions diff --git a/src/Ajax.php b/src/Ajax.php index a2f3e6090..a4005ee90 100644 --- a/src/Ajax.php +++ b/src/Ajax.php @@ -68,7 +68,7 @@ class Ajax */ public function exec() { - global $lang, $bb_cfg; + global $lang; // Exit if we already have errors if (!empty($this->response['error_code'])) { @@ -89,8 +89,8 @@ class Ajax } // Exit if board is disabled via ON/OFF trigger or by admin - if ($bb_cfg['board_disable'] || is_file(BB_DISABLED)) { - if ($bb_cfg['board_disable']) { + if (config()->get('board_disable') || is_file(BB_DISABLED)) { + if (config()->get('board_disable')) { $this->ajax_die($lang['BOARD_DISABLE']); } elseif (is_file(BB_DISABLED) && $this->action !== 'manage_admin') { $this->ajax_die($lang['BOARD_DISABLE_CRON']); diff --git a/src/Config.php b/src/Config.php new file mode 100644 index 000000000..2490e94c3 --- /dev/null +++ b/src/Config.php @@ -0,0 +1,182 @@ +config = $config; + } + + /** + * Get the singleton instance of Config + */ + public static function getInstance(array $config = []): Config + { + if (self::$instance === null) { + self::$instance = new self($config); + } + return self::$instance; + } + + /** + * Initialize the config with the global $bb_cfg array + */ + public static function init(array $bb_cfg): Config + { + self::$instance = new self($bb_cfg); + return self::$instance; + } + + /** + * Get a configuration value by key + * Supports dot notation for nested arrays (e.g., 'db.host') + */ + public function get(string $key, mixed $default = null): mixed + { + if (str_contains($key, '.')) { + return $this->getNestedValue($key, $default); + } + + return $this->config[$key] ?? $default; + } + + /** + * Set a configuration value by key + * Supports dot notation for nested arrays + */ + public function set(string $key, mixed $value): void + { + if (str_contains($key, '.')) { + $this->setNestedValue($key, $value); + } else { + $this->config[$key] = $value; + } + } + + /** + * Check if a configuration key exists + * Supports dot notation for nested arrays + */ + public function has(string $key): bool + { + if (str_contains($key, '.')) { + return $this->getNestedValue($key) !== null; + } + + return array_key_exists($key, $this->config); + } + + /** + * Get all configuration values + */ + public function all(): array + { + return $this->config; + } + + /** + * Get a nested value using dot notation + */ + private function getNestedValue(string $key, mixed $default = null): mixed + { + $keys = explode('.', $key); + $value = $this->config; + + foreach ($keys as $k) { + if (!is_array($value) || !array_key_exists($k, $value)) { + return $default; + } + $value = $value[$k]; + } + + return $value; + } + + /** + * Set a nested value using dot notation + */ + private function setNestedValue(string $key, mixed $value): void + { + $keys = explode('.', $key); + $target = &$this->config; + + foreach ($keys as $k) { + if (!isset($target[$k]) || !is_array($target[$k])) { + $target[$k] = []; + } + $target = &$target[$k]; + } + + $target = $value; + } + + /** + * Merge additional configuration values + */ + public function merge(array $config): void + { + $this->config = array_merge_recursive($this->config, $config); + } + + /** + * Get a section of the configuration + */ + public function getSection(string $section): array + { + return $this->config[$section] ?? []; + } + + /** + * Magic method to allow property access + */ + public function __get(string $key): mixed + { + return $this->get($key); + } + + /** + * Magic method to allow property setting + */ + public function __set(string $key, mixed $value): void + { + $this->set($key, $value); + } + + /** + * Magic method to check if property exists + */ + public function __isset(string $key): bool + { + return $this->has($key); + } + + /** + * Prevent cloning of the singleton instance + */ + private function __clone() {} + + /** + * Prevent unserialization of the singleton instance + */ + public function __wakeup() + { + throw new \Exception("Cannot unserialize a singleton."); + } +} \ No newline at end of file diff --git a/src/Emailer.php b/src/Emailer.php index 7330f9405..d31e3716e 100644 --- a/src/Emailer.php +++ b/src/Emailer.php @@ -87,17 +87,15 @@ class Emailer */ public function set_template(string $template_file, string $template_lang = ''): void { - global $bb_cfg; - if (!$template_lang) { - $template_lang = $bb_cfg['default_lang']; + $template_lang = config()->get('default_lang'); } if (empty($this->tpl_msg[$template_lang . $template_file])) { $tpl_file = LANG_ROOT_DIR . '/' . $template_lang . '/email/' . $template_file . '.html'; if (!is_file($tpl_file)) { - $tpl_file = LANG_ROOT_DIR . '/' . $bb_cfg['default_lang'] . '/email/' . $template_file . '.html'; + $tpl_file = LANG_ROOT_DIR . '/' . config()->get('default_lang') . '/email/' . $template_file . '.html'; if (!is_file($tpl_file)) { throw new Exception('Could not find email template file: ' . $template_file); @@ -125,9 +123,9 @@ class Emailer */ public function send(string $email_format = 'text/plain'): bool { - global $bb_cfg, $lang; + global $lang; - if (!$bb_cfg['emailer']['enabled']) { + if (!config()->get('emailer.enabled')) { return false; } @@ -142,24 +140,25 @@ class Emailer $this->subject = !empty($this->subject) ? $this->subject : $lang['EMAILER_SUBJECT']['EMPTY']; /** Prepare message */ - if ($bb_cfg['emailer']['smtp']['enabled']) { - if (!empty($bb_cfg['emailer']['smtp']['host'])) { - if (empty($bb_cfg['emailer']['smtp']['ssl_type'])) { - $bb_cfg['emailer']['smtp']['ssl_type'] = null; + if (config()->get('emailer.smtp.enabled')) { + if (!empty(config()->get('emailer.smtp.host'))) { + $sslType = config()->get('emailer.smtp.ssl_type'); + if (empty($sslType)) { + $sslType = null; } /** @var EsmtpTransport $transport external SMTP with SSL */ $transport = (new EsmtpTransport( - $bb_cfg['emailer']['smtp']['host'], - $bb_cfg['emailer']['smtp']['port'], - $bb_cfg['emailer']['smtp']['ssl_type'] + config()->get('emailer.smtp.host'), + config()->get('emailer.smtp.port'), + $sslType )) - ->setUsername($bb_cfg['emailer']['smtp']['username']) - ->setPassword($bb_cfg['emailer']['smtp']['password']); + ->setUsername(config()->get('emailer.smtp.username')) + ->setPassword(config()->get('emailer.smtp.password')); } else { $transport = new EsmtpTransport('localhost', 25); } } else { - $transport = new SendmailTransport($bb_cfg['emailer']['sendmail_command']); + $transport = new SendmailTransport(config()->get('emailer.sendmail_command')); } $mailer = new Mailer($transport); @@ -168,9 +167,9 @@ class Emailer $message = (new Email()) ->subject($this->subject) ->to($this->to) - ->from(new Address($bb_cfg['board_email'], $bb_cfg['board_email_sitename'])) - ->returnPath(new Address($bb_cfg['bounce_email'])) - ->replyTo($this->reply ?? new Address($bb_cfg['board_email'])); + ->from(new Address(config()->get('board_email'), config()->get('board_email_sitename'))) + ->returnPath(new Address(config()->get('bounce_email'))) + ->replyTo($this->reply ?? new Address(config()->get('board_email'))); /** * This non-standard header tells compliant autoresponders ("email holiday mode") to not @@ -209,12 +208,10 @@ class Emailer */ public function assign_vars($vars): void { - global $bb_cfg; - $this->vars = array_merge([ - 'BOARD_EMAIL' => $bb_cfg['board_email'], - 'SITENAME' => $bb_cfg['board_email_sitename'], - 'EMAIL_SIG' => !empty($bb_cfg['board_email_sig']) ? "-- \n{$bb_cfg['board_email_sig']}" : '', + 'BOARD_EMAIL' => config()->get('board_email'), + 'SITENAME' => config()->get('board_email_sitename'), + 'EMAIL_SIG' => !empty(config()->get('board_email_sig')) ? "-- \n" . config()->get('board_email_sig') : '', ], $vars); } }