Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
948b36c80d
|
||
|
|
635b68ab46
|
||
|
|
8df2e64872
|
||
|
|
427426bebe
|
||
|
|
014a548096
|
||
|
|
298a1e34ac
|
||
|
|
4af7ae3521
|
||
|
|
9d4cb86d41
|
||
|
|
bf4520a7dd
|
||
|
|
fda796ab18
|
||
|
|
ba33a9bb37
|
||
|
|
8a20bb76ef
|
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
# SokoWeb
|
||||||
|
|
||||||
|
[](https://ci.esoko.eu/job/soko-web/job/master/)
|
||||||
|
|
||||||
|
This is the SokoWeb framework.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*License: **GNU GPL 3.0**. Full license text can be found in file `LICENSE`.*
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php namespace SokoWeb\Interfaces\Authentication;
|
||||||
|
|
||||||
|
interface IAuthenticationRequired
|
||||||
|
{
|
||||||
|
public function isAuthenticationRequired(): bool;
|
||||||
|
}
|
||||||
@@ -12,6 +12,8 @@ interface IRequest
|
|||||||
|
|
||||||
public function post(string $key);
|
public function post(string $key);
|
||||||
|
|
||||||
|
public function header(string $key);
|
||||||
|
|
||||||
public function session(): ISession;
|
public function session(): ISession;
|
||||||
|
|
||||||
public function setUser(?IUser $user): void;
|
public function setUser(?IUser $user): void;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class PersistentDataManager
|
|||||||
$value = current($data);
|
$value = current($data);
|
||||||
$relation = key($relations);
|
$relation = key($relations);
|
||||||
|
|
||||||
if (strpos($key, '__') == false) {
|
if (strpos($key, '__') === false) {
|
||||||
$method = 'set' . str_replace('_', '', ucwords($key, '_'));
|
$method = 'set' . str_replace('_', '', ucwords($key, '_'));
|
||||||
|
|
||||||
if (method_exists($model, $method) && isset($value)) {
|
if (method_exists($model, $method) && isset($value)) {
|
||||||
|
|||||||
+19
-1
@@ -15,15 +15,24 @@ class Request implements IRequest
|
|||||||
|
|
||||||
private array $post;
|
private array $post;
|
||||||
|
|
||||||
|
private array $headers;
|
||||||
|
|
||||||
private Session $session;
|
private Session $session;
|
||||||
|
|
||||||
private ?IUser $user = null;
|
private ?IUser $user = null;
|
||||||
|
|
||||||
public function __construct(string $base, array &$get, array &$post, array &$session, IUserRepository $userRepository)
|
public function __construct(
|
||||||
|
string $base,
|
||||||
|
array &$get,
|
||||||
|
array &$post,
|
||||||
|
array $headers,
|
||||||
|
array &$session,
|
||||||
|
IUserRepository $userRepository)
|
||||||
{
|
{
|
||||||
$this->base = $base;
|
$this->base = $base;
|
||||||
$this->get = &$get;
|
$this->get = &$get;
|
||||||
$this->post = &$post;
|
$this->post = &$post;
|
||||||
|
$this->headers = $headers;
|
||||||
$this->session = new Session($session);
|
$this->session = new Session($session);
|
||||||
|
|
||||||
$userId = $this->session->get('userId');
|
$userId = $this->session->get('userId');
|
||||||
@@ -64,6 +73,15 @@ class Request implements IRequest
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function header($key)
|
||||||
|
{
|
||||||
|
if (isset($this->headers[$key])) {
|
||||||
|
return $this->headers[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public function session(): ISession
|
public function session(): ISession
|
||||||
{
|
{
|
||||||
return $this->session;
|
return $this->session;
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php namespace SokoWeb\Response;
|
||||||
|
|
||||||
|
use SokoWeb\Interfaces\Response\IRedirect;
|
||||||
|
use SokoWeb\Interfaces\Response\IContent;
|
||||||
|
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||||
|
use SokoWeb\Interfaces\Authorization\ISecured;
|
||||||
|
use SokoWeb\Interfaces\Request\IRequest;
|
||||||
|
use SokoWeb\Response\Redirect;
|
||||||
|
use SokoWeb\Response\HtmlContent;
|
||||||
|
use SokoWeb\Response\JsonContent;
|
||||||
|
use SokoWeb\Routing\RouteCollection;
|
||||||
|
|
||||||
|
class HttpResponse
|
||||||
|
{
|
||||||
|
private IRequest $request;
|
||||||
|
|
||||||
|
private RouteCollection $routeCollection;
|
||||||
|
|
||||||
|
private array $appConfig;
|
||||||
|
|
||||||
|
private string $method;
|
||||||
|
|
||||||
|
private string $rawUrl;
|
||||||
|
|
||||||
|
private array $parsedUrl;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
IRequest $request,
|
||||||
|
RouteCollection $routeCollection,
|
||||||
|
array $appConfig,
|
||||||
|
string $requestMethod,
|
||||||
|
string $requestUrl
|
||||||
|
) {
|
||||||
|
$this->request = $request;
|
||||||
|
$this->routeCollection = $routeCollection;
|
||||||
|
$this->appConfig = $appConfig;
|
||||||
|
$this->method = strtolower($requestMethod);
|
||||||
|
$this->parsedUrl = parse_url($requestUrl);
|
||||||
|
$this->rawUrl = $requestUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): void
|
||||||
|
{
|
||||||
|
$match = $this->routeCollection->match($this->method, $this->parsedUrl['path']);
|
||||||
|
if ($match === null) {
|
||||||
|
$this->render404();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($route, $params) = $match;
|
||||||
|
$this->request->setParsedRouteParams($params);
|
||||||
|
$handler = $route->getHandler();
|
||||||
|
$controller = new $handler[0]($this->request);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$controller instanceof IAuthenticationRequired &&
|
||||||
|
$controller->isAuthenticationRequired() &&
|
||||||
|
$this->request->user() === null
|
||||||
|
) {
|
||||||
|
$this->redirectToLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$this->method === 'post' &&
|
||||||
|
!in_array($this->parsedUrl['path'], $this->appConfig['antiCsrfTokenExceptions']) &&
|
||||||
|
$this->request->post($this->appConfig['antiCsrfTokenName']) !== $this->request->session()->get($this->appConfig['antiCsrfTokenName'])
|
||||||
|
) {
|
||||||
|
$this->renderAntiCsrfError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($controller instanceof ISecured && !$controller->authorize()) {
|
||||||
|
$this->render404();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = call_user_func([$controller, $handler[1]]);
|
||||||
|
if ($response instanceof IContent) {
|
||||||
|
header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8');
|
||||||
|
$response->render();
|
||||||
|
} elseif ($response instanceof IRedirect) {
|
||||||
|
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
|
||||||
|
} else {
|
||||||
|
$this->render404();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function redirectToLogin(): void
|
||||||
|
{
|
||||||
|
$this->request->session()->set('redirect_after_login', $this->rawUrl);
|
||||||
|
$response = new Redirect($this->routeCollection->getRoute($this->appConfig['loginRouteId'])->generateLink(), IRedirect::TEMPORARY);
|
||||||
|
header('Location: ' . $response->getUrl(), true, $response->getHttpCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderAntiCsrfError(): void
|
||||||
|
{
|
||||||
|
$content = new JsonContent($this->appConfig['antiCsrfTokenErrorResponse']);
|
||||||
|
header('Content-Type: text/html; charset=UTF-8', true, 403);
|
||||||
|
$content->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function render404(): void
|
||||||
|
{
|
||||||
|
$content = new HtmlContent($this->appConfig['error404View']);
|
||||||
|
header('Content-Type: text/html; charset=UTF-8', true, 404);
|
||||||
|
$content->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ class Redirect implements IRedirect
|
|||||||
if (preg_match('/^http(s)?/', $this->target) === 1) {
|
if (preg_match('/^http(s)?/', $this->target) === 1) {
|
||||||
$link = $this->target;
|
$link = $this->target;
|
||||||
} else {
|
} else {
|
||||||
$link = \Container::$request->getBase() . '/' . $this->target;
|
$link = \Container::$request->getBase() . $this->target;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $link;
|
return $link;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class Route
|
|||||||
|
|
||||||
$query = count($queryParams) > 0 ? '?' . http_build_query($queryParams) : '';
|
$query = count($queryParams) > 0 ? '?' . http_build_query($queryParams) : '';
|
||||||
|
|
||||||
return implode('/', $link) . $query;
|
return '/' . implode('/', $link) . $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAgainst(array $path): ?array
|
public function testAgainst(array $path): ?array
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ class RouteCollection
|
|||||||
return $this->routes[$id];
|
return $this->routes[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function match(string $method, array $uri): ?array
|
public function match(string $method, string $uri): ?array
|
||||||
{
|
{
|
||||||
$groupNumber = count($uri);
|
$path = $uri === '/' ? [] : explode('/', ltrim($uri, '/'));
|
||||||
|
$groupNumber = count($path);
|
||||||
|
|
||||||
// response to HEAD request with the GET content
|
// response to HEAD request with the GET content
|
||||||
if ($method === 'head') {
|
if ($method === 'head') {
|
||||||
@@ -55,7 +56,7 @@ class RouteCollection
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->searchTable[$method][$groupNumber] as $route) {
|
foreach ($this->searchTable[$method][$groupNumber] as $route) {
|
||||||
if (($parameters = $route->testAgainst($uri)) !== null) {
|
if (($parameters = $route->testAgainst($path)) !== null) {
|
||||||
return [$route, $parameters];
|
return [$route, $parameters];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user