|
4 | 4 |
|
5 | 5 | namespace MicroPHP\Framework\Http; |
6 | 6 |
|
| 7 | +use GuzzleHttp\Psr7\HttpFactory; |
| 8 | +use GuzzleHttp\Psr7\Uri; |
| 9 | +use InvalidArgumentException; |
7 | 10 | use MicroPHP\Framework\Http\Traits\InputTrait; |
8 | | -use MicroPHP\Framework\Http\Traits\MessageTrait; |
| 11 | +use Psr\Http\Message\RequestInterface; |
9 | 12 | use Psr\Http\Message\ServerRequestInterface; |
10 | 13 | use Psr\Http\Message\UriInterface; |
| 14 | +use Swoole\Http\Request; |
11 | 15 |
|
12 | | -class ServerRequest implements ServerRequestInterface |
| 16 | +class ServerRequest extends \GuzzleHttp\Psr7\ServerRequest implements ServerRequestInterface |
13 | 17 | { |
14 | | - use MessageTrait; |
15 | 18 | use InputTrait; |
16 | 19 |
|
17 | 20 | private ServerRequestInterface $bind; |
18 | 21 |
|
19 | | - public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1', array $serverParams = []) |
| 22 | + public static function fromPsr7(ServerRequestInterface $request): ServerRequestInterface|ServerRequest |
20 | 23 | { |
21 | | - $this->bind = new \Nyholm\Psr7\ServerRequest($method, $uri, $headers, $body, $version, $serverParams); |
22 | | - } |
23 | | - |
24 | | - public static function fromPsr7(ServerRequestInterface $request): static |
25 | | - { |
26 | | - return new static($request->getMethod(), $request->getUri(), $request->getHeaders(), $request->getBody(), $request->getProtocolVersion(), $request->getServerParams()); |
27 | | - } |
28 | | - |
29 | | - public function getServerParams(): array |
30 | | - { |
31 | | - return $this->bind->getServerParams(); |
32 | | - } |
33 | | - |
34 | | - public function getCookieParams(): array |
35 | | - { |
36 | | - return $this->bind->getCookieParams(); |
37 | | - } |
38 | | - |
39 | | - public function withCookieParams(array $cookies): static |
40 | | - { |
41 | | - $new = clone $this; |
42 | | - $new->bind = $this->bind->withCookieParams($cookies); |
43 | | - |
44 | | - return $new; |
45 | | - } |
46 | | - |
47 | | - public function getQueryParams(): array |
48 | | - { |
49 | | - return $this->bind->getQueryParams(); |
50 | | - } |
51 | | - |
52 | | - public function withQueryParams(array $query): static |
53 | | - { |
54 | | - $new = clone $this; |
55 | | - $new->bind = $this->bind->withQueryParams($query); |
56 | | - |
57 | | - return $new; |
58 | | - } |
59 | | - |
60 | | - public function getUploadedFiles(): array |
61 | | - { |
62 | | - return $this->bind->getUploadedFiles(); |
63 | | - } |
64 | | - |
65 | | - public function withUploadedFiles(array $uploadedFiles): static |
66 | | - { |
67 | | - $new = clone $this; |
68 | | - $new->bind = $this->bind->withUploadedFiles($uploadedFiles); |
69 | | - |
70 | | - return $new; |
71 | | - } |
72 | | - |
73 | | - public function getParsedBody(): object|array|null |
74 | | - { |
75 | | - return $this->bind->getParsedBody(); |
76 | | - } |
77 | | - |
78 | | - public function withParsedBody($data): static |
79 | | - { |
80 | | - $new = clone $this; |
81 | | - $new->bind = $this->bind->withParsedBody($data); |
82 | | - |
83 | | - return $new; |
84 | | - } |
85 | | - |
86 | | - public function getAttributes(): array |
87 | | - { |
88 | | - return $this->bind->getAttributes(); |
89 | | - } |
90 | | - |
91 | | - public function getAttribute(string $name, $default = null) |
92 | | - { |
93 | | - return $this->bind->getAttribute($name, $default); |
94 | | - } |
95 | | - |
96 | | - public function withAttribute(string $name, $value): static |
97 | | - { |
98 | | - $new = clone $this; |
99 | | - $new->bind = $this->bind->withAttribute($name, $value); |
100 | | - |
101 | | - return $new; |
102 | | - } |
103 | | - |
104 | | - public function withoutAttribute(string $name): static |
105 | | - { |
106 | | - $new = clone $this; |
107 | | - $new->bind = $this->bind->withoutAttribute($name); |
108 | | - |
109 | | - return $new; |
110 | | - } |
111 | | - |
112 | | - public function getRequestTarget(): string |
113 | | - { |
114 | | - return $this->bind->getRequestTarget(); |
115 | | - } |
116 | | - |
117 | | - public function withRequestTarget(string $requestTarget): static |
118 | | - { |
119 | | - $new = clone $this; |
120 | | - $new->bind = $this->bind->withRequestTarget($requestTarget); |
121 | | - |
122 | | - return $new; |
123 | | - } |
124 | | - |
125 | | - public function getMethod(): string |
126 | | - { |
127 | | - return $this->bind->getMethod(); |
128 | | - } |
129 | | - |
130 | | - public function withMethod(string $method): static |
131 | | - { |
132 | | - $new = clone $this; |
133 | | - $new->bind = $this->bind->withMethod($method); |
134 | | - |
135 | | - return $new; |
136 | | - } |
137 | | - |
138 | | - public function getUri(): UriInterface |
139 | | - { |
140 | | - return $this->bind->getUri(); |
141 | | - } |
142 | | - |
143 | | - public function withUri(UriInterface $uri, bool $preserveHost = false): static |
144 | | - { |
145 | | - $new = clone $this; |
146 | | - $new->bind = $this->bind->withUri($uri, $preserveHost); |
147 | | - |
148 | | - return $new; |
149 | | - } |
150 | | - |
151 | | - public function getProtocolVersion(): string |
152 | | - { |
153 | | - return $this->bind->getProtocolVersion(); |
| 24 | + return (new static($request->getMethod(), $request->getUri(), $request->getHeaders(), $request->getBody(), $request->getProtocolVersion(), $request->getServerParams())) |
| 25 | + ->withParsedBody(self::normalizeParsedBody($request->getParsedBody(), $request)) |
| 26 | + ->withUploadedFiles($request->getUploadedFiles()) |
| 27 | + ->withCookieParams($request->getCookieParams()) |
| 28 | + ->withQueryParams($request->getQueryParams()); |
| 29 | + } |
| 30 | + |
| 31 | + public static function fromSwoole(Request $swooleRequest): ServerRequestInterface|ServerRequest |
| 32 | + { |
| 33 | + $server = $swooleRequest->server; |
| 34 | + $method = $server['request_method'] ?? 'GET'; |
| 35 | + $headers = $swooleRequest->header ?? []; |
| 36 | + $uri = self::getUriFromSwooleRequest($swooleRequest); |
| 37 | + $httpFactory = new HttpFactory(); |
| 38 | + $body = $httpFactory->createStream((string) $swooleRequest->rawContent()); |
| 39 | + $protocol = isset($server['server_protocol']) ? str_replace('HTTP/', '', $server['server_protocol']) : '1.1'; |
| 40 | + $request = new ServerRequest($method, $uri, $headers, $body, $protocol, $server); |
| 41 | + return $request->withCookieParams($swooleRequest->cookie ?? []) |
| 42 | + ->withQueryParams($swooleRequest->get ?? []) |
| 43 | + ->withParsedBody(self::normalizeParsedBody($swooleRequest->post ?? [], $request)) |
| 44 | + ->withUploadedFiles(self::normalizeFiles($swooleRequest->files ?? [])); |
| 45 | + } |
| 46 | + |
| 47 | + private static function getUriFromSwooleRequest(Request $swooleRequest): UriInterface |
| 48 | + { |
| 49 | + $server = $swooleRequest->server; |
| 50 | + $header = $swooleRequest->header; |
| 51 | + $uri = new Uri(); |
| 52 | + $uri = $uri->withScheme(! empty($server['https']) && $server['https'] !== 'off' ? 'https' : 'http'); |
| 53 | + |
| 54 | + $hasPort = false; |
| 55 | + if (isset($server['http_host'])) { |
| 56 | + [$host, $port] = self::parseHost($server['http_host']); |
| 57 | + $uri = $uri->withHost($host); |
| 58 | + if (isset($port)) { |
| 59 | + $hasPort = true; |
| 60 | + $uri = $uri->withPort($port); |
| 61 | + } |
| 62 | + } elseif (isset($server['server_name'])) { |
| 63 | + $uri = $uri->withHost($server['server_name']); |
| 64 | + } elseif (isset($server['server_addr'])) { |
| 65 | + $uri = $uri->withHost($server['server_addr']); |
| 66 | + } elseif (isset($header['host'])) { |
| 67 | + $hasPort = true; |
| 68 | + [$host, $port] = self::parseHost($header['host']); |
| 69 | + if (isset($port) && $port !== self::getUriDefaultPort($uri)) { |
| 70 | + $uri = $uri->withPort($port); |
| 71 | + } |
| 72 | + |
| 73 | + $uri = $uri->withHost($host); |
| 74 | + } |
| 75 | + |
| 76 | + if (! $hasPort && isset($server['server_port'])) { |
| 77 | + $uri = $uri->withPort($server['server_port']); |
| 78 | + } |
| 79 | + |
| 80 | + $hasQuery = false; |
| 81 | + if (isset($server['request_uri'])) { |
| 82 | + $requestUriParts = explode('?', $server['request_uri']); |
| 83 | + $uri = $uri->withPath($requestUriParts[0]); |
| 84 | + if (isset($requestUriParts[1])) { |
| 85 | + $hasQuery = true; |
| 86 | + $uri = $uri->withQuery($requestUriParts[1]); |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + if (! $hasQuery && isset($server['query_string'])) { |
| 91 | + $uri = $uri->withQuery($server['query_string']); |
| 92 | + } |
| 93 | + |
| 94 | + return $uri; |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * Get host parts, support ipv6. |
| 99 | + */ |
| 100 | + private static function parseHost(string $httpHost): array |
| 101 | + { |
| 102 | + $parts = parse_url('//' . $httpHost); |
| 103 | + if (! isset($parts['host'])) { |
| 104 | + throw new InvalidArgumentException('Invalid host: ' . $httpHost); |
| 105 | + } |
| 106 | + |
| 107 | + return [$parts['host'], $parts['port'] ?? null]; |
| 108 | + } |
| 109 | + |
| 110 | + private static function getUriDefaultPort(UriInterface $uri): ?int |
| 111 | + { |
| 112 | + return $uri->getScheme() === 'https' ? 443 : ($uri->getScheme() === 'http' ? 80 : null); |
| 113 | + } |
| 114 | + |
| 115 | + protected static function normalizeParsedBody(array $data = [], ?RequestInterface $request = null): array |
| 116 | + { |
| 117 | + if (! $request) { |
| 118 | + return $data; |
| 119 | + } |
| 120 | + |
| 121 | + $rawContentType = $request->getHeaderLine('content-type'); |
| 122 | + if (($pos = strpos($rawContentType, ';')) !== false) { |
| 123 | + $contentType = strtolower(substr($rawContentType, 0, $pos)); |
| 124 | + } else { |
| 125 | + $contentType = strtolower($rawContentType); |
| 126 | + } |
| 127 | + switch ($contentType) { |
| 128 | + case 'application/json': |
| 129 | + case 'text/json': |
| 130 | + $data = json_decode((string) $request->getBody(), true); |
| 131 | + break; |
| 132 | + case 'application/xml': |
| 133 | + case 'text/xml': |
| 134 | + $data = (array) simplexml_load_string((string) $request->getBody()); |
| 135 | + break; |
| 136 | + } |
| 137 | + |
| 138 | + return $data; |
154 | 139 | } |
155 | 140 | } |
0 commit comments