. */ declare(strict_types=1); namespace Fisharebest\Webtrees; use Closure; use DebugBar\StandardDebugBar; use ErrorException; use Fisharebest\Webtrees\Http\Middleware\BootModules; use Fisharebest\Webtrees\Http\Middleware\CheckCsrf; use Fisharebest\Webtrees\Http\Middleware\CheckForMaintenanceMode; use Fisharebest\Webtrees\Http\Middleware\DoHousekeeping; use Fisharebest\Webtrees\Http\Middleware\EmitResponse; use Fisharebest\Webtrees\Http\Middleware\HandleExceptions; use Fisharebest\Webtrees\Http\Middleware\ModuleMiddleware; use Fisharebest\Webtrees\Http\Middleware\NoRouteFound; use Fisharebest\Webtrees\Http\Middleware\PhpEnvironment; use Fisharebest\Webtrees\Http\Middleware\RequestRouter; use Fisharebest\Webtrees\Http\Middleware\UpdateDatabaseSchema; use Fisharebest\Webtrees\Http\Middleware\UseCache; use Fisharebest\Webtrees\Http\Middleware\UseDatabase; use Fisharebest\Webtrees\Http\Middleware\UseDebugbar; use Fisharebest\Webtrees\Http\Middleware\UseFilesystem; use Fisharebest\Webtrees\Http\Middleware\UseLocale; use Fisharebest\Webtrees\Http\Middleware\UseSession; use Fisharebest\Webtrees\Http\Middleware\UseTheme; use Fisharebest\Webtrees\Http\Middleware\UseTransaction; use Fisharebest\Webtrees\Http\Middleware\UseTree; use Fisharebest\Webtrees\Http\Request; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7Server\ServerRequestCreator; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UriFactoryInterface; use Psr\Http\Server\MiddlewareInterface; use Throwable; use function app; use function class_exists; use function dirname; use function error_reporting; use function ob_end_clean; use function ob_get_level; use function set_error_handler; use function set_exception_handler; use function str_replace; use const PHP_EOL; /** * Definitions for the webtrees application. */ class Webtrees { // The root folder of this installation public const ROOT_DIR = __DIR__ . '/../'; // Location of the file containing the database connection details. public const CONFIG_FILE = self::ROOT_DIR . 'data/config.ini.php'; // Location of the file that triggers maintenance mode. public const OFFLINE_FILE = self::ROOT_DIR . 'data/offline.txt'; // Location of our modules. public const MODULES_PATH = 'modules_v4/'; public const MODULES_DIR = self::ROOT_DIR . self::MODULES_PATH; // Enable debugging on development builds. public const DEBUG = self::STABILITY !== ''; // We want to know about all PHP errors during development, and fewer in production. public const ERROR_REPORTING = self::DEBUG ? E_ALL | E_STRICT | E_NOTICE | E_DEPRECATED : E_ALL; // The name of the application. public const NAME = 'webtrees'; // Required version of database tables/columns/indexes/etc. public const SCHEMA_VERSION = 43; // e.g. "dev", "alpha", "beta.3", etc. public const STABILITY = 'alpha.5'; // Version number public const VERSION = '2.0.0' . (self::STABILITY === '' ? '' : '-') . self::STABILITY; // Project website. public const URL = 'https://www.webtrees.net/'; /** * Initialise the application. * * @return void */ public function bootstrap(): void { // Show all errors and warnings in development, fewer in production. error_reporting(self::ERROR_REPORTING); set_error_handler($this->phpErrorHandler()); set_exception_handler($this->phpExceptionHandler()); } /** * An error handler that can be passed to set_error_handler(). * * @return Closure */ private function phpErrorHandler(): Closure { return static function (int $errno, string $errstr, string $errfile, int $errline): bool { // Ignore errors that are silenced with '@' if (error_reporting() & $errno) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } return true; }; } /** * An exception handler that can be passed to set_exception_handler(). * Display any exception that are not caught by the middleware exception handler. * * @return Closure */ private function phpExceptionHandler(): Closure { return static function (Throwable $ex): void { $base_path = dirname(__DIR__); $trace = $ex->getMessage() . PHP_EOL . $ex->getTraceAsString(); $trace = str_replace($base_path, '…', $trace); while (ob_get_level() > 0) { ob_end_clean(); } echo '
' . $trace . ''; }; } /** * We can use any PSR-7 / PSR-17 compatible message factory. * * @return void */ public function selectMessageFactory(): void { app()->bind(ResponseFactoryInterface::class, Psr17Factory::class); app()->bind(ServerRequestFactoryInterface::class, Psr17Factory::class); app()->bind(StreamFactoryInterface::class, Psr17Factory::class); app()->bind(UploadedFileFactoryInterface::class, Psr17Factory::class); app()->bind(UriFactoryInterface::class, Psr17Factory::class); } /** * We can use any PSR-7 compatible requests. * * @return ServerRequestInterface */ public function createServerRequest(): ServerRequestInterface { $server_request_creator = new ServerRequestCreator( app(ServerRequestFactoryInterface::class), app(UriFactoryInterface::class), app(UploadedFileFactoryInterface::class), app(StreamFactoryInterface::class) ); // Until all the code is rewritten to use PSR-7 requests, we still need our hybrid request. if (class_exists(Request::class)) { return Request::createFromGlobals(); } return $server_request_creator->fromGlobals(); } /** * The webtrees application is built from middleware. * * @return MiddlewareInterface[] */ public function middleware(): array { return [ PhpEnvironment::class, EmitResponse::class, HandleExceptions::class, CheckForMaintenanceMode::class, UseDatabase::class, UseDebugbar::class, UpdateDatabaseSchema::class, UseCache::class, UseFilesystem::class, UseSession::class, UseTree::class, UseLocale::class, UseTheme::class, DoHousekeeping::class, CheckCsrf::class, UseTransaction::class, BootModules::class, ModuleMiddleware::class, RequestRouter::class, NoRouteFound::class, ]; } }