This commit is contained in:
2021-09-10 10:45:24 +08:00
parent dca5d3e6ec
commit f217a14f23
29 changed files with 148 additions and 1544 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
namespace Server\Constrict;
use Server\ResponseInterface;
use Server\Constrict\ResponseInterface;
interface Emitter
{
-2
View File
@@ -12,8 +12,6 @@ use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
use Server\Message\Response;
use Server\RequestInterface;
use Server\ResponseInterface;
class Request implements RequestInterface
@@ -1,6 +1,6 @@
<?php
namespace Server;
namespace Server\Constrict;
use Http\IInterface\AuthIdentity;
-2
View File
@@ -10,8 +10,6 @@ use Kiri\Kiri;
use Psr\Http\Message\StreamInterface;
use Server\Message\Request as RequestMessage;
use Server\Message\Response as Psr7Response;
use Server\RequestInterface;
use Server\ResponseInterface;
use Server\ServerManager;
use Server\SInterface\DownloadInterface;
@@ -3,8 +3,6 @@
namespace Server\Constrict;
use Annotation\Inject;
use Server\ResponseInterface;
use Server\RequestInterface;
use Server\SInterface\DownloadInterface;
use Swoole\Server;
@@ -1,6 +1,6 @@
<?php
namespace Server;
namespace Server\Constrict;
use JetBrains\PhpStorm\Pure;
+1 -1
View File
@@ -4,7 +4,7 @@ namespace Server\Constrict;
use Exception;
use Http\Context\Formatter\FileFormatter;
use Server\ResponseInterface;
use Server\Constrict\ResponseInterface;
use Swoole\Server;
+1 -1
View File
@@ -3,7 +3,7 @@
namespace Server\Constrict;
use Kiri\Exception\NotFindClassException;
use Server\ResponseInterface;
use Server\Constrict\ResponseInterface;
use Swoole\Server;
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Server\Constrict;
use Exception;
use Kiri\Kiri;
use Server\ServerManager;
use Server\ResponseInterface;
use Server\Constrict\ResponseInterface;
/**
*
-105
View File
@@ -1,105 +0,0 @@
<?php
namespace Server\Message;
use Server\SInterface\DownloadInterface;
class Download extends Response implements DownloadInterface
{
use Message;
private string $path;
private bool $isChunk;
private int $size;
private int $offset;
const IMAGES = [
'png' => 'image/png',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'svg' => 'image/svg+xml',
];
/**
* @param string $path
* @param false $isChunk
* @param int $size
* @param int $offset
* @return $this
*/
public function path(string $path, bool $isChunk = false, int $size = -1, int $offset = 0): Download
{
$this->path = $path;
$this->isChunk = $isChunk;
$this->size = $size;
$this->offset = $offset;
return $this->emitter();
}
/**
* @return $this
*/
public function emitter(): static
{
$explode = explode('/', $this->path);
$this->withHeader('Pragma', 'public');
$this->withHeader('Expires', '0');
$this->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
$this->withHeader('Content-Disposition', 'attachment;filename=' . end($explode));
$this->withHeader('Content-Type', $type = get_file_extension($this->path));
if (!in_array($type, self::IMAGES)) {
$this->withHeader('Content-Transfer-Encoding', 'binary');
}
if ($this->isChunk) {
$resource = fopen($this->path, 'r');
$state = fstat($resource);
$this->withHeader('Content-length', $state['size']);
}
return $this;
}
/**
* @param \Swoole\Http\Response $response
*/
public function dispatch(mixed $response)
{
if (!$this->isChunk) {
$response->sendfile($this->path);
} else {
$this->chunk($response);
}
}
/**
* @param \Swoole\Http\Response $response
*/
private function chunk(\Swoole\Http\Response $response): void
{
$resource = fopen($this->path, 'r');
$state = fstat($resource);
$offset = $this->offset;
while ($file = fread($resource, $this->size)) {
$response->write($file);
fseek($resource, $offset);
if ($offset >= $state['size']) {
break;
}
$offset += $this->size;
}
$response->end();
}
}
-44
View File
@@ -1,44 +0,0 @@
<?php
namespace Server\Message;
class Headers
{
private array $headers = [];
/**
* @param array $headers
* @return $this
*/
public function withHeader(array $headers): static
{
$class = clone $this;
$class->headers = $headers;
return $class;
}
/**
* @param $name
* @param null $default
* @return string|array|float|int|null
*/
public function get($name, $default = null): string|array|float|int|null
{
return $this->headers[$name] ?? $default;
}
/**
* @return array
*/
public function toArray(): array
{
return $this->headers;
}
}
-295
View File
@@ -1,295 +0,0 @@
<?php
namespace Server\Message;
use JetBrains\PhpStorm\Pure;
use Kiri\Core\Xml;
use Psr\Http\Message\StreamInterface;
use Server\RequestInterface;
use Server\ResponseInterface;
/**
*
*/
trait Message
{
public string $version;
public StreamInterface $stream;
public array $headers = [];
public array $servers = [];
public array $cookies = [];
/**
* @return array
*/
public function getServers(): array
{
return $this->servers;
}
/**
* @return string
*/
public function getProtocolVersion(): string
{
return $this->version;
}
/**
* @param $name
* @param null $value
* @param null $expires
* @param null $path
* @param null $domain
* @param null $secure
* @param null $httponly
* @param null $samesite
* @param null $priority
* @return static
*/
public function withCookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null, $priority = null): static
{
$this->cookies[$name] = [$value, $expires, $path, $domain, $secure, $httponly, $samesite, $priority];
return $this;
}
/**
* @return array
*/
public function getCookie(): array
{
return $this->cookies;
}
/**
* @return string|null
*/
#[Pure] public function getAccessControlAllowOrigin(): ?string
{
return $this->getHeaderLine('Access-Control-Allow-Origin');
}
/**
* @return string|null
*/
#[Pure] public function getAccessControlAllowHeaders(): ?string
{
return $this->getHeaderLine('Access-Control-Allow-Headers');
}
/**
* @return string|null
*/
#[Pure] public function getAccessControlRequestMethod(): ?string
{
return $this->getHeaderLine('Access-Control-Request-Method');
}
/**
* @param $version
* @return static
*/
public function withProtocolVersion($version): static
{
$this->version = $version;
return $this;
}
/**
* @return array
*/
public function getHeaders(): array
{
return $this->headers;
}
/**
* @return array
*/
public function getCookies(): array
{
return $this->cookies;
}
/**
* @param $name
* @return bool
*/
public function hasHeader($name): bool
{
return array_key_exists($name, $this->headers);
}
/**
* @param $name
* @return string|array|null
*/
#[Pure] public function getHeader($name): string|null|array
{
if (!$this->hasHeader($name)) {
return null;
}
return $this->headers[$name];
}
/**
* @param \Swoole\Http\Request $request
* @return static
*/
private function parseRequestHeaders(\Swoole\Http\Request $request): static
{
$index = strpos($request->getData(), "\r\n\r\n");
$headers = explode("\r\n", substr($request->getData(), 0, $index));
array_shift($headers);
foreach ($headers as $header) {
[$key, $value] = explode(': ', $header);
$this->addRequestHeader($key, $value);
}
return $this;
}
/**
* @param $key
* @param $value
*/
private function addRequestHeader($key, $value)
{
$this->headers[$key] = [$value];
}
/**
* @param $name
* @return string|null
*/
#[Pure] public function getHeaderLine($name): string|null
{
if ($this->hasHeader($name)) {
return implode(';', $this->headers[$name]);
}
return null;
}
/**
* @param $name
* @param $value
* @return static
*/
public function withHeader($name, $value): static
{
if (!is_array($value)) {
$value = [$value];
}
$this->headers[$name] = $value;
return $this;
}
/**
* @param $name
* @param $value
* @return static
* @throws
*/
public function withAddedHeader($name, $value): static
{
if (!array_key_exists($name, $this->headers)) {
throw new \Exception('Headers `' . $name . '` not exists.');
}
$this->headers[$name][] = $value;
return $this;
}
/**
* @param $name
* @return static
*/
public function withoutHeader($name): static
{
unset($this->headers[$name]);
return $this;
}
/**
* @return string
*/
#[Pure] public function getBody(): string
{
return $this->stream->getContents();
}
/**
* @param StreamInterface $body
* @return static
*/
public function withBody(StreamInterface $body): static
{
$this->stream = $body;
return $this;
}
/**
* @param StreamInterface $stream
* @return mixed
*/
public function parseBody(StreamInterface $stream): mixed
{
$content = $stream->getContents();
if (empty($content)) {
return $content;
}
$contentType = $this->getHeaderLine('content-type');
if (str_contains($contentType, 'json')) {
return json_encode($contentType);
}
if (str_contains($contentType, 'xml')) {
return Xml::toArray($contentType);
}
if (str_contains($contentType, 'x-www-form-urlencoded')) {
parse_str($content, $array);
return $array;
}
if (str_contains($contentType, 'serialize')) {
return unserialize($content);
}
return $content;
}
/**
* @param $host
* @return static
*/
public function redirectTo($host): static
{
return $this->withHeader('Location', $host)
->withStatus(302);
}
}
-381
View File
@@ -1,381 +0,0 @@
<?php
namespace Server\Message;
use BadMethodCallException;
use Exception;
use Http\IInterface\AuthIdentity;
use JetBrains\PhpStorm\Pure;
use Psr\Http\Message\UriInterface;
use Server\RequestInterface;
/**
*
*/
class Request implements RequestInterface
{
use Message;
public string $requestTarget;
public string $method;
/**
* @var Uri|UriInterface
*/
private Uri|UriInterface $uri;
private \Swoole\Http\Request $serverRequest;
private array $parseBody;
private array $files = [];
/**
* @var AuthIdentity|null
*/
public ?AuthIdentity $authority = null;
/**
* @return int
*/
public function getClientId(): int
{
return $this->serverRequest->fd;
}
/**
* @param AuthIdentity $authority
*/
public function setAuthority(AuthIdentity $authority): void
{
$this->authority = $authority;
}
/**
* @param \Swoole\Http\Request $request
* @return RequestInterface
*/
public static function parseRequest(\Swoole\Http\Request $request): RequestInterface
{
$message = new Request();
$message->uri = Uri::parseUri($request);
$message->method = $request->getMethod();
$message->requestTarget = '';
$message->serverRequest = $request;
$message->version = $request->server['server_protocol'];
$message->stream = new Stream($request->getContent());
$message->servers = $request->server;
$message->parseRequestHeaders($request);
return $message;
}
/**
* @return float
*/
#[Pure] public function getStartTime(): float
{
return $this->servers['request_time_float'];
}
/**
* @param $name
* @param null $default
* @return mixed
*/
public function input($name, $default = null): mixed
{
if (empty($this->parseBody)) {
$this->parseBody = $this->parseBody($this->stream);
}
if (!is_array($this->parseBody)) {
return $default;
}
return $this->parseBody[$name] ?? $default;
}
/**
* @param $name
* @param null $default
* @return mixed
*/
public function post($name, $default = null): mixed
{
return $this->serverRequest->post[$name] ?? $default;
}
/**
* @param string $field
* @param int $max
* @return int
*/
public function size(string $field = 'size', int $max = 100): int
{
$size = (int)$this->query($field);
if ($size < 1) {
$size = 1;
} else if ($size > $max) {
$size = $max;
}
return $size;
}
/**
* @param string $field
* @param string $sizeField
* @param int $max
* @return float|int
*/
public function offset(string $field = 'page', string $sizeField = 'size', int $max = 100): float|int
{
$page = (int)$this->query($field);
if ($page < 1) {
$page = 1;
}
return ($page - 1) * $this->size($sizeField, $max);
}
/**
* @param string $name
* @param bool $required
* @return string|null
* @throws Exception
*/
public function string(string $name, bool $required = false): ?string
{
if (is_null($data = $this->post($name))) {
if ($required) {
throw new Exception('Parameter is required and cannot be empty.');
}
return null;
}
return (string)$data;
}
/**
* @param string $name
* @param bool $required
* @return int|null
* @throws Exception
*/
public function int(string $name, bool $required = false): ?int
{
if (is_null($data = $this->post($name))) {
if ($required) {
throw new Exception('Parameter is required and cannot be empty.');
}
return null;
}
return (string)$data;
}
/**
* @param string $name
* @param bool $required
* @return float|null
* @throws Exception
*/
public function float(string $name, bool $required = false): ?float
{
if (is_null($data = $this->post($name))) {
if ($required) {
throw new Exception('Parameter is required and cannot be empty.');
}
return null;
}
return (float)$data;
}
/**
* @param string $name
* @param array $default
* @return mixed
*/
public function array(string $name, array $default = []): array
{
$data = $this->post($name);
if (!is_array($data)) {
return $default;
}
return $data;
}
/**
* @return array|null
*/
public function gets(): ?array
{
return $this->serverRequest->get;
}
/**
* @param $name
* @param null $default
* @return mixed
*/
public function query($name, $default = null): mixed
{
return $this->serverRequest->get[$name] ?? $default;
}
/**
* @param $name
* @return Uploaded|null
*/
public function file($name): ?Uploaded
{
if (isset($this->serverRequest->files[$name])) {
return new Uploaded($this->serverRequest->files[$name]);
}
return null;
}
/**
* @return array
*/
public function all(): array
{
if (empty($this->parseBody)) {
$this->parseBody = $this->parseBody($this->stream);
}
return array_merge($this->serverRequest->post ?? [],
$this->serverRequest->get ?? [],
is_array($this->parseBody) ? $this->parseBody : []
);
}
/**
* @return string
*/
public function getRequestTarget(): string
{
throw new BadMethodCallException('Not Accomplish Method.');
}
/**
* @param mixed $requestTarget
* @return RequestInterface
*/
public function withRequestTarget($requestTarget): RequestInterface
{
$this->requestTarget = $requestTarget;
return $this;
}
/**
* @return string
*/
public function getMethod(): string
{
return $this->method;
}
/**
* @param string $method
* @return bool
*/
public function isMethod(string $method): bool
{
return $this->method === $method;
}
/**
* @param string $method
* @return RequestInterface
*/
public function withMethod($method): RequestInterface
{
$class = clone $this;
$class->method = $method;
return $class;
}
/**
* @return Uri|UriInterface
*/
public function getUri(): Uri|UriInterface
{
return $this->uri;
}
/**
* @param UriInterface $uri
* @param false $preserveHost
* @return RequestInterface
*/
public function withUri(UriInterface $uri, $preserveHost = false): RequestInterface
{
$class = clone $this;
$class->uri = $uri;
return $class;
}
/**
* @param string $name
* @param bool $required
* @return string|null
* @throws Exception
*/
public function date(string $name, bool $required = false): ?string
{
$param = $this->post($name, null);
if (empty($param)) {
if ($required) {
throw new Exception('Required ' . $name . ' is must.');
}
return $param;
}
return $param;
}
/**
* @param string $name
* @param bool $required
* @return int|null
* @throws Exception
*/
public function timestamp(string $name, bool $required = false): ?int
{
$param = $this->post($name, null);
if (empty($param)) {
if ($required) {
throw new Exception('Required ' . $name . ' is must.');
}
return $param;
}
return (int)$param;
}
}
-208
View File
@@ -1,208 +0,0 @@
<?php
namespace Server\Message;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Core\Help;
use Kiri\ToArray;
use Psr\Http\Message\ResponseInterface;
use Server\SInterface\DownloadInterface;
/**
*
*/
class Response implements ResponseInterface, \Server\ResponseInterface
{
use Message;
public int $statusCode = 200;
public string $reasonPhrase = '';
const CONTENT_TYPE_JSON = 'application/json;charset=utf-8';
const CONTENT_TYPE_HTML = 'text/html;charset=utf-8';
const CONTENT_TYPE_STREAM = 'octet-stream';
const CONTENT_TYPE_XML = 'application/xml;charset=utf-8';
/**
*
*/
#[Pure] public function __construct()
{
$this->stream = new Stream('');
}
/**
* @param string $type
* @return $this
* @throws Exception
*/
public function withContentType(string $type): static
{
return $this->withHeader('Content-Type', $type);
}
/**
* @return bool
*/
#[Pure] public function hasContentType(): bool
{
return $this->hasHeader('Content-Type');
}
/**
* @return string
*/
#[Pure] public function getContentType(): string
{
return $this->getHeaderLine('Content-Type');
}
/**
* @return int
*/
public function getStatusCode(): int
{
// TODO: Implement getStatusCode() method.
return $this->statusCode;
}
/**
* @param int $code
* @param string $reasonPhrase
* @return static
*/
public function withStatus($code, $reasonPhrase = ''): static
{
$this->statusCode = $code;
$this->reasonPhrase = $reasonPhrase;
return $this;
}
/**
* @return string
*/
public function getReasonPhrase(): string
{
// TODO: Implement getReasonPhrase() method.
return $this->reasonPhrase;
}
/**
* @param string|null $value
* @return Response
*/
public function withAccessControlAllowHeaders(?string $value): static
{
return $this->withHeader('Access-Control-Allow-Headers', $value);
}
/**
* @param string|null $value
* @return Response
*/
public function withAccessControlRequestMethod(?string $value): static
{
return $this->withHeader('Access-Control-Request-Method', $value);
}
/**
* @param string|null $value
* @return Response
*/
public function withAccessControlAllowOrigin(?string $value): static
{
return $this->withHeader('Access-Control-Allow-Origin', $value);
}
/**
* @param $data
* @return \Server\ResponseInterface
* @throws Exception
*/
public function json($data): \Server\ResponseInterface
{
if (!is_array($data = $this->_toArray($data))) {
throw new Exception('Json data format error.');
}
$this->stream->write(json_encode($this->_toArray($data)));
return $this->withContentType(self::CONTENT_TYPE_JSON);
}
/**
* @param $data
* @return \Server\ResponseInterface
* @throws Exception
*/
public function html($data): \Server\ResponseInterface
{
$this->stream->write((string)$this->_toArray($data));
return $this->withContentType(self::CONTENT_TYPE_HTML);
}
/**
* @param $data
* @return \Server\ResponseInterface
* @throws Exception
*/
public function xml($data): \Server\ResponseInterface
{
if (!is_array($data = $this->_toArray($data))) {
throw new Exception('Xml data format error.');
}
$this->stream->write(Help::toXml($data));
return $this->withContentType(self::CONTENT_TYPE_XML);
}
/**
* @param $path
* @param bool $isChunk
* @param int $size
* @param int $offset
* @return DownloadInterface
* @throws Exception
*/
public function file($path, bool $isChunk = false, int $size = -1, int $offset = 0): DownloadInterface
{
$path = realpath($path);
if (!file_exists($path) || !is_readable($path)) {
throw new Exception('Cannot read file "' . $path . '", no permission');
}
return (new Download())->path($path, $isChunk, $size, $offset);
}
/**
* @param $responseData
* @return string|array|bool|int|null
*/
public function _toArray($responseData): string|array|null|bool|int
{
if (is_object($responseData)) {
$responseData = $responseData instanceof ToArray ? $responseData->toArray() : get_object_vars($responseData);
}
return $responseData;
}
}
-93
View File
@@ -1,93 +0,0 @@
<?php
namespace Server\Message;
class StatusCode
{
const CODE_100 = 100;
const CODE_101 = 101;
const CODE_200 = 200;
const CODE_201 = 201;
const CODE_202 = 202;
const CODE_203 = 203;
const CODE_204 = 204;
const CODE_205 = 205;
const CODE_206 = 206;
const CODE_300 = 300;
const CODE_301 = 301;
const CODE_302 = 302;
const CODE_303 = 303;
const CODE_304 = 304;
const CODE_305 = 305;
const CODE_307 = 307;
const CODE_400 = 400;
const CODE_401 = 401;
const CODE_403 = 403;
const CODE_404 = 404;
const CODE_405 = 405;
const CODE_406 = 406;
const CODE_407 = 407;
const CODE_408 = 408;
const CODE_409 = 409;
const CODE_410 = 410;
const CODE_411 = 411;
const CODE_412 = 412;
const CODE_413 = 413;
const CODE_414 = 414;
const CODE_415 = 415;
const CODE_416 = 416;
const CODE_417 = 417;
const CODE_423 = 423;
const CODE_500 = 500;
const CODE_501 = 501;
const CODE_502 = 502;
const CODE_503 = 503;
const CODE_504 = 504;
const CODE_505 = 505;
const CODE_STATUS = [
self::CODE_100 => 'Continue 初始的请求已经接受,客户应当继续发送请求的其余部分。(HTTP 1.1新)',
self::CODE_101 => 'Switching Protocols 服务器将遵从客户的请求转换到另外一种协议(HTTP 1.1新)',
self::CODE_200 => '(成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。',
self::CODE_201 => '(已创建) 请求成功并且服务器创建了新的资源。',
self::CODE_202 => '(已接受) 服务器已接受请求,但尚未处理。',
self::CODE_203 => '(非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。',
self::CODE_204 => '(无内容) 服务器成功处理了请求,但没有返回任何内容。',
self::CODE_205 => '(重置内容) 服务器成功处理了请求,但没有返回任何内容。',
self::CODE_206 => '(部分内容) 服务器成功处理了部分 GET 请求。',
self::CODE_300 => '(多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。',
self::CODE_301 => '(永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。',
self::CODE_302 => '(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。',
self::CODE_303 => '(查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。',
self::CODE_304 => '(未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。',
self::CODE_305 => '(使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。',
self::CODE_307 => '(临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。',
self::CODE_400 => '(错误请求) 服务器不理解请求的语法。',
self::CODE_401 => '(未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。',
self::CODE_403 => '(禁止) 服务器拒绝请求。',
self::CODE_404 => '(未找到) 服务器找不到请求的网页。',
self::CODE_405 => '(方法禁用) 禁用请求中指定的方法。',
self::CODE_406 => '(不接受) 无法使用请求的内容特性响应请求的网页。',
self::CODE_407 => '(需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。',
self::CODE_408 => '(请求超时) 服务器等候请求时发生超时。',
self::CODE_409 => '(冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。',
self::CODE_410 => '(已删除) 如果请求的资源已永久删除,服务器就会返回此响应。',
self::CODE_411 => '(需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。',
self::CODE_412 => '(未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。',
self::CODE_413 => '(请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。',
self::CODE_414 => '(请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。',
self::CODE_415 => '(不支持的媒体类型) 请求的格式不受请求页面的支持。',
self::CODE_416 => '(请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。',
self::CODE_417 => '(未满足期望值) 服务器未满足"期望"请求标头字段的要求。',
self::CODE_423 => ' 锁定的错误。',
self::CODE_500 => '(服务器内部错误) 服务器遇到错误,无法完成请求。',
self::CODE_501 => '(尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。',
self::CODE_502 => '(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。',
self::CODE_503 => '(服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。',
self::CODE_504 => '(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。',
self::CODE_505 => '(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。',
];
}
-193
View File
@@ -1,193 +0,0 @@
<?php
namespace Server\Message;
use Psr\Http\Message\StreamInterface;
/**
*
*/
class Stream implements StreamInterface
{
private string $body;
private int $size;
private int $offset = 0;
private bool $writable = true;
/**
* @param string $body
*/
public function __construct(string $body)
{
$this->body = $body;
}
/**
* @return string
*/
public function __toString(): string
{
return $this->body;
}
/**
*
*/
public function close(): void
{
$this->detach();
}
/**
*
*/
public function detach(): void
{
$this->body = '';
$this->size = 0;
$this->writable = false;
}
/**
* @return int
*/
public function getSize(): int
{
if ($this->size == 0) {
$this->size = strlen($this->body);
}
return $this->size;
}
/**
* @return int
*/
public function tell(): int
{
return $this->offset;
}
/**
* @return bool
*/
public function eof(): bool
{
return true;
}
/**
* @return bool
*/
public function isSeekable(): bool
{
return $this->offset == 0;
}
/**
* @param int $offset
* @param int $whence
*/
public function seek($offset, $whence = SEEK_SET)
{
$this->offset = $offset;
}
/**
*
*/
public function rewind(): void
{
$this->offset = 0;
}
/**
* @return bool
*/
public function isWritable(): bool
{
return $this->writable;
}
/**
* @param string $string
* @return int
*/
public function write($string): int
{
$this->body = $string;
$this->size = strlen($this->body);
return $this->size;
}
/**
* @param string $string
* @return int
*/
public function append(string $string): int
{
$this->body .= $string;
$this->size = strlen($this->body);
return $this->size;
}
/**
* @return bool
*/
public function isReadable(): bool
{
return true;
}
/**
* @param int $length
* @return string
*/
public function read($length = -1): string
{
if ($length > 0) {
return substr($this->body, 0, $length);
}
return $this->body;
}
/**
* @return string
*/
public function getContents(): string
{
return $this->body;
}
/**
* @param null $key
* @return mixed
*/
public function getMetadata($key = null): mixed
{
throw new \BadMethodCallException('Not Accomplish Method.');
}
}
-106
View File
@@ -1,106 +0,0 @@
<?php
namespace Server\Message;
use JetBrains\PhpStorm\Pure;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
/**
*
*/
class Uploaded implements UploadedFileInterface
{
public string $tmp_name;
public string $name;
public string $type;
public string $size;
public int $error;
const ERROR = [
0 => "There is no error, the file uploaded with success",
1 => "The uploaded file exceeds the upload_max_filesize directive in php.ini",
2 => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
3 => "The uploaded file was only partially uploaded",
4 => "No file was uploaded",
6 => "Missing a temporary folder"
];
/**
* @param mixed $file
*/
public function __construct(array $file)
{
$this->tmp_name = $file['tmp_name'];
$this->name = $file['name'];
$this->type = $file['type'];
$this->size = $file['size'];
$this->error = $file['error'];
}
/**
* @return StreamInterface
*/
public function getStream(): StreamInterface
{
return new Stream(file_get_contents($this->tmp_name));
}
/**
* @param string $targetPath
* @return bool
*/
public function moveTo($targetPath): bool
{
@move_uploaded_file($this->tmp_name, $targetPath);
return file_exists($targetPath);
}
/**
* @return int
*/
public function getSize(): int
{
return $this->size;
}
/**
* @return string
*/
public function getError(): string
{
return Uploaded::ERROR[$this->error] ?? 'unknown error';
}
/**
* @return string|null
*/
public function getClientFilename(): string|null
{
return $this->name;
}
/**
* @return string|null
*/
public function getClientMediaType(): string|null
{
return $this->type;
}
}
-287
View File
@@ -1,287 +0,0 @@
<?php
namespace Server\Message;
use Psr\Http\Message\UriInterface;
class Uri implements UriInterface
{
public string $scheme = '';
public string $host = '';
public int $port = 80;
public string $path = '';
public string $query = '';
public string $fragment = '';
public string $username = '';
public string $password = '';
private array $_explode = [];
/**
* @return string[]
*/
public function getExplode(): array
{
if ($this->path == '/' || $this->path == '') {
return ['/'];
}
if (empty($this->_explode)) {
$this->_explode = array_filter(explode('/', $this->path));
}
return $this->_explode;
}
/**
* @return string
*/
public function getScheme(): string
{
return $this->scheme;
}
/**
* @return mixed
*/
public function getAuthority(): string
{
throw new \BadMethodCallException('Not Accomplish Method.');
}
public function getUserInfo()
{
// TODO: Implement getUserInfo() method.
}
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @return string
*/
public function getPath(): string
{
return $this->path;
}
/**
* @return string
*/
public function getQuery(): string
{
return $this->query;
}
/**
* @return string
*/
public function getFragment(): string
{
return $this->fragment;
}
/**
* @param string $scheme
* @return UriInterface
*/
public function withScheme($scheme): UriInterface
{
$this->scheme = $scheme;
return $this;
}
/**
* @param string $user
* @param null $password
* @return $this
*/
public function withUserInfo($user, $password = null): UriInterface
{
$this->username = $user;
$this->password = $password;
return $this;
}
/**
* @param string $host
* @return UriInterface
*/
public function withHost($host): UriInterface
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getDefaultPort(): int
{
return $this->scheme == 'https' ? 443 : 80;
}
/**
* @param int|null $port
* @return UriInterface
*/
public function withPort($port): UriInterface
{
$this->port = $port;
return $this;
}
/**
* @param string $path
* @return UriInterface
*/
public function withPath($path): UriInterface
{
$this->path = $path;
return $this;
}
/**
* @param string $query
* @return UriInterface
*/
public function withQuery($query): UriInterface
{
$this->query = $query;
return $this;
}
/**
* @param string $fragment
* @return UriInterface
*/
public function withFragment($fragment): UriInterface
{
$this->fragment = $fragment;
return $this;
}
/**
* @return string
*/
public function __toString(): string
{
$domain = sprintf('%s://%s', $this->scheme, $this->host);
if (!in_array($this->port, [80, 443])) {
$domain .= ':' . $this->port;
}
if (empty($this->query) && empty($this->fragment)) {
return $domain . $this->path;
}
return sprintf('%s?%s#%s', $domain . $this->path,
$this->query, $this->fragment);
}
/**
* @param \Swoole\Http\Request $request
* @return UriInterface
*/
public static function parseUri(\Swoole\Http\Request $request): UriInterface
{
$server = $request->server;
$header = $request->header;
$uri = new Uri();
$uri = $uri->withScheme(!empty($server['https']) && $server['https'] !== 'off' ? 'https' : 'http');
if (isset($request->header['x-forwarded-proto'])) {
$uri->withScheme($request->header['x-forwarded-proto'])->withPort(443);
}
$hasPort = false;
if (isset($server['http_host'])) {
$hostHeaderParts = explode(':', $server['http_host']);
$uri = $uri->withHost($hostHeaderParts[0]);
if (isset($hostHeaderParts[1])) {
$hasPort = true;
$uri = $uri->withPort($hostHeaderParts[1]);
}
} elseif (isset($server['server_name'])) {
$uri = $uri->withHost($server['server_name']);
} elseif (isset($server['server_addr'])) {
$uri = $uri->withHost($server['server_addr']);
} elseif (isset($header['host'])) {
$hasPort = true;
if (strpos($header['host'], ':')) {
[$host, $port] = explode(':', $header['host'], 2);
if ($port != $uri->getDefaultPort()) {
$uri = $uri->withPort($port);
}
} else {
$host = $header['host'];
}
$uri = $uri->withHost($host);
}
if (!$hasPort && isset($server['server_port'])) {
$uri = $uri->withPort($server['server_port']);
}
$hasQuery = false;
if (isset($server['request_uri'])) {
$requestUriParts = explode('?', $server['request_uri']);
$uri = $uri->withPath($requestUriParts[0]);
if (isset($requestUriParts[1])) {
$hasQuery = true;
$uri = $uri->withQuery($requestUriParts[1]);
}
}
if (!$hasQuery && isset($server['query_string'])) {
$uri = $uri->withQuery($server['query_string']);
}
return $uri;
}
}
+2 -2
View File
@@ -10,8 +10,8 @@ use Kiri\Core\Help;
use Server\Constant;
use Server\Events\OnAfterRequest;
use Server\Message\Response as MsgResponse;
use Server\RequestInterface;
use Server\ResponseInterface;
use Server\Constrict\RequestInterface;
use Server\Constrict\ResponseInterface;
use Server\SInterface\OnClose;
use Server\SInterface\OnConnect;
use Swoole\Error;