This commit is contained in:
cutemeli
2025-12-22 10:35:30 +00:00
parent 0bfc6c8425
commit 5ce7ca2c5d
38927 changed files with 0 additions and 4594700 deletions

View File

@@ -1,5 +0,0 @@
parameters:
level: 8
paths:
- src
- tests

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
colors="true"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="PHP-View Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src/</directory>
</include>
</coverage>
</phpunit>

View File

@@ -1,13 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/PHP-View/blob/3.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Views\Exception;
final class PhpTemplateNotFoundException extends \RuntimeException
{
}

View File

@@ -1,194 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/PHP-View/blob/3.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Views;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
use PleskRestApi\Slim\Views\Exception\PhpTemplateNotFoundException;
use Throwable;
class PhpRenderer
{
protected string $templatePath;
/**
* @var array<string, mixed>
*/
protected array $attributes;
protected string $layout;
/**
* @param string $templatePath
* @param array<string, mixed> $attributes
* @param string $layout
*/
public function __construct(string $templatePath = '', array $attributes = [], string $layout = '')
{
$this->templatePath = \rtrim($templatePath, '/\\') . '/';
$this->attributes = $attributes;
$this->setLayout($layout);
}
/**
* @param ResponseInterface $response
* @param string $template
* @param array<string, mixed> $data
*
* @throws Throwable
*
* @return ResponseInterface
*/
public function render(ResponseInterface $response, string $template, array $data = []) : ResponseInterface
{
$output = $this->fetch($template, $data, \true);
$response->getBody()->write($output);
return $response;
}
/**
* @return string
*/
public function getLayout() : string
{
return $this->layout;
}
/**
* @param string $layout
*
* @throws PhpTemplateNotFoundException
*
* @return void
*/
public function setLayout(string $layout) : void
{
if ($layout && !$this->templateExists($layout)) {
throw new PhpTemplateNotFoundException('Layout template "' . $layout . '" does not exist');
}
$this->layout = $layout;
}
/**
* @return array<string, mixed>
*/
public function getAttributes() : array
{
return $this->attributes;
}
/**
* @param array<string, mixed> $attributes
*
* @return void
*/
public function setAttributes(array $attributes) : void
{
$this->attributes = $attributes;
}
/**
* @param string $key
* @param mixed $value
*
* @return void
*/
public function addAttribute(string $key, $value) : void
{
$this->attributes[$key] = $value;
}
/**
* @param string $key
*
* @return bool|mixed
*/
public function getAttribute(string $key)
{
if (!isset($this->attributes[$key])) {
return \false;
}
return $this->attributes[$key];
}
/**
* @return string
*/
public function getTemplatePath() : string
{
return $this->templatePath;
}
/**
* @param string $templatePath
*/
public function setTemplatePath(string $templatePath) : void
{
$this->templatePath = \rtrim($templatePath, '/\\') . '/';
}
/**
* @param string $template
* @param array<string, mixed> $data
* @param bool $useLayout
*
* @throws Throwable
*
* @return string
*/
public function fetch(string $template, array $data = [], bool $useLayout = \false) : string
{
$output = $this->fetchTemplate($template, $data);
if ($this->layout && $useLayout) {
$data['content'] = $output;
$output = $this->fetchTemplate($this->layout, $data);
}
return $output;
}
/**
* @param string $template
* @param array<string, mixed> $data
*
* @throws Throwable
*
* @return string
*/
public function fetchTemplate(string $template, array $data = []) : string
{
if (isset($data['template'])) {
throw new InvalidArgumentException('Duplicate template key found');
}
if (!$this->templateExists($template)) {
throw new PhpTemplateNotFoundException('View cannot render "' . $template . '" because the template does not exist');
}
$data = \array_merge($this->attributes, $data);
try {
\ob_start();
$this->protectedIncludeScope($this->templatePath . $template, $data);
$output = \ob_get_clean();
if ($output === \false) {
throw new RuntimeException('Failed to fetch the template output');
}
} catch (Throwable $e) {
\ob_end_clean();
throw $e;
}
return $output;
}
/**
* Returns true is template exists, false if not
*
* @param string $template
*
* @return bool
*/
public function templateExists(string $template) : bool
{
$path = $this->templatePath . $template;
return \is_file($path) && \is_readable($path);
}
/**
* @param string $template
* @param array<string, mixed> $data
*
* @return void
*/
protected function protectedIncludeScope(string $template, array $data) : void
{
\extract($data);
include \func_get_arg(0);
}
}

View File

@@ -1,174 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use function array_key_exists;
use function array_replace;
use function count;
use function explode;
use function gmdate;
use function in_array;
use function is_array;
use function is_string;
use function preg_split;
use function rtrim;
use function strtolower;
use function strtotime;
use function urldecode;
use function urlencode;
class Cookies
{
/**
* Cookies from HTTP request
*/
protected array $requestCookies = [];
/**
* Cookies for HTTP response
*/
protected array $responseCookies = [];
/**
* Default cookie properties
*/
protected array $defaults = ['value' => '', 'domain' => null, 'hostonly' => null, 'path' => null, 'expires' => null, 'secure' => \false, 'httponly' => \false, 'samesite' => null];
/**
* @param array $cookies
*/
public function __construct(array $cookies = [])
{
$this->requestCookies = $cookies;
}
/**
* Set default cookie properties
*
* @param array $settings
*
* @return static
*/
public function setDefaults(array $settings) : self
{
$this->defaults = array_replace($this->defaults, $settings);
return $this;
}
/**
* Get cookie
*
* @param string $name
* @param string|array|null $default
* @return mixed|null
*/
public function get(string $name, $default = null)
{
return array_key_exists($name, $this->requestCookies) ? $this->requestCookies[$name] : $default;
}
/**
* Set cookie
*
* @param string $name
* @param string|array $value
* @return static
*/
public function set(string $name, $value) : self
{
if (!is_array($value)) {
$value = ['value' => $value];
}
$this->responseCookies[$name] = array_replace($this->defaults, $value);
return $this;
}
/**
* Convert all response cookies into an associate array of header values
*
* @return array
*/
public function toHeaders() : array
{
$headers = [];
foreach ($this->responseCookies as $name => $properties) {
$headers[] = $this->toHeader($name, $properties);
}
return $headers;
}
/**
* Convert to `Set-Cookie` header
*
* @param string $name Cookie name
* @param array $properties Cookie properties
*
* @return string
*/
protected function toHeader(string $name, array $properties) : string
{
$result = urlencode($name) . '=' . urlencode($properties['value']);
if (isset($properties['domain'])) {
$result .= '; domain=' . $properties['domain'];
}
if (isset($properties['path'])) {
$result .= '; path=' . $properties['path'];
}
if (isset($properties['expires'])) {
if (is_string($properties['expires'])) {
$timestamp = strtotime($properties['expires']);
} else {
$timestamp = (int) $properties['expires'];
}
if ($timestamp && $timestamp !== 0) {
$result .= '; expires=' . gmdate('D, d M Y H:i:s', $timestamp) . ' GMT';
}
}
if (isset($properties['secure']) && $properties['secure']) {
$result .= '; secure';
}
if (isset($properties['hostonly']) && $properties['hostonly']) {
$result .= '; HostOnly';
}
if (isset($properties['httponly']) && $properties['httponly']) {
$result .= '; HttpOnly';
}
if (isset($properties['samesite']) && in_array(strtolower($properties['samesite']), ['lax', 'strict', 'none'], \true)) {
// While strtolower is needed for correct comparison, the RFC doesn't care about case
$result .= '; SameSite=' . $properties['samesite'];
}
return $result;
}
/**
* Parse cookie values from header value
*
* Returns an associative array of cookie names and values
*
* @param string|array $header
*
* @return array
*/
public static function parseHeader($header) : array
{
if (is_array($header)) {
$header = $header[0] ?? '';
}
if (!is_string($header)) {
throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.');
}
$header = rtrim($header, "\r\n");
$pieces = preg_split('@[;]\\s*@', $header);
$cookies = [];
if (is_array($pieces)) {
foreach ($pieces as $cookie) {
$cookie = explode('=', $cookie, 2);
if (count($cookie) === 2) {
$key = urldecode($cookie[0]);
$value = urldecode($cookie[1]);
if (!isset($cookies[$key])) {
$cookies[$key] = $value;
}
}
}
}
return $cookies;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use function array_merge;
use function microtime;
use function time;
class Environment
{
/**
* @param array $data Array of custom environment keys and values
*
* @return array
*/
public static function mock(array $data = []) : array
{
if (isset($data['HTTPS']) && $data['HTTPS'] !== 'off' || isset($data['REQUEST_SCHEME']) && $data['REQUEST_SCHEME'] === 'https') {
$scheme = 'https';
$port = 443;
} else {
$scheme = 'http';
$port = 80;
}
return array_merge(['HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', 'HTTP_USER_AGENT' => 'Slim Framework', 'QUERY_STRING' => '', 'REMOTE_ADDR' => '127.0.0.1', 'REQUEST_METHOD' => 'GET', 'REQUEST_SCHEME' => $scheme, 'REQUEST_TIME' => time(), 'REQUEST_TIME_FLOAT' => microtime(\true), 'REQUEST_URI' => '', 'SCRIPT_NAME' => '', 'SERVER_NAME' => 'localhost', 'SERVER_PORT' => $port, 'SERVER_PROTOCOL' => 'HTTP/1.1'], $data);
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use InvalidArgumentException;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
use Psr\Http\Message\UriInterface;
use PleskRestApi\Slim\Psr7\Headers;
use PleskRestApi\Slim\Psr7\Request;
use function is_string;
class RequestFactory implements RequestFactoryInterface
{
protected StreamFactoryInterface $streamFactory;
protected UriFactoryInterface $uriFactory;
/**
* @param StreamFactoryInterface|null $streamFactory
* @param UriFactoryInterface|null $uriFactory
*/
public function __construct(?StreamFactoryInterface $streamFactory = null, ?UriFactoryInterface $uriFactory = null)
{
$this->streamFactory = $streamFactory ?? new StreamFactory();
$this->uriFactory = $uriFactory ?? new UriFactory();
}
/**
* {@inheritdoc}
*/
public function createRequest(string $method, $uri) : RequestInterface
{
if (is_string($uri)) {
$uri = $this->uriFactory->createUri($uri);
}
if (!$uri instanceof UriInterface) {
throw new InvalidArgumentException('Parameter 2 of RequestFactory::createRequest() must be a string or a compatible UriInterface.');
}
$body = $this->streamFactory->createStream();
return new Request($method, $uri, new Headers(), [], [], $body);
}
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use PleskRestApi\Fig\Http\Message\StatusCodeInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use PleskRestApi\Slim\Psr7\Response;
class ResponseFactory implements ResponseFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createResponse(int $code = StatusCodeInterface::STATUS_OK, string $reasonPhrase = '') : ResponseInterface
{
$res = new Response($code);
if ($reasonPhrase !== '') {
$res = $res->withStatus($code, $reasonPhrase);
}
return $res;
}
}

View File

@@ -1,92 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
use Psr\Http\Message\UriInterface;
use PleskRestApi\Slim\Psr7\Cookies;
use PleskRestApi\Slim\Psr7\Headers;
use PleskRestApi\Slim\Psr7\Request;
use PleskRestApi\Slim\Psr7\Stream;
use PleskRestApi\Slim\Psr7\UploadedFile;
use function current;
use function explode;
use function fopen;
use function in_array;
use function is_string;
class ServerRequestFactory implements ServerRequestFactoryInterface
{
protected StreamFactoryInterface $streamFactory;
protected UriFactoryInterface $uriFactory;
/**
* @param StreamFactoryInterface|null $streamFactory
* @param UriFactoryInterface|null $uriFactory
*/
public function __construct(?StreamFactoryInterface $streamFactory = null, ?UriFactoryInterface $uriFactory = null)
{
$this->streamFactory = $streamFactory ?? new StreamFactory();
$this->uriFactory = $uriFactory ?? new UriFactory();
}
/**
* {@inheritdoc}
*/
public function createServerRequest(string $method, $uri, array $serverParams = []) : ServerRequestInterface
{
if (is_string($uri)) {
$uri = $this->uriFactory->createUri($uri);
}
if (!$uri instanceof UriInterface) {
throw new InvalidArgumentException('URI must either be string or instance of ' . UriInterface::class);
}
$body = $this->streamFactory->createStream();
$headers = new Headers();
$cookies = [];
if (!empty($serverParams)) {
$headers = Headers::createFromGlobals();
$cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));
}
return new Request($method, $uri, $headers, $cookies, $serverParams, $body);
}
/**
* Create new ServerRequest from environment.
*
* @internal This method is not part of PSR-17
*
* @return Request
*/
public static function createFromGlobals() : Request
{
/** @var string $method */
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$uri = (new UriFactory())->createFromGlobals($_SERVER);
$headers = Headers::createFromGlobals();
$cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));
// Cache the php://input stream as it cannot be re-read
$cacheResource = fopen('php://temp', 'wb+');
$cache = $cacheResource ? new Stream($cacheResource) : null;
$body = (new StreamFactory())->createStreamFromFile('php://input', 'r', $cache);
$uploadedFiles = UploadedFile::createFromGlobals($_SERVER);
$request = new Request($method, $uri, $headers, $cookies, $_SERVER, $body, $uploadedFiles);
$contentTypes = $request->getHeader('Content-Type');
$parsedContentType = '';
foreach ($contentTypes as $contentType) {
$fragments = explode(';', $contentType);
$parsedContentType = current($fragments);
}
$contentTypesWithParsedBodies = ['application/x-www-form-urlencoded', 'multipart/form-data'];
if ($method === 'POST' && in_array($parsedContentType, $contentTypesWithParsedBodies)) {
return $request->withParsedBody($_POST);
}
return $request;
}
}

View File

@@ -1,70 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use InvalidArgumentException;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use PleskRestApi\Slim\Psr7\Stream;
use ValueError;
use function fopen;
use function fwrite;
use function is_resource;
use function restore_error_handler;
use function rewind;
use function set_error_handler;
class StreamFactory implements StreamFactoryInterface
{
/**
* {@inheritdoc}
*
* @throws RuntimeException
*/
public function createStream(string $content = '') : StreamInterface
{
$resource = fopen('php://temp', 'rw+');
if (!is_resource($resource)) {
throw new RuntimeException('StreamFactory::createStream() could not open temporary file stream.');
}
fwrite($resource, $content);
rewind($resource);
return $this->createStreamFromResource($resource);
}
/**
* {@inheritdoc}
*/
public function createStreamFromFile(string $filename, string $mode = 'r', ?StreamInterface $cache = null) : StreamInterface
{
set_error_handler(static function (int $errno, string $errstr) use($filename, $mode) : void {
throw new RuntimeException("Unable to open {$filename} using mode {$mode}: {$errstr}", $errno);
});
try {
$resource = fopen($filename, $mode);
} catch (ValueError $exception) {
throw new RuntimeException("Unable to open {$filename} using mode {$mode}: " . $exception->getMessage());
} finally {
restore_error_handler();
}
if (!is_resource($resource)) {
throw new RuntimeException("StreamFactory::createStreamFromFile() could not create resource from file `{$filename}`");
}
return new Stream($resource, $cache);
}
/**
* {@inheritdoc}
*/
public function createStreamFromResource($resource, ?StreamInterface $cache = null) : StreamInterface
{
if (!is_resource($resource)) {
throw new InvalidArgumentException('Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.');
}
return new Stream($resource, $cache);
}
}

View File

@@ -1,34 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Psr\Http\Message\UploadedFileInterface;
use PleskRestApi\Slim\Psr7\UploadedFile;
use function is_string;
use const UPLOAD_ERR_OK;
class UploadedFileFactory implements UploadedFileFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createUploadedFile(StreamInterface $stream, ?int $size = null, int $error = UPLOAD_ERR_OK, ?string $clientFilename = null, ?string $clientMediaType = null) : UploadedFileInterface
{
$file = $stream->getMetadata('uri');
if (!is_string($file) || !$stream->isReadable()) {
throw new InvalidArgumentException('File is not readable.');
}
if ($size === null) {
$size = $stream->getSize();
}
return new UploadedFile($stream, $clientFilename, $clientMediaType, $size, $error);
}
}

View File

@@ -1,96 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Factory;
use InvalidArgumentException;
use Psr\Http\Message\UriFactoryInterface;
use Psr\Http\Message\UriInterface;
use PleskRestApi\Slim\Psr7\Uri;
use function count;
use function explode;
use function parse_url;
use function preg_match;
use function strpos;
use function strstr;
use function substr;
use const PHP_URL_QUERY;
class UriFactory implements UriFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createUri(string $uri = '') : UriInterface
{
$parts = parse_url($uri);
if ($parts === \false) {
throw new InvalidArgumentException('URI cannot be parsed');
}
$scheme = $parts['scheme'] ?? '';
$user = $parts['user'] ?? '';
$pass = $parts['pass'] ?? '';
$host = $parts['host'] ?? '';
$port = $parts['port'] ?? null;
$path = $parts['path'] ?? '';
$query = $parts['query'] ?? '';
$fragment = $parts['fragment'] ?? '';
return new Uri($scheme, $host, $port, $path, $query, $fragment, $user, $pass);
}
/**
* Create new Uri from environment.
*
* @internal This method is not part of PSR-17
*
* @param array $globals The global server variables.
*
* @return Uri
*/
public function createFromGlobals(array $globals) : Uri
{
// Scheme
$https = $globals['HTTPS'] ?? \false;
$scheme = !$https || $https === 'off' ? 'http' : 'https';
// Authority: Username and password
$username = $globals['PHP_AUTH_USER'] ?? '';
$password = $globals['PHP_AUTH_PW'] ?? '';
// Authority: Host
$host = '';
if (isset($globals['HTTP_HOST'])) {
$host = $globals['HTTP_HOST'];
} elseif (isset($globals['SERVER_NAME'])) {
$host = $globals['SERVER_NAME'];
}
// Authority: Port
$port = !empty($globals['SERVER_PORT']) ? (int) $globals['SERVER_PORT'] : ($scheme === 'https' ? 443 : 80);
if (preg_match('/^(\\[[a-fA-F0-9:.]+])(:\\d+)?\\z/', $host, $matches)) {
$host = $matches[1];
if (isset($matches[2])) {
$port = (int) substr($matches[2], 1);
}
} else {
$pos = strpos($host, ':');
if ($pos !== \false) {
$port = (int) substr($host, $pos + 1);
$host = strstr($host, ':', \true);
}
}
// Query string
$queryString = $globals['QUERY_STRING'] ?? '';
// Request URI
$requestUri = '';
if (isset($globals['REQUEST_URI'])) {
$uriFragments = explode('?', $globals['REQUEST_URI']);
$requestUri = $uriFragments[0];
if ($queryString === '' && count($uriFragments) > 1) {
$queryString = parse_url('https://www.example.com' . $globals['REQUEST_URI'], PHP_URL_QUERY) ?? '';
}
}
// Build Uri and return
return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password);
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use function array_merge;
use function is_string;
class Header
{
private string $originalName;
private string $normalizedName;
private array $values;
public function __construct(string $originalName, string $normalizedName, array $values)
{
$this->originalName = $originalName;
$this->normalizedName = $normalizedName;
$this->values = $values;
}
public function getOriginalName() : string
{
return $this->originalName;
}
public function getNormalizedName() : string
{
return $this->normalizedName;
}
public function addValue(string $value) : self
{
$this->values[] = $value;
return $this;
}
public function addValues(array|string $values) : self
{
if (is_string($values)) {
return $this->addValue($values);
}
$this->values = array_merge($this->values, $values);
return $this;
}
public function getValues() : array
{
return $this->values;
}
}

View File

@@ -1,271 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use PleskRestApi\Slim\Psr7\Interfaces\HeadersInterface;
use function base64_encode;
use function function_exists;
use function getallheaders;
use function is_array;
use function is_numeric;
use function is_string;
use function preg_match;
use function strpos;
use function strtolower;
use function strtr;
use function substr;
use function trim;
class Headers implements HeadersInterface
{
protected array $globals;
/**
* @var Header[]
*/
protected array $headers;
/**
* @param array $headers
* @param array|null $globals
*/
public final function __construct(array $headers = [], ?array $globals = null)
{
$this->globals = $globals ?? $_SERVER;
$this->setHeaders($headers);
}
/**
* {@inheritdoc}
*/
public function addHeader($name, $value) : HeadersInterface
{
[$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);
if (isset($this->headers[$normalizedName])) {
$header = $this->headers[$normalizedName];
$header->addValues($values);
} else {
$this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function removeHeader(string $name) : HeadersInterface
{
$name = $this->normalizeHeaderName($name);
unset($this->headers[$name]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getHeader(string $name, $default = []) : array
{
$name = $this->normalizeHeaderName($name);
if (isset($this->headers[$name])) {
$header = $this->headers[$name];
return $header->getValues();
}
if (empty($default)) {
return $default;
}
$this->validateHeader($name, $default);
return $this->trimHeaderValue($default);
}
/**
* {@inheritdoc}
*/
public function setHeader($name, $value) : HeadersInterface
{
[$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);
// Ensure we preserve original case if the header already exists in the stack
if (isset($this->headers[$normalizedName])) {
$existingHeader = $this->headers[$normalizedName];
$originalName = $existingHeader->getOriginalName();
}
$this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);
return $this;
}
/**
* {@inheritdoc}
*/
public function setHeaders(array $headers) : HeadersInterface
{
$this->headers = [];
foreach ($this->parseAuthorizationHeader($headers) as $name => $value) {
$this->addHeader($name, $value);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function hasHeader(string $name) : bool
{
$name = $this->normalizeHeaderName($name);
return isset($this->headers[$name]);
}
/**
* {@inheritdoc}
*/
public function getHeaders(bool $originalCase = \false) : array
{
$headers = [];
foreach ($this->headers as $header) {
$name = $originalCase ? $header->getOriginalName() : $header->getNormalizedName();
$headers[$name] = $header->getValues();
}
return $headers;
}
/**
* @param string $name
* @param bool $preserveCase
* @return string
*/
protected function normalizeHeaderName(string $name, bool $preserveCase = \false) : string
{
$name = strtr($name, '_', '-');
if (!$preserveCase) {
$name = strtolower($name);
}
if (strpos(strtolower($name), 'http-') === 0) {
$name = substr($name, 5);
}
return $name;
}
/**
* Parse incoming headers and determine Authorization header from original headers
*
* @param array $headers
* @return array
*/
protected function parseAuthorizationHeader(array $headers) : array
{
$hasAuthorizationHeader = \false;
foreach ($headers as $name => $value) {
if (strtolower((string) $name) === 'authorization') {
$hasAuthorizationHeader = \true;
break;
}
}
if (!$hasAuthorizationHeader) {
if (isset($this->globals['REDIRECT_HTTP_AUTHORIZATION'])) {
$headers['Authorization'] = $this->globals['REDIRECT_HTTP_AUTHORIZATION'];
} elseif (isset($this->globals['PHP_AUTH_USER'])) {
$pw = $this->globals['PHP_AUTH_PW'] ?? '';
$headers['Authorization'] = 'Basic ' . base64_encode($this->globals['PHP_AUTH_USER'] . ':' . $pw);
} elseif (isset($this->globals['PHP_AUTH_DIGEST'])) {
$headers['Authorization'] = $this->globals['PHP_AUTH_DIGEST'];
}
}
return $headers;
}
/**
* @param array|string $value
*
* @return array
*/
protected function trimHeaderValue($value) : array
{
$items = is_array($value) ? $value : [$value];
$result = [];
foreach ($items as $item) {
$result[] = trim((string) $item, " \t");
}
return $result;
}
/**
* @param string $name
* @param array|string $value
*
* @throws InvalidArgumentException
*
* @return array
*/
protected function prepareHeader($name, $value) : array
{
$this->validateHeader($name, $value);
$values = $this->trimHeaderValue($value);
$originalName = $this->normalizeHeaderName($name, \true);
$normalizedName = $this->normalizeHeaderName($name);
return [$values, $originalName, $normalizedName];
}
/**
* Make sure the header complies with RFC 7230.
*
* Header names must be a non-empty string consisting of token characters.
*
* Header values must be strings consisting of visible characters with all optional
* leading and trailing whitespace stripped. This method will always strip such
* optional whitespace. Note that the method does not allow folding whitespace within
* the values as this was deprecated for almost all instances by the RFC.
*
* header-field = field-name ":" OWS field-value OWS
* field-name = 1*( "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^"
* / "_" / "`" / "|" / "~" / %x30-39 / ( %x41-5A / %x61-7A ) )
* OWS = *( SP / HTAB )
* field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] )
*
* @see https://tools.ietf.org/html/rfc7230#section-3.2.4
*
* @param string $name
* @param array|string $value
*
* @throws InvalidArgumentException
*/
protected function validateHeader($name, $value) : void
{
$this->validateHeaderName($name);
$this->validateHeaderValue($value);
}
/**
* @param mixed $name
*
* @throws InvalidArgumentException
*/
protected function validateHeaderName($name) : void
{
if (!is_string($name) || preg_match("@^[!#\$%&'*+.^_`|~0-9A-Za-z-]+\$@D", $name) !== 1) {
throw new InvalidArgumentException('Header name must be an RFC 7230 compatible string.');
}
}
/**
* @param mixed $value
*
* @throws InvalidArgumentException
*/
protected function validateHeaderValue($value) : void
{
$items = is_array($value) ? $value : [$value];
if (empty($items)) {
throw new InvalidArgumentException('Header values must be a string or an array of strings, empty array given.');
}
$pattern = "@^[ \t!-~\x80-\xff]*\$@D";
foreach ($items as $item) {
$hasInvalidType = !is_numeric($item) && !is_string($item);
$rejected = $hasInvalidType || preg_match($pattern, (string) $item) !== 1;
if ($rejected) {
throw new InvalidArgumentException('Header values must be RFC 7230 compatible strings.');
}
}
}
/**
* @return static
*/
public static function createFromGlobals()
{
$headers = null;
if (function_exists('getallheaders')) {
$headers = getallheaders();
}
if (!is_array($headers)) {
$headers = [];
}
return new static($headers);
}
}

View File

@@ -1,81 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7\Interfaces;
use InvalidArgumentException;
interface HeadersInterface
{
/**
* Add header value
*
* This method appends the value to the existing array of values
*
* @param string $name
* @param array|string $value
*
* @return HeadersInterface
*
* @throws InvalidArgumentException
*/
public function addHeader($name, $value) : HeadersInterface;
/**
* Remove header value
*
* @param string $name
* @return HeadersInterface
*/
public function removeHeader(string $name) : HeadersInterface;
/**
* Get header value or values.
* If the array has a single value it will return that single value.
* If the array has multiple values, it will return an array of values.
*
* @param string $name
* @param string[] $default
*
* @return array
*/
public function getHeader(string $name, $default = []) : array;
/**
* Replaces the existing header value with the new value.
*
* @param string $name
* @param array|string $value
*
* @return HeadersInterface
*
* @throws InvalidArgumentException
*/
public function setHeader($name, $value) : HeadersInterface;
/**
* Replaces all existing headers with the new values.
*
* @param array $headers
*
* @return HeadersInterface
*
* @throws InvalidArgumentException
*/
public function setHeaders(array $headers) : HeadersInterface;
/**
* Is the header present in the stack.
*
* @param string $name
* @return bool
*/
public function hasHeader(string $name) : bool;
/**
* Return all headers in the stack.
*
* @param bool $originalCase
*
* @return array
*/
public function getHeaders(bool $originalCase) : array;
}

View File

@@ -1,149 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;
use PleskRestApi\Slim\Psr7\Interfaces\HeadersInterface;
use function array_keys;
use function header;
use function header_remove;
use function implode;
use function sprintf;
abstract class Message implements MessageInterface
{
protected string $protocolVersion = '1.1';
protected static array $validProtocolVersions = ['1.0' => \true, '1.1' => \true, '2.0' => \true, '2' => \true];
/**
* @var HeadersInterface
*/
protected $headers;
/**
* @var StreamInterface
*/
protected $body;
/**
* Disable magic setter to ensure immutability
*
* @param string $name The property name
* @param mixed $value The property value
*
* @return void
*/
public function __set($name, $value) : void
{
// Do nothing
}
/**
* {@inheritdoc}
*/
public function getProtocolVersion() : string
{
return $this->protocolVersion;
}
/**
* @return static
* {@inheritdoc}
*/
public function withProtocolVersion($version) : MessageInterface
{
if (!isset(self::$validProtocolVersions[$version])) {
throw new InvalidArgumentException('Invalid HTTP version. Must be one of: ' . implode(', ', array_keys(self::$validProtocolVersions)));
}
$clone = clone $this;
$clone->protocolVersion = $version;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getHeaders() : array
{
return $this->headers->getHeaders(\true);
}
/**
* {@inheritdoc}
*/
public function hasHeader($name) : bool
{
return $this->headers->hasHeader($name);
}
/**
* {@inheritdoc}
*/
public function getHeader($name) : array
{
return $this->headers->getHeader($name);
}
/**
* {@inheritdoc}
*/
public function getHeaderLine($name) : string
{
$values = $this->headers->getHeader($name);
return implode(',', $values);
}
/**
* @return static
* {@inheritdoc}
*/
public function withHeader($name, $value) : MessageInterface
{
$clone = clone $this;
$clone->headers->setHeader($name, $value);
if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));
}
return $clone;
}
/**
* @return static
* {@inheritdoc}
*/
public function withAddedHeader($name, $value) : MessageInterface
{
$clone = clone $this;
$clone->headers->addHeader($name, $value);
if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));
}
return $clone;
}
/**
* @return static
* {@inheritdoc}
*/
public function withoutHeader($name) : MessageInterface
{
$clone = clone $this;
$clone->headers->removeHeader($name);
if ($this instanceof Response && $this->body instanceof NonBufferedBody) {
header_remove($name);
}
return $clone;
}
/**
* {@inheritdoc}
*/
public function getBody() : StreamInterface
{
return $this->body;
}
/**
* @return static
* {@inheritdoc}
*/
public function withBody(StreamInterface $body) : MessageInterface
{
$clone = clone $this;
$clone->body = $body;
return $clone;
}
}

View File

@@ -1,131 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use function flush;
use function ob_get_clean;
use function ob_get_level;
use function strlen;
use const SEEK_SET;
class NonBufferedBody implements StreamInterface
{
/**
* {@inheritdoc}
*/
public function __toString() : string
{
return '';
}
/**
* {@inheritdoc}
*/
public function close() : void
{
throw new RuntimeException('A NonBufferedBody is not closable.');
}
/**
* {@inheritdoc}
*/
public function detach()
{
return null;
}
/**
* {@inheritdoc}
*/
public function getSize() : ?int
{
return null;
}
/**
* {@inheritdoc}
*/
public function tell() : int
{
return 0;
}
/**
* {@inheritdoc}
*/
public function eof() : bool
{
return \true;
}
/**
* {@inheritdoc}
*/
public function isSeekable() : bool
{
return \false;
}
/**
* {@inheritdoc}
*/
public function seek($offset, $whence = SEEK_SET) : void
{
throw new RuntimeException('A NonBufferedBody is not seekable.');
}
/**
* {@inheritdoc}
*/
public function rewind() : void
{
throw new RuntimeException('A NonBufferedBody is not rewindable.');
}
/**
* {@inheritdoc}
*/
public function isWritable() : bool
{
return \true;
}
/**
* {@inheritdoc}
*/
public function write($string) : int
{
$buffered = '';
while (0 < ob_get_level()) {
$buffered = ob_get_clean() . $buffered;
}
echo $buffered . $string;
flush();
return strlen($string) + strlen($buffered);
}
/**
* {@inheritdoc}
*/
public function isReadable() : bool
{
return \false;
}
/**
* {@inheritdoc}
*/
public function read($length) : string
{
throw new RuntimeException('A NonBufferedBody is not readable.');
}
/**
* {@inheritdoc}
*/
public function getContents() : string
{
return '';
}
/**
* {@inheritdoc}
*/
public function getMetadata($key = null) : ?array
{
return null;
}
}

View File

@@ -1,308 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
use PleskRestApi\Slim\Psr7\Interfaces\HeadersInterface;
use function get_class;
use function gettype;
use function is_array;
use function is_null;
use function is_object;
use function is_string;
use function ltrim;
use function parse_str;
use function preg_match;
use function sprintf;
use function str_replace;
class Request extends Message implements ServerRequestInterface
{
protected string $method;
/**
* @var UriInterface
*/
protected $uri;
/**
* @var string
*/
protected $requestTarget;
/**
* @var ?array
*/
protected $queryParams;
protected array $cookies;
protected array $serverParams;
protected array $attributes;
/**
* @var null|array|object
*/
protected $parsedBody;
/**
* @var UploadedFileInterface[]
*/
protected array $uploadedFiles;
/**
* @param string $method The request method
* @param UriInterface $uri The request URI object
* @param HeadersInterface $headers The request headers collection
* @param array $cookies The request cookies collection
* @param array $serverParams The server environment variables
* @param StreamInterface $body The request body object
* @param array $uploadedFiles The request uploadedFiles collection
* @throws InvalidArgumentException on invalid HTTP method
*/
public function __construct($method, UriInterface $uri, HeadersInterface $headers, array $cookies, array $serverParams, StreamInterface $body, array $uploadedFiles = [])
{
$this->method = $this->filterMethod($method);
$this->uri = $uri;
$this->headers = $headers;
$this->cookies = $cookies;
$this->serverParams = $serverParams;
$this->attributes = [];
$this->body = $body;
$this->uploadedFiles = $uploadedFiles;
if (isset($serverParams['SERVER_PROTOCOL'])) {
$this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']);
}
if (!$this->headers->hasHeader('Host') || $this->uri->getHost() !== '') {
$this->headers->setHeader('Host', $this->uri->getHost());
}
}
/**
* This method is applied to the cloned object after PHP performs an initial shallow-copy.
* This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.
*/
public function __clone()
{
$this->headers = clone $this->headers;
$this->body = clone $this->body;
}
/**
* {@inheritdoc}
*/
public function getMethod() : string
{
return $this->method;
}
/**
* {@inheritdoc}
* @return static
*/
public function withMethod($method) : RequestInterface
{
$method = $this->filterMethod($method);
$clone = clone $this;
$clone->method = $method;
return $clone;
}
/**
* Validate the HTTP method
*
* @param string $method
*
* @return string
*
* @throws InvalidArgumentException on invalid HTTP method.
*/
protected function filterMethod($method) : string
{
/** @var mixed $method */
if (!is_string($method)) {
throw new InvalidArgumentException(sprintf('Unsupported HTTP method; must be a string, received %s', is_object($method) ? get_class($method) : gettype($method)));
}
if (preg_match("/^[!#\$%&'*+.^_`|~0-9a-z-]+\$/i", $method) !== 1) {
throw new InvalidArgumentException(sprintf('Unsupported HTTP method "%s" provided', $method));
}
return $method;
}
/**
* {@inheritdoc}
*/
public function getRequestTarget() : string
{
if ($this->requestTarget) {
return $this->requestTarget;
}
if ($this->uri === null) {
return '/';
}
$path = $this->uri->getPath();
$path = '/' . ltrim($path, '/');
$query = $this->uri->getQuery();
if ($query) {
$path .= '?' . $query;
}
return $path;
}
/**
* {@inheritdoc}
* @return static
*/
public function withRequestTarget($requestTarget) : RequestInterface
{
if (!is_string($requestTarget) || preg_match('#\\s#', $requestTarget)) {
throw new InvalidArgumentException('Invalid request target provided; must be a string and cannot contain whitespace');
}
$clone = clone $this;
$clone->requestTarget = $requestTarget;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getUri() : UriInterface
{
return $this->uri;
}
/**
* {@inheritdoc}
* @return static
*/
public function withUri(UriInterface $uri, $preserveHost = \false) : RequestInterface
{
$clone = clone $this;
$clone->uri = $uri;
if (!$preserveHost && $uri->getHost() !== '') {
$clone->headers->setHeader('Host', $uri->getHost());
return $clone;
}
if ($uri->getHost() !== '' && !$this->hasHeader('Host') || $this->getHeaderLine('Host') === '') {
$clone->headers->setHeader('Host', $uri->getHost());
return $clone;
}
return $clone;
}
/**
* {@inheritdoc}
*/
public function getCookieParams() : array
{
return $this->cookies;
}
/**
* {@inheritdoc}
* @return static
*/
public function withCookieParams(array $cookies) : ServerRequestInterface
{
$clone = clone $this;
$clone->cookies = $cookies;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getQueryParams() : array
{
if (is_array($this->queryParams)) {
return $this->queryParams;
}
if ($this->uri === null) {
return [];
}
// Decode URL data
parse_str($this->uri->getQuery(), $this->queryParams);
return is_array($this->queryParams) ? $this->queryParams : [];
}
/**
* {@inheritdoc}
* @return static
*/
public function withQueryParams(array $query) : ServerRequestInterface
{
$clone = clone $this;
$clone->queryParams = $query;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getUploadedFiles() : array
{
return $this->uploadedFiles;
}
/**
* {@inheritdoc}
* @return static
*/
public function withUploadedFiles(array $uploadedFiles) : ServerRequestInterface
{
$clone = clone $this;
$clone->uploadedFiles = $uploadedFiles;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getServerParams() : array
{
return $this->serverParams;
}
/**
* {@inheritdoc}
*/
public function getAttributes() : array
{
return $this->attributes;
}
/**
* {@inheritdoc}
* @return mixed
*/
public function getAttribute($name, $default = null)
{
return $this->attributes[$name] ?? $default;
}
/**
* {@inheritdoc}
* @return static
*/
public function withAttribute($name, $value) : ServerRequestInterface
{
$clone = clone $this;
$clone->attributes[$name] = $value;
return $clone;
}
/**
* {@inheritdoc}
* @return static
*/
public function withoutAttribute($name) : ServerRequestInterface
{
$clone = clone $this;
unset($clone->attributes[$name]);
return $clone;
}
/**
* {@inheritdoc}
*/
public function getParsedBody()
{
return $this->parsedBody;
}
/**
* {@inheritdoc}
* @return static
*/
public function withParsedBody($data) : ServerRequestInterface
{
/** @var mixed $data */
if (!is_null($data) && !is_object($data) && !is_array($data)) {
throw new InvalidArgumentException('Parsed body value must be an array, an object, or null');
}
$clone = clone $this;
$clone->parsedBody = $data;
return $clone;
}
}

View File

@@ -1,186 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use PleskRestApi\Fig\Http\Message\StatusCodeInterface;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use PleskRestApi\Slim\Psr7\Factory\StreamFactory;
use PleskRestApi\Slim\Psr7\Interfaces\HeadersInterface;
use function is_integer;
use function is_object;
use function is_string;
use function method_exists;
class Response extends Message implements ResponseInterface
{
protected int $status = StatusCodeInterface::STATUS_OK;
protected string $reasonPhrase = '';
protected static array $messages = [
// Informational 1xx
StatusCodeInterface::STATUS_CONTINUE => 'Continue',
StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols',
StatusCodeInterface::STATUS_PROCESSING => 'Processing',
// Successful 2xx
StatusCodeInterface::STATUS_OK => 'OK',
StatusCodeInterface::STATUS_CREATED => 'Created',
StatusCodeInterface::STATUS_ACCEPTED => 'Accepted',
StatusCodeInterface::STATUS_NON_AUTHORITATIVE_INFORMATION => 'Non-Authoritative Information',
StatusCodeInterface::STATUS_NO_CONTENT => 'No Content',
StatusCodeInterface::STATUS_RESET_CONTENT => 'Reset Content',
StatusCodeInterface::STATUS_PARTIAL_CONTENT => 'Partial Content',
StatusCodeInterface::STATUS_MULTI_STATUS => 'Multi-Status',
StatusCodeInterface::STATUS_ALREADY_REPORTED => 'Already Reported',
StatusCodeInterface::STATUS_IM_USED => 'IM Used',
// Redirection 3xx
StatusCodeInterface::STATUS_MULTIPLE_CHOICES => 'Multiple Choices',
StatusCodeInterface::STATUS_MOVED_PERMANENTLY => 'Moved Permanently',
StatusCodeInterface::STATUS_FOUND => 'Found',
StatusCodeInterface::STATUS_SEE_OTHER => 'See Other',
StatusCodeInterface::STATUS_NOT_MODIFIED => 'Not Modified',
StatusCodeInterface::STATUS_USE_PROXY => 'Use Proxy',
StatusCodeInterface::STATUS_RESERVED => '(Unused)',
StatusCodeInterface::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect',
StatusCodeInterface::STATUS_PERMANENT_REDIRECT => 'Permanent Redirect',
// Client Error 4xx
StatusCodeInterface::STATUS_BAD_REQUEST => 'Bad Request',
StatusCodeInterface::STATUS_UNAUTHORIZED => 'Unauthorized',
StatusCodeInterface::STATUS_PAYMENT_REQUIRED => 'Payment Required',
StatusCodeInterface::STATUS_FORBIDDEN => 'Forbidden',
StatusCodeInterface::STATUS_NOT_FOUND => 'Not Found',
StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed',
StatusCodeInterface::STATUS_NOT_ACCEPTABLE => 'Not Acceptable',
StatusCodeInterface::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required',
StatusCodeInterface::STATUS_REQUEST_TIMEOUT => 'Request Timeout',
StatusCodeInterface::STATUS_CONFLICT => 'Conflict',
StatusCodeInterface::STATUS_GONE => 'Gone',
StatusCodeInterface::STATUS_LENGTH_REQUIRED => 'Length Required',
StatusCodeInterface::STATUS_PRECONDITION_FAILED => 'Precondition Failed',
StatusCodeInterface::STATUS_PAYLOAD_TOO_LARGE => 'Request Entity Too Large',
StatusCodeInterface::STATUS_URI_TOO_LONG => 'Request-URI Too Long',
StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',
StatusCodeInterface::STATUS_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',
StatusCodeInterface::STATUS_EXPECTATION_FAILED => 'Expectation Failed',
StatusCodeInterface::STATUS_IM_A_TEAPOT => 'I\'m a teapot',
StatusCodeInterface::STATUS_MISDIRECTED_REQUEST => 'Misdirected Request',
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity',
StatusCodeInterface::STATUS_LOCKED => 'Locked',
StatusCodeInterface::STATUS_FAILED_DEPENDENCY => 'Failed Dependency',
StatusCodeInterface::STATUS_UPGRADE_REQUIRED => 'Upgrade Required',
StatusCodeInterface::STATUS_PRECONDITION_REQUIRED => 'Precondition Required',
StatusCodeInterface::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests',
StatusCodeInterface::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large',
444 => 'Connection Closed Without Response',
StatusCodeInterface::STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons',
499 => 'Client Closed Request',
// Server Error 5xx
StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error',
StatusCodeInterface::STATUS_NOT_IMPLEMENTED => 'Not Implemented',
StatusCodeInterface::STATUS_BAD_GATEWAY => 'Bad Gateway',
StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable',
StatusCodeInterface::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout',
StatusCodeInterface::STATUS_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported',
StatusCodeInterface::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',
StatusCodeInterface::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage',
StatusCodeInterface::STATUS_LOOP_DETECTED => 'Loop Detected',
StatusCodeInterface::STATUS_NOT_EXTENDED => 'Not Extended',
StatusCodeInterface::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required',
599 => 'Network Connect Timeout Error',
];
/**
* @param int $status The response status code.
* @param HeadersInterface|null $headers The response headers.
* @param StreamInterface|null $body The response body.
*/
public function __construct(int $status = StatusCodeInterface::STATUS_OK, ?HeadersInterface $headers = null, ?StreamInterface $body = null)
{
$this->status = $this->filterStatus($status);
$this->headers = $headers ?: new Headers([], []);
$this->body = $body ?: (new StreamFactory())->createStream();
}
/**
* This method is applied to the cloned object after PHP performs an initial shallow-copy.
* This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.
*/
public function __clone()
{
$this->headers = clone $this->headers;
}
/**
* {@inheritdoc}
*/
public function getStatusCode() : int
{
return $this->status;
}
/**
* {@inheritdoc}
* @return static
*/
public function withStatus($code, $reasonPhrase = '') : ResponseInterface
{
$code = $this->filterStatus($code);
$reasonPhrase = $this->filterReasonPhrase($reasonPhrase);
$clone = clone $this;
$clone->status = $code;
$clone->reasonPhrase = $reasonPhrase;
return $clone;
}
/**
* {@inheritdoc}
*/
public function getReasonPhrase() : string
{
if ($this->reasonPhrase !== '') {
return $this->reasonPhrase;
}
if (isset(static::$messages[$this->status])) {
return static::$messages[$this->status];
}
return '';
}
/**
* Filter HTTP status code.
*
* @param int $status HTTP status code.
*
* @return int
*
* @throws InvalidArgumentException If an invalid HTTP status code is provided.
*/
protected function filterStatus($status) : int
{
if (!is_integer($status) || $status < StatusCodeInterface::STATUS_CONTINUE || $status > 599) {
throw new InvalidArgumentException('Invalid HTTP status code.');
}
return $status;
}
/**
* Filter Reason Phrase
*
* @param mixed $reasonPhrase
*
* @return string
*
* @throws InvalidArgumentException
*/
protected function filterReasonPhrase($reasonPhrase = '') : string
{
if (is_object($reasonPhrase) && method_exists($reasonPhrase, '__toString')) {
$reasonPhrase = (string) $reasonPhrase;
}
if (!is_string($reasonPhrase)) {
throw new InvalidArgumentException('Response reason phrase must be a string.');
}
if (\strpos($reasonPhrase, "\r") !== \false || \strpos($reasonPhrase, "\n") !== \false) {
throw new InvalidArgumentException('Reason phrase contains one of the following prohibited characters: \\r \\n');
}
return $reasonPhrase;
}
}

View File

@@ -1,328 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use function fclose;
use function feof;
use function fread;
use function fseek;
use function fstat;
use function ftell;
use function fwrite;
use function is_array;
use function is_resource;
use function is_string;
use function pclose;
use function rewind;
use function stream_get_contents;
use function stream_get_meta_data;
use function strstr;
use const SEEK_SET;
class Stream implements StreamInterface
{
/**
* Bit mask to determine if the stream is a pipe
*
* This is octal as per header stat.h
*/
public const FSTAT_MODE_S_IFIFO = 010000;
/**
* The underlying stream resource
*
* @var resource|null
*/
protected $stream;
protected ?array $meta;
protected ?bool $readable = null;
protected ?bool $writable = null;
protected ?bool $seekable = null;
protected ?int $size = null;
protected ?bool $isPipe = null;
protected bool $finished = \false;
protected ?StreamInterface $cache;
/**
* @param resource $stream A PHP resource handle.
* @param StreamInterface|null $cache A stream to cache $stream (useful for non-seekable streams)
*
* @throws InvalidArgumentException If argument is not a resource.
*/
public function __construct($stream, ?StreamInterface $cache = null)
{
$this->attach($stream);
if ($cache && (!$cache->isSeekable() || !$cache->isWritable())) {
throw new RuntimeException('Cache stream must be seekable and writable');
}
$this->cache = $cache;
}
/**
* {@inheritdoc}
* @return array|mixed
*/
public function getMetadata($key = null)
{
if (!$this->stream) {
return null;
}
$this->meta = stream_get_meta_data($this->stream);
if (!$key) {
return $this->meta;
}
return $this->meta[$key] ?? null;
}
/**
* Attach new resource to this object.
*
* @internal This method is not part of the PSR-7 standard.
*
* @param resource $stream A PHP resource handle.
*
* @throws InvalidArgumentException If argument is not a valid PHP resource.
*
* @return void
*/
protected function attach($stream) : void
{
if (!is_resource($stream)) {
throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');
}
if ($this->stream) {
$this->detach();
}
$this->stream = $stream;
}
/**
* {@inheritdoc}
*/
public function detach()
{
$oldResource = $this->stream;
$this->stream = null;
$this->meta = null;
$this->readable = null;
$this->writable = null;
$this->seekable = null;
$this->size = null;
$this->isPipe = null;
$this->cache = null;
$this->finished = \false;
return $oldResource;
}
/**
* {@inheritdoc}
*/
public function __toString() : string
{
if (!$this->stream) {
return '';
}
if ($this->cache && $this->finished) {
$this->cache->rewind();
return $this->cache->getContents();
}
if ($this->isSeekable()) {
$this->rewind();
}
return $this->getContents();
}
/**
* {@inheritdoc}
*/
public function close() : void
{
if ($this->stream) {
if ($this->isPipe()) {
pclose($this->stream);
} else {
fclose($this->stream);
}
}
$this->detach();
}
/**
* {@inheritdoc}
*/
public function getSize() : ?int
{
if ($this->stream && !$this->size) {
$stats = fstat($this->stream);
if ($stats) {
$this->size = !$this->isPipe() ? $stats['size'] : null;
}
}
return $this->size;
}
/**
* {@inheritdoc}
*/
public function tell() : int
{
$position = \false;
if ($this->stream) {
$position = ftell($this->stream);
}
if ($position === \false || $this->isPipe()) {
throw new RuntimeException('Could not get the position of the pointer in stream.');
}
return $position;
}
/**
* {@inheritdoc}
*/
public function eof() : bool
{
return !$this->stream || feof($this->stream);
}
/**
* {@inheritdoc}
*/
public function isReadable() : bool
{
if ($this->readable !== null) {
return $this->readable;
}
$this->readable = \false;
if ($this->stream) {
$mode = $this->getMetadata('mode');
if (is_string($mode) && (strstr($mode, 'r') !== \false || strstr($mode, '+') !== \false)) {
$this->readable = \true;
}
}
return $this->readable;
}
/**
* {@inheritdoc}
*/
public function isWritable() : bool
{
if ($this->writable === null) {
$this->writable = \false;
if ($this->stream) {
$mode = $this->getMetadata('mode');
if (is_string($mode) && (strstr($mode, 'w') !== \false || strstr($mode, '+') !== \false)) {
$this->writable = \true;
}
}
}
return $this->writable;
}
/**
* {@inheritdoc}
*/
public function isSeekable() : bool
{
if ($this->seekable === null) {
$this->seekable = \false;
if ($this->stream) {
$this->seekable = !$this->isPipe() && $this->getMetadata('seekable');
}
}
return $this->seekable;
}
/**
* {@inheritdoc}
*/
public function seek($offset, $whence = SEEK_SET) : void
{
if (!$this->isSeekable() || $this->stream && fseek($this->stream, $offset, $whence) === -1) {
throw new RuntimeException('Could not seek in stream.');
}
}
/**
* {@inheritdoc}
*/
public function rewind() : void
{
if (!$this->isSeekable() || $this->stream && rewind($this->stream) === \false) {
throw new RuntimeException('Could not rewind stream.');
}
}
/**
* {@inheritdoc}
*/
public function read($length) : string
{
$data = \false;
if ($this->isReadable() && $this->stream && $length > 0) {
$data = fread($this->stream, $length);
}
if (is_string($data)) {
if ($this->cache) {
$this->cache->write($data);
}
if ($this->eof()) {
$this->finished = \true;
}
return $data;
}
throw new RuntimeException('Could not read from stream.');
}
/**
* {@inheritdoc}
* @return int
*/
public function write($string) : int
{
$written = \false;
if ($this->isWritable() && $this->stream) {
$written = fwrite($this->stream, $string);
}
if ($written !== \false) {
$this->size = null;
return $written;
}
throw new RuntimeException('Could not write to stream.');
}
/**
* {@inheritdoc}
*/
public function getContents() : string
{
if ($this->cache && $this->finished) {
$this->cache->rewind();
return $this->cache->getContents();
}
$contents = \false;
if ($this->stream) {
$contents = stream_get_contents($this->stream);
}
if (is_string($contents)) {
if ($this->cache) {
$this->cache->write($contents);
}
if ($this->eof()) {
$this->finished = \true;
}
return $contents;
}
throw new RuntimeException('Could not get contents of stream.');
}
/**
* Returns whether or not the stream is a pipe.
*
* @internal This method is not part of the PSR-7 standard.
*
* @return bool
*/
public function isPipe() : bool
{
if ($this->isPipe === null) {
$this->isPipe = \false;
if ($this->stream) {
$stats = fstat($this->stream);
if (is_array($stats)) {
$this->isPipe = ($stats['mode'] & self::FSTAT_MODE_S_IFIFO) !== 0;
}
}
}
return $this->isPipe;
}
}

View File

@@ -1,230 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use RuntimeException;
use PleskRestApi\Slim\Psr7\Factory\StreamFactory;
use function copy;
use function dirname;
use function is_array;
use function is_string;
use function is_uploaded_file;
use function is_writable;
use function move_uploaded_file;
use function rename;
use function sprintf;
use function strpos;
use function unlink;
use const UPLOAD_ERR_OK;
class UploadedFile implements UploadedFileInterface
{
/**
* The client-provided full path to the file
*/
protected string $file;
/**
* The client-provided file name.
*/
protected ?string $name;
/**
* The client-provided media type of the file.
*/
protected ?string $type;
protected ?int $size;
/**
* A valid PHP UPLOAD_ERR_xxx code for the file upload.
*/
protected int $error = UPLOAD_ERR_OK;
/**
* Indicates if the upload is from a SAPI environment.
*/
protected bool $sapi = \false;
/**
* @var StreamInterface|null
*/
protected $stream;
/**
* Indicates if the uploaded file has already been moved.
*/
protected bool $moved = \false;
/**
* @param string|StreamInterface $fileNameOrStream The full path to the uploaded file provided by the client,
* or a StreamInterface instance.
* @param string|null $name The file name.
* @param string|null $type The file media type.
* @param int|null $size The file size in bytes.
* @param int $error The UPLOAD_ERR_XXX code representing the status of the upload.
* @param bool $sapi Indicates if the upload is in a SAPI environment.
*/
public final function __construct($fileNameOrStream, ?string $name = null, ?string $type = null, ?int $size = null, int $error = UPLOAD_ERR_OK, bool $sapi = \false)
{
if ($fileNameOrStream instanceof StreamInterface) {
$file = $fileNameOrStream->getMetadata('uri');
if (!is_string($file)) {
throw new InvalidArgumentException('No URI associated with the stream.');
}
$this->file = $file;
$this->stream = $fileNameOrStream;
} elseif (is_string($fileNameOrStream)) {
$this->file = $fileNameOrStream;
} else {
throw new InvalidArgumentException('Please provide a string (full path to the uploaded file) or an instance of StreamInterface.');
}
$this->name = $name;
$this->type = $type;
$this->size = $size;
$this->error = $error;
$this->sapi = $sapi;
}
/**
* {@inheritdoc}
* @return StreamInterface
*/
public function getStream() : StreamInterface
{
if ($this->moved) {
throw new RuntimeException(sprintf('Uploaded file %s has already been moved', $this->name));
}
if (!$this->stream) {
$this->stream = (new StreamFactory())->createStreamFromFile($this->file);
}
return $this->stream;
}
/**
* {@inheritdoc}
*/
public function moveTo($targetPath) : void
{
if ($this->moved) {
throw new RuntimeException('Uploaded file already moved');
}
$targetIsStream = strpos($targetPath, '://') > 0;
if (!$targetIsStream && !is_writable(dirname($targetPath))) {
throw new InvalidArgumentException('Upload target path is not writable');
}
if ($targetIsStream) {
if (!copy($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
}
if (!unlink($this->file)) {
throw new RuntimeException(sprintf('Error removing uploaded file %s', $this->name));
}
} elseif ($this->sapi) {
if (!is_uploaded_file($this->file)) {
throw new RuntimeException(sprintf('%s is not a valid uploaded file', $this->file));
}
if (!move_uploaded_file($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
}
} else {
if (!rename($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));
}
}
$this->moved = \true;
}
/**
* {@inheritdoc}
*/
public function getError() : int
{
return $this->error;
}
/**
* {@inheritdoc}
*/
public function getClientFilename() : ?string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getClientMediaType() : ?string
{
return $this->type;
}
/**
* {@inheritdoc}
*/
public function getSize() : ?int
{
return $this->size;
}
/**
* Returns the client-provided full path to the file
*
* @internal This method is not part of the PSR-7 standard
*
* @return string
*/
public function getFilePath() : string
{
return $this->file;
}
/**
* Create a normalized tree of UploadedFile instances from the Environment.
*
* @internal This method is not part of the PSR-7 standard.
*
* @param array $globals The global server variables.
*
* @return array A normalized tree of UploadedFile instances or null if none are provided.
*/
public static function createFromGlobals(array $globals) : array
{
if (isset($globals['slim.files']) && is_array($globals['slim.files'])) {
return $globals['slim.files'];
}
if (!empty($_FILES)) {
return self::parseUploadedFiles($_FILES);
}
return [];
}
/**
* Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data.
*
* @internal This method is not part of the PSR-7 standard.
*
* @param array $uploadedFiles The non-normalized tree of uploaded file data.
*
* @return array A normalized tree of UploadedFile instances.
*/
private static function parseUploadedFiles(array $uploadedFiles) : array
{
$parsed = [];
foreach ($uploadedFiles as $field => $uploadedFile) {
if (!isset($uploadedFile['error'])) {
if (is_array($uploadedFile)) {
$parsed[$field] = self::parseUploadedFiles($uploadedFile);
}
continue;
}
$parsed[$field] = [];
if (!is_array($uploadedFile['error'])) {
$parsed[$field] = new static($uploadedFile['tmp_name'], $uploadedFile['name'] ?? null, $uploadedFile['type'] ?? null, $uploadedFile['size'] ?? null, $uploadedFile['error'], \true);
} else {
$subArray = [];
foreach ($uploadedFile['error'] as $fileIdx => $error) {
// Normalize sub array and re-parse to move the input's key name up a level
$subArray[$fileIdx]['name'] = $uploadedFile['name'][$fileIdx];
$subArray[$fileIdx]['type'] = $uploadedFile['type'][$fileIdx];
$subArray[$fileIdx]['tmp_name'] = $uploadedFile['tmp_name'][$fileIdx];
$subArray[$fileIdx]['error'] = $uploadedFile['error'][$fileIdx];
$subArray[$fileIdx]['size'] = $uploadedFile['size'][$fileIdx];
$parsed[$field] = self::parseUploadedFiles($subArray);
}
}
}
return $parsed;
}
}

View File

@@ -1,400 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Psr7;
use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use function filter_var;
use function is_integer;
use function is_null;
use function is_object;
use function is_string;
use function ltrim;
use function method_exists;
use function preg_replace_callback;
use function rawurlencode;
use function str_replace;
use function str_starts_with;
use function strtolower;
use const FILTER_FLAG_IPV6;
use const FILTER_VALIDATE_IP;
class Uri implements UriInterface
{
public const SUPPORTED_SCHEMES = ['' => null, 'http' => 80, 'https' => 443];
/**
* Uri scheme (without "://" suffix)
*/
protected string $scheme = '';
protected string $user = '';
protected string $password = '';
protected string $host = '';
protected ?int $port;
protected string $path = '';
/**
* Uri query string (without "?" prefix)
*/
protected string $query = '';
/**
* Uri fragment string (without "#" prefix)
*/
protected string $fragment = '';
/**
* @param string $scheme Uri scheme.
* @param string $host Uri host.
* @param int|null $port Uri port number.
* @param string $path Uri path.
* @param string $query Uri query string.
* @param string $fragment Uri fragment.
* @param string $user Uri user.
* @param string $password Uri password.
*/
public function __construct(string $scheme, string $host, ?int $port = null, string $path = '/', string $query = '', string $fragment = '', string $user = '', string $password = '')
{
$this->scheme = $this->filterScheme($scheme);
$this->host = $this->filterHost($host);
$this->port = $this->filterPort($port);
$this->path = $this->filterPath($path);
$this->query = $this->filterQuery($query);
$this->fragment = $this->filterFragment($fragment);
$this->user = $this->filterUserInfo($user);
$this->password = $this->filterUserInfo($password);
}
/**
* {@inheritdoc}
*/
public function getScheme() : string
{
return $this->scheme;
}
/**
* {@inheritdoc}
* @return static
*/
public function withScheme($scheme) : UriInterface
{
$scheme = $this->filterScheme($scheme);
$clone = clone $this;
$clone->scheme = $scheme;
return $clone;
}
/**
* Filter Uri scheme.
*
* @param mixed $scheme Raw Uri scheme.
*
* @return string
*
* @throws InvalidArgumentException If the Uri scheme is not a string.
* @throws InvalidArgumentException If Uri scheme is not exists in SUPPORTED_SCHEMES
*/
protected function filterScheme($scheme) : string
{
if (!is_string($scheme)) {
throw new InvalidArgumentException('Uri scheme must be a string.');
}
$scheme = str_replace('://', '', strtolower($scheme));
if (!\key_exists($scheme, static::SUPPORTED_SCHEMES)) {
throw new InvalidArgumentException('Uri scheme must be one of: "' . \implode('", "', \array_keys(static::SUPPORTED_SCHEMES)) . '"');
}
return $scheme;
}
/**
* {@inheritdoc}
*/
public function getAuthority() : string
{
$userInfo = $this->getUserInfo();
$host = $this->getHost();
$port = $this->getPort();
return ($userInfo !== '' ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : '');
}
/**
* {@inheritdoc}
*/
public function getUserInfo() : string
{
$info = $this->user;
if ($this->password !== '') {
$info .= ':' . $this->password;
}
return $info;
}
/**
* {@inheritdoc}
* @return static
*/
public function withUserInfo($user, $password = null) : UriInterface
{
$clone = clone $this;
$clone->user = $this->filterUserInfo($user);
if ($clone->user !== '') {
$clone->password = $this->filterUserInfo($password);
} else {
$clone->password = '';
}
return $clone;
}
/**
* Filters the user info string.
*
* Returns the percent-encoded query string.
*
* @param string|null $info The raw uri query string.
*
* @return string
*/
protected function filterUserInfo(?string $info = null) : string
{
if (!is_string($info)) {
return '';
}
$match = preg_replace_callback('/(?:[^%a-zA-Z0-9_\\-\\.~\\pL!\\$&\'\\(\\)\\*\\+,;=]+|%(?![A-Fa-f0-9]{2}))/', function ($match) {
return rawurlencode($match[0]);
}, $info);
return is_string($match) ? $match : '';
}
/**
* {@inheritdoc}
*/
public function getHost() : string
{
return $this->host;
}
/**
* {@inheritdoc}
* @return static
*/
public function withHost($host) : UriInterface
{
$clone = clone $this;
$clone->host = $this->filterHost($host);
return $clone;
}
/**
* Filter Uri host.
*
* If the supplied host is an IPv6 address, then it is converted to a reference
* as per RFC 2373.
*
* @param mixed $host The host to filter.
*
* @return string
*
* @throws InvalidArgumentException for invalid host names.
*/
protected function filterHost($host) : string
{
if (is_object($host) && method_exists($host, '__toString')) {
$host = (string) $host;
}
if (!is_string($host)) {
throw new InvalidArgumentException('Uri host must be a string');
}
if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$host = '[' . $host . ']';
}
return strtolower($host);
}
/**
* {@inheritdoc}
*/
public function getPort() : ?int
{
return $this->port && !$this->hasStandardPort() ? $this->port : null;
}
/**
* {@inheritdoc}
* @return static
*/
public function withPort($port) : UriInterface
{
$port = $this->filterPort($port);
$clone = clone $this;
$clone->port = $port;
return $clone;
}
/**
* Does this Uri use a standard port?
*
* @return bool
*/
protected function hasStandardPort() : bool
{
return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port;
}
/**
* Filter Uri port.
*
* @param int|string|null $port The Uri port number.
*
* @return int|null
*
* @throws InvalidArgumentException If the port is invalid.
*/
protected function filterPort($port) : ?int
{
if (is_null($port)) {
return null;
}
$port = (int) $port;
if ($port >= 1 && $port <= 65535) {
return $port;
}
throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)');
}
/**
* {@inheritdoc}
*/
public function getPath() : string
{
if (str_starts_with($this->path, '/')) {
// Use only one leading slash to prevent XSS attempts.
return '/' . ltrim($this->path, '/');
}
return $this->path;
}
/**
* {@inheritdoc}
* @return static
*/
public function withPath($path) : UriInterface
{
if (!is_string($path)) {
throw new InvalidArgumentException('Uri path must be a string');
}
$clone = clone $this;
$clone->path = $this->filterPath($path);
return $clone;
}
/**
* Filter Uri path.
*
* This method percent-encodes all reserved characters in the provided path string.
* This method will NOT double-encode characters that are already percent-encoded.
*
* @param string $path The raw uri path.
*
* @return string The RFC 3986 percent-encoded uri path.
*
* @link http://www.faqs.org/rfcs/rfc3986.html
*/
protected function filterPath($path) : string
{
$match = preg_replace_callback('/(?:[^a-zA-Z0-9_\\-\\.~:@&=\\+\\$,\\/;%]+|%(?![A-Fa-f0-9]{2}))/', fn(array $match) => rawurlencode($match[0]), $path);
return is_string($match) ? $match : '';
}
/**
* {@inheritdoc}
*/
public function getQuery() : string
{
return $this->query;
}
/**
* {@inheritdoc}
* @return static
*/
public function withQuery($query) : UriInterface
{
$query = ltrim($this->filterQuery($query), '?');
$clone = clone $this;
$clone->query = $query;
return $clone;
}
/**
* Filters the query string of a URI.
*
* Returns the percent-encoded query string.
*
* @param mixed $query The raw uri query string.
*
* @return string
*/
protected function filterQuery($query) : string
{
if (is_object($query) && method_exists($query, '__toString')) {
$query = (string) $query;
}
if (!is_string($query)) {
throw new InvalidArgumentException('Uri query must be a string.');
}
$match = preg_replace_callback('/(?:[^a-zA-Z0-9_\\-\\.~!\\$&\'\\(\\)\\*\\+,;=%:@\\/\\?]+|%(?![A-Fa-f0-9]{2}))/', function ($match) {
return rawurlencode($match[0]);
}, $query);
return is_string($match) ? $match : '';
}
/**
* {@inheritdoc}
*/
public function getFragment() : string
{
return $this->fragment;
}
/**
* {@inheritdoc}
* @return static
*/
public function withFragment($fragment) : UriInterface
{
$fragment = $this->filterFragment($fragment);
$clone = clone $this;
$clone->fragment = $fragment;
return $clone;
}
/**
* Filters fragment of a URI.
*
* Returns the percent-encoded fragment.
*
* @param mixed $fragment The raw uri query string.
*
* @return string
*/
protected function filterFragment($fragment) : string
{
if (is_object($fragment) && method_exists($fragment, '__toString')) {
$fragment = (string) $fragment;
}
if (!is_string($fragment)) {
throw new InvalidArgumentException('Uri fragment must be a string.');
}
$fragment = ltrim($fragment, '#');
$match = preg_replace_callback('/(?:[^a-zA-Z0-9_\\-\\.~!\\$&\'\\(\\)\\*\\+,;=%:@\\/\\?]+|%(?![A-Fa-f0-9]{2}))/', function ($match) {
return rawurlencode($match[0]);
}, $fragment);
return is_string($match) ? $match : '';
}
/**
* {@inheritdoc}
*/
public function __toString() : string
{
$scheme = $this->getScheme();
$authority = $this->getAuthority();
$path = $this->path;
$query = $this->getQuery();
$fragment = $this->getFragment();
if ($path !== '') {
if ($path[0] !== '/') {
if ($authority !== '') {
// If the path is rootless and an authority is present, the path MUST be prefixed by "/".
$path = '/' . $path;
}
} elseif (isset($path[1]) && $path[1] === '/') {
if ($authority === '') {
// If the path is starting with more than one "/" and no authority is present,
// the starting slashes MUST be reduced to one.
$path = ltrim($path, '/');
$path = '/' . $path;
}
}
}
return ($scheme !== '' ? $scheme . ':' : '') . ($authority !== '' ? '//' . $authority : '') . $path . ($query !== '' ? '?' . $query : '') . ($fragment !== '' ? '#' . $fragment : '');
}
}

View File

@@ -1,179 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use PleskRestApi\Slim\Factory\ServerRequestCreatorFactory;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\MiddlewareDispatcherInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteResolverInterface;
use PleskRestApi\Slim\Middleware\BodyParsingMiddleware;
use PleskRestApi\Slim\Middleware\ErrorMiddleware;
use PleskRestApi\Slim\Middleware\RoutingMiddleware;
use PleskRestApi\Slim\Routing\RouteCollectorProxy;
use PleskRestApi\Slim\Routing\RouteResolver;
use PleskRestApi\Slim\Routing\RouteRunner;
use function strtoupper;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
* @template-extends RouteCollectorProxy<TContainerInterface>
*/
class App extends RouteCollectorProxy implements RequestHandlerInterface
{
/**
* Current version
*
* @var string
*/
public const VERSION = '4.15.1';
protected RouteResolverInterface $routeResolver;
protected MiddlewareDispatcherInterface $middlewareDispatcher;
/**
* @param TContainerInterface $container
*/
public function __construct(ResponseFactoryInterface $responseFactory, ?ContainerInterface $container = null, ?CallableResolverInterface $callableResolver = null, ?RouteCollectorInterface $routeCollector = null, ?RouteResolverInterface $routeResolver = null, ?MiddlewareDispatcherInterface $middlewareDispatcher = null)
{
parent::__construct($responseFactory, $callableResolver ?? new CallableResolver($container), $container, $routeCollector);
$this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
} else {
$middlewareDispatcher->seedMiddlewareStack($routeRunner);
}
$this->middlewareDispatcher = $middlewareDispatcher;
}
/**
* @return RouteResolverInterface
*/
public function getRouteResolver() : RouteResolverInterface
{
return $this->routeResolver;
}
/**
* @return MiddlewareDispatcherInterface
*/
public function getMiddlewareDispatcher() : MiddlewareDispatcherInterface
{
return $this->middlewareDispatcher;
}
/**
* @param MiddlewareInterface|string|callable $middleware
* @return App<TContainerInterface>
*/
public function add($middleware) : self
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* @param MiddlewareInterface $middleware
* @return App<TContainerInterface>
*/
public function addMiddleware(MiddlewareInterface $middleware) : self
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* Add the Slim built-in routing middleware to the app middleware stack
*
* This method can be used to control middleware order and is not required for default routing operation.
*
* @return RoutingMiddleware
*/
public function addRoutingMiddleware() : RoutingMiddleware
{
$routingMiddleware = new RoutingMiddleware($this->getRouteResolver(), $this->getRouteCollector()->getRouteParser());
$this->add($routingMiddleware);
return $routingMiddleware;
}
/**
* Add the Slim built-in error middleware to the app middleware stack
*
* @param bool $displayErrorDetails
* @param bool $logErrors
* @param bool $logErrorDetails
* @param LoggerInterface|null $logger
*
* @return ErrorMiddleware
*/
public function addErrorMiddleware(bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails, ?LoggerInterface $logger = null) : ErrorMiddleware
{
$errorMiddleware = new ErrorMiddleware($this->getCallableResolver(), $this->getResponseFactory(), $displayErrorDetails, $logErrors, $logErrorDetails, $logger);
$this->add($errorMiddleware);
return $errorMiddleware;
}
/**
* Add the Slim body parsing middleware to the app middleware stack
*
* @param callable[] $bodyParsers
*
* @return BodyParsingMiddleware
*/
public function addBodyParsingMiddleware(array $bodyParsers = []) : BodyParsingMiddleware
{
$bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);
$this->add($bodyParsingMiddleware);
return $bodyParsingMiddleware;
}
/**
* Run application
*
* This method traverses the application middleware stack and then sends the
* resultant Response object to the HTTP client.
*
* @param ServerRequestInterface|null $request
* @return void
*/
public function run(?ServerRequestInterface $request = null) : void
{
if (!$request) {
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
}
$response = $this->handle($request);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
}
/**
* Handle a request
*
* This method traverses the application middleware stack and then returns the
* resultant Response object.
*
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request) : ResponseInterface
{
$response = $this->middlewareDispatcher->handle($request);
/**
* This is to be in compliance with RFC 2616, Section 9.
* If the incoming request method is HEAD, we need to ensure that the response body
* is empty as the request may fall back on a GET route handler due to FastRoute's
* routing logic which could potentially append content to the response body
* https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
*/
$method = strtoupper($request->getMethod());
if ($method === 'HEAD') {
$emptyBody = $this->responseFactory->createResponse()->getBody();
return $response->withBody($emptyBody);
}
return $response;
}
}

View File

@@ -1,183 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim;
use Closure;
use Psr\Container\ContainerInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\AdvancedCallableResolverInterface;
use function class_exists;
use function is_array;
use function is_callable;
use function is_object;
use function is_string;
use function json_encode;
use function preg_match;
use function sprintf;
/**
* @template TContainerInterface of (ContainerInterface|null)
*/
final class CallableResolver implements AdvancedCallableResolverInterface
{
public static string $callablePattern = '!^([^\\:]+)\\:([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)$!';
/** @var TContainerInterface $container */
private ?ContainerInterface $container;
/**
* @param TContainerInterface $container
*/
public function __construct(?ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function resolve($toResolve) : callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if (is_string($toResolve)) {
$resolved = $this->resolveSlimNotation($toResolve);
$resolved[1] ??= '__invoke';
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* {@inheritdoc}
*/
public function resolveRoute($toResolve) : callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');
}
/**
* {@inheritdoc}
*/
public function resolveMiddleware($toResolve) : callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');
}
/**
* @param callable|array{class-string, string}|string $toResolve
*
* @throws RuntimeException
*/
private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod) : callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if ($predicate($toResolve)) {
$resolved = [$toResolve, $defaultMethod];
}
if (is_string($toResolve)) {
[$instance, $method] = $this->resolveSlimNotation($toResolve);
if ($method === null && $predicate($instance)) {
$method = $defaultMethod;
}
$resolved = [$instance, $method ?? '__invoke'];
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* @param mixed $toResolve
*/
private function isRoute($toResolve) : bool
{
return $toResolve instanceof RequestHandlerInterface;
}
/**
* @param mixed $toResolve
*/
private function isMiddleware($toResolve) : bool
{
return $toResolve instanceof MiddlewareInterface;
}
/**
* @throws RuntimeException
*
* @return array{object, string|null} [Instance, Method Name]
*/
private function resolveSlimNotation(string $toResolve) : array
{
/** @psalm-suppress ArgumentTypeCoercion */
preg_match(CallableResolver::$callablePattern, $toResolve, $matches);
[$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];
if ($this->container && $this->container->has($class)) {
$instance = $this->container->get($class);
if (!is_object($instance)) {
throw new RuntimeException(sprintf('%s container entry is not an object', $class));
}
} else {
if (!class_exists($class)) {
if ($method) {
$class .= '::' . $method . '()';
}
throw new RuntimeException(sprintf('Callable %s does not exist', $class));
}
$instance = new $class($this->container);
}
return [$instance, $method];
}
/**
* @param mixed $resolved
* @param mixed $toResolve
*
* @throws RuntimeException
*/
private function assertCallable($resolved, $toResolve) : callable
{
if (!is_callable($resolved)) {
if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) {
$formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== \false ? $toResolveJson : '';
} else {
$formatedToResolve = is_string($toResolve) ? $toResolve : '';
}
throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve));
}
return $resolved;
}
private function bindToContainer(callable $callable) : callable
{
if (is_array($callable) && $callable[0] instanceof Closure) {
$callable = $callable[0];
}
if ($this->container && $callable instanceof Closure) {
/** @var Closure $callable */
$callable = $callable->bindTo($this->container);
}
return $callable;
}
/**
* @param callable|string|array{class-string, string}|mixed $toResolve
*
* @return callable|string|array{class-string, string}|mixed
*/
private function prepareToResolve($toResolve)
{
if (!is_array($toResolve)) {
return $toResolve;
}
$candidate = $toResolve;
$class = \array_shift($candidate);
$method = \array_shift($candidate);
if (is_string($class) && is_string($method)) {
return $class . ':' . $method;
}
return $toResolve;
}
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Error;
use PleskRestApi\Slim\Exception\HttpException;
use PleskRestApi\Slim\Interfaces\ErrorRendererInterface;
use Throwable;
/**
* Abstract Slim application error renderer
*
* It outputs the error message and diagnostic information in one of the following formats:
* JSON, XML, Plain Text or HTML
*/
abstract class AbstractErrorRenderer implements ErrorRendererInterface
{
protected string $defaultErrorTitle = 'Slim Application Error';
protected string $defaultErrorDescription = 'A website error has occurred. Sorry for the temporary inconvenience.';
protected function getErrorTitle(Throwable $exception) : string
{
if ($exception instanceof HttpException) {
return $exception->getTitle();
}
return $this->defaultErrorTitle;
}
protected function getErrorDescription(Throwable $exception) : string
{
if ($exception instanceof HttpException) {
return $exception->getDescription();
}
return $this->defaultErrorDescription;
}
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Error\Renderers;
use PleskRestApi\Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function htmlentities;
use function sprintf;
/**
* Default Slim application HTML Error Renderer
*/
class HtmlErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails) : string
{
if ($displayErrorDetails) {
$html = '<p>The application could not run because of the following error:</p>';
$html .= '<h2>Details</h2>';
$html .= $this->renderExceptionFragment($exception);
} else {
$html = "<p>{$this->getErrorDescription($exception)}</p>";
}
return $this->renderHtmlBody($this->getErrorTitle($exception), $html);
}
private function renderExceptionFragment(Throwable $exception) : string
{
$html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
$code = $exception->getCode();
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
$html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($exception->getMessage()));
$html .= sprintf('<div><strong>File:</strong> %s</div>', $exception->getFile());
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $exception->getLine());
$html .= '<h2>Trace</h2>';
$html .= sprintf('<pre>%s</pre>', htmlentities($exception->getTraceAsString()));
return $html;
}
public function renderHtmlBody(string $title = '', string $html = '') : string
{
return sprintf('<!doctype html>' . '<html lang="en">' . ' <head>' . ' <meta charset="utf-8">' . ' <meta name="viewport" content="width=device-width, initial-scale=1">' . ' <title>%s</title>' . ' <style>' . ' body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif}' . ' h1{margin:0;font-size:48px;font-weight:normal;line-height:48px}' . ' strong{display:inline-block;width:65px}' . ' </style>' . ' </head>' . ' <body>' . ' <h1>%s</h1>' . ' <div>%s</div>' . ' <a href="#" onclick="window.history.go(-1)">Go Back</a>' . ' </body>' . '</html>', $title, $title, $html);
}
}

View File

@@ -1,41 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Error\Renderers;
use PleskRestApi\Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function json_encode;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
/**
* Default Slim application JSON Error Renderer
*/
class JsonErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails) : string
{
$error = ['message' => $this->getErrorTitle($exception)];
if ($displayErrorDetails) {
$error['exception'] = [];
do {
$error['exception'][] = $this->formatExceptionFragment($exception);
} while ($exception = $exception->getPrevious());
}
return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
/**
* @return array<string|int>
*/
private function formatExceptionFragment(Throwable $exception) : array
{
$code = $exception->getCode();
return ['type' => get_class($exception), 'code' => $code, 'message' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()];
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Error\Renderers;
use PleskRestApi\Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function htmlentities;
use function sprintf;
/**
* Default Slim application Plain Text Error Renderer
*/
class PlainTextErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails) : string
{
$text = "{$this->getErrorTitle($exception)}\n";
if ($displayErrorDetails) {
$text .= $this->formatExceptionFragment($exception);
while ($exception = $exception->getPrevious()) {
$text .= "\nPrevious Error:\n";
$text .= $this->formatExceptionFragment($exception);
}
}
return $text;
}
private function formatExceptionFragment(Throwable $exception) : string
{
$text = sprintf("Type: %s\n", get_class($exception));
$code = $exception->getCode();
$text .= sprintf("Code: %s\n", $code);
$text .= sprintf("Message: %s\n", $exception->getMessage());
$text .= sprintf("File: %s\n", $exception->getFile());
$text .= sprintf("Line: %s\n", $exception->getLine());
$text .= sprintf('Trace: %s', $exception->getTraceAsString());
return $text;
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Error\Renderers;
use PleskRestApi\Slim\Error\AbstractErrorRenderer;
use Throwable;
use function get_class;
use function sprintf;
use function str_replace;
/**
* Default Slim application XML Error Renderer
*/
class XmlErrorRenderer extends AbstractErrorRenderer
{
public function __invoke(Throwable $exception, bool $displayErrorDetails) : string
{
$xml = '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . ">\n";
$xml .= "<error>\n <message>" . $this->createCdataSection($this->getErrorTitle($exception)) . "</message>\n";
if ($displayErrorDetails) {
do {
$xml .= " <exception>\n";
$xml .= ' <type>' . get_class($exception) . "</type>\n";
$xml .= ' <code>' . $exception->getCode() . "</code>\n";
$xml .= ' <message>' . $this->createCdataSection($exception->getMessage()) . "</message>\n";
$xml .= ' <file>' . $exception->getFile() . "</file>\n";
$xml .= ' <line>' . $exception->getLine() . "</line>\n";
$xml .= " </exception>\n";
} while ($exception = $exception->getPrevious());
}
$xml .= '</error>';
return $xml;
}
/**
* Returns a CDATA section with the given content.
*/
private function createCdataSection(string $content) : string
{
return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
}
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpBadRequestException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 400;
/**
* @var string
*/
protected $message = 'Bad request.';
protected string $title = '400 Bad Request';
protected string $description = 'The server cannot or will not process ' . 'the request due to an apparent client error.';
}

View File

@@ -1,50 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use Throwable;
/**
* @api
* @method int getCode()
*/
class HttpException extends RuntimeException
{
protected ServerRequestInterface $request;
protected string $title = '';
protected string $description = '';
public function __construct(ServerRequestInterface $request, string $message = '', int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->request = $request;
}
public function getRequest() : ServerRequestInterface
{
return $this->request;
}
public function getTitle() : string
{
return $this->title;
}
public function setTitle(string $title) : self
{
$this->title = $title;
return $this;
}
public function getDescription() : string
{
return $this->description;
}
public function setDescription(string $description) : self
{
$this->description = $description;
return $this;
}
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpForbiddenException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 403;
/**
* @var string
*/
protected $message = 'Forbidden.';
protected string $title = '403 Forbidden';
protected string $description = 'You are not permitted to perform the requested operation.';
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpGoneException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 410;
/**
* @var string
*/
protected $message = 'Gone.';
protected string $title = '410 Gone';
protected string $description = 'The target resource is no longer available at the origin server.';
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpInternalServerErrorException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 500;
/**
* @var string
*/
protected $message = 'Internal server error.';
protected string $title = '500 Internal Server Error';
protected string $description = 'Unexpected condition encountered preventing server from fulfilling request.';
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
use function implode;
class HttpMethodNotAllowedException extends HttpSpecializedException
{
/**
* @var string[]
*/
protected array $allowedMethods = [];
/**
* @var int
*/
protected $code = 405;
/**
* @var string
*/
protected $message = 'Method not allowed.';
protected string $title = '405 Method Not Allowed';
protected string $description = 'The request method is not supported for the requested resource.';
/**
* @return string[]
*/
public function getAllowedMethods() : array
{
return $this->allowedMethods;
}
/**
* @param string[] $methods
*/
public function setAllowedMethods(array $methods) : self
{
$this->allowedMethods = $methods;
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
return $this;
}
}

View File

@@ -1,23 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
class HttpNotFoundException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 404;
/**
* @var string
*/
protected $message = 'Not found.';
protected string $title = '404 Not Found';
protected string $description = 'The requested resource could not be found. Please verify the URI and try again.';
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpNotImplementedException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 501;
/**
* @var string
*/
protected $message = 'Not implemented.';
protected string $title = '501 Not Implemented';
protected string $description = 'The server does not support the functionality required to fulfill the request.';
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
abstract class HttpSpecializedException extends HttpException
{
/**
* @param ServerRequestInterface $request
* @param string|null $message
* @param Throwable|null $previous
*/
public function __construct(ServerRequestInterface $request, ?string $message = null, ?Throwable $previous = null)
{
if ($message !== null) {
$this->message = $message;
}
// @phpstan-ignore-next-line
parent::__construct($request, $this->message, $this->code, $previous);
}
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpTooManyRequestsException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 429;
/**
* @var string
*/
protected $message = 'Too many requests.';
protected string $title = '429 Too Many Requests';
protected string $description = 'The client application has surpassed its rate limit, ' . 'or number of requests they can send in a given period of time.';
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Exception;
/** @api */
class HttpUnauthorizedException extends HttpSpecializedException
{
/**
* @var int
*/
protected $code = 401;
/**
* @var string
*/
protected $message = 'Unauthorized.';
protected string $title = '401 Unauthorized';
protected string $description = 'The request requires valid user authentication.';
}

View File

@@ -1,128 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
use PleskRestApi\Slim\App;
use PleskRestApi\Slim\Factory\Psr17\Psr17Factory;
use PleskRestApi\Slim\Factory\Psr17\Psr17FactoryProvider;
use PleskRestApi\Slim\Factory\Psr17\SlimHttpPsr17Factory;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\MiddlewareDispatcherInterface;
use PleskRestApi\Slim\Interfaces\Psr17FactoryProviderInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteResolverInterface;
/** @api */
class AppFactory
{
protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;
protected static ?ResponseFactoryInterface $responseFactory = null;
protected static ?StreamFactoryInterface $streamFactory = null;
protected static ?ContainerInterface $container = null;
protected static ?CallableResolverInterface $callableResolver = null;
protected static ?RouteCollectorInterface $routeCollector = null;
protected static ?RouteResolverInterface $routeResolver = null;
protected static ?MiddlewareDispatcherInterface $middlewareDispatcher = null;
protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = \true;
/**
* @template TContainerInterface of (ContainerInterface|null)
* @param TContainerInterface $container
* @return (TContainerInterface is ContainerInterface ? App<TContainerInterface> : App<ContainerInterface|null>)
*/
public static function create(?ResponseFactoryInterface $responseFactory = null, ?ContainerInterface $container = null, ?CallableResolverInterface $callableResolver = null, ?RouteCollectorInterface $routeCollector = null, ?RouteResolverInterface $routeResolver = null, ?MiddlewareDispatcherInterface $middlewareDispatcher = null) : App
{
static::$responseFactory = $responseFactory ?? static::$responseFactory;
return new App(self::determineResponseFactory(), $container ?? static::$container, $callableResolver ?? static::$callableResolver, $routeCollector ?? static::$routeCollector, $routeResolver ?? static::$routeResolver, $middlewareDispatcher ?? static::$middlewareDispatcher);
}
/**
* @template TContainerInterface of (ContainerInterface)
* @param TContainerInterface $container
* @return App<TContainerInterface>
*/
public static function createFromContainer(ContainerInterface $container) : App
{
$responseFactory = $container->has(ResponseFactoryInterface::class) && ($responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class)) instanceof ResponseFactoryInterface ? $responseFactoryFromContainer : self::determineResponseFactory();
$callableResolver = $container->has(CallableResolverInterface::class) && ($callableResolverFromContainer = $container->get(CallableResolverInterface::class)) instanceof CallableResolverInterface ? $callableResolverFromContainer : null;
$routeCollector = $container->has(RouteCollectorInterface::class) && ($routeCollectorFromContainer = $container->get(RouteCollectorInterface::class)) instanceof RouteCollectorInterface ? $routeCollectorFromContainer : null;
$routeResolver = $container->has(RouteResolverInterface::class) && ($routeResolverFromContainer = $container->get(RouteResolverInterface::class)) instanceof RouteResolverInterface ? $routeResolverFromContainer : null;
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class) && ($middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class)) instanceof MiddlewareDispatcherInterface ? $middlewareDispatcherFromContainer : null;
return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver, $middlewareDispatcher);
}
/**
* @throws RuntimeException
*/
public static function determineResponseFactory() : ResponseFactoryInterface
{
if (static::$responseFactory) {
if (static::$streamFactory) {
return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);
}
return static::$responseFactory;
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {
if ($psr17factory::isResponseFactoryAvailable()) {
$responseFactory = $psr17factory::getResponseFactory();
if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) {
$streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();
return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);
}
return $responseFactory;
}
}
throw new RuntimeException("Could not detect any PSR-17 ResponseFactory implementations. " . "Please install a supported implementation in order to use `AppFactory::create()`. " . "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations.");
}
protected static function attemptResponseFactoryDecoration(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) : ResponseFactoryInterface
{
if (static::$slimHttpDecoratorsAutomaticDetectionEnabled && SlimHttpPsr17Factory::isResponseFactoryAvailable()) {
return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);
}
return $responseFactory;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider) : void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setResponseFactory(ResponseFactoryInterface $responseFactory) : void
{
static::$responseFactory = $responseFactory;
}
public static function setStreamFactory(StreamFactoryInterface $streamFactory) : void
{
static::$streamFactory = $streamFactory;
}
public static function setContainer(ContainerInterface $container) : void
{
static::$container = $container;
}
public static function setCallableResolver(CallableResolverInterface $callableResolver) : void
{
static::$callableResolver = $callableResolver;
}
public static function setRouteCollector(RouteCollectorInterface $routeCollector) : void
{
static::$routeCollector = $routeCollector;
}
public static function setRouteResolver(RouteResolverInterface $routeResolver) : void
{
static::$routeResolver = $routeResolver;
}
public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher) : void
{
static::$middlewareDispatcher = $middlewareDispatcher;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled) : void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}

View File

@@ -1,17 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
class GuzzlePsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\GuzzleHttp\\Psr7\\HttpFactory';
protected static string $streamFactoryClass = 'PleskRestApi\\GuzzleHttp\\Psr7\\HttpFactory';
protected static string $serverRequestCreatorClass = 'PleskRestApi\\GuzzleHttp\\Psr7\\ServerRequest';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
}

View File

@@ -1,17 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
class HttpSoftPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\HttpSoft\\Message\\ResponseFactory';
protected static string $streamFactoryClass = 'PleskRestApi\\HttpSoft\\Message\\StreamFactory';
protected static string $serverRequestCreatorClass = 'PleskRestApi\\HttpSoft\\ServerRequest\\ServerRequestCreator';
protected static string $serverRequestCreatorMethod = 'createFromGlobals';
}

View File

@@ -1,17 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
class LaminasDiactorosPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\Laminas\\Diactoros\\ResponseFactory';
protected static string $streamFactoryClass = 'PleskRestApi\\Laminas\\Diactoros\\StreamFactory';
protected static string $serverRequestCreatorClass = 'PleskRestApi\\Laminas\\Diactoros\\ServerRequestFactory';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
}

View File

@@ -1,26 +0,0 @@
<?php
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use PleskRestApi\Slim\Interfaces\ServerRequestCreatorInterface;
class NyholmPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\Nyholm\\Psr7\\Factory\\Psr17Factory';
protected static string $streamFactoryClass = 'PleskRestApi\\Nyholm\\Psr7\\Factory\\Psr17Factory';
protected static string $serverRequestCreatorClass = 'PleskRestApi\\Nyholm\\Psr7Server\\ServerRequestCreator';
protected static string $serverRequestCreatorMethod = 'fromGlobals';
/**
* {@inheritdoc}
*/
public static function getServerRequestCreator() : ServerRequestCreatorInterface
{
/*
* Nyholm Psr17Factory implements all factories in one unified
* factory which implements all of the PSR-17 factory interfaces
*/
$psr17Factory = new static::$responseFactoryClass();
$serverRequestCreator = new static::$serverRequestCreatorClass($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
return new ServerRequestCreator($serverRequestCreator, static::$serverRequestCreatorMethod);
}
}

View File

@@ -1,75 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\Psr17FactoryInterface;
use PleskRestApi\Slim\Interfaces\ServerRequestCreatorInterface;
use function class_exists;
use function get_called_class;
abstract class Psr17Factory implements Psr17FactoryInterface
{
protected static string $responseFactoryClass;
protected static string $streamFactoryClass;
protected static string $serverRequestCreatorClass;
protected static string $serverRequestCreatorMethod;
/**
* {@inheritdoc}
*/
public static function getResponseFactory() : ResponseFactoryInterface
{
if (!static::isResponseFactoryAvailable() || !($responseFactory = new static::$responseFactoryClass()) instanceof ResponseFactoryInterface) {
throw new RuntimeException(get_called_class() . ' could not instantiate a response factory.');
}
return $responseFactory;
}
/**
* {@inheritdoc}
*/
public static function getStreamFactory() : StreamFactoryInterface
{
if (!static::isStreamFactoryAvailable() || !($streamFactory = new static::$streamFactoryClass()) instanceof StreamFactoryInterface) {
throw new RuntimeException(get_called_class() . ' could not instantiate a stream factory.');
}
return $streamFactory;
}
/**
* {@inheritdoc}
*/
public static function getServerRequestCreator() : ServerRequestCreatorInterface
{
if (!static::isServerRequestCreatorAvailable()) {
throw new RuntimeException(get_called_class() . ' could not instantiate a server request creator.');
}
return new ServerRequestCreator(static::$serverRequestCreatorClass, static::$serverRequestCreatorMethod);
}
/**
* {@inheritdoc}
*/
public static function isResponseFactoryAvailable() : bool
{
return static::$responseFactoryClass && class_exists(static::$responseFactoryClass);
}
/**
* {@inheritdoc}
*/
public static function isStreamFactoryAvailable() : bool
{
return static::$streamFactoryClass && class_exists(static::$streamFactoryClass);
}
/**
* {@inheritdoc}
*/
public static function isServerRequestCreatorAvailable() : bool
{
return static::$serverRequestCreatorClass && static::$serverRequestCreatorMethod && class_exists(static::$serverRequestCreatorClass);
}
}

View File

@@ -1,40 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use PleskRestApi\Slim\Interfaces\Psr17FactoryProviderInterface;
use function array_unshift;
class Psr17FactoryProvider implements Psr17FactoryProviderInterface
{
/**
* @var string[]
*/
protected static array $factories = [SlimPsr17Factory::class, HttpSoftPsr17Factory::class, NyholmPsr17Factory::class, LaminasDiactorosPsr17Factory::class, GuzzlePsr17Factory::class];
/**
* {@inheritdoc}
*/
public static function getFactories() : array
{
return static::$factories;
}
/**
* {@inheritdoc}
*/
public static function setFactories(array $factories) : void
{
static::$factories = $factories;
}
/**
* {@inheritdoc}
*/
public static function addFactory(string $factory) : void
{
array_unshift(static::$factories, $factory);
}
}

View File

@@ -1,39 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use Closure;
use Psr\Http\Message\ServerRequestInterface;
use PleskRestApi\Slim\Interfaces\ServerRequestCreatorInterface;
class ServerRequestCreator implements ServerRequestCreatorInterface
{
/**
* @var object|string
*/
protected $serverRequestCreator;
protected string $serverRequestCreatorMethod;
/**
* @param object|string $serverRequestCreator
*/
public function __construct($serverRequestCreator, string $serverRequestCreatorMethod)
{
$this->serverRequestCreator = $serverRequestCreator;
$this->serverRequestCreatorMethod = $serverRequestCreatorMethod;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals() : ServerRequestInterface
{
/** @var callable $callable */
$callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
/** @var ServerRequestInterface */
return Closure::fromCallable($callable)();
}
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
class SlimHttpPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\Slim\\Http\\Factory\\DecoratedResponseFactory';
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function createDecoratedResponseFactory(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) : ResponseFactoryInterface
{
if (!($decoratedResponseFactory = new static::$responseFactoryClass($responseFactory, $streamFactory)) instanceof ResponseFactoryInterface) {
throw new RuntimeException(\get_called_class() . ' could not instantiate a decorated response factory.');
}
return $decoratedResponseFactory;
}
}

View File

@@ -1,41 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\ServerRequestCreatorInterface;
use function class_exists;
class SlimHttpServerRequestCreator implements ServerRequestCreatorInterface
{
protected ServerRequestCreatorInterface $serverRequestCreator;
protected static string $serverRequestDecoratorClass = 'PleskRestApi\\Slim\\Http\\ServerRequest';
public function __construct(ServerRequestCreatorInterface $serverRequestCreator)
{
$this->serverRequestCreator = $serverRequestCreator;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals() : ServerRequestInterface
{
if (!static::isServerRequestDecoratorAvailable()) {
throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');
}
$request = $this->serverRequestCreator->createServerRequestFromGlobals();
if (!($decoratedServerRequest = new static::$serverRequestDecoratorClass($request)) instanceof ServerRequestInterface) {
throw new RuntimeException(\get_called_class() . ' could not instantiate a decorated server request.');
}
return $decoratedServerRequest;
}
public static function isServerRequestDecoratorAvailable() : bool
{
return class_exists(static::$serverRequestDecoratorClass);
}
}

View File

@@ -1,17 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory\Psr17;
class SlimPsr17Factory extends Psr17Factory
{
protected static string $responseFactoryClass = 'PleskRestApi\\Slim\\Psr7\\Factory\\ResponseFactory';
protected static string $streamFactoryClass = 'PleskRestApi\\Slim\\Psr7\\Factory\\StreamFactory';
protected static string $serverRequestCreatorClass = 'PleskRestApi\\Slim\\Psr7\\Factory\\ServerRequestFactory';
protected static string $serverRequestCreatorMethod = 'createFromGlobals';
}

View File

@@ -1,64 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Factory;
use RuntimeException;
use PleskRestApi\Slim\Factory\Psr17\Psr17Factory;
use PleskRestApi\Slim\Factory\Psr17\Psr17FactoryProvider;
use PleskRestApi\Slim\Factory\Psr17\SlimHttpServerRequestCreator;
use PleskRestApi\Slim\Interfaces\Psr17FactoryProviderInterface;
use PleskRestApi\Slim\Interfaces\ServerRequestCreatorInterface;
/** @api */
class ServerRequestCreatorFactory
{
protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;
protected static ?ServerRequestCreatorInterface $serverRequestCreator = null;
protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = \true;
public static function create() : ServerRequestCreatorInterface
{
return static::determineServerRequestCreator();
}
/**
* @throws RuntimeException
*/
public static function determineServerRequestCreator() : ServerRequestCreatorInterface
{
if (static::$serverRequestCreator) {
return static::attemptServerRequestCreatorDecoration(static::$serverRequestCreator);
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17Factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17Factory) {
if ($psr17Factory::isServerRequestCreatorAvailable()) {
$serverRequestCreator = $psr17Factory::getServerRequestCreator();
return static::attemptServerRequestCreatorDecoration($serverRequestCreator);
}
}
throw new RuntimeException("Could not detect any ServerRequest creator implementations. " . "Please install a supported implementation in order to use `App::run()` " . "without having to pass in a `ServerRequest` object. " . "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations.");
}
protected static function attemptServerRequestCreatorDecoration(ServerRequestCreatorInterface $serverRequestCreator) : ServerRequestCreatorInterface
{
if (static::$slimHttpDecoratorsAutomaticDetectionEnabled && SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()) {
return new SlimHttpServerRequestCreator($serverRequestCreator);
}
return $serverRequestCreator;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider) : void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator) : void
{
self::$serverRequestCreator = $serverRequestCreator;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled) : void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}

View File

@@ -1,250 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Handlers;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use PleskRestApi\Slim\Error\Renderers\HtmlErrorRenderer;
use PleskRestApi\Slim\Error\Renderers\JsonErrorRenderer;
use PleskRestApi\Slim\Error\Renderers\PlainTextErrorRenderer;
use PleskRestApi\Slim\Error\Renderers\XmlErrorRenderer;
use PleskRestApi\Slim\Exception\HttpException;
use PleskRestApi\Slim\Exception\HttpMethodNotAllowedException;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\ErrorHandlerInterface;
use PleskRestApi\Slim\Interfaces\ErrorRendererInterface;
use PleskRestApi\Slim\Logger;
use Throwable;
use function array_intersect;
use function array_key_exists;
use function array_keys;
use function call_user_func;
use function count;
use function current;
use function explode;
use function implode;
use function next;
use function preg_match;
/**
* Default Slim application error handler
*
* It outputs the error message and diagnostic information in one of the following formats:
* JSON, XML, Plain Text or HTML based on the Accept header.
* @api
*/
class ErrorHandler implements ErrorHandlerInterface
{
protected string $defaultErrorRendererContentType = 'text/html';
/**
* @var ErrorRendererInterface|string|callable
*/
protected $defaultErrorRenderer = HtmlErrorRenderer::class;
/**
* @var ErrorRendererInterface|string|callable
*/
protected $logErrorRenderer = PlainTextErrorRenderer::class;
/**
* @var array<string|callable>
*/
protected array $errorRenderers = ['application/json' => JsonErrorRenderer::class, 'application/xml' => XmlErrorRenderer::class, 'text/xml' => XmlErrorRenderer::class, 'text/html' => HtmlErrorRenderer::class, 'text/plain' => PlainTextErrorRenderer::class];
protected bool $displayErrorDetails = \false;
protected bool $logErrors;
protected bool $logErrorDetails = \false;
protected ?string $contentType = null;
protected ?string $method = null;
protected ServerRequestInterface $request;
protected Throwable $exception;
protected int $statusCode;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected LoggerInterface $logger;
public function __construct(CallableResolverInterface $callableResolver, ResponseFactoryInterface $responseFactory, ?LoggerInterface $logger = null)
{
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->logger = $logger ?: $this->getDefaultLogger();
}
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param Throwable $exception The caught Exception object
* @param bool $displayErrorDetails Whether or not to display the error details
* @param bool $logErrors Whether or not to log errors
* @param bool $logErrorDetails Whether or not to log error details
*/
public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails) : ResponseInterface
{
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->request = $request;
$this->exception = $exception;
$this->method = $request->getMethod();
$this->statusCode = $this->determineStatusCode();
if ($this->contentType === null) {
$this->contentType = $this->determineContentType($request);
}
if ($logErrors) {
$this->writeToErrorLog();
}
return $this->respond();
}
/**
* Force the content type for all error handler responses.
*
* @param string|null $contentType The content type
*/
public function forceContentType(?string $contentType) : void
{
$this->contentType = $contentType;
}
protected function determineStatusCode() : int
{
if ($this->method === 'OPTIONS') {
return 200;
}
if ($this->exception instanceof HttpException) {
return $this->exception->getCode();
}
return 500;
}
/**
* Determine which content type we know about is wanted using Accept header
*
* Note: This method is a bare-bones implementation designed specifically for
* Slim's error handling requirements. Consider a fully-feature solution such
* as willdurand/negotiation for any other situation.
*/
protected function determineContentType(ServerRequestInterface $request) : ?string
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(explode(',', $acceptHeader), array_keys($this->errorRenderers));
$count = count($selectedContentTypes);
if ($count) {
$current = current($selectedContentTypes);
/**
* Ensure other supported content types take precedence over text/plain
* when multiple content types are provided via Accept header.
*/
if ($current === 'text/plain' && $count > 1) {
$next = next($selectedContentTypes);
if (\is_string($next)) {
return $next;
}
}
// @phpstan-ignore-next-line
if (\is_string($current)) {
return $current;
}
}
if (preg_match('/\\+(json|xml)/', $acceptHeader, $matches)) {
$mediaType = 'application/' . $matches[1];
if (array_key_exists($mediaType, $this->errorRenderers)) {
return $mediaType;
}
}
return null;
}
/**
* Determine which renderer to use based on content type
*
* @throws RuntimeException
*/
protected function determineRenderer() : callable
{
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$renderer = $this->errorRenderers[$this->contentType];
} else {
$renderer = $this->defaultErrorRenderer;
}
return $this->callableResolver->resolve($renderer);
}
/**
* Register an error renderer for a specific content-type
*
* @param string $contentType The content-type this renderer should be registered to
* @param ErrorRendererInterface|string|callable $errorRenderer The error renderer
*/
public function registerErrorRenderer(string $contentType, $errorRenderer) : void
{
$this->errorRenderers[$contentType] = $errorRenderer;
}
/**
* Set the default error renderer
*
* @param string $contentType The content type of the default error renderer
* @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer
*/
public function setDefaultErrorRenderer(string $contentType, $errorRenderer) : void
{
$this->defaultErrorRendererContentType = $contentType;
$this->defaultErrorRenderer = $errorRenderer;
}
/**
* Set the renderer for the error logger
*
* @param ErrorRendererInterface|string|callable $logErrorRenderer
*/
public function setLogErrorRenderer($logErrorRenderer) : void
{
$this->logErrorRenderer = $logErrorRenderer;
}
/**
* Write to the error log if $logErrors has been set to true
*/
protected function writeToErrorLog() : void
{
$renderer = $this->callableResolver->resolve($this->logErrorRenderer);
/** @var string $error */
$error = $renderer($this->exception, $this->logErrorDetails);
if ($this->logErrorRenderer === PlainTextErrorRenderer::class && !$this->displayErrorDetails) {
$error .= "\nTips: To display error details in HTTP response ";
$error .= 'set "displayErrorDetails" to true in the ErrorHandler constructor.';
}
$this->logError($error);
}
/**
* Wraps the error_log function so that this can be easily tested
*/
protected function logError(string $error) : void
{
$this->logger->error($error);
}
/**
* Returns a default logger implementation.
*/
protected function getDefaultLogger() : LoggerInterface
{
return new Logger();
}
protected function respond() : ResponseInterface
{
$response = $this->responseFactory->createResponse($this->statusCode);
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$response = $response->withHeader('Content-type', $this->contentType);
} else {
$response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);
}
if ($this->exception instanceof HttpMethodNotAllowedException) {
$allowedMethods = implode(', ', $this->exception->getAllowedMethods());
$response = $response->withHeader('Allow', $allowedMethods);
}
$renderer = $this->determineRenderer();
$body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);
if ($body !== \false) {
/** @var string $body */
$response->getBody()->write($body);
}
return $response;
}
}

View File

@@ -1,39 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use PleskRestApi\Slim\Interfaces\RequestHandlerInvocationStrategyInterface;
/**
* PSR-15 RequestHandler invocation strategy
*/
class RequestHandler implements RequestHandlerInvocationStrategyInterface
{
protected bool $appendRouteArgumentsToRequestAttributes;
public function __construct(bool $appendRouteArgumentsToRequestAttributes = \false)
{
$this->appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes;
}
/**
* Invoke a route callable that implements RequestHandlerInterface
*
* @param array<string, string> $routeArguments
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments) : ResponseInterface
{
if ($this->appendRouteArgumentsToRequestAttributes) {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
}
/** @var ResponseInterface */
return $callable($request);
}
}

View File

@@ -1,33 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use PleskRestApi\Slim\Interfaces\InvocationStrategyInterface;
/**
* Default route callback strategy with route parameters as an array of arguments.
*/
class RequestResponse implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response, and all route parameters
* as an array of arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments) : ResponseInterface
{
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
/** @var ResponseInterface */
return $callable($request, $response, $routeArguments);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use PleskRestApi\Slim\Interfaces\InvocationStrategyInterface;
use function array_values;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseArgs implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments) : ResponseInterface
{
/** @var ResponseInterface */
return $callable($request, $response, ...array_values($routeArguments));
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use PleskRestApi\Slim\Interfaces\InvocationStrategyInterface;
use RuntimeException;
/**
* Route callback strategy with route parameters as individual arguments.
* @api
*/
class RequestResponseNamedArgs implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array<string, string> $routeArguments
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments) : ResponseInterface
{
/** @var ResponseInterface */
return $callable($request, $response, ...$routeArguments);
}
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
interface AdvancedCallableResolverInterface extends CallableResolverInterface
{
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveRoute($toResolve) : callable;
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolveMiddleware($toResolve) : callable;
}

View File

@@ -1,19 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
interface CallableResolverInterface
{
/**
* Resolve $toResolve into a callable
*
* @param callable|array{class-string, string}|string $toResolve
*/
public function resolve($toResolve) : callable;
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use PleskRestApi\Slim\Routing\RoutingResults;
interface DispatcherInterface
{
/**
* Get routing results for a given request method and uri
*/
public function dispatch(string $method, string $uri) : RoutingResults;
/**
* Get allowed methods for a given uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri) : array;
}

View File

@@ -1,17 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
interface ErrorHandlerInterface
{
public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails) : ResponseInterface;
}

View File

@@ -1,15 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Throwable;
interface ErrorRendererInterface
{
public function __invoke(Throwable $exception, bool $displayErrorDetails) : string;
}

View File

@@ -1,29 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Defines a contract for invoking a route callable.
*/
interface InvocationStrategyInterface
{
/**
* Invoke a route callable.
*
* @param callable $callable The callable to invoke using the strategy.
* @param ServerRequestInterface $request The request object.
* @param ResponseInterface $response The response object.
* @param array<string, string> $routeArguments The route's placeholder arguments
*
* @return ResponseInterface The response from the callable.
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments) : ResponseInterface;
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
/** @api */
interface MiddlewareDispatcherInterface extends RequestHandlerInterface
{
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware) : self;
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addMiddleware(MiddlewareInterface $middleware) : self;
/**
* Seed the middleware stack with the inner request handler
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel) : void;
}

View File

@@ -1,40 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use RuntimeException;
interface Psr17FactoryInterface
{
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getResponseFactory() : ResponseFactoryInterface;
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getStreamFactory() : StreamFactoryInterface;
/**
* @throws RuntimeException when the factory could not be instantiated
*/
public static function getServerRequestCreator() : ServerRequestCreatorInterface;
/**
* Is the PSR-17 ResponseFactory available
*/
public static function isResponseFactoryAvailable() : bool;
/**
* Is the PSR-17 StreamFactory available
*/
public static function isStreamFactoryAvailable() : bool;
/**
* Is the ServerRequest creator available
*/
public static function isServerRequestCreatorAvailable() : bool;
}

View File

@@ -1,23 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
/** @api */
interface Psr17FactoryProviderInterface
{
/**
* @return string[]
*/
public static function getFactories() : array;
/**
* @param string[] $factories
*/
public static function setFactories(array $factories) : void;
public static function addFactory(string $factory) : void;
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
interface RequestHandlerInvocationStrategyInterface extends InvocationStrategyInterface
{
}

View File

@@ -1,88 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use InvalidArgumentException;
use RuntimeException;
/** @api */
interface RouteCollectorInterface
{
/**
* Get the route parser
*/
public function getRouteParser() : RouteParserInterface;
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy() : InvocationStrategyInterface;
/**
* Set default route invocation strategy
*/
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy) : RouteCollectorInterface;
/**
* Get path to FastRoute cache file
*/
public function getCacheFile() : ?string;
/**
* Set path to FastRoute cache file
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function setCacheFile(string $cacheFile) : RouteCollectorInterface;
/**
* Get the base path used in pathFor()
*/
public function getBasePath() : string;
/**
* Set the base path used in pathFor()
*/
public function setBasePath(string $basePath) : RouteCollectorInterface;
/**
* Get route objects
*
* @return RouteInterface[]
*/
public function getRoutes() : array;
/**
* Get named route object
*
* @param string $name Route name
*
* @throws RuntimeException If named route does not exist
*/
public function getNamedRoute(string $name) : RouteInterface;
/**
* Remove named route
*
* @param string $name Route name
*
* @throws RuntimeException If named route does not exist
*/
public function removeNamedRoute(string $name) : RouteCollectorInterface;
/**
* Lookup a route via the route's unique identifier
*
* @throws RuntimeException If route of identifier does not exist
*/
public function lookupRoute(string $identifier) : RouteInterface;
/**
* Add route group
* @param string|callable $callable
*/
public function group(string $pattern, $callable) : RouteGroupInterface;
/**
* Add route
*
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable|array{class-string, string}|string $handler The route callable
*/
public function map(array $methods, string $pattern, $handler) : RouteInterface;
}

View File

@@ -1,108 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\UriInterface;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
interface RouteCollectorProxyInterface
{
public function getResponseFactory() : ResponseFactoryInterface;
public function getCallableResolver() : CallableResolverInterface;
/**
* @return TContainerInterface
*/
public function getContainer() : ?ContainerInterface;
public function getRouteCollector() : RouteCollectorInterface;
/**
* Get the RouteCollectorProxy's base path
*/
public function getBasePath() : string;
/**
* Set the RouteCollectorProxy's base path
* @return RouteCollectorProxyInterface<TContainerInterface>
*/
public function setBasePath(string $basePath) : RouteCollectorProxyInterface;
/**
* Add GET route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function get(string $pattern, $callable) : RouteInterface;
/**
* Add POST route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function post(string $pattern, $callable) : RouteInterface;
/**
* Add PUT route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function put(string $pattern, $callable) : RouteInterface;
/**
* Add PATCH route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function patch(string $pattern, $callable) : RouteInterface;
/**
* Add DELETE route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function delete(string $pattern, $callable) : RouteInterface;
/**
* Add OPTIONS route
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function options(string $pattern, $callable) : RouteInterface;
/**
* Add route for any HTTP method
*
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function any(string $pattern, $callable) : RouteInterface;
/**
* Add route with multiple methods
*
* @param string[] $methods Numeric array of HTTP method names
* @param string $pattern The route URI pattern
* @param callable|array{class-string, string}|string $callable The route callback routine
*/
public function map(array $methods, string $pattern, $callable) : RouteInterface;
/**
* Route Groups
*
* This method accepts a route pattern and a callback. All route
* declarations in the callback will be prepended by the group(s)
* that it is in.
* @param string|callable $callable
*/
public function group(string $pattern, $callable) : RouteGroupInterface;
/**
* Add a route that sends an HTTP redirect
*
* @param string|UriInterface $to
*/
public function redirect(string $from, $to, int $status = 302) : RouteInterface;
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Server\MiddlewareInterface;
use PleskRestApi\Slim\MiddlewareDispatcher;
/** @api */
interface RouteGroupInterface
{
public function collectRoutes() : RouteGroupInterface;
/**
* Add middleware to the route group
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware) : RouteGroupInterface;
/**
* Add middleware to the route group
*/
public function addMiddleware(MiddlewareInterface $middleware) : RouteGroupInterface;
/**
* Append the group's middleware to the MiddlewareDispatcher
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher) : RouteGroupInterface;
/**
* Get the RouteGroup's pattern
*/
public function getPattern() : string;
}

View File

@@ -1,108 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
/** @api */
interface RouteInterface
{
/**
* Get route invocation strategy
*/
public function getInvocationStrategy() : InvocationStrategyInterface;
/**
* Set route invocation strategy
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy) : RouteInterface;
/**
* Get route methods
*
* @return string[]
*/
public function getMethods() : array;
/**
* Get route pattern
*/
public function getPattern() : string;
/**
* Set route pattern
*/
public function setPattern(string $pattern) : RouteInterface;
/**
* Get route callable
*
* @return callable|array{class-string, string}|string
*/
public function getCallable();
/**
* Set route callable
*
* @param callable|array{class-string, string}|string $callable
*/
public function setCallable($callable) : RouteInterface;
/**
* Get route name
*/
public function getName() : ?string;
/**
* Set route name
*
* @return static
*/
public function setName(string $name) : RouteInterface;
/**
* Get the route's unique identifier
*/
public function getIdentifier() : string;
/**
* Retrieve a specific route argument
*/
public function getArgument(string $name, ?string $default = null) : ?string;
/**
* Get route arguments
*
* @return array<string, string>
*/
public function getArguments() : array;
/**
* Set a route argument
*
* @deprecated 4.14.1 Use a middleware for custom route arguments now.
*/
public function setArgument(string $name, string $value) : RouteInterface;
/**
* Replace route arguments
*
* @param array<string, string> $arguments
*
* @deprecated 4.14.1 Use a middleware for custom route arguments now.
*/
public function setArguments(array $arguments) : self;
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware) : self;
public function addMiddleware(MiddlewareInterface $middleware) : self;
/**
* Prepare the route for use
*
* @param array<string, string> $arguments
*/
public function prepare(array $arguments) : self;
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*/
public function run(ServerRequestInterface $request) : ResponseInterface;
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use RuntimeException;
/** @api */
interface RouteParserInterface
{
/**
* Build the path for a named route excluding the base path
*
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []) : string;
/**
* Build the path for a named route including the base path
*
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []) : string;
/**
* Get fully qualified URL for named route
*
* @param UriInterface $uri
* @param string $routeName Route name
* @param array<string, string> $data Named argument replacement data
* @param array<string, string | array<array-key, string>> $queryParams Optional query string parameters
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []) : string;
}

View File

@@ -1,14 +0,0 @@
<?php
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use PleskRestApi\Slim\Routing\RoutingResults;
interface RouteResolverInterface
{
/**
* @param string $uri Should be ServerRequestInterface::getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method) : RoutingResults;
public function resolveRoute(string $identifier) : RouteInterface;
}

View File

@@ -1,15 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Interfaces;
use Psr\Http\Message\ServerRequestInterface;
interface ServerRequestCreatorInterface
{
public function createServerRequestFromGlobals() : ServerRequestInterface;
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim;
use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Stringable;
use function error_log;
class Logger extends AbstractLogger
{
/**
* @param mixed $level
* @param string|Stringable $message
* @param array<mixed> $context
*
* @throws InvalidArgumentException
*/
public function log($level, $message, array $context = []) : void
{
error_log((string) $message);
}
}

View File

@@ -1,164 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use function count;
use function explode;
use function is_array;
use function is_object;
use function is_string;
use function json_decode;
use function libxml_clear_errors;
use function libxml_disable_entity_loader;
use function libxml_use_internal_errors;
use function parse_str;
use function simplexml_load_string;
use function strtolower;
use function trim;
use const LIBXML_VERSION;
/** @api */
class BodyParsingMiddleware implements MiddlewareInterface
{
/**
* @var callable[]
*/
protected array $bodyParsers;
/**
* @param callable[] $bodyParsers list of body parsers as an associative array of mediaType => callable
*/
public function __construct(array $bodyParsers = [])
{
$this->registerDefaultBodyParsers();
foreach ($bodyParsers as $mediaType => $parser) {
$this->registerBodyParser($mediaType, $parser);
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
$parsedBody = $request->getParsedBody();
if (empty($parsedBody)) {
$parsedBody = $this->parseBody($request);
$request = $request->withParsedBody($parsedBody);
}
return $handler->handle($request);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param callable $callable A callable that returns parsed contents for media type.
*/
public function registerBodyParser(string $mediaType, callable $callable) : self
{
$this->bodyParsers[$mediaType] = $callable;
return $this;
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
*/
public function hasBodyParser(string $mediaType) : bool
{
return isset($this->bodyParsers[$mediaType]);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @throws RuntimeException
*/
public function getBodyParser(string $mediaType) : callable
{
if (!isset($this->bodyParsers[$mediaType])) {
throw new RuntimeException('No parser for type ' . $mediaType);
}
return $this->bodyParsers[$mediaType];
}
protected function registerDefaultBodyParsers() : void
{
$this->registerBodyParser('application/json', static function ($input) {
/** @var string $input */
$result = json_decode($input, \true);
if (!is_array($result)) {
return null;
}
return $result;
});
$this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) {
/** @var string $input */
parse_str($input, $data);
return $data;
});
$xmlCallable = static function ($input) {
/** @var string $input */
$backup = self::disableXmlEntityLoader(\true);
$backup_errors = libxml_use_internal_errors(\true);
$result = simplexml_load_string($input);
self::disableXmlEntityLoader($backup);
libxml_clear_errors();
libxml_use_internal_errors($backup_errors);
if ($result === \false) {
return null;
}
return $result;
};
$this->registerBodyParser('application/xml', $xmlCallable);
$this->registerBodyParser('text/xml', $xmlCallable);
}
/**
* @return null|array<mixed>|object
*/
protected function parseBody(ServerRequestInterface $request)
{
$mediaType = $this->getMediaType($request);
if ($mediaType === null) {
return null;
}
// Check if this specific media type has a parser registered first
if (!isset($this->bodyParsers[$mediaType])) {
// If not, look for a media type with a structured syntax suffix (RFC 6839)
$parts = explode('+', $mediaType);
if (count($parts) >= 2) {
$mediaType = 'application/' . $parts[count($parts) - 1];
}
}
if (isset($this->bodyParsers[$mediaType])) {
$body = (string) $request->getBody();
$parsed = $this->bodyParsers[$mediaType]($body);
if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) {
throw new RuntimeException('Request body media type parser return value must be an array, an object, or null');
}
return $parsed;
}
return null;
}
/**
* @return string|null The serverRequest media type, minus content-type params
*/
protected function getMediaType(ServerRequestInterface $request) : ?string
{
$contentType = $request->getHeader('Content-Type')[0] ?? null;
if (is_string($contentType) && trim($contentType) !== '') {
$contentTypeParts = explode(';', $contentType);
return strtolower(trim($contentTypeParts[0]));
}
return null;
}
protected static function disableXmlEntityLoader(bool $disable) : bool
{
if (LIBXML_VERSION >= 20900) {
// libxml >= 2.9.0 disables entity loading by default, so it is
// safe to skip the real call (deprecated in PHP 8).
return \true;
}
// @codeCoverageIgnoreStart
return libxml_disable_entity_loader($disable);
// @codeCoverageIgnoreEnd
}
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
/** @api */
class ContentLengthMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
$response = $handler->handle($request);
// Add Content-Length header if not already added
$size = $response->getBody()->getSize();
if ($size !== null && !$response->hasHeader('Content-Length')) {
$response = $response->withHeader('Content-Length', (string) $size);
}
return $response;
}
}

View File

@@ -1,178 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
use PleskRestApi\Slim\Exception\HttpException;
use PleskRestApi\Slim\Handlers\ErrorHandler;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\ErrorHandlerInterface;
use Throwable;
use function get_class;
use function is_subclass_of;
/** @api */
class ErrorMiddleware implements MiddlewareInterface
{
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected bool $displayErrorDetails;
protected bool $logErrors;
protected bool $logErrorDetails;
protected ?LoggerInterface $logger = null;
/**
* @var ErrorHandlerInterface[]|callable[]|string[]
*/
protected array $handlers = [];
/**
* @var ErrorHandlerInterface[]|callable[]|string[]
*/
protected array $subClassHandlers = [];
/**
* @var ErrorHandlerInterface|callable|string|null
*/
protected $defaultErrorHandler;
public function __construct(CallableResolverInterface $callableResolver, ResponseFactoryInterface $responseFactory, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails, ?LoggerInterface $logger = null)
{
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->logger = $logger;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
try {
return $handler->handle($request);
} catch (Throwable $e) {
return $this->handleException($request, $e);
}
}
public function handleException(ServerRequestInterface $request, Throwable $exception) : ResponseInterface
{
if ($exception instanceof HttpException) {
$request = $exception->getRequest();
}
$exceptionType = get_class($exception);
$handler = $this->getErrorHandler($exceptionType);
/** @var ResponseInterface */
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
}
/**
* Get callable to handle scenarios where an error
* occurs when processing the current request.
*
* @param string $type Exception/Throwable name. ie: RuntimeException::class
* @return callable|ErrorHandler
*/
public function getErrorHandler(string $type)
{
if (isset($this->handlers[$type])) {
return $this->callableResolver->resolve($this->handlers[$type]);
}
if (isset($this->subClassHandlers[$type])) {
return $this->callableResolver->resolve($this->subClassHandlers[$type]);
}
foreach ($this->subClassHandlers as $class => $handler) {
if (is_subclass_of($type, $class)) {
return $this->callableResolver->resolve($handler);
}
}
return $this->getDefaultErrorHandler();
}
/**
* Get default error handler
*
* @return ErrorHandler|callable
*/
public function getDefaultErrorHandler()
{
if ($this->defaultErrorHandler === null) {
$this->defaultErrorHandler = new ErrorHandler($this->callableResolver, $this->responseFactory, $this->logger);
}
return $this->callableResolver->resolve($this->defaultErrorHandler);
}
/**
* Set callable as the default Slim application error handler.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* @param string|callable|ErrorHandler $handler
* @see ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
*/
public function setDefaultErrorHandler($handler) : self
{
$this->defaultErrorHandler = $handler;
return $this;
}
/**
* Set callable to handle scenarios where an error
* occurs when processing the current request.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* Pass true to $handleSubclasses to make the handler handle all subclasses of
* the type as well. Pass an array of classes to make the same function handle multiple exceptions.
*
* @param string|string[] $typeOrTypes Exception/Throwable name.
* ie: RuntimeException::class or an array of classes
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
* @param string|callable|ErrorHandlerInterface $handler
*
* @see ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
*/
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = \false) : self
{
if (\is_array($typeOrTypes)) {
foreach ($typeOrTypes as $type) {
$this->addErrorHandler($type, $handler, $handleSubclasses);
}
} else {
$this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
}
return $this;
}
/**
* Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
* @param string|callable|ErrorHandlerInterface $handler
*/
private function addErrorHandler(string $type, $handler, bool $handleSubclasses) : void
{
if ($handleSubclasses) {
$this->subClassHandlers[$type] = $handler;
} else {
$this->handlers[$type] = $handler;
}
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use function is_array;
use function strtoupper;
/** @api */
class MethodOverrideMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
$methodHeader = $request->getHeaderLine('X-Http-Method-Override');
if ($methodHeader) {
$request = $request->withMethod($methodHeader);
} elseif (strtoupper($request->getMethod()) === 'POST') {
$body = $request->getParsedBody();
if (is_array($body) && !empty($body['_METHOD']) && \is_string($body['_METHOD'])) {
$request = $request->withMethod($body['_METHOD']);
}
if ($request->getBody()->eof()) {
$request->getBody()->rewind();
}
}
return $handler->handle($request);
}
}

View File

@@ -1,64 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Throwable;
use function in_array;
use function ob_end_clean;
use function ob_get_clean;
use function ob_start;
/** @api */
class OutputBufferingMiddleware implements MiddlewareInterface
{
public const APPEND = 'append';
public const PREPEND = 'prepend';
protected StreamFactoryInterface $streamFactory;
protected string $style;
/**
* @param string $style Either "append" or "prepend"
*/
public function __construct(StreamFactoryInterface $streamFactory, string $style = 'append')
{
$this->streamFactory = $streamFactory;
$this->style = $style;
if (!in_array($style, [static::APPEND, static::PREPEND], \true)) {
throw new InvalidArgumentException("Invalid style `{$style}`. Must be `append` or `prepend`");
}
}
/**
* @throws Throwable
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
try {
ob_start();
$response = $handler->handle($request);
$output = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
throw $e;
}
if (!empty($output)) {
if ($this->style === static::PREPEND) {
$body = $this->streamFactory->createStream();
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) {
$response->getBody()->write($output);
}
}
return $response;
}
}

View File

@@ -1,79 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use PleskRestApi\Slim\Exception\HttpMethodNotAllowedException;
use PleskRestApi\Slim\Exception\HttpNotFoundException;
use PleskRestApi\Slim\Interfaces\RouteParserInterface;
use PleskRestApi\Slim\Interfaces\RouteResolverInterface;
use PleskRestApi\Slim\Routing\RouteContext;
use PleskRestApi\Slim\Routing\RoutingResults;
class RoutingMiddleware implements MiddlewareInterface
{
protected RouteResolverInterface $routeResolver;
protected RouteParserInterface $routeParser;
public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser)
{
$this->routeResolver = $routeResolver;
$this->routeParser = $routeParser;
}
/**
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{
$request = $this->performRouting($request);
return $handler->handle($request);
}
/**
* Perform routing
*
* @param ServerRequestInterface $request PSR7 Server Request
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function performRouting(ServerRequestInterface $request) : ServerRequestInterface
{
$request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser);
$routingResults = $this->resolveRoutingResultsFromRequest($request);
$routeStatus = $routingResults->getRouteStatus();
$request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults);
switch ($routeStatus) {
case RoutingResults::FOUND:
$routeArguments = $routingResults->getRouteArguments();
$routeIdentifier = $routingResults->getRouteIdentifier() ?? '';
$route = $this->routeResolver->resolveRoute($routeIdentifier)->prepare($routeArguments);
return $request->withAttribute(RouteContext::ROUTE, $route);
case RoutingResults::NOT_FOUND:
throw new HttpNotFoundException($request);
case RoutingResults::METHOD_NOT_ALLOWED:
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routingResults->getAllowedMethods());
throw $exception;
default:
throw new RuntimeException('An unexpected error occurred while performing routing.');
}
}
/**
* Resolves the route from the given request
*/
protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request) : RoutingResults
{
return $this->routeResolver->computeRoutingResults($request->getUri()->getPath(), $request->getMethod());
}
}

View File

@@ -1,230 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim;
use Closure;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\AdvancedCallableResolverInterface;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\MiddlewareDispatcherInterface;
use function class_exists;
use function function_exists;
use function is_callable;
use function is_string;
use function preg_match;
use function sprintf;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
class MiddlewareDispatcher implements MiddlewareDispatcherInterface
{
/**
* Tip of the middleware call stack
*/
protected RequestHandlerInterface $tip;
protected ?CallableResolverInterface $callableResolver;
/** @var TContainerInterface $container */
protected ?ContainerInterface $container;
/**
* @param TContainerInterface $container
*/
public function __construct(RequestHandlerInterface $kernel, ?CallableResolverInterface $callableResolver = null, ?ContainerInterface $container = null)
{
$this->seedMiddlewareStack($kernel);
$this->callableResolver = $callableResolver;
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel) : void
{
$this->tip = $kernel;
}
/**
* Invoke the middleware stack
*/
public function handle(ServerRequestInterface $request) : ResponseInterface
{
return $this->tip->handle($request);
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware) : MiddlewareDispatcherInterface
{
if ($middleware instanceof MiddlewareInterface) {
return $this->addMiddleware($middleware);
}
if (is_string($middleware)) {
return $this->addDeferred($middleware);
}
if (is_callable($middleware)) {
return $this->addCallable($middleware);
}
/** @phpstan-ignore-next-line */
throw new RuntimeException('A middleware must be an object/class name referencing an implementation of ' . 'MiddlewareInterface or a callable with a matching signature.');
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addMiddleware(MiddlewareInterface $middleware) : MiddlewareDispatcherInterface
{
$next = $this->tip;
$this->tip = new class($middleware, $next) implements RequestHandlerInterface
{
private MiddlewareInterface $middleware;
private RequestHandlerInterface $next;
public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request) : ResponseInterface
{
return $this->middleware->process($request, $this->next);
}
};
return $this;
}
/**
* Add a new middleware by class name
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
* @return MiddlewareDispatcher<TContainerInterface>
*/
public function addDeferred(string $middleware) : self
{
$next = $this->tip;
$this->tip = new class($middleware, $next, $this->container, $this->callableResolver) implements RequestHandlerInterface
{
private string $middleware;
private RequestHandlerInterface $next;
private ?ContainerInterface $container;
private ?CallableResolverInterface $callableResolver;
public function __construct(string $middleware, RequestHandlerInterface $next, ?ContainerInterface $container = null, ?CallableResolverInterface $callableResolver = null)
{
$this->middleware = $middleware;
$this->next = $next;
$this->container = $container;
$this->callableResolver = $callableResolver;
}
public function handle(ServerRequestInterface $request) : ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveMiddleware($this->middleware);
/** @var ResponseInterface */
return $callable($request, $this->next);
}
$callable = null;
if ($this->callableResolver instanceof CallableResolverInterface) {
try {
$callable = $this->callableResolver->resolve($this->middleware);
} catch (RuntimeException $e) {
// Do Nothing
}
}
if (!$callable) {
$resolved = $this->middleware;
$instance = null;
$method = null;
/** @psalm-suppress ArgumentTypeCoercion */
// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {
$resolved = $matches[1];
$method = $matches[2];
}
if ($this->container && $this->container->has($resolved)) {
$instance = $this->container->get($resolved);
if ($instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
} elseif (!function_exists($resolved)) {
if (!class_exists($resolved)) {
throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved));
}
$instance = new $resolved($this->container);
}
if ($instance && $instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
$callable = $instance ?? $resolved;
if ($instance && $method) {
$callable = [$instance, $method];
}
if ($this->container && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
}
if (!is_callable($callable)) {
throw new RuntimeException(sprintf('Middleware %s is not resolvable', $this->middleware));
}
/** @var ResponseInterface */
return $callable($request, $this->next);
}
};
return $this;
}
/**
* Add a (non-standard) callable middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
* @return MiddlewareDispatcher<TContainerInterface>
*/
public function addCallable(callable $middleware) : self
{
$next = $this->tip;
if ($this->container && $middleware instanceof Closure) {
/** @var Closure $middleware */
$middleware = $middleware->bindTo($this->container);
}
$this->tip = new class($middleware, $next) implements RequestHandlerInterface
{
/**
* @var callable
*/
private $middleware;
/**
* @var RequestHandlerInterface
*/
private $next;
public function __construct(callable $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request) : ResponseInterface
{
/** @var ResponseInterface */
return ($this->middleware)($request, $this->next);
}
};
return $this;
}
}

View File

@@ -1,113 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim;
use Psr\Http\Message\ResponseInterface;
use function connection_status;
use function header;
use function headers_sent;
use function in_array;
use function min;
use function sprintf;
use function strlen;
use function strtolower;
use const CONNECTION_NORMAL;
class ResponseEmitter
{
private int $responseChunkSize;
public function __construct(int $responseChunkSize = 4096)
{
$this->responseChunkSize = $responseChunkSize;
}
/**
* Send the response the client
*/
public function emit(ResponseInterface $response) : void
{
$isEmpty = $this->isResponseEmpty($response);
if (headers_sent() === \false) {
$this->emitHeaders($response);
// Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers.
// See https://github.com/slimphp/Slim/issues/1730
$this->emitStatusLine($response);
}
if (!$isEmpty) {
$this->emitBody($response);
}
}
/**
* Emit Response Headers
*/
private function emitHeaders(ResponseInterface $response) : void
{
foreach ($response->getHeaders() as $name => $values) {
$first = strtolower($name) !== 'set-cookie';
foreach ($values as $value) {
$header = sprintf('%s: %s', $name, $value);
header($header, $first);
$first = \false;
}
}
}
/**
* Emit Status Line
*/
private function emitStatusLine(ResponseInterface $response) : void
{
$statusLine = sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatusCode(), $response->getReasonPhrase());
header($statusLine, \true, $response->getStatusCode());
}
/**
* Emit Body
*/
private function emitBody(ResponseInterface $response) : void
{
$body = $response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
$amountToRead = (int) $response->getHeaderLine('Content-Length');
if (!$amountToRead) {
$amountToRead = $body->getSize();
}
if ($amountToRead) {
while ($amountToRead > 0 && !$body->eof()) {
$length = min($this->responseChunkSize, $amountToRead);
$data = $body->read($length);
echo $data;
$amountToRead -= strlen($data);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
} else {
while (!$body->eof()) {
echo $body->read($this->responseChunkSize);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
}
}
/**
* Asserts response body is empty or status code is 204, 205 or 304
*/
public function isResponseEmpty(ResponseInterface $response) : bool
{
if (in_array($response->getStatusCode(), [204, 205, 304], \true)) {
return \true;
}
$stream = $response->getBody();
$seekable = $stream->isSeekable();
if ($seekable) {
$stream->rewind();
}
return $seekable ? $stream->read(1) === '' : $stream->eof();
}
}

View File

@@ -1,58 +0,0 @@
<?php
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use PleskRestApi\FastRoute\DataGenerator\GroupCountBased;
use PleskRestApi\FastRoute\RouteCollector as FastRouteCollector;
use PleskRestApi\FastRoute\RouteParser\Std;
use PleskRestApi\Slim\Interfaces\DispatcherInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
class Dispatcher implements DispatcherInterface
{
private RouteCollectorInterface $routeCollector;
private ?FastRouteDispatcher $dispatcher = null;
public function __construct(RouteCollectorInterface $routeCollector)
{
$this->routeCollector = $routeCollector;
}
protected function createDispatcher() : FastRouteDispatcher
{
if ($this->dispatcher) {
return $this->dispatcher;
}
$routeDefinitionCallback = function (FastRouteCollector $r) : void {
$basePath = $this->routeCollector->getBasePath();
foreach ($this->routeCollector->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
}
};
$cacheFile = $this->routeCollector->getCacheFile();
if ($cacheFile) {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \PleskRestApi\FastRoute\cachedDispatcher($routeDefinitionCallback, ['dataGenerator' => GroupCountBased::class, 'dispatcher' => FastRouteDispatcher::class, 'routeParser' => new Std(), 'cacheFile' => $cacheFile]);
} else {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \PleskRestApi\FastRoute\simpleDispatcher($routeDefinitionCallback, ['dataGenerator' => GroupCountBased::class, 'dispatcher' => FastRouteDispatcher::class, 'routeParser' => new Std()]);
}
$this->dispatcher = $dispatcher;
return $this->dispatcher;
}
/**
* {@inheritdoc}
*/
public function dispatch(string $method, string $uri) : RoutingResults
{
$dispatcher = $this->createDispatcher();
$results = $dispatcher->dispatch($method, $uri);
return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]);
}
/**
* {@inheritdoc}
*/
public function getAllowedMethods(string $uri) : array
{
$dispatcher = $this->createDispatcher();
return $dispatcher->getAllowedMethods($uri);
}
}

View File

@@ -1,94 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use PleskRestApi\FastRoute\Dispatcher\GroupCountBased;
class FastRouteDispatcher extends GroupCountBased
{
/**
* @var string[][]
*/
private array $allowedMethods = [];
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array<string, string>}
*/
public function dispatch($httpMethod, $uri) : array
{
$routingResults = $this->routingResults($httpMethod, $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
$routingResults = $this->routingResults('GET', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
}
// If nothing else matches, try fallback routes
$routingResults = $this->routingResults('*', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
if (!empty($this->getAllowedMethods($uri))) {
return [self::METHOD_NOT_ALLOWED, null, []];
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array<string, string>}
*/
private function routingResults(string $httpMethod, string $uri) : array
{
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
/** @var string $routeIdentifier */
$routeIdentifier = $this->staticRouteMap[$httpMethod][$uri];
return [self::FOUND, $routeIdentifier, []];
}
if (isset($this->variableRouteData[$httpMethod])) {
/** @var array{0: int, 1?: string, 2?: array<string, string>} $result */
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
/** @var array{int, string, array<string, string>} $result */
return [self::FOUND, $result[1], $result[2]];
}
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri) : array
{
if (isset($this->allowedMethods[$uri])) {
return $this->allowedMethods[$uri];
}
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if (isset($uriMap[$uri])) {
$allowedMethods[$method] = \true;
}
}
foreach ($this->variableRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[$method] = \true;
}
}
return $this->allowedMethods[$uri] = \array_keys($allowedMethods);
}
}

View File

@@ -1,303 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use PleskRestApi\Slim\Handlers\Strategies\RequestHandler;
use PleskRestApi\Slim\Handlers\Strategies\RequestResponse;
use PleskRestApi\Slim\Interfaces\AdvancedCallableResolverInterface;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\InvocationStrategyInterface;
use PleskRestApi\Slim\Interfaces\RequestHandlerInvocationStrategyInterface;
use PleskRestApi\Slim\Interfaces\RouteGroupInterface;
use PleskRestApi\Slim\Interfaces\RouteInterface;
use PleskRestApi\Slim\MiddlewareDispatcher;
use function array_key_exists;
use function array_replace;
use function array_reverse;
use function class_implements;
use function in_array;
use function is_array;
/**
* @api
* @template TContainerInterface of (ContainerInterface|null)
*/
class Route implements RouteInterface, RequestHandlerInterface
{
/**
* HTTP methods supported by this route
*
* @var string[]
*/
protected array $methods = [];
/**
* Route identifier
*/
protected string $identifier;
/**
* Route name
*/
protected ?string $name = null;
/**
* Parent route groups
*
* @var RouteGroupInterface[]
*/
protected array $groups;
protected InvocationStrategyInterface $invocationStrategy;
/**
* Route parameters
*
* @var array<string, string>
*/
protected array $arguments = [];
/**
* Route arguments parameters
*
* @var array<string, string>
*/
protected array $savedArguments = [];
/**
* Container
* @var TContainerInterface $container
*/
protected ?ContainerInterface $container = null;
/** @var MiddlewareDispatcher<TContainerInterface> $middlewareDispatcher */
protected MiddlewareDispatcher $middlewareDispatcher;
/**
* Route callable
*
* @var callable|array{class-string, string}|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
/**
* Route pattern
*/
protected string $pattern;
protected bool $groupMiddlewareAppended = \false;
/**
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable|array{class-string, string}|string $callable The route callable
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param TContainerInterface $container
* @param InvocationStrategyInterface|null $invocationStrategy
* @param RouteGroupInterface[] $groups The parent route groups
* @param int $identifier The route identifier
*/
public function __construct(array $methods, string $pattern, $callable, ResponseFactoryInterface $responseFactory, CallableResolverInterface $callableResolver, ?ContainerInterface $container = null, ?InvocationStrategyInterface $invocationStrategy = null, array $groups = [], int $identifier = 0)
{
$this->methods = $methods;
$this->pattern = $pattern;
$this->callable = $callable;
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->invocationStrategy = $invocationStrategy ?? new RequestResponse();
$this->groups = $groups;
$this->identifier = 'route' . $identifier;
$this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container);
}
public function getCallableResolver() : CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getInvocationStrategy() : InvocationStrategyInterface
{
return $this->invocationStrategy;
}
/**
* {@inheritdoc}
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy) : RouteInterface
{
$this->invocationStrategy = $invocationStrategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getMethods() : array
{
return $this->methods;
}
/**
* {@inheritdoc}
*/
public function getPattern() : string
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function setPattern(string $pattern) : RouteInterface
{
$this->pattern = $pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCallable()
{
return $this->callable;
}
/**
* {@inheritdoc}
*/
public function setCallable($callable) : RouteInterface
{
$this->callable = $callable;
return $this;
}
/**
* {@inheritdoc}
*/
public function getName() : ?string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName(string $name) : RouteInterface
{
$this->name = $name;
return $this;
}
/**
* {@inheritdoc}
*/
public function getIdentifier() : string
{
return $this->identifier;
}
/**
* {@inheritdoc}
*/
public function getArgument(string $name, ?string $default = null) : ?string
{
if (array_key_exists($name, $this->arguments)) {
return $this->arguments[$name];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getArguments() : array
{
return $this->arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments, bool $includeInSavedArguments = \true) : RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments = $arguments;
}
$this->arguments = $arguments;
return $this;
}
/**
* @return RouteGroupInterface[]
*/
public function getGroups() : array
{
return $this->groups;
}
/**
* {@inheritdoc}
*/
public function add($middleware) : RouteInterface
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware) : RouteInterface
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function prepare(array $arguments) : RouteInterface
{
$this->arguments = array_replace($this->savedArguments, $arguments);
return $this;
}
/**
* {@inheritdoc}
*/
public function setArgument(string $name, string $value, bool $includeInSavedArguments = \true) : RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments[$name] = $value;
}
$this->arguments[$name] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function run(ServerRequestInterface $request) : ResponseInterface
{
if (!$this->groupMiddlewareAppended) {
$this->appendGroupMiddlewareToRoute();
}
return $this->middlewareDispatcher->handle($request);
}
/**
* @return void
*/
protected function appendGroupMiddlewareToRoute() : void
{
$inner = $this->middlewareDispatcher;
$this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container);
foreach (array_reverse($this->groups) as $group) {
$group->appendMiddlewareToDispatcher($this->middlewareDispatcher);
}
$this->groupMiddlewareAppended = \true;
}
/**
* {@inheritdoc}
*/
public function handle(ServerRequestInterface $request) : ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$strategy = $this->invocationStrategy;
$strategyImplements = class_implements($strategy);
if (is_array($callable) && $callable[0] instanceof RequestHandlerInterface && !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements)) {
$strategy = new RequestHandler();
}
$response = $this->responseFactory->createResponse();
return $strategy($callable, $request, $response, $this->arguments);
}
}

View File

@@ -1,232 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use RuntimeException;
use PleskRestApi\Slim\Handlers\Strategies\RequestResponse;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\InvocationStrategyInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorProxyInterface;
use PleskRestApi\Slim\Interfaces\RouteGroupInterface;
use PleskRestApi\Slim\Interfaces\RouteInterface;
use PleskRestApi\Slim\Interfaces\RouteParserInterface;
use function array_pop;
use function dirname;
use function file_exists;
use function is_readable;
use function is_writable;
use function sprintf;
/**
* RouteCollector is used to collect routes and route groups
* as well as generate paths and URLs relative to its environment
* @template TContainerInterface of (ContainerInterface|null)
*/
class RouteCollector implements RouteCollectorInterface
{
protected RouteParserInterface $routeParser;
protected CallableResolverInterface $callableResolver;
protected ?ContainerInterface $container = null;
protected InvocationStrategyInterface $defaultInvocationStrategy;
/**
* Base path used in pathFor()
*/
protected string $basePath = '';
/**
* Path to fast route cache file. Set to null to disable route caching
*/
protected ?string $cacheFile = null;
/**
* Routes
*
* @var RouteInterface[]
*/
protected array $routes = [];
/**
* Routes indexed by name
*
* @var RouteInterface[]
*/
protected array $routesByName = [];
/**
* Route groups
*
* @var RouteGroupInterface[]
*/
protected array $routeGroups = [];
/**
* Route counter incrementer
*/
protected int $routeCounter = 0;
protected ResponseFactoryInterface $responseFactory;
/**
* @param TContainerInterface $container
*/
public function __construct(ResponseFactoryInterface $responseFactory, CallableResolverInterface $callableResolver, ?ContainerInterface $container = null, ?InvocationStrategyInterface $defaultInvocationStrategy = null, ?RouteParserInterface $routeParser = null, ?string $cacheFile = null)
{
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse();
$this->routeParser = $routeParser ?? new RouteParser($this);
if ($cacheFile) {
$this->setCacheFile($cacheFile);
}
}
public function getRouteParser() : RouteParserInterface
{
return $this->routeParser;
}
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy() : InvocationStrategyInterface
{
return $this->defaultInvocationStrategy;
}
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy) : RouteCollectorInterface
{
$this->defaultInvocationStrategy = $strategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCacheFile() : ?string
{
return $this->cacheFile;
}
/**
* {@inheritdoc}
*/
public function setCacheFile(string $cacheFile) : RouteCollectorInterface
{
if (file_exists($cacheFile) && !is_readable($cacheFile)) {
throw new RuntimeException(sprintf('Route collector cache file `%s` is not readable', $cacheFile));
}
if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {
throw new RuntimeException(sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile)));
}
$this->cacheFile = $cacheFile;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBasePath() : string
{
return $this->basePath;
}
/**
* Set the base path used in urlFor()
*/
public function setBasePath(string $basePath) : RouteCollectorInterface
{
$this->basePath = $basePath;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRoutes() : array
{
return $this->routes;
}
/**
* {@inheritdoc}
*/
public function removeNamedRoute(string $name) : RouteCollectorInterface
{
$route = $this->getNamedRoute($name);
/** @psalm-suppress PossiblyNullArrayOffset */
unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getNamedRoute(string $name) : RouteInterface
{
if (isset($this->routesByName[$name])) {
$route = $this->routesByName[$name];
if ($route->getName() === $name) {
return $route;
}
unset($this->routesByName[$name]);
}
foreach ($this->routes as $route) {
if ($name === $route->getName()) {
$this->routesByName[$name] = $route;
return $route;
}
}
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
/**
* {@inheritdoc}
*/
public function lookupRoute(string $identifier) : RouteInterface
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable) : RouteGroupInterface
{
$routeGroup = $this->createGroup($pattern, $callable);
$this->routeGroups[] = $routeGroup;
$routeGroup->collectRoutes();
array_pop($this->routeGroups);
return $routeGroup;
}
/**
* @param string|callable $callable
*/
protected function createGroup(string $pattern, $callable) : RouteGroupInterface
{
$routeCollectorProxy = $this->createProxy($pattern);
return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy);
}
/**
* @return RouteCollectorProxyInterface<TContainerInterface>
*/
protected function createProxy(string $pattern) : RouteCollectorProxyInterface
{
/** @var RouteCollectorProxy<TContainerInterface> */
return new RouteCollectorProxy($this->responseFactory, $this->callableResolver, $this->container, $this, $pattern);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $handler) : RouteInterface
{
$route = $this->createRoute($methods, $pattern, $handler);
$this->routes[$route->getIdentifier()] = $route;
$routeName = $route->getName();
if ($routeName !== null && !isset($this->routesByName[$routeName])) {
$this->routesByName[$routeName] = $route;
}
$this->routeCounter++;
return $route;
}
/**
* @param string[] $methods
* @param callable|array{class-string, string}|string $callable
*/
protected function createRoute(array $methods, string $pattern, $callable) : RouteInterface
{
return new Route($methods, $pattern, $callable, $this->responseFactory, $this->callableResolver, $this->container, $this->defaultInvocationStrategy, $this->routeGroups, $this->routeCounter);
}
}

View File

@@ -1,162 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorProxyInterface;
use PleskRestApi\Slim\Interfaces\RouteGroupInterface;
use PleskRestApi\Slim\Interfaces\RouteInterface;
/**
* @template TContainerInterface of (ContainerInterface|null)
* @template-implements RouteCollectorProxyInterface<TContainerInterface>
*/
class RouteCollectorProxy implements RouteCollectorProxyInterface
{
protected ResponseFactoryInterface $responseFactory;
protected CallableResolverInterface $callableResolver;
/** @var TContainerInterface */
protected ?ContainerInterface $container = null;
protected RouteCollectorInterface $routeCollector;
protected string $groupPattern;
/**
* @param TContainerInterface $container
*/
public function __construct(ResponseFactoryInterface $responseFactory, CallableResolverInterface $callableResolver, ?ContainerInterface $container = null, ?RouteCollectorInterface $routeCollector = null, string $groupPattern = '')
{
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
$this->groupPattern = $groupPattern;
}
/**
* {@inheritdoc}
*/
public function getResponseFactory() : ResponseFactoryInterface
{
return $this->responseFactory;
}
/**
* {@inheritdoc}
*/
public function getCallableResolver() : CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
* @return TContainerInterface
*/
public function getContainer() : ?ContainerInterface
{
return $this->container;
}
/**
* {@inheritdoc}
*/
public function getRouteCollector() : RouteCollectorInterface
{
return $this->routeCollector;
}
/**
* {@inheritdoc}
*/
public function getBasePath() : string
{
return $this->routeCollector->getBasePath();
}
/**
* {@inheritdoc}
*/
public function setBasePath(string $basePath) : RouteCollectorProxyInterface
{
$this->routeCollector->setBasePath($basePath);
return $this;
}
/**
* {@inheritdoc}
*/
public function get(string $pattern, $callable) : RouteInterface
{
return $this->map(['GET'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function post(string $pattern, $callable) : RouteInterface
{
return $this->map(['POST'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function put(string $pattern, $callable) : RouteInterface
{
return $this->map(['PUT'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function patch(string $pattern, $callable) : RouteInterface
{
return $this->map(['PATCH'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function delete(string $pattern, $callable) : RouteInterface
{
return $this->map(['DELETE'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function options(string $pattern, $callable) : RouteInterface
{
return $this->map(['OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function any(string $pattern, $callable) : RouteInterface
{
return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $callable) : RouteInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->map($methods, $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable) : RouteGroupInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->group($pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function redirect(string $from, $to, int $status = 302) : RouteInterface
{
$responseFactory = $this->responseFactory;
$handler = function () use($to, $status, $responseFactory) {
$response = $responseFactory->createResponse($status);
return $response->withHeader('Location', (string) $to);
};
return $this->get($from, $handler);
}
}

View File

@@ -1,67 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\RouteInterface;
use PleskRestApi\Slim\Interfaces\RouteParserInterface;
/** @api */
final class RouteContext
{
public const ROUTE = '__route__';
public const ROUTE_PARSER = '__routeParser__';
public const ROUTING_RESULTS = '__routingResults__';
public const BASE_PATH = '__basePath__';
public static function fromRequest(ServerRequestInterface $serverRequest) : self
{
$route = $serverRequest->getAttribute(self::ROUTE);
$routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);
$routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);
$basePath = $serverRequest->getAttribute(self::BASE_PATH);
if ($routeParser === null || $routingResults === null) {
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
}
/** @var RouteInterface|null $route */
/** @var RouteParserInterface $routeParser */
/** @var RoutingResults $routingResults */
/** @var string|null $basePath */
return new self($route, $routeParser, $routingResults, $basePath);
}
private ?RouteInterface $route;
private RouteParserInterface $routeParser;
private RoutingResults $routingResults;
private ?string $basePath;
private function __construct(?RouteInterface $route, RouteParserInterface $routeParser, RoutingResults $routingResults, ?string $basePath = null)
{
$this->route = $route;
$this->routeParser = $routeParser;
$this->routingResults = $routingResults;
$this->basePath = $basePath;
}
public function getRoute() : ?RouteInterface
{
return $this->route;
}
public function getRouteParser() : RouteParserInterface
{
return $this->routeParser;
}
public function getRoutingResults() : RoutingResults
{
return $this->routingResults;
}
public function getBasePath() : string
{
if ($this->basePath === null) {
throw new RuntimeException('No base path defined.');
}
return $this->basePath;
}
}

View File

@@ -1,91 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Http\Server\MiddlewareInterface;
use PleskRestApi\Slim\Interfaces\AdvancedCallableResolverInterface;
use PleskRestApi\Slim\Interfaces\CallableResolverInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorProxyInterface;
use PleskRestApi\Slim\Interfaces\RouteGroupInterface;
use PleskRestApi\Slim\MiddlewareDispatcher;
class RouteGroup implements RouteGroupInterface
{
/**
* @var callable|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
/**
* @var RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null>
*/
protected RouteCollectorProxyInterface $routeCollectorProxy;
/**
* @var MiddlewareInterface[]|string[]|callable[]
*/
protected array $middleware = [];
protected string $pattern;
/**
* @param callable|string $callable
* @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy
*/
public function __construct(string $pattern, $callable, CallableResolverInterface $callableResolver, RouteCollectorProxyInterface $routeCollectorProxy)
{
$this->pattern = $pattern;
$this->callable = $callable;
$this->callableResolver = $callableResolver;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* {@inheritdoc}
*/
public function collectRoutes() : RouteGroupInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$callable($this->routeCollectorProxy);
return $this;
}
/**
* {@inheritdoc}
*/
public function add($middleware) : RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware) : RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
* @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher) : RouteGroupInterface
{
foreach ($this->middleware as $middleware) {
$dispatcher->add($middleware);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getPattern() : string
{
return $this->pattern;
}
}

View File

@@ -1,108 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use PleskRestApi\FastRoute\RouteParser\Std;
use InvalidArgumentException;
use Psr\Http\Message\UriInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteParserInterface;
use function array_key_exists;
use function array_reverse;
use function http_build_query;
use function implode;
use function is_string;
class RouteParser implements RouteParserInterface
{
private RouteCollectorInterface $routeCollector;
private Std $routeParser;
public function __construct(RouteCollectorInterface $routeCollector)
{
$this->routeCollector = $routeCollector;
$this->routeParser = new Std();
}
/**
* {@inheritdoc}
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []) : string
{
$route = $this->routeCollector->getNamedRoute($routeName);
$pattern = $route->getPattern();
$segments = [];
$segmentName = '';
/*
* $routes is an associative array of expressions representing a route as multiple segments
* There is an expression for each optional parameter plus one without the optional parameters
* The most specific is last, hence why we reverse the array before iterating over it
*/
$expressions = array_reverse($this->routeParser->parse($pattern));
foreach ($expressions as $expression) {
foreach ($expression as $segment) {
/*
* Each $segment is either a string or an array of strings
* containing optional parameters of an expression
*/
if (is_string($segment)) {
$segments[] = $segment;
continue;
}
/** @var string[] $segment */
/*
* If we don't have a data element for this segment in the provided $data
* we cancel testing to move onto the next expression with a less specific item
*/
if (!array_key_exists($segment[0], $data)) {
$segments = [];
$segmentName = $segment[0];
break;
}
$segments[] = $data[$segment[0]];
}
/*
* If we get to this logic block we have found all the parameters
* for the provided $data which means we don't need to continue testing
* less specific expressions
*/
if (!empty($segments)) {
break;
}
}
if (empty($segments)) {
throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
}
$url = implode('', $segments);
if ($queryParams) {
$url .= '?' . http_build_query($queryParams);
}
return $url;
}
/**
* {@inheritdoc}
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []) : string
{
$basePath = $this->routeCollector->getBasePath();
$url = $this->relativeUrlFor($routeName, $data, $queryParams);
if ($basePath) {
$url = $basePath . $url;
}
return $url;
}
/**
* {@inheritdoc}
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []) : string
{
$path = $this->urlFor($routeName, $data, $queryParams);
$scheme = $uri->getScheme();
$authority = $uri->getAuthority();
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
return $protocol . $path;
}
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use RuntimeException;
use PleskRestApi\Slim\Interfaces\DispatcherInterface;
use PleskRestApi\Slim\Interfaces\RouteCollectorInterface;
use PleskRestApi\Slim\Interfaces\RouteInterface;
use PleskRestApi\Slim\Interfaces\RouteResolverInterface;
use function rawurldecode;
/**
* RouteResolver instantiates the FastRoute dispatcher
* and computes the routing results of a given URI and request method
*/
class RouteResolver implements RouteResolverInterface
{
protected RouteCollectorInterface $routeCollector;
private DispatcherInterface $dispatcher;
public function __construct(RouteCollectorInterface $routeCollector, ?DispatcherInterface $dispatcher = null)
{
$this->routeCollector = $routeCollector;
$this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector);
}
/**
* @param string $uri Should be $request->getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method) : RoutingResults
{
$uri = rawurldecode($uri);
if ($uri === '' || $uri[0] !== '/') {
$uri = '/' . $uri;
}
return $this->dispatcher->dispatch($method, $uri);
}
/**
* @throws RuntimeException
*/
public function resolveRoute(string $identifier) : RouteInterface
{
return $this->routeCollector->lookupRoute($identifier);
}
}

View File

@@ -1,61 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use PleskRestApi\Slim\Exception\HttpMethodNotAllowedException;
use PleskRestApi\Slim\Exception\HttpNotFoundException;
use PleskRestApi\Slim\Interfaces\RouteCollectorProxyInterface;
use PleskRestApi\Slim\Interfaces\RouteParserInterface;
use PleskRestApi\Slim\Interfaces\RouteResolverInterface;
use PleskRestApi\Slim\Middleware\RoutingMiddleware;
class RouteRunner implements RequestHandlerInterface
{
private RouteResolverInterface $routeResolver;
private RouteParserInterface $routeParser;
/**
* @var RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null>
*/
private ?RouteCollectorProxyInterface $routeCollectorProxy;
/**
* @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy
*/
public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser, ?RouteCollectorProxyInterface $routeCollectorProxy = null)
{
$this->routeResolver = $routeResolver;
$this->routeParser = $routeParser;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* This request handler is instantiated automatically in App::__construct()
* It is at the very tip of the middleware queue meaning it will be executed
* last and it detects whether or not routing has been performed in the user
* defined middleware stack. In the event that the user did not perform routing
* it is done here
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function handle(ServerRequestInterface $request) : ResponseInterface
{
// If routing hasn't been done, then do it now so we can dispatch
if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) {
$routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser);
$request = $routingMiddleware->performRouting($request);
}
if ($this->routeCollectorProxy !== null) {
$request = $request->withAttribute(RouteContext::BASE_PATH, $this->routeCollectorProxy->getBasePath());
}
/** @var Route<\Psr\Container\ContainerInterface|null> $route */
$route = $request->getAttribute(RouteContext::ROUTE);
return $route->run($request);
}
}

View File

@@ -1,87 +0,0 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
declare (strict_types=1);
namespace PleskRestApi\Slim\Routing;
use PleskRestApi\Slim\Interfaces\DispatcherInterface;
use function rawurldecode;
/** @api */
class RoutingResults
{
public const NOT_FOUND = 0;
public const FOUND = 1;
public const METHOD_NOT_ALLOWED = 2;
protected DispatcherInterface $dispatcher;
protected string $method;
protected string $uri;
/**
* The status is one of the constants shown above
* NOT_FOUND = 0
* FOUND = 1
* METHOD_NOT_ALLOWED = 2
*/
protected int $routeStatus;
protected ?string $routeIdentifier = null;
/**
* @var array<string, string>
*/
protected array $routeArguments;
/**
* @param array<string, string> $routeArguments
*/
public function __construct(DispatcherInterface $dispatcher, string $method, string $uri, int $routeStatus, ?string $routeIdentifier = null, array $routeArguments = [])
{
$this->dispatcher = $dispatcher;
$this->method = $method;
$this->uri = $uri;
$this->routeStatus = $routeStatus;
$this->routeIdentifier = $routeIdentifier;
$this->routeArguments = $routeArguments;
}
public function getDispatcher() : DispatcherInterface
{
return $this->dispatcher;
}
public function getMethod() : string
{
return $this->method;
}
public function getUri() : string
{
return $this->uri;
}
public function getRouteStatus() : int
{
return $this->routeStatus;
}
public function getRouteIdentifier() : ?string
{
return $this->routeIdentifier;
}
/**
* @return array<string, string>
*/
public function getRouteArguments(bool $urlDecode = \true) : array
{
if (!$urlDecode) {
return $this->routeArguments;
}
$routeArguments = [];
foreach ($this->routeArguments as $key => $value) {
$routeArguments[$key] = rawurldecode($value);
}
return $routeArguments;
}
/**
* @return string[]
*/
public function getAllowedMethods() : array
{
return $this->dispatcher->getAllowedMethods($this->uri);
}
}