|
|
@ -17,6 +17,7 @@ use function GuzzleHttp\Psr7\copy_to_stream;
|
|
|
|
use GuzzleHttp\Psr7\Response;
|
|
|
|
use GuzzleHttp\Psr7\Response;
|
|
|
|
use GuzzleHttp\Psr7\ServerRequest;
|
|
|
|
use GuzzleHttp\Psr7\ServerRequest;
|
|
|
|
use function GuzzleHttp\Psr7\stream_for;
|
|
|
|
use function GuzzleHttp\Psr7\stream_for;
|
|
|
|
|
|
|
|
use Psr\Http\Message\RequestInterface;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
|
|
|
|
|
|
|
@ -24,6 +25,10 @@ class Server
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private $routes = [];
|
|
|
|
private $routes = [];
|
|
|
|
private $container;
|
|
|
|
private $container;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @var Dispatcher
|
|
|
|
|
|
|
|
*/
|
|
|
|
private $router;
|
|
|
|
private $router;
|
|
|
|
|
|
|
|
|
|
|
|
public function __construct($routes, Container $container)
|
|
|
|
public function __construct($routes, Container $container)
|
|
|
@ -78,12 +83,29 @@ class Server
|
|
|
|
public function serve()
|
|
|
|
public function serve()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
$request = ServerRequest::fromGlobals();
|
|
|
|
$request = ServerRequest::fromGlobals();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$response = $this->respond($request);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$wrote = [];
|
|
|
|
|
|
|
|
foreach ($response->getHeaders() as [$headerName, $headerValue]) {
|
|
|
|
|
|
|
|
// Only replace header if we didn't write on those yet
|
|
|
|
|
|
|
|
header($headerName . ': ' . $headerValue, !isset($wrote[$headerName]));
|
|
|
|
|
|
|
|
$wrote[$headerName] = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$stdout = fopen('php://output', 'w+');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
copy_to_stream($response->getBody(), stream_for($stdout));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function respond(ServerRequestInterface $request, ResponseInterface $response = null): ResponseInterface
|
|
|
|
|
|
|
|
{
|
|
|
|
$path = $request->getUri()->getPath();
|
|
|
|
$path = $request->getUri()->getPath();
|
|
|
|
$method = $request->getMethod();
|
|
|
|
$method = $request->getMethod();
|
|
|
|
$routeInfo = $this->router->dispatch($method, $path);
|
|
|
|
$routeInfo = $this->router->dispatch($method, $path);
|
|
|
|
|
|
|
|
|
|
|
|
$response = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch ($routeInfo[0]) {
|
|
|
|
switch ($routeInfo[0]) {
|
|
|
|
case Dispatcher::NOT_FOUND:
|
|
|
|
case Dispatcher::NOT_FOUND:
|
|
|
|
// todo: Error page
|
|
|
|
// todo: Error page
|
|
|
@ -93,7 +115,7 @@ class Server
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case Dispatcher::FOUND:
|
|
|
|
case Dispatcher::FOUND:
|
|
|
|
[$_, $handler, $vars] = $routeInfo;
|
|
|
|
[$_, $handler, $vars] = $routeInfo;
|
|
|
|
$response = $this->handleHttp($request, $handler, $vars);
|
|
|
|
$response = $this->handleHttp($request, $handler, $vars, $response);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -101,50 +123,50 @@ class Server
|
|
|
|
// todo: Error page
|
|
|
|
// todo: Error page
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
header('Status: ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
|
|
|
|
return $response;
|
|
|
|
|
|
|
|
|
|
|
|
$wrote = [];
|
|
|
|
|
|
|
|
foreach ($response->getHeaders() as [$headerName, $headerValue]) {
|
|
|
|
|
|
|
|
// Only replace header if we didn't write on those yet
|
|
|
|
|
|
|
|
header($headerName . ': ' . $headerValue, !isset($wrote[$headerName]));
|
|
|
|
|
|
|
|
$wrote[$headerName] = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$stdout = fopen('php://output', 'w+');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
copy_to_stream($response->getBody(), stream_for($stdout));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function handleHttp(ServerRequestInterface $request, array $handler, array $vars): ResponseInterface
|
|
|
|
public function handleHttp(ServerRequestInterface $request, array $handler, array $vars, ResponseInterface $response = null): ResponseInterface
|
|
|
|
{
|
|
|
|
{
|
|
|
|
[$_, $_, $middlewareArray] = $handler;
|
|
|
|
[$_, $_, $middlewareArray] = $handler;
|
|
|
|
|
|
|
|
|
|
|
|
$middlewarePointer = 0;
|
|
|
|
$middlewarePointer = 0;
|
|
|
|
|
|
|
|
|
|
|
|
$next = null;
|
|
|
|
$next = null;
|
|
|
|
$response = new Response(200, [], stream_for('No answer'));
|
|
|
|
|
|
|
|
|
|
|
|
if ($response === null) {
|
|
|
|
|
|
|
|
$response = new Response(200, [], stream_for('No answer'));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$next = function ($request, $response, $vars) use ($handler, $middlewareArray, &$middlewarePointer, &$next) {
|
|
|
|
$next = function ($request, $response, $vars) use ($handler, $middlewareArray, &$middlewarePointer, &$next) {
|
|
|
|
$output = null;
|
|
|
|
$output = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (count($middlewareArray) >= $middlewarePointer) {
|
|
|
|
if (count($middlewareArray) >= $middlewarePointer) {
|
|
|
|
$obj = $this->container->get($handler[0]);
|
|
|
|
$obj = $this->container->get($handler[0]);
|
|
|
|
$output = $obj->{$handler[1]}($request, $response, $vars);
|
|
|
|
$call = [$obj, $handler[1]];
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
[$name, $func] = $middlewareArray[$middlewarePointer++];
|
|
|
|
[$name, $func] = $middlewareArray[$middlewarePointer++];
|
|
|
|
|
|
|
|
|
|
|
|
$middleware = $this->container->get($name);
|
|
|
|
$middleware = $this->container->get($name);
|
|
|
|
$output = $middleware->{$func}($request, $response, $vars);
|
|
|
|
$call = [$middleware, $func];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$output = $this->container->call($call, [
|
|
|
|
|
|
|
|
RequestInterface::class => $request,
|
|
|
|
|
|
|
|
ResponseInterface::class => $response,
|
|
|
|
|
|
|
|
'request' => $request,
|
|
|
|
|
|
|
|
'response' => $response,
|
|
|
|
|
|
|
|
'vars' => $vars,
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $this->normalizeResponse($output, $response);
|
|
|
|
return $this->normalizeResponse($output, $response);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return $next($request, $response, $vars);
|
|
|
|
return $next($request, $response, $vars);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function normalizeResponse($response, ResponseInterface $previousResponse) {
|
|
|
|
private function normalizeResponse($response, ResponseInterface $previousResponse)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ($response instanceof ResponseInterface) {
|
|
|
|
if ($response instanceof ResponseInterface) {
|
|
|
|
return $response;
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
}
|
|
|
|