From 06788d451f8028e01622d78fcd1a791e48aa7c71 Mon Sep 17 00:00:00 2001 From: BertKoor Date: Thu, 4 Jun 2026 14:23:54 +0200 Subject: [PATCH 1/3] removed usage of I18N in Validator: it is then not yet initialised --- app/Validator.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/Validator.php b/app/Validator.php index 91ba14714e..0508be8bb6 100644 --- a/app/Validator.php +++ b/app/Validator.php @@ -260,7 +260,7 @@ public function boolean(string $parameter, bool|null $default = null): bool } if ($default === null) { - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } return $default; @@ -276,7 +276,7 @@ public function array(string $parameter): array $value = $this->parameters[$parameter] ?? null; if (!is_array($value) && $value !== null) { - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } $callback = static fn (array|null $value, Closure $rule): array|null => $rule($value); @@ -305,7 +305,7 @@ public function float(string $parameter, float|null $default = null): float $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } return $value; @@ -338,7 +338,7 @@ public function integer(string $parameter, int|null $default = null): int $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } return $value; @@ -357,7 +357,7 @@ public function route(string $parameter = 'route'): Route return $value; } - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } /** @@ -379,7 +379,7 @@ public function string(string $parameter, string|null $default = null): string $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } return $value; @@ -398,7 +398,7 @@ public function tree(string $parameter = 'tree'): Tree return $value; } - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } public function treeOptional(string $parameter = 'tree'): Tree|null @@ -409,7 +409,7 @@ public function treeOptional(string $parameter = 'tree'): Tree|null return $value; } - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } public function user(string $parameter = 'user'): UserInterface @@ -420,6 +420,12 @@ public function user(string $parameter = 'user'): UserInterface return $value; } - throw new HttpBadRequestException(I18N::translate('The parameter “%s” is missing.', $parameter)); + throw $this->newBadRequestException($parameter); } + + private function newBadRequestException(string $parameter): HttpBadRequestException + { + return new HttpBadRequestException('The parameter “' . $parameter . '” is missing.'); + } + } From 74558101502c2ec5ff704b4b858e531a024dca7a Mon Sep 17 00:00:00 2001 From: BertKoor Date: Thu, 4 Jun 2026 14:25:30 +0200 Subject: [PATCH 2/3] dump a stack trace on http exceptions: database connection is not yet established --- app/Http/Middleware/HandleExceptions.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Http/Middleware/HandleExceptions.php b/app/Http/Middleware/HandleExceptions.php index 6b699d6162..a65b183794 100644 --- a/app/Http/Middleware/HandleExceptions.php +++ b/app/Http/Middleware/HandleExceptions.php @@ -19,6 +19,7 @@ namespace Fisharebest\Webtrees\Http\Middleware; +use Error; use Fig\Http\Message\RequestMethodInterface; use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Http\Exceptions\HttpException; @@ -143,10 +144,14 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface */ private function httpExceptionResponse(ServerRequestInterface $request, HttpException $exception): ResponseInterface { - $tree = Validator::attributes($request)->treeOptional(); - $default = Site::getPreference('DEFAULT_GEDCOM'); - $tree ??= $this->tree_service->all()[$default] ?? $this->tree_service->all()->first(); - + $tree = Validator::attributes($request)->treeOptional(); + try { + $default = Site::getPreference('DEFAULT_GEDCOM'); + $tree ??= $this->tree_service->all()[$default] ?? $this->tree_service->all()->first(); + } catch (Error) { + // httpException can be thrown before database connection is made: return a simple stack trace dump + return response(nl2br((string) $exception), $exception->getCode()); + } $status_code = $exception->getCode(); // If this was a GET request, then we were probably fetching HTML to display, for From 18ab9a7285a3486fbdef3cf7b57dcee23978b6a8 Mon Sep 17 00:00:00 2001 From: BertKoor Date: Wed, 1 Jul 2026 13:31:48 +0200 Subject: [PATCH 3/3] do not translate HttpBadRequestExceptions --- .../AdminMediaFileDownload.php | 2 +- .../AdminMediaFileThumbnail.php | 2 +- app/Validator.php | 38 ++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/app/Http/RequestHandlers/AdminMediaFileDownload.php b/app/Http/RequestHandlers/AdminMediaFileDownload.php index ea63bd32f1..31b1621993 100644 --- a/app/Http/RequestHandlers/AdminMediaFileDownload.php +++ b/app/Http/RequestHandlers/AdminMediaFileDownload.php @@ -48,6 +48,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface } } - throw new HttpBadRequestException(I18N::translate('The parameter “path” is invalid.')); + throw new HttpBadRequestException('The parameter “path” is invalid.'); } } diff --git a/app/Http/RequestHandlers/AdminMediaFileThumbnail.php b/app/Http/RequestHandlers/AdminMediaFileThumbnail.php index 0b8dbdd786..5d96031e89 100644 --- a/app/Http/RequestHandlers/AdminMediaFileThumbnail.php +++ b/app/Http/RequestHandlers/AdminMediaFileThumbnail.php @@ -48,6 +48,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface } } - throw new HttpBadRequestException(I18N::translate('The parameter “path” is invalid.')); + throw new HttpBadRequestException('The parameter “path” is invalid.'); } } diff --git a/app/Validator.php b/app/Validator.php index 33120f6a24..0e953ea330 100644 --- a/app/Validator.php +++ b/app/Validator.php @@ -212,7 +212,7 @@ public function boolean(string $parameter, bool|null $default = null): bool } if ($default === null) { - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } return $default; @@ -226,7 +226,7 @@ public function list(string $parameter): array $values = $this->array($parameter); if (!array_is_list($values)) { - throw new HttpBadRequestException(sprintf('The parameter “%s” is not a list.', $parameter)); + throw $this->badParameterException($parameter, 'not a list'); } return $values; @@ -241,7 +241,7 @@ public function array(string $parameter): array foreach ($values as $value) { if (!is_string($value)) { - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } } @@ -257,15 +257,12 @@ public function arrayArray(string $parameter): array foreach ($values as $array_value) { if (!is_array($array_value)) { - $message = sprintf('The parameter “%s” is not an array of arrays.', $parameter); - throw new HttpBadRequestException($message); + throw $this->badParameterException($parameter, 'not an array of arrays'); } foreach ($array_value as $value) { if (!is_string($value)) { - $message = sprintf('The parameter “%s” is not an array of array of strings.', $parameter); - - throw new HttpBadRequestException($message); + throw $this->badParameterException($parameter, 'not an array of array of strings'); } } } @@ -281,7 +278,7 @@ private function arrayData(string $parameter): array $value = $this->parameters[$parameter] ?? []; if (!is_array($value)) { - throw new HttpBadRequestException(sprintf('The parameter “%s” is not an array.', $parameter)); + throw $this->badParameterException($parameter, 'not an array'); } $callback = static fn (array|null $value, Closure $rule): array|null => $rule($value); @@ -304,7 +301,7 @@ public function float(string $parameter, float|null $default = null): float $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } return $value; @@ -331,7 +328,7 @@ public function integer(string $parameter, int|null $default = null): int $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } return $value; @@ -345,7 +342,7 @@ public function route(string $parameter = 'route'): Route return $value; } - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } public function string(string $parameter, string|null $default = null): string @@ -361,7 +358,7 @@ public function string(string $parameter, string|null $default = null): string $value = array_reduce($this->rules, $callback, $value) ?? $default; if ($value === null) { - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } return $value; @@ -375,7 +372,7 @@ public function tree(string $parameter = 'tree'): Tree return $value; } - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } public function treeOptional(string $parameter = 'tree'): Tree|null @@ -386,7 +383,7 @@ public function treeOptional(string $parameter = 'tree'): Tree|null return $value; } - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); } public function user(string $parameter = 'user'): UserInterface @@ -397,12 +394,17 @@ public function user(string $parameter = 'user'): UserInterface return $value; } - throw $this->newBadRequestException($parameter); + throw $this->parameterMissingException($parameter); + } + + private function parameterMissingException(string $parameter): HttpBadRequestException + { + return $this->badParameterException($parameter, 'missing'); } - private function newBadRequestException(string $parameter): HttpBadRequestException + private function badParameterException(string $parameter, string $complaint): HttpBadRequestException { - return new HttpBadRequestException('The parameter “' . $parameter . '” is missing.'); + return new HttpBadRequestException(sprintf('The parameter “%s” is %s.', $parameter, $complaint)); } }