Use .env file instead of local config.

This commit is contained in:
flash 2025-02-09 23:34:28 +00:00
parent 4110cd5190
commit e1cb500f99
16 changed files with 517 additions and 98 deletions

25
.env.example Normal file
View file

@ -0,0 +1,25 @@
# Database connection setting
# This uses the Index library's DSN syntax
# Currently Misuzu only supports MariaDB, or Null of course since that does nothing
#
# For normal TCP connection you can use the following syntax:
#DATABASE_DSN="mariadb://username:password@hostname/dbname?charset=utf8mb4"
#
# For a UNIX socket connection you can use the following syntax:
#DATABASE_DSN="mariadb://username:password@:unix:/dbname?socket=/path/to/mysqld.sock&charset=utf8mb4"
#
# And here's your unsensible default:
DATABASE_DSN="null:"
# Sentry error reporting setting
# I have not idea this works, just shove the value Sentry gives you in here.
# You can also leave it commented.
#SENTRY_DSN="https://6e41e3a2507d1542fd1e9aaf54f05d87@o4505858016870400.ingest.sentry.io/4505858023751680"
# Domain roles
# This assigns what domain has what role, domains can also have multiple roles!
# Pairs are split by ;, domain and role pairs are split by =, roles are split by , and if you want a prefix use :
# The example below maps everything to localhost for development.
# But to make things more understandable, the value for Flashii is also included
#DOMAIN_ROLES="flashii.net=main; fii.moe=redirect"
DOMAIN_ROLES="localhost=main,redirect:/go"

1
.gitignore vendored
View file

@ -11,6 +11,7 @@
/composer.local.json
# Configuration
/.env
/config/config.cfg
/config/github.cfg
/config/config.ini

View file

@ -1 +1 @@
20250209
20250210

View file

@ -10,7 +10,9 @@
"symfony/mailer": "~7.2",
"matomo/device-detector": "~6.4",
"sentry/sdk": "~4.0",
"nesbot/carbon": "~3.8"
"nesbot/carbon": "~3.8",
"vlucas/phpdotenv": "~5.6",
"filp/whoops": "~2.17"
},
"autoload": {
"classmap": [
@ -27,7 +29,6 @@
]
},
"require-dev": {
"phpstan/phpstan": "~2.1",
"filp/whoops": "~2.17"
"phpstan/phpstan": "~2.1"
}
}

373
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3cc1fc369aa12ce9ebbf324bc13a7d9d",
"content-hash": "ba6f5f293f0f3e3c7ad9b5335aee2b36",
"packages": [
{
"name": "carbonphp/carbon-doctrine-types",
@ -428,6 +428,77 @@
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "filp/whoops",
"version": "2.17.0",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/075bc0c26631110584175de6523ab3f1652eb28e",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3",
"symfony/var-dumper": "^4.0 || ^5.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool kids",
"homepage": "https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.17.0"
},
"funding": [
{
"url": "https://github.com/denis-sokolov",
"type": "github"
}
],
"time": "2025-01-25T12:00:00+00:00"
},
{
"name": "flashii/rpcii",
"version": "v4.0.0",
@ -522,6 +593,68 @@
"homepage": "https://railgun.sh/index",
"time": "2025-01-22T12:38:11+00:00"
},
{
"name": "graham-campbell/result-type",
"version": "v1.1.3",
"source": {
"type": "git",
"url": "https://github.com/GrahamCampbell/Result-Type.git",
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945",
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"phpoption/phpoption": "^1.9.3"
},
"require-dev": {
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
},
"type": "library",
"autoload": {
"psr-4": {
"GrahamCampbell\\ResultType\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
}
],
"description": "An Implementation Of The Result Type",
"keywords": [
"Graham Campbell",
"GrahamCampbell",
"Result Type",
"Result-Type",
"result"
],
"support": {
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
"type": "tidelift"
}
],
"time": "2024-07-20T21:45:45+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.7.0",
@ -926,6 +1059,81 @@
],
"time": "2024-12-27T09:25:35+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.9.3",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/php-option.git",
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"PhpOption\\": "src/PhpOption/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Johannes M. Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh"
},
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
}
],
"description": "Option Type for PHP",
"keywords": [
"language",
"option",
"php",
"type"
],
"support": {
"issues": "https://github.com/schmittjoh/php-option/issues",
"source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
"type": "tidelift"
}
],
"time": "2024-07-20T21:41:07+00:00"
},
{
"name": "psr/clock",
"version": "1.0.0",
@ -2274,6 +2482,86 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.31.0",
@ -2829,80 +3117,93 @@
}
],
"time": "2025-01-29T07:06:14+00:00"
}
],
"packages-dev": [
},
{
"name": "filp/whoops",
"version": "2.17.0",
"name": "vlucas/phpdotenv",
"version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e"
"url": "https://github.com/vlucas/phpdotenv.git",
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/075bc0c26631110584175de6523ab3f1652eb28e",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e",
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2",
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
"ext-pcre": "*",
"graham-campbell/result-type": "^1.1.3",
"php": "^7.2.5 || ^8.0",
"phpoption/phpoption": "^1.9.3",
"symfony/polyfill-ctype": "^1.24",
"symfony/polyfill-mbstring": "^1.24",
"symfony/polyfill-php80": "^1.24"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3",
"symfony/var-dumper": "^4.0 || ^5.0"
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-filter": "*",
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
"ext-filter": "Required to use the boolean validator."
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
"Dotenv\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
"BSD-3-Clause"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Vance Lucas",
"email": "vance@vancelucas.com",
"homepage": "https://github.com/vlucas"
}
],
"description": "php error handling for cool kids",
"homepage": "https://filp.github.io/whoops/",
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
"dotenv",
"env",
"environment"
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.17.0"
"issues": "https://github.com/vlucas/phpdotenv/issues",
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1"
},
"funding": [
{
"url": "https://github.com/denis-sokolov",
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
"type": "tidelift"
}
],
"time": "2025-01-25T12:00:00+00:00"
},
"time": "2024-07-20T21:52:34+00:00"
}
],
"packages-dev": [
{
"name": "phpstan/phpstan",
"version": "2.1.3",

View file

@ -1,11 +0,0 @@
# Example configuration for Misuzu
# and ; can be used at the start of a line for comments.
database:dsn mariadb://<user>:<pass>@<host>/<name>?charset=utf8mb4
;sentry:dsn https://sentry dsn here
;sentry:tracesRate 1.0
;sentry:profilesRate 1.0
domain:localhost main redirect
domain:localhost:redirect:path /go

View file

@ -1,26 +1,28 @@
<?php
namespace Misuzu;
use Index\Config\Fs\FsConfig;
define('MSZ_STARTUP', microtime(true));
define('MSZ_ROOT', __DIR__);
require_once __DIR__ . '/vendor/autoload.php';
$env = FsConfig::fromFile(Misuzu::PATH_CONFIG . '/config.cfg');
\Dotenv\Dotenv::createImmutable(Misuzu::PATH_ROOT)->load();
if($env->hasValues('sentry:dsn'))
(function($env) {
\Sentry\init([
'dsn' => $env->getString('dsn'),
'traces_sample_rate' => $env->getFloat('tracesRate', 0.2),
'profiles_sample_rate' => $env->getFloat('profilesRate', 0.2),
]);
if(!empty($_ENV['SENTRY_DSN']))
\Sentry\init(['dsn' => $_ENV['SENTRY_DSN']]);
set_exception_handler(function(\Throwable $ex) {
\Sentry\captureException($ex);
});
})($env->scopeTo('sentry'));
(function(\Whoops\RunInterface $whoops) {
if(Misuzu::cli())
$whoops->pushHandler(new Whoops\SentryPlainTextHandler);
elseif(Misuzu::debug())
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
else
$whoops->pushHandler(new Whoops\SentryPageHandler);
$msz = new MisuzuContext($env);
$whoops->register();
})(new \Whoops\Run);
$msz = new MisuzuContext(
$_ENV['DATABASE_DSN'] ?? 'null:',
$_ENV['DOMAIN_ROLES'] ?? 'localhost=main,redirect:/go'
);

View file

@ -9,23 +9,6 @@ require_once __DIR__ . '/../misuzu.php';
if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
die('Misuzu is not initialised.');
if(class_exists(\Whoops\Run::class))
(function($whoops) {
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
})(new \Whoops\Run);
else
set_exception_handler(function(\Throwable $ex) {
\Sentry\captureException($ex);
http_response_code(500);
ob_clean();
header('Content-Type: text/html; charset=utf-8');
header('X-Accel-Redirect: /error-500.html');
exit;
});
// The whole wall of shit before the router setup and dispatch should be worked away
// Lockdown things should be middleware when there's no more legacy files
@ -128,7 +111,7 @@ CSRF::init(
$router = $msz->createRouting($request);
$msz->startTemplating();
if(in_array('main', $msz->env->getArray(sprintf('domain:%s', $request->getHeaderLine('Host'))))) {
if($msz->domainRoles->hasRole($request->getHeaderLine('Host'), 'main')) {
$mszRequestPath = substr($request->path, 1);
$mszLegacyPathPrefix = Misuzu::PATH_PUBLIC_LEGACY . '/';
$mszLegacyPath = $mszLegacyPathPrefix . $mszRequestPath;

View file

@ -11,8 +11,10 @@ class DatabaseContext implements RouteHandler {
public private(set) DbConnection $conn;
public function __construct(Config $config) {
$this->conn = DbBackends::create($config->getString('dsn', 'null:'));
public function __construct(
#[\SensitiveParameter] string $dsn
) {
$this->conn = DbBackends::create($dsn);
$this->conn->execute(<<<SQL
SET SESSION
time_zone = '+00:00',

52
src/DomainRoles.php Normal file
View file

@ -0,0 +1,52 @@
<?php
namespace Misuzu;
use Index\XArray;
class DomainRoles {
/** @var array<string, array<string, string>> */
private array $domainRoles;
/** @param string|array<string, array<string, string>> $domainRoles */
public function __construct(string|array $domainRoles) {
if(is_string($domainRoles)) {
$domains = explode(';', $domainRoles);
$domainRoles = [];
foreach($domains as $domain) {
[$domain, $rolesRaw] = XArray::select(explode('=', $domain, 2), fn($part) => trim($part));
$roles = [];
$rolesRaw = explode(',', $rolesRaw);
foreach($rolesRaw as $roleRaw) {
$role = XArray::select(explode(':', $roleRaw, 2), fn($part) => trim($part));
$roles[$role[0]] = empty($role[1]) ? '' : $role[1];
}
$domainRoles[$domain] = $roles;
}
}
$this->domainRoles = $domainRoles;
}
public function hasRole(string $domain, string $role): bool {
return array_key_exists($domain, $this->domainRoles)
&& array_key_exists($role, $this->domainRoles[$domain]);
}
/** @return string[] */
public function getRoles(string $domain): array {
return array_key_exists($domain, $this->domainRoles)
? array_keys($this->domainRoles[$domain])
: [];
}
public function getPrefix(string $domain, string $role): ?string {
if(!array_key_exists($domain, $this->domainRoles))
return null;
if(!array_key_exists($role, $this->domainRoles[$domain]))
return null;
return $this->domainRoles[$domain][$role];
}
}

View file

@ -39,4 +39,8 @@ final class Misuzu {
public static function debug(): bool {
return !empty(ini_get('display_errors'));
}
public static function cli(): bool {
return php_sapi_name() === 'cli';
}
}

View file

@ -18,6 +18,7 @@ class MisuzuContext {
public private(set) Dependencies $deps;
public private(set) Config $config;
public private(set) DomainRoles $domainRoles;
public private(set) TplEnvironment $templating;
public private(set) AuditLog\AuditLogData $auditLog;
@ -47,17 +48,18 @@ class MisuzuContext {
public private(set) UrlRegistry $urls;
public function __construct(
public private(set) Config $env
#[\SensitiveParameter] string $dsn,
string $domainRoles
) {
$this->deps = new Dependencies;
$this->deps->register($this);
$this->deps->register($this->deps);
$this->deps->register($this->env);
$this->deps->register($this->dbCtx = new DatabaseContext($this->env->scopeTo('database')));
$this->deps->register($this->dbCtx = new DatabaseContext($dsn));
$this->deps->register($this->dbCtx->conn);
$this->deps->register($this->config = $this->deps->constructLazy(DbConfig::class, tableName: 'msz_config'));
$this->deps->register($this->domainRoles = $this->deps->constructLazy(DomainRoles::class, domainRoles: $domainRoles));
$this->deps->register($this->perms = $this->deps->constructLazy(Perms\PermissionsData::class));
$this->deps->register($this->authInfo = $this->deps->constructLazy(Auth\AuthInfo::class));
@ -138,9 +140,8 @@ class MisuzuContext {
}
public function createRouting(HttpRequest $request): BackedRoutingContext {
$prefix = sprintf('domain:%s', $request->getHeaderLine('Host'));
$hostInfo = $this->env->scopeTo($prefix);
$purposes = $this->env->getArray($prefix);
$host = $request->getHeaderLine('Host');
$roles = $this->domainRoles->getRoles($host);
$routingCtx = new BackedRoutingContext;
$this->deps->register($this->urls = $routingCtx->urls);
@ -150,15 +151,15 @@ class MisuzuContext {
new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret'))
));
if(in_array('main', $purposes))
if(in_array('main', $roles))
$this->registerMainRoutes(
$routingCtx->scopeTo($hostInfo->getString('main:path')),
$routingCtx->scopeTo($this->domainRoles->getPrefix($host, 'main')),
$rpcServer
);
if(in_array('redirect', $purposes))
if(in_array('redirect', $roles))
$this->registerRedirectorRoutes(
$routingCtx->scopeTo($hostInfo->getString('redirect:path'))
$routingCtx->scopeTo($this->domainRoles->getPrefix($host, 'redirect'))
);
return $routingCtx;

View file

@ -6,6 +6,7 @@ use InvalidArgumentException;
use RuntimeException;
use Index\XDateTime;
use Index\Db\{DbConnection,DbStatement,DbStatementCache,DbTools};
use Misuzu\Misuzu;
use Misuzu\Forum\{ForumCategoriesData,ForumCategoryInfo};
use Misuzu\Users\{RoleInfo,UserInfo};
@ -381,7 +382,7 @@ class PermissionsData {
* @param bool|float|int|string|null ...$args
*/
private static function precalculatePermissionsLog(string $fmt, ...$args): void {
if(php_sapi_name() === 'cli')
if(!Misuzu::cli())
return;
echo XDateTime::now()->format('[H:i:s.u] ');

View file

@ -0,0 +1,38 @@
<?php
namespace Misuzu\Whoops;
use Throwable;
use Misuzu\Misuzu;
use Sentry\EventId;
use Whoops\Handler\Handler;
class SentryPageHandler extends Handler {
/** @return int */
public function handle() {
$throwable = $this->getException();
$eventId = $throwable instanceof Throwable ? \Sentry\captureException($throwable) : null;
$path = Misuzu::PATH_PUBLIC . DIRECTORY_SEPARATOR . 'error-500.html';
$message = $eventId instanceof EventId
? sprintf("Error has been reported: <code>%s</code>", (string)$eventId)
: 'Error could not be reported.';
http_response_code(500);
if(is_file($path)) {
$body = file_get_contents($path);
if(is_string($body))
$body = str_replace(
'<span class=error-additional></span>',
sprintf('<br>%s', $message),
$body
);
}
if(empty($body) || !is_string($body))
$body = '<!doctype html>Something went very wrong. Please report what you were trying to do to a developer. ' . $message;
header('Content-Type: text/html; charset=utf-8');
echo $body;
return Handler::QUIT;
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Misuzu\Whoops;
use Throwable;
use Sentry\EventId;
use Whoops\Handler\PlainTextHandler;
class SentryPlainTextHandler extends PlainTextHandler {
#[\Override]
public function generateResponse() {
$throwable = $this->getException();
$eventId = $throwable instanceof Throwable ? \Sentry\captureException($throwable) : null;
$message = $eventId instanceof EventId
? sprintf('Error has been reported: %s', (string)$eventId)
: 'Error could not be reported.';
return parent::generateResponse() . $message . "\n";
}
}

View file

@ -38,7 +38,7 @@
<i class="{{ error_icon }}"></i>
</div>
<h1 class="error-title">{{ error_string }}</h1>
<p class="error-blerb">{{ error_blerb }}</p>
<p class="error-blerb">{{ error_blerb }}<span class=error-additional></span></p>
</article>
<footer class="error-footer">
<p>