diff --git a/lib/Arsse.php b/lib/Arsse.php index ec04d249..18f568f5 100644 --- a/lib/Arsse.php +++ b/lib/Arsse.php @@ -8,6 +8,15 @@ namespace JKingWeb\Arsse; class Arsse { public const VERSION = "0.9.2"; + public const REQUIRED_EXTENSIONS = [ + "intl", // as this extension is required to prepare formatted messages, its absence will throw a distinct English-only exception + "dom", + "filter", + "json", // part of the PHP core since version 8.0 + "hash", // part of the PHP core since version 7.4 + "simplexml", // required by PicoFeed only + "iconv", // required by PicoFeed only + ]; /** @var Factory */ public static $obj; @@ -29,6 +38,7 @@ class Arsse { static::$user = static::$user ?? new User; } + /** Checks whether the specified extensions are loaded and throws an exception if any are not */ public static function checkExtensions(string ...$ext): void { $missing = []; foreach ($ext as $e) { diff --git a/lib/CLI.php b/lib/CLI.php index c6e4969a..3bb271ee 100644 --- a/lib/CLI.php +++ b/lib/CLI.php @@ -80,11 +80,15 @@ USAGE_TEXT; 'help' => false, ]); try { + // ensure the require extensions are loaded + Arsse::checkExtensions(...Arsse::REQUIRED_EXTENSIONS); + // reconstitute multi-token commands (e.g. user add) into a single string $cmd = $this->command($args); if ($cmd && !in_array($cmd, ["", "conf save-defaults", "daemon"])) { // only certain commands don't require configuration to be loaded; daemon loads configuration after forking (if applicable) $this->loadConf(); } + // run the requested command switch ($cmd) { case "": if ($args['--version']) { diff --git a/lib/REST.php b/lib/REST.php index 8d26628e..d8dce626 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -80,10 +80,12 @@ class REST { } public function dispatch(ServerRequestInterface $req = null): ResponseInterface { - // create a request object if not provided - $req = $req ?? ServerRequestFactory::fromGlobals(); - // find the API to handle try { + // ensure the require extensions are loaded + Arsse::checkExtensions(...Arsse::REQUIRED_EXTENSIONS); + // create a request object if not provided + $req = $req ?? ServerRequestFactory::fromGlobals(); + // find the API to handle [$api, $target, $class] = $this->apiMatch($req->getRequestTarget(), $this->apis); // authenticate the request pre-emptively $req = $this->authenticateRequest($req); diff --git a/lib/Service/Daemon.php b/lib/Service/Daemon.php index a07d15f9..da134c17 100644 --- a/lib/Service/Daemon.php +++ b/lib/Service/Daemon.php @@ -7,9 +7,15 @@ declare(strict_types=1); namespace JKingWeb\Arsse\Service; use JKingWeb\Arsse\AbstractException; +use JKingWeb\Arsse\Arsse; class Daemon { protected const PID_PATTERN = '/^([1-9]\d{0,77})?$/D'; // no more than 78 digits (256-bit unsigned integer), starting with a digit other than zero + protected const REQUIRED_EXTENSIONS = ["posix", "pcntl"]; + + public function __construct() { + Arsse::checkExtensions(...self::REQUIRED_EXTENSIONS); + } /** Daemonizes the process via the traditional sysvinit double-fork procedure *