From db84d0aef3e50975e226176f5439c40eb4e91533 Mon Sep 17 00:00:00 2001 From: Douglas Silva Date: Fri, 20 Mar 2020 12:37:35 -0300 Subject: [PATCH] Added custom exceptions --- .../Exception/AccessDeniedHttpException.php | 30 +++++++++++++ .../Bundle/Exception/HttpException.php | 39 ++++++++++++++++ .../MethodNotAllowedHttpException.php | 32 +++++++++++++ .../Exception/NotFoundHttpException.php | 30 +++++++++++++ .../Exception/ServerErrorHttpException.php | 30 +++++++++++++ src/Fragments/Component/CsrfTokenManager.php | 4 +- src/Fragments/Component/ExceptionHandler.php | 45 +++++++++++++++++++ src/Fragments/Component/PDOBuilder.php | 10 ++--- .../Component/Routing/RequestMatcher.php | 36 ++++++--------- src/Fragments/Component/Routing/Router.php | 10 ++--- .../SessionManagement/Init/SessionStrict.php | 4 +- .../SessionManagement/Init/SessionUnsafe.php | 4 +- .../Component/SessionManagement/Session.php | 3 +- 13 files changed, 238 insertions(+), 39 deletions(-) create mode 100644 src/Fragments/Bundle/Exception/AccessDeniedHttpException.php create mode 100644 src/Fragments/Bundle/Exception/HttpException.php create mode 100644 src/Fragments/Bundle/Exception/MethodNotAllowedHttpException.php create mode 100644 src/Fragments/Bundle/Exception/NotFoundHttpException.php create mode 100644 src/Fragments/Bundle/Exception/ServerErrorHttpException.php create mode 100644 src/Fragments/Component/ExceptionHandler.php diff --git a/src/Fragments/Bundle/Exception/AccessDeniedHttpException.php b/src/Fragments/Bundle/Exception/AccessDeniedHttpException.php new file mode 100644 index 0000000..c0c9bf0 --- /dev/null +++ b/src/Fragments/Bundle/Exception/AccessDeniedHttpException.php @@ -0,0 +1,30 @@ +. + */ + +namespace Fragments\Bundle\Exception; + +class AccessDeniedHttpException extends HttpException +{ + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0) + { + parent::__construct(403, $message, $previous, $code); + } +} \ No newline at end of file diff --git a/src/Fragments/Bundle/Exception/HttpException.php b/src/Fragments/Bundle/Exception/HttpException.php new file mode 100644 index 0000000..1f09d56 --- /dev/null +++ b/src/Fragments/Bundle/Exception/HttpException.php @@ -0,0 +1,39 @@ +. + */ + +namespace Fragments\Bundle\Exception; + +class HttpException extends \RuntimeException +{ + private $statusCode; + + public function __construct(int $statusCode, string $message = null, \Throwable $previous = null, ?int $code = 0) + { + $this->statusCode = $statusCode; + + parent::__construct($message, $code, $previous); + } + + public function getStatusCode(): int + { + return $this->statusCode; + } +} \ No newline at end of file diff --git a/src/Fragments/Bundle/Exception/MethodNotAllowedHttpException.php b/src/Fragments/Bundle/Exception/MethodNotAllowedHttpException.php new file mode 100644 index 0000000..113d599 --- /dev/null +++ b/src/Fragments/Bundle/Exception/MethodNotAllowedHttpException.php @@ -0,0 +1,32 @@ +. + */ + +namespace Fragments\Bundle\Exception; + +class MethodNotAllowedHttpException extends HttpException +{ + public function __construct(\Throwable $previous = null, int $code = 0) + { + $message = 'Method not allowed.'; + + parent::__construct(405, $message, $previous, $code); + } +} \ No newline at end of file diff --git a/src/Fragments/Bundle/Exception/NotFoundHttpException.php b/src/Fragments/Bundle/Exception/NotFoundHttpException.php new file mode 100644 index 0000000..fb6a69d --- /dev/null +++ b/src/Fragments/Bundle/Exception/NotFoundHttpException.php @@ -0,0 +1,30 @@ +. + */ + +namespace Fragments\Bundle\Exception; + +class NotFoundHttpException extends HttpException +{ + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0) + { + parent::__construct(404, $message, $previous, $code); + } +} \ No newline at end of file diff --git a/src/Fragments/Bundle/Exception/ServerErrorHttpException.php b/src/Fragments/Bundle/Exception/ServerErrorHttpException.php new file mode 100644 index 0000000..d788c47 --- /dev/null +++ b/src/Fragments/Bundle/Exception/ServerErrorHttpException.php @@ -0,0 +1,30 @@ +. + */ + +namespace Fragments\Bundle\Exception; + +class ServerErrorHttpException extends HttpException +{ + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0) + { + parent::__construct(500, $message, $previous, $code); + } +} \ No newline at end of file diff --git a/src/Fragments/Component/CsrfTokenManager.php b/src/Fragments/Component/CsrfTokenManager.php index e8a598b..c35557a 100644 --- a/src/Fragments/Component/CsrfTokenManager.php +++ b/src/Fragments/Component/CsrfTokenManager.php @@ -22,6 +22,7 @@ namespace Fragments\Component; use Fragments\Component\SessionManagement\Session; +use Fragments\Bundle\Exception\AccessDeniedHttpException; /** * Manage tokens used to prevent CSRF attacks. @@ -64,8 +65,7 @@ public function isTokenValid(string $tokenReceived, string $targetId): bool $targetId = self::PREFIX . $targetId; if (false === $this->session->exists($targetId)) { - // FIXME: throw access denied exception - return false; + throw new AccessDeniedHttpException('The CSRF token identifier could not be found.'); } $tokenStored = $this->session->get($targetId); diff --git a/src/Fragments/Component/ExceptionHandler.php b/src/Fragments/Component/ExceptionHandler.php new file mode 100644 index 0000000..4a7b2f7 --- /dev/null +++ b/src/Fragments/Component/ExceptionHandler.php @@ -0,0 +1,45 @@ +. + */ + +namespace Fragments\Component; + +/** + * Converts all PHP errors to exceptions. + */ +class ExceptionHandler +{ + public function handler($severity, $message, $file, $line) + { + if (!(error_reporting() & $severity)) { + // This error code is not included in error_reporting + return; + } + + // FIXME: handle different severities differently + + throw new \ErrorException($message, 0, $severity, $file, $line); + } + + public function setHandler() + { + set_error_handler([$this, 'handler']); + } +} \ No newline at end of file diff --git a/src/Fragments/Component/PDOBuilder.php b/src/Fragments/Component/PDOBuilder.php index 45a789d..6e995f7 100644 --- a/src/Fragments/Component/PDOBuilder.php +++ b/src/Fragments/Component/PDOBuilder.php @@ -21,6 +21,8 @@ namespace Fragments\Component; +use Fragments\Bundle\Exception\ServerErrorHttpException; + class PDOBuilder { public function getConnection(): \PDO @@ -38,8 +40,7 @@ public function getConnection(): \PDO $config['username'], $config['password'], $options ); } catch(\PDOException $error) { - // FIXME: throw server error exception - exit; + throw new ServerErrorHttpException('Failed to connect to the database.'); } return $pdo; @@ -49,11 +50,6 @@ private function getConfig(): array { $config = parse_ini_file('../config/database.ini'); - if (false === $config) { - // FIXME: throw server error exception - exit; - } - // FIXME: test for missing configuration keys return $config; } diff --git a/src/Fragments/Component/Routing/RequestMatcher.php b/src/Fragments/Component/Routing/RequestMatcher.php index edd2ab5..cf1b080 100644 --- a/src/Fragments/Component/Routing/RequestMatcher.php +++ b/src/Fragments/Component/Routing/RequestMatcher.php @@ -21,6 +21,8 @@ namespace Fragments\Component\Routing; +use Fragments\Bundle\Exception\MethodNotAllowedHttpException; + /** * Request matcher * @@ -44,12 +46,12 @@ class RequestMatcher /** * When a matching route is found, its name is stored here. */ - public $matchedRouteName = null; + public $matchedRouteName; /** * The parameter to be passed to the controller. */ - public $parameter = null; + public $parameter; public function __construct($routeCollection, RequestContext $context) { @@ -66,21 +68,13 @@ public function match() } } - private function testWildcard(Route $route) + private function testWildcard(Route $route): bool { if ($this->containsWildcard($route) === true) { - if ($this->matchPathWithWildcard($route) === true) { - return true; - } - - return false; - } else { - if ($this->matchPathWithoutWildcard($route) == true) { - return true; - } - - return false; + return $this->matchPathWithWildcard($route); } + + return $this->matchPathWithoutWildcard($route); } /** @@ -88,12 +82,6 @@ private function testWildcard(Route $route) * and retrieve the parameter. */ private function matchPathWithWildcard(Route $route): bool { - if (!in_array($this->context->requestMethod, $route->methods)) { - // FIXME: throw access denied exception - - return false; - } - $path = $route->path; $pattern = '/\/{alpha}/'; $replacement = ''; @@ -103,7 +91,11 @@ private function matchPathWithWildcard(Route $route): bool { // Using ~ as the regex delimiter to prevent conflict $prefix = '~^' . $prefix . '\/' . '(?[a-zA-Z0-9_]+)$~'; - if (preg_match($prefix, $this->context->uri, $match) == true) { + if (true == preg_match($prefix, $this->context->uri, $match)) { + if (!in_array($this->context->requestMethod, $route->methods)) { + throw new MethodNotAllowedHttpException; + } + $this->parameter = $match['alpha']; return true; @@ -122,7 +114,7 @@ private function matchPathWithoutWildcard(Route $route): bool } if (!in_array($this->context->requestMethod, $route->methods)) { - return false; + throw new MethodNotAllowedHttpException; } return true; diff --git a/src/Fragments/Component/Routing/Router.php b/src/Fragments/Component/Routing/Router.php index 3e0569b..8d49a42 100644 --- a/src/Fragments/Component/Routing/Router.php +++ b/src/Fragments/Component/Routing/Router.php @@ -21,6 +21,8 @@ namespace Fragments\Component\Routing; +use Fragments\Bundle\Exception\NotFoundHttpException; + /** * The router controller. * @@ -41,13 +43,11 @@ public function start() $matcher = new RequestMatcher($routeCollection, $context); $matcher->match(); - if (is_null($matcher->matchedRouteName)) { - // FIXME: throw not found exception - - return; + if (!$matcher->matchedRouteName) { + throw new NotFoundHttpException('The page you were looking for could not be found.'); } - if (!is_null($matcher->parameter)) { + if ($matcher->parameter) { $this->parameter = $matcher->parameter; } diff --git a/src/Fragments/Component/SessionManagement/Init/SessionStrict.php b/src/Fragments/Component/SessionManagement/Init/SessionStrict.php index 7407a95..8aba3be 100644 --- a/src/Fragments/Component/SessionManagement/Init/SessionStrict.php +++ b/src/Fragments/Component/SessionManagement/Init/SessionStrict.php @@ -21,13 +21,15 @@ namespace Fragments\Component\SessionManagement\Init; +use Fragments\Bundle\Exception\ServerErrorHttpException; + class SessionStrict extends AbstractSessionInit { public function init() { $this->options['use_strict_mode'] = 1; if (!session_start($this->options)) { - // FIXME: throw server error exception + throw new ServerErrorHttpException('Failed to start the session.'); } } } diff --git a/src/Fragments/Component/SessionManagement/Init/SessionUnsafe.php b/src/Fragments/Component/SessionManagement/Init/SessionUnsafe.php index 4e7e46e..0f52eb5 100644 --- a/src/Fragments/Component/SessionManagement/Init/SessionUnsafe.php +++ b/src/Fragments/Component/SessionManagement/Init/SessionUnsafe.php @@ -21,13 +21,15 @@ namespace Fragments\Component\SessionManagement\Init; +use Fragments\Bundle\Exception\ServerErrorHttpException; + class SessionUnsafe extends AbstractSessionInit { public function init() { $this->options['use_strict_mode'] = 0; if (!session_start($this->options)) { - // FIXME: throw server error exception + throw new ServerErrorHttpException('Failed to start the session.'); } } } diff --git a/src/Fragments/Component/SessionManagement/Session.php b/src/Fragments/Component/SessionManagement/Session.php index 412a521..8f53a9c 100644 --- a/src/Fragments/Component/SessionManagement/Session.php +++ b/src/Fragments/Component/SessionManagement/Session.php @@ -23,6 +23,7 @@ use Fragments\Component\SessionManagement\Init\SessionStrict; use Fragments\Component\SessionManagement\Init\SessionUnsafe; +use Fragments\Bundle\Exception\AccessDeniedHttpException; /** * Session Utility. @@ -77,7 +78,7 @@ public function start() if ($obsoleteTime < time() - 300) { $this->destroyAll(); - // FIXME: throw access denied exception + throw new AccessDeniedHttpException('The session has expired.'); } /*