From 20c03a155d2017101a098cefa602116a4a331d71 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 7 Aug 2018 03:18:22 +0200 Subject: [PATCH] Implemented PSR-15 middleware handler --- composer.json | 2 + locale/de_DE.UTF-8/LC_MESSAGES/default.mo | Bin 44974 -> 44999 bytes locale/de_DE.UTF-8/LC_MESSAGES/default.po | 14 +- public/index.php | 263 ++------------------ src/Middleware/Dispatcher.php | 110 +++++++++ src/Middleware/ExceptionHandler.php | 48 ++++ src/Middleware/LegacyMiddleware.php | 284 ++++++++++++++++++++++ src/Middleware/NotFoundResponse.php | 47 ++++ src/Middleware/SendResponseHandler.php | 45 ++++ src/helpers.php | 30 ++- 10 files changed, 591 insertions(+), 252 deletions(-) create mode 100644 src/Middleware/Dispatcher.php create mode 100644 src/Middleware/ExceptionHandler.php create mode 100644 src/Middleware/LegacyMiddleware.php create mode 100644 src/Middleware/NotFoundResponse.php create mode 100644 src/Middleware/SendResponseHandler.php diff --git a/composer.json b/composer.json index df9ee57b..911df1f5 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,13 @@ ], "require": { "php": ">=7.0.0", + "ext-gettext": "*", "erusev/parsedown": "^1.6", "illuminate/container": "5.5.*", "illuminate/database": "5.5.*", "illuminate/support": "^5.5", "psr/container": "^1.0", + "psr/http-server-middleware": "^1.0", "psr/log": "^1.0", "symfony/http-foundation": "^3.3", "symfony/psr-http-message-bridge": "^1.0", diff --git a/locale/de_DE.UTF-8/LC_MESSAGES/default.mo b/locale/de_DE.UTF-8/LC_MESSAGES/default.mo index 3939e87019df710e0047e1cd4bfdc3c7146383f3..8b3b7dcfd07fb338a896d194bee431f0e3de2443 100644 GIT binary patch delta 8170 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 delta 8141 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 WL2+@OmzT6~`&Txu`e=(^(Ek7oZn~5J diff --git a/locale/de_DE.UTF-8/LC_MESSAGES/default.po b/locale/de_DE.UTF-8/LC_MESSAGES/default.po index 7187b32c..49973ca9 100644 --- a/locale/de_DE.UTF-8/LC_MESSAGES/default.po +++ b/locale/de_DE.UTF-8/LC_MESSAGES/default.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Engelsystem 2.0\n" "POT-Creation-Date: 2017-12-29 19:01+0100\n" -"PO-Revision-Date: 2017-12-29 19:03+0100\n" +"PO-Revision-Date: 2018-08-07 02:00+0200\n" "Last-Translator: msquare \n" "Language-Team: \n" "Language: de_DE\n" @@ -2874,13 +2874,13 @@ msgstr "" "keine Nummer hast, bitte einfach \"-\" angeben." #: /Users/msquare/workspace/projects/engelsystem/public/index.php:218 -msgid "No Access" -msgstr "Kein Zugriff" +msgid "Page not found" +msgstr "Seite nicht gefunden" #: /Users/msquare/workspace/projects/engelsystem/public/index.php:219 msgid "" -"You don't have permission to view this page . You probably have to sign in " -"or register in order to gain access!" +"This page could not be found or you don't have permission to view it. You " +"probably have to sign in or register in order to gain access!" msgstr "" -"Du hast keinen Zugriff auf diese Seite. Registriere Dich und logge Dich " -"bitte ein, um Zugriff zu erhalten!" +"Diese Seite existiert nicht oder Du hast keinen Zugriff. Melde Dich an um Zugriff " +"zu erhalten!" diff --git a/public/index.php b/public/index.php index db4c4294..88e57252 100644 --- a/public/index.php +++ b/public/index.php @@ -1,252 +1,27 @@ get('psr7.request'); -/** @var Request $request */ -$request = $app->get('request'); -$page = $request->query->get('p'); -if (empty($page)) { - $page = $request->path(); - $page = str_replace('-', '_', $page); -} -if ($page == '/') { - $page = isset($user) ? 'news' : 'login'; -} - -if ( - preg_match('/^\w*$/i', $page) - && ( - in_array($page, $free_pages) - || (isset($privileges) && in_array($page, $privileges)) - ) -) { - $title = $page; - - switch ($page) { - case 'api': - error('Api disabled temporarily.'); - redirect(page_link_to()); - break; - case 'ical': - require_once realpath(__DIR__ . '/../includes/pages/user_ical.php'); - user_ical(); - break; - case 'atom': - require_once realpath(__DIR__ . '/../includes/pages/user_atom.php'); - user_atom(); - break; - case 'shifts_json_export': - require_once realpath(__DIR__ . '/../includes/controller/shifts_controller.php'); - shifts_json_export_controller(); - break; - case 'shifts_json_export_all': - require_once realpath(__DIR__ . '/../includes/controller/shifts_controller.php'); - shifts_json_export_all_controller(); - break; - case 'stats': - require_once realpath(__DIR__ . '/../includes/pages/guest_stats.php'); - guest_stats(); - break; - case 'user_password_recovery': - require_once realpath(__DIR__ . '/../includes/controller/users_controller.php'); - $title = user_password_recovery_title(); - $content = user_password_recovery_controller(); - break; - case 'public_dashboard': - list($title, $content) = public_dashboard_controller(); - break; - case 'angeltypes': - list($title, $content) = angeltypes_controller(); - break; - case 'shift_entries': - list($title, $content) = shift_entries_controller(); - break; - case 'shifts': - list($title, $content) = shifts_controller(); - break; - case 'users': - list($title, $content) = users_controller(); - break; - case 'user_angeltypes': - list($title, $content) = user_angeltypes_controller(); - break; - case 'user_driver_licenses': - list($title, $content) = user_driver_licenses_controller(); - break; - case 'shifttypes': - list($title, $content) = shifttypes_controller(); - break; - case 'admin_event_config': - list($title, $content) = event_config_edit_controller(); - break; - case 'rooms': - list($title, $content) = rooms_controller(); - break; - case 'news': - $title = news_title(); - $content = user_news(); - break; - case 'news_comments': - require_once realpath(__DIR__ . '/../includes/pages/user_news.php'); - $title = user_news_comments_title(); - $content = user_news_comments(); - break; - case 'user_meetings': - $title = meetings_title(); - $content = user_meetings(); - break; - case 'user_myshifts': - $title = myshifts_title(); - $content = user_myshifts(); - break; - case 'user_shifts': - $title = shifts_title(); - $content = user_shifts(); - break; - case 'user_worklog': - list($title, $content) = user_worklog_controller(); - break; - case 'user_messages': - $title = messages_title(); - $content = user_messages(); - break; - case 'user_questions': - $title = questions_title(); - $content = user_questions(); - break; - case 'user_settings': - $title = settings_title(); - $content = user_settings(); - break; - case 'login': - $title = login_title(); - $content = guest_login(); - break; - case 'register': - $title = register_title(); - $content = guest_register(); - break; - case 'logout': - $title = logout_title(); - $content = guest_logout(); - break; - case 'admin_questions': - $title = admin_questions_title(); - $content = admin_questions(); - break; - case 'admin_user': - $title = admin_user_title(); - $content = admin_user(); - break; - case 'admin_arrive': - $title = admin_arrive_title(); - $content = admin_arrive(); - break; - case 'admin_active': - $title = admin_active_title(); - $content = admin_active(); - break; - case 'admin_free': - $title = admin_free_title(); - $content = admin_free(); - break; - case 'admin_news': - require_once realpath(__DIR__ . '/../includes/pages/admin_news.php'); - $content = admin_news(); - break; - case 'admin_rooms': - $title = admin_rooms_title(); - $content = admin_rooms(); - break; - case 'admin_groups': - $title = admin_groups_title(); - $content = admin_groups(); - break; - case 'admin_import': - $title = admin_import_title(); - $content = admin_import(); - break; - case 'admin_shifts': - $title = admin_shifts_title(); - $content = admin_shifts(); - break; - case 'admin_log': - $title = admin_log_title(); - $content = admin_log(); - break; - case 'credits': - require_once realpath(__DIR__ . '/../includes/pages/guest_credits.php'); - $title = credits_title(); - $content = guest_credits(); - break; - default: - require_once realpath(__DIR__ . '/../includes/pages/guest_start.php'); - $content = guest_start(); - break; - } -} else { - // Wenn schon eingeloggt, keine-Berechtigung-Seite anzeigen - if (isset($user)) { - $title = _('No Access'); - $content = _('You don\'t have permission to view this page . You probably have to sign in or register in order to gain access!'); - } else { - // Sonst zur Loginseite leiten - redirect(page_link_to('login')); - } -} - -$event_config = EventConfig(); - -$parameters = [ - 'key' => (isset($user) ? $user['api_key'] : ''), -]; -if ($page == 'user_meetings') { - $parameters['meetings'] = 1; -} - -echo view(__DIR__ . '/../templates/layout.html', [ - 'theme' => isset($user) ? $user['color'] : config('theme'), - 'title' => $title, - 'atom_link' => ($page == 'news' || $page == 'user_meetings') - ? ' ' - : '', - 'start_page_url' => page_link_to('/'), - 'credits_url' => page_link_to('credits'), - 'menu' => make_menu(), - 'content' => msg() . $content, - 'header_toolbar' => header_toolbar(), - 'faq_url' => config('faq_url'), - 'contact_email' => config('contact_email'), - 'locale' => locale(), - 'event_info' => EventConfig_info($event_config) . '
' +$dispatcher = new Dispatcher([ + SendResponseHandler::class, + ExceptionHandler::class, + LegacyMiddleware::class, + NotFoundResponse::class, ]); +$dispatcher->setContainer($app); + +$dispatcher->handle($request); diff --git a/src/Middleware/Dispatcher.php b/src/Middleware/Dispatcher.php new file mode 100644 index 00000000..774040fb --- /dev/null +++ b/src/Middleware/Dispatcher.php @@ -0,0 +1,110 @@ +stack = $stack; + $this->container = $container; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * response creation to a handler. + * + * Could be used to group middleware + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process( + ServerRequestInterface $request, + RequestHandlerInterface $handler + ): ResponseInterface { + $this->next = $handler; + + return $this->handle($request); + } + + /** + * Handle the request and return a response. + * + * It calls all configured middleware and handles their response + * + * @param ServerRequestInterface $request + * @return ResponseInterface + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + $middleware = array_shift($this->stack); + + if (!$middleware) { + if ($this->next) { + return $this->next->handle($request); + } + + throw new LogicException('Middleware queue is empty'); + } + + if (is_string($middleware)) { + $middleware = $this->resolveMiddleware($middleware); + } + + if (!$middleware instanceof MiddlewareInterface) { + throw new InvalidArgumentException('Middleware is no instance of ' . MiddlewareInterface::class); + } + + return $middleware->process($request, $this); + } + + /** + * Resolve the middleware with the container + * + * @param string $middleware + * @return MiddlewareInterface + */ + protected function resolveMiddleware($middleware) + { + if (!$this->container instanceof Application) { + throw new InvalidArgumentException('Unable to resolve middleware ' . $middleware); + } + + if ($this->container->has($middleware)) { + return $this->container->get($middleware); + } + + return $this->container->make($middleware); + } + + /** + * @param Application $container + */ + public function setContainer(Application $container) + { + $this->container = $container; + } +} diff --git a/src/Middleware/ExceptionHandler.php b/src/Middleware/ExceptionHandler.php new file mode 100644 index 00000000..a5db0337 --- /dev/null +++ b/src/Middleware/ExceptionHandler.php @@ -0,0 +1,48 @@ +container = $container; + } + + /** + * Handles any exceptions that occurred inside other middleware while returning it to the default response handler + * + * Should be added at the beginning + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process( + ServerRequestInterface $request, + RequestHandlerInterface $handler + ): ResponseInterface { + try { + return $handler->handle($request); + } catch (\Throwable $e) { + /** @var ExceptionsHandler $handler */ + $handler = $this->container->get('error.handler'); + $content = $handler->exceptionHandler($e, true); + + return response($content, 500); + } + } +} diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php new file mode 100644 index 00000000..41b2e471 --- /dev/null +++ b/src/Middleware/LegacyMiddleware.php @@ -0,0 +1,284 @@ +container = $container; + } + + /** + * Handle the request the old way + * + * Should be used before a 404 is send + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process( + ServerRequestInterface $request, + RequestHandlerInterface $handler + ): ResponseInterface { + global $user; + global $privileges; + + /** @var Request $appRequest */ + $appRequest = $this->container->get('request'); + + // Default page content + $content = ''; + + $page = $appRequest->query->get('p'); + if (empty($page)) { + $page = $appRequest->path(); + $page = str_replace('-', '_', $page); + } + if ($page == '/') { + $page = isset($user) ? 'news' : 'login'; + } + + if ( + preg_match('/^\w+$/i', $page) + && ( + in_array($page, $this->free_pages) + || (isset($privileges) && in_array($page, $privileges)) + ) + ) { + $title = $page; + + switch ($page) { + case 'api': + error('Api disabled temporarily.'); + redirect(page_link_to()); + break; + case 'ical': + require_once realpath(__DIR__ . '/../includes/pages/user_ical.php'); + user_ical(); + break; + case 'atom': + require_once realpath(__DIR__ . '/../includes/pages/user_atom.php'); + user_atom(); + break; + case 'shifts_json_export': + require_once realpath(__DIR__ . '/../includes/controller/shifts_controller.php'); + shifts_json_export_controller(); + break; + case 'shifts_json_export_all': + require_once realpath(__DIR__ . '/../includes/controller/shifts_controller.php'); + shifts_json_export_all_controller(); + break; + case 'stats': + require_once realpath(__DIR__ . '/../includes/pages/guest_stats.php'); + guest_stats(); + break; + case 'user_password_recovery': + require_once realpath(__DIR__ . '/../includes/controller/users_controller.php'); + $title = user_password_recovery_title(); + $content = user_password_recovery_controller(); + break; + case 'public_dashboard': + list($title, $content) = public_dashboard_controller(); + break; + case 'angeltypes': + list($title, $content) = angeltypes_controller(); + break; + case 'shift_entries': + list($title, $content) = shift_entries_controller(); + break; + case 'shifts': + list($title, $content) = shifts_controller(); + break; + case 'users': + list($title, $content) = users_controller(); + break; + case 'user_angeltypes': + list($title, $content) = user_angeltypes_controller(); + break; + case 'user_driver_licenses': + list($title, $content) = user_driver_licenses_controller(); + break; + case 'shifttypes': + list($title, $content) = shifttypes_controller(); + break; + case 'admin_event_config': + list($title, $content) = event_config_edit_controller(); + break; + case 'rooms': + list($title, $content) = rooms_controller(); + break; + case 'news': + $title = news_title(); + $content = user_news(); + break; + case 'news_comments': + require_once realpath(__DIR__ . '/../includes/pages/user_news.php'); + $title = user_news_comments_title(); + $content = user_news_comments(); + break; + case 'user_meetings': + $title = meetings_title(); + $content = user_meetings(); + break; + case 'user_myshifts': + $title = myshifts_title(); + $content = user_myshifts(); + break; + case 'user_shifts': + $title = shifts_title(); + $content = user_shifts(); + break; + case 'user_worklog': + list($title, $content) = user_worklog_controller(); + break; + case 'user_messages': + $title = messages_title(); + $content = user_messages(); + break; + case 'user_questions': + $title = questions_title(); + $content = user_questions(); + break; + case 'user_settings': + $title = settings_title(); + $content = user_settings(); + break; + case 'login': + $title = login_title(); + $content = guest_login(); + break; + case 'register': + $title = register_title(); + $content = guest_register(); + break; + case 'logout': + $title = logout_title(); + $content = guest_logout(); + break; + case 'admin_questions': + $title = admin_questions_title(); + $content = admin_questions(); + break; + case 'admin_user': + $title = admin_user_title(); + $content = admin_user(); + break; + case 'admin_arrive': + $title = admin_arrive_title(); + $content = admin_arrive(); + break; + case 'admin_active': + $title = admin_active_title(); + $content = admin_active(); + break; + case 'admin_free': + $title = admin_free_title(); + $content = admin_free(); + break; + case 'admin_news': + require_once realpath(__DIR__ . '/../includes/pages/admin_news.php'); + $content = admin_news(); + break; + case 'admin_rooms': + $title = admin_rooms_title(); + $content = admin_rooms(); + break; + case 'admin_groups': + $title = admin_groups_title(); + $content = admin_groups(); + break; + case 'admin_import': + $title = admin_import_title(); + $content = admin_import(); + break; + case 'admin_shifts': + $title = admin_shifts_title(); + $content = admin_shifts(); + break; + case 'admin_log': + $title = admin_log_title(); + $content = admin_log(); + break; + case 'credits': + require_once realpath(__DIR__ . '/../includes/pages/guest_credits.php'); + $title = credits_title(); + $content = guest_credits(); + break; + default: + require_once realpath(__DIR__ . '/../includes/pages/guest_start.php'); + $content = guest_start(); + break; + } + } else { + return $handler->handle($request); + } + + if (empty($title) and empty($content)) { + return $handler->handle($request); + } + + $event_config = EventConfig(); + + $parameters = [ + 'key' => (isset($user) ? $user['api_key'] : ''), + ]; + if ($page == 'user_meetings') { + $parameters['meetings'] = 1; + } + + return response(view(__DIR__ . '/../../templates/layout.html', [ + 'theme' => isset($user) ? $user['color'] : config('theme'), + 'title' => $title, + 'atom_link' => ($page == 'news' || $page == 'user_meetings') + ? ' ' + : '', + 'start_page_url' => page_link_to('/'), + 'credits_url' => page_link_to('credits'), + 'menu' => make_menu(), + 'content' => msg() . $content, + 'header_toolbar' => header_toolbar(), + 'faq_url' => config('faq_url'), + 'contact_email' => config('contact_email'), + 'locale' => locale(), + 'event_info' => EventConfig_info($event_config) . '
' + ])); + } +} diff --git a/src/Middleware/NotFoundResponse.php b/src/Middleware/NotFoundResponse.php new file mode 100644 index 00000000..c5d51d2d --- /dev/null +++ b/src/Middleware/NotFoundResponse.php @@ -0,0 +1,47 @@ + isset($user) ? $user['color'] : config('theme'), + 'title' => _('Page not found'), + 'atom_link' => '', + 'start_page_url' => page_link_to('/'), + 'credits_url' => page_link_to('credits'), + 'menu' => make_menu(), + 'content' => msg() . $content, + 'header_toolbar' => header_toolbar(), + 'faq_url' => config('faq_url'), + 'contact_email' => config('contact_email'), + 'locale' => locale(), + 'event_info' => EventConfig_info($event_config) . '
' + ]), 404); + } +} diff --git a/src/Middleware/SendResponseHandler.php b/src/Middleware/SendResponseHandler.php new file mode 100644 index 00000000..06406fe0 --- /dev/null +++ b/src/Middleware/SendResponseHandler.php @@ -0,0 +1,45 @@ +handle($request); + + if (!headers_sent()) { + header(sprintf( + 'HTTP/%s %s %s', + $response->getProtocolVersion(), + $response->getStatusCode(), + $response->getReasonPhrase() + ), true, $response->getStatusCode()); + + foreach ($response->getHeaders() as $name => $values) { + foreach ($values as $value) { + header($name . ': ' . $value, false); + } + } + } + + echo $response->getBody(); + return $response; + } +} diff --git a/src/helpers.php b/src/helpers.php index c3c727ec..2a90dcde 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -6,13 +6,15 @@ use Engelsystem\Config\Config; use Engelsystem\Http\Request; use Engelsystem\Renderer\Renderer; use Engelsystem\Routing\UrlGenerator; +use Psr\Http\Message\ResponseInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Zend\Diactoros\Stream; /** * Get the global app instance * * @param string $id - * @return mixed + * @return mixed|Application */ function app($id = null) { @@ -80,6 +82,32 @@ function request($key = null, $default = null) return $request->input($key, $default); } +/** + * @param string $content + * @param int $status + * @param array $headers + * @return ResponseInterface + */ +function response($content = '', $status = 200, $headers = []) +{ + /** @var ResponseInterface $response */ + $response = app('psr7.response'); + + /** @var Stream $stream */ + $stream = app()->make(Stream::class, ['stream' => 'php://memory', 'mode' => 'wb+']); + $stream->write($content); + $stream->rewind(); + + $response = $response + ->withBody($stream) + ->withStatus($status); + foreach ($headers as $key => $value) { + $response = $response->withAddedHeader($key, $value); + } + + return $response; +} + /** * @param string $key * @param mixed $default