From 4faaa7910174d419152993bc268fb214dda5242e Mon Sep 17 00:00:00 2001 From: Dag Date: Wed, 7 Aug 2024 03:15:43 +0200 Subject: [PATCH] refactor: change the way dependencies are wired (#4194) * refactor: change the way dependencies are setup * lint --- bin/cache-clear | 17 ++++++- bin/cache-prune | 17 ++++++- caches/ArrayCache.php | 3 ++ docs/04_For_Developers/05_Debug_mode.md | 14 +----- index.php | 63 +++++++++++++------------ lib/Configuration.php | 3 ++ lib/Debug.php | 3 ++ lib/RssBridge.php | 35 ++++++-------- lib/bootstrap.php | 6 --- lib/logger.php | 13 ++--- 10 files changed, 93 insertions(+), 81 deletions(-) diff --git a/bin/cache-clear b/bin/cache-clear index 3563abad..635f41d5 100755 --- a/bin/cache-clear +++ b/bin/cache-clear @@ -7,8 +7,21 @@ require __DIR__ . '/../lib/bootstrap.php'; -$rssBridge = new RssBridge(); +$config = []; +if (file_exists(__DIR__ . '/../config.ini.php')) { + $config = parse_ini_file(__DIR__ . '/../config.ini.php', true, INI_SCANNER_TYPED); + if (!$config) { + http_response_code(500); + exit("Error parsing config.ini.php\n"); + } +} +Configuration::loadConfiguration($config, getenv()); -$cache = RssBridge::getCache(); +$logger = new SimpleLogger('rssbridge'); + +$logger->addHandler(new StreamHandler('php://stderr', Logger::INFO)); + +$cacheFactory = new CacheFactory($logger); +$cache = $cacheFactory->create(); $cache->clear(); diff --git a/bin/cache-prune b/bin/cache-prune index 7b7a6031..281c019d 100755 --- a/bin/cache-prune +++ b/bin/cache-prune @@ -7,8 +7,21 @@ require __DIR__ . '/../lib/bootstrap.php'; -$rssBridge = new RssBridge(); +$config = []; +if (file_exists(__DIR__ . '/../config.ini.php')) { + $config = parse_ini_file(__DIR__ . '/../config.ini.php', true, INI_SCANNER_TYPED); + if (!$config) { + http_response_code(500); + exit("Error parsing config.ini.php\n"); + } +} +Configuration::loadConfiguration($config, getenv()); -$cache = RssBridge::getCache(); +$logger = new SimpleLogger('rssbridge'); + +$logger->addHandler(new StreamHandler('php://stderr', Logger::INFO)); + +$cacheFactory = new CacheFactory($logger); +$cache = $cacheFactory->create(); $cache->prune(); diff --git a/caches/ArrayCache.php b/caches/ArrayCache.php index efce4f35..55b18519 100644 --- a/caches/ArrayCache.php +++ b/caches/ArrayCache.php @@ -2,6 +2,9 @@ declare(strict_types=1); +/** + * Also known as an in-memory/runtime cache + */ class ArrayCache implements CacheInterface { private array $data = []; diff --git a/docs/04_For_Developers/05_Debug_mode.md b/docs/04_For_Developers/05_Debug_mode.md index 6bdb1d48..7d503acd 100644 --- a/docs/04_For_Developers/05_Debug_mode.md +++ b/docs/04_For_Developers/05_Debug_mode.md @@ -1,6 +1,7 @@

Warning!

-Enabling debug mode on a public server may result in malicious clients retrieving sensitive data about your server and possibly gaining access to it. Do not enable debug mode on a public server, unless you understand the implications of your doing! +Enabling debug mode on a public server may result in malicious clients retrieving sensitive data about your server and possibly gaining access to it. +Do not enable debug mode on a public server, unless you understand the implications of your doing! *** @@ -20,14 +21,3 @@ _Notice_: * The bridge whitelist still applies! (debug mode does **not** enable all bridges) RSS-Bridge will give you a visual feedback when debug mode is enabled. - -While debug mode is active, RSS-Bridge will write additional data to your servers `error.log`. - -Debug mode is controlled by the static class `Debug`. It provides three core functions: - -* `Debug::isEnabled()`: Returns `true` if debug mode is enabled. -* `Debug::log($message)`: Adds a message to `error.log`. It takes one parameter, which can be anything. - -Example: `Debug::log('Hello World!');` - -**Notice**: `Debug::log($message)` calls `Debug::isEnabled()` internally. You don't have to do that manually. \ No newline at end of file diff --git a/index.php b/index.php index f23d8441..ccb2316f 100644 --- a/index.php +++ b/index.php @@ -2,25 +2,31 @@ if (version_compare(\PHP_VERSION, '7.4.0') === -1) { http_response_code(500); - print 'RSS-Bridge requires minimum PHP version 7.4'; - exit; -} - -if (! is_readable(__DIR__ . '/lib/bootstrap.php')) { - http_response_code(500); - print 'Unable to read lib/bootstrap.php. Check file permissions.'; - exit; + exit("RSS-Bridge requires minimum PHP version 7.4\n"); } require_once __DIR__ . '/lib/bootstrap.php'; -set_exception_handler(function (\Throwable $e) { +$config = []; +if (file_exists(__DIR__ . '/config.ini.php')) { + $config = parse_ini_file(__DIR__ . '/config.ini.php', true, INI_SCANNER_TYPED); + if (!$config) { + http_response_code(500); + exit("Error parsing config.ini.php\n"); + } +} +Configuration::loadConfiguration($config, getenv()); + +$logger = new SimpleLogger('rssbridge'); + +set_exception_handler(function (\Throwable $e) use ($logger) { $response = new Response(render(__DIR__ . '/templates/exception.html.php', ['e' => $e]), 500); $response->send(); - RssBridge::getLogger()->error('Uncaught Exception', ['e' => $e]); + $logger->error('Uncaught Exception', ['e' => $e]); }); -set_error_handler(function ($code, $message, $file, $line) { +set_error_handler(function ($code, $message, $file, $line) use ($logger) { + // Consider: ini_set('error_reporting', E_ALL & ~E_DEPRECATED); if ((error_reporting() & $code) === 0) { // Deprecation messages and other masked errors are typically ignored here return false; @@ -35,11 +41,12 @@ set_error_handler(function ($code, $message, $file, $line) { sanitize_root($file), $line ); - RssBridge::getLogger()->warning($text); + $logger->warning($text); + // todo: return false to prevent default error handler from running? }); // There might be some fatal errors which are not caught by set_error_handler() or \Throwable. -register_shutdown_function(function () { +register_shutdown_function(function () use ($logger) { $error = error_get_last(); if ($error) { $message = sprintf( @@ -49,33 +56,29 @@ register_shutdown_function(function () { sanitize_root($error['file']), $error['line'] ); - RssBridge::getLogger()->error($message); - if (Debug::isEnabled()) { - // This output can interfere with json output etc - // This output is written at the bottom - print sprintf("
%s
\n", e($message)); - } + $logger->error($message); } }); -$errors = Configuration::checkInstallation(); -if ($errors) { - http_response_code(500); - print '
' . implode("\n", $errors) . '
'; - exit; +$cacheFactory = new CacheFactory($logger); +if (Debug::isEnabled()) { + $logger->addHandler(new StreamHandler('php://stderr', Logger::DEBUG)); + $cache = $cacheFactory->create('array'); +} else { + $logger->addHandler(new StreamHandler('php://stderr', Logger::INFO)); + $cache = $cacheFactory->create(); } - -// Consider: ini_set('error_reporting', E_ALL & ~E_DEPRECATED); +$httpClient = new CurlHttpClient(); date_default_timezone_set(Configuration::getConfig('system', 'timezone')); try { - $rssBridge = new RssBridge(); + $rssBridge = new RssBridge($logger, $cache, $httpClient); $response = $rssBridge->main($argv ?? []); $response->send(); } catch (\Throwable $e) { // Probably an exception inside an action - RssBridge::getLogger()->error('Exception in RssBridge::main()', ['e' => $e]); - http_response_code(500); - print render(__DIR__ . '/templates/exception.html.php', ['e' => $e]); + $logger->error('Exception in RssBridge::main()', ['e' => $e]); + $response = new Response(render(__DIR__ . '/templates/exception.html.php', ['e' => $e]), 500); + $response->send(); } diff --git a/lib/Configuration.php b/lib/Configuration.php index 63f67a3c..b104a251 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -198,6 +198,9 @@ final class Configuration public static function getConfig(string $section, string $key, $default = null) { + if (self::$config === []) { + throw new \Exception('Config has not been loaded'); + } return self::$config[strtolower($section)][strtolower($key)] ?? $default; } diff --git a/lib/Debug.php b/lib/Debug.php index 4333b3a5..ba9e787e 100644 --- a/lib/Debug.php +++ b/lib/Debug.php @@ -16,6 +16,9 @@ class Debug return false; } + /** + * @deprecated Use $this->logger->debug() + */ public static function log($message) { $e = new \Exception(); diff --git a/lib/RssBridge.php b/lib/RssBridge.php index 87b11f52..e80e6f0a 100644 --- a/lib/RssBridge.php +++ b/lib/RssBridge.php @@ -2,25 +2,18 @@ final class RssBridge { - private static CacheInterface $cache; private static Logger $logger; + private static CacheInterface $cache; private static HttpClient $httpClient; - public function __construct() - { - self::$logger = new SimpleLogger('rssbridge'); - if (Debug::isEnabled()) { - self::$logger->addHandler(new StreamHandler(Logger::DEBUG)); - } else { - self::$logger->addHandler(new StreamHandler(Logger::INFO)); - } - self::$httpClient = new CurlHttpClient(); - $cacheFactory = new CacheFactory(self::$logger); - if (Debug::isEnabled()) { - self::$cache = $cacheFactory->create('array'); - } else { - self::$cache = $cacheFactory->create(); - } + public function __construct( + Logger $logger, + CacheInterface $cache, + HttpClient $httpClient + ) { + self::$logger = $logger; + self::$cache = $cache; + self::$httpClient = $httpClient; } public function main(array $argv = []): Response @@ -105,16 +98,16 @@ final class RssBridge return $response; } - public static function getCache(): CacheInterface - { - return self::$cache; - } - public static function getLogger(): Logger { return self::$logger; } + public static function getCache(): CacheInterface + { + return self::$cache; + } + public static function getHttpClient(): HttpClient { return self::$httpClient; diff --git a/lib/bootstrap.php b/lib/bootstrap.php index bfc7be39..1d866067 100644 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -45,9 +45,3 @@ spl_autoload_register(function ($className) { } } }); - -$customConfig = []; -if (file_exists(__DIR__ . '/../config.ini.php')) { - $customConfig = parse_ini_file(__DIR__ . '/../config.ini.php', true, INI_SCANNER_TYPED); -} -Configuration::loadConfiguration($customConfig, getenv()); diff --git a/lib/logger.php b/lib/logger.php index e579915d..916e65ed 100644 --- a/lib/logger.php +++ b/lib/logger.php @@ -83,10 +83,12 @@ final class SimpleLogger implements Logger final class StreamHandler { + private $stream; private int $level; - public function __construct(int $level = Logger::DEBUG) + public function __construct(string $stream, int $level = Logger::DEBUG) { + $this->stream = $stream; $this->level = $level; } @@ -147,13 +149,8 @@ final class StreamHandler $record['message'], $context ); - error_log($text); - if ($record['level'] < Logger::ERROR && Debug::isEnabled()) { - // The record level is INFO or WARNING here - // Not a good idea to print here because http headers might not have been sent - print sprintf("
%s
\n", e($text)); - } - //$bytes = file_put_contents('/tmp/rss-bridge.log', $text, FILE_APPEND | LOCK_EX); + + $bytes = file_put_contents($this->stream, $text, FILE_APPEND | LOCK_EX); } }