1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace WyriHaximus; |
6
|
|
|
|
7
|
|
|
use Ancarda\Psr7\StringStream\ReadOnlyStringStream; |
8
|
|
|
use Cake\Utility\Hash; |
9
|
|
|
use Psr\Http\Message\RequestInterface; |
10
|
|
|
use Psr\Http\Message\ResponseInterface; |
11
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
12
|
|
|
use Psr\Http\Message\UploadedFileInterface; |
13
|
|
|
use React\Http\Io\UploadedFile; |
14
|
|
|
use RingCentral\Psr7\Request; |
15
|
|
|
use RingCentral\Psr7\Response; |
16
|
|
|
use RingCentral\Psr7\ServerRequest; |
17
|
|
|
|
18
|
5 |
|
use function base64_encode; |
19
|
|
|
use function count; |
20
|
|
|
use function Safe\base64_decode; |
21
|
|
|
use function Safe\json_decode; |
22
|
|
|
use function Safe\json_encode; |
23
|
10 |
|
use function Safe\ksort; |
24
|
10 |
|
|
25
|
10 |
|
function psr7_response_json_encode(ResponseInterface $response): string |
26
|
10 |
|
{ |
27
|
10 |
|
return json_encode(psr7_response_encode($response)); |
28
|
10 |
|
} |
29
|
|
|
|
30
|
10 |
|
/** |
31
|
|
|
* @return array{protocol_version: string, status_code: int, reason_phrase: string, headers: array, body: string} |
32
|
|
|
*/ |
33
|
|
|
function psr7_response_encode(ResponseInterface $response): array |
34
|
|
|
{ |
35
|
|
|
$json = []; |
36
|
|
|
$json['protocol_version'] = $response->getProtocolVersion(); |
37
|
|
|
$json['status_code'] = $response->getStatusCode(); |
38
|
2 |
|
$json['reason_phrase'] = $response->getReasonPhrase(); |
39
|
|
|
$json['headers'] = sort_headers($response->getHeaders()); |
40
|
|
|
$json['body'] = base64_encode((string) $response->getBody()); |
41
|
|
|
|
42
|
|
|
return $json; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @throws NotAnEncodedResponseException |
47
|
4 |
|
*/ |
48
|
|
|
function psr7_response_json_decode(string $json): ResponseInterface |
49
|
|
|
{ |
50
|
|
|
return psr7_response_decode(json_decode($json, true)); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
4 |
|
* @param array{protocol_version: string, status_code: int, reason_phrase: string, headers: array, body: string} $json |
55
|
|
|
* |
56
|
2 |
|
* @throws NotAnEncodedResponseException |
57
|
2 |
|
*/ |
58
|
2 |
|
function psr7_response_decode(array $json): ResponseInterface |
59
|
2 |
|
{ |
60
|
2 |
|
$properties = [ |
61
|
2 |
|
'protocol_version' => 'string', |
62
|
|
|
'status_code' => 'integer', |
63
|
|
|
'reason_phrase' => 'string', |
64
|
|
|
'headers' => 'array', |
65
|
|
|
'body' => 'string', |
66
|
|
|
]; |
67
|
5 |
|
|
68
|
|
|
validate_array($json, $properties, NotAnEncodedResponseException::class); |
69
|
|
|
|
70
|
|
|
return new Response( |
71
|
|
|
$json['status_code'], |
72
|
10 |
|
$json['headers'], |
73
|
10 |
|
new ReadOnlyStringStream(base64_decode($json['body'], true)), |
74
|
10 |
|
$json['protocol_version'], |
75
|
10 |
|
$json['reason_phrase'] |
76
|
10 |
|
); |
77
|
10 |
|
} |
78
|
|
|
|
79
|
10 |
|
function psr7_request_json_encode(RequestInterface $request): string |
80
|
|
|
{ |
81
|
|
|
return json_encode(psr7_request_encode($request)); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @return array{protocol_version: string, method: string, uri: string, headers: array, body: string} |
86
|
|
|
*/ |
87
|
2 |
|
function psr7_request_encode(RequestInterface $request): array |
88
|
|
|
{ |
89
|
|
|
$json = []; |
90
|
|
|
$json['protocol_version'] = $request->getProtocolVersion(); |
91
|
|
|
$json['method'] = $request->getMethod(); |
92
|
|
|
$json['uri'] = (string) $request->getUri(); |
93
|
|
|
$json['headers'] = sort_headers($request->getHeaders()); |
94
|
|
|
$json['body'] = base64_encode((string) $request->getBody()); |
95
|
|
|
|
96
|
4 |
|
return $json; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @throws NotAnEncodedRequestException |
101
|
|
|
*/ |
102
|
|
|
function psr7_request_json_decode(string $json): RequestInterface |
103
|
4 |
|
{ |
104
|
|
|
return psr7_request_decode(json_decode($json, true)); |
105
|
2 |
|
} |
106
|
2 |
|
|
107
|
2 |
|
/** |
108
|
2 |
|
* @param array{protocol_version: string, method: string, uri: string, headers: array, body: string} $json |
109
|
2 |
|
* |
110
|
2 |
|
* @throws NotAnEncodedRequestException |
111
|
|
|
*/ |
112
|
|
|
function psr7_request_decode(array $json): RequestInterface |
113
|
|
|
{ |
114
|
|
|
$properties = [ |
115
|
|
|
'protocol_version' => 'string', |
116
|
5 |
|
'method' => 'string', |
117
|
|
|
'uri' => 'string', |
118
|
|
|
'headers' => 'array', |
119
|
|
|
'body' => 'string', |
120
|
|
|
]; |
121
|
260 |
|
|
122
|
260 |
|
validate_array($json, $properties, NotAnEncodedRequestException::class); |
123
|
260 |
|
|
124
|
260 |
|
return new Request( |
125
|
260 |
|
$json['method'], |
126
|
260 |
|
$json['uri'], |
127
|
|
|
$json['headers'], |
128
|
260 |
|
new ReadOnlyStringStream(base64_decode($json['body'], true)), |
129
|
|
|
$json['protocol_version'] |
130
|
|
|
); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
function psr7_uploaded_file_json_encode(UploadedFileInterface $uploadedFile): string |
134
|
|
|
{ |
135
|
|
|
return json_encode(psr7_uploaded_file_encode($uploadedFile)); |
136
|
2 |
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @return array{stream: string, size: ?int, error: int, filename: ?string, media_type: ?string} |
140
|
|
|
*/ |
141
|
|
|
function psr7_uploaded_file_encode(UploadedFileInterface $uploadedFile): array |
142
|
|
|
{ |
143
|
|
|
$json = []; |
144
|
|
|
$json['filename'] = $uploadedFile->getClientFilename(); |
145
|
6 |
|
$json['media_type'] = $uploadedFile->getClientMediaType(); |
146
|
|
|
$json['error'] = $uploadedFile->getError(); |
147
|
|
|
$json['size'] = $uploadedFile->getSize(); |
148
|
|
|
$json['stream'] = base64_encode((string) $uploadedFile->getStream()); |
149
|
|
|
|
150
|
|
|
return $json; |
151
|
|
|
} |
152
|
6 |
|
|
153
|
|
|
/** |
154
|
4 |
|
* @throws NotAnEncodedUploadedFileException |
155
|
4 |
|
*/ |
156
|
4 |
|
function psr7_uploaded_file_json_decode(string $json): UploadedFileInterface |
157
|
4 |
|
{ |
158
|
4 |
|
return psr7_uploaded_file_decode(json_decode($json, true)); |
159
|
4 |
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* @param array{stream: string, size: int, error: int, filename: string, media_type: string} $json |
163
|
|
|
* |
164
|
|
|
* @throws NotAnEncodedUploadedFileException |
165
|
125 |
|
*/ |
166
|
|
|
function psr7_uploaded_file_decode(array $json): UploadedFileInterface |
167
|
|
|
{ |
168
|
|
|
$properties = [ |
169
|
|
|
'stream' => 'string', |
170
|
250 |
|
'size' => ['integer', 'NULL'], |
171
|
250 |
|
'error' => 'integer', |
172
|
250 |
|
'filename' => ['string', 'NULL'], |
173
|
250 |
|
'media_type' => ['string', 'NULL'], |
174
|
250 |
|
]; |
175
|
250 |
|
|
176
|
250 |
|
validate_array($json, $properties, NotAnEncodedUploadedFileException::class); |
177
|
250 |
|
|
178
|
250 |
|
/** |
179
|
250 |
|
* @psalm-suppress InternalMethod |
180
|
250 |
|
*/ |
181
|
250 |
|
return new UploadedFile( |
182
|
250 |
|
new ReadOnlyStringStream(base64_decode($json['stream'], true)), |
183
|
250 |
|
$json['size'], |
184
|
250 |
|
$json['error'], |
185
|
|
|
$json['filename'], |
186
|
|
|
$json['media_type'] |
187
|
250 |
|
); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
function psr7_server_request_json_encode(ServerRequestInterface $request): string |
191
|
|
|
{ |
192
|
|
|
return json_encode(psr7_server_request_encode($request)); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
2 |
|
* @return array{protocol_version: string, method: string, uri: string, query_params: array, cookie_params: array, server_params: array, headers: array, attributes: array, body: string, parsed_body: (array|object|null), files: array} |
197
|
|
|
*/ |
198
|
|
|
function psr7_server_request_encode(ServerRequestInterface $request): array |
199
|
|
|
{ |
200
|
|
|
$json = []; |
201
|
|
|
$json['protocol_version'] = $request->getProtocolVersion(); |
202
|
|
|
$json['method'] = $request->getMethod(); |
203
|
|
|
$json['uri'] = (string) $request->getUri(); |
204
|
|
|
$json['query_params'] = $request->getQueryParams(); |
205
|
|
|
$json['cookie_params'] = $request->getCookieParams(); |
206
|
4 |
|
$json['server_params'] = $request->getServerParams(); |
207
|
|
|
$json['headers'] = sort_headers($request->getHeaders()); |
208
|
|
|
$json['attributes'] = $request->getAttributes(); |
209
|
|
|
$json['body'] = base64_encode((string) $request->getBody()); |
210
|
|
|
$json['parsed_body'] = $request->getParsedBody(); |
211
|
|
|
$json['files'] = $request->getUploadedFiles(); |
212
|
|
|
$json['files'] = Hash::flatten($json['files']); |
213
|
|
|
foreach ($json['files'] as $key => $file) { |
214
|
|
|
$json['files'][$key] = psr7_uploaded_file_encode($file); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
return $json; |
218
|
|
|
} |
219
|
4 |
|
|
220
|
|
|
/** |
221
|
2 |
|
* @throws NotAnEncodedServerRequestException |
222
|
2 |
|
* @throws NotAnEncodedUploadedFileException |
223
|
2 |
|
*/ |
224
|
2 |
|
function psr7_server_request_json_decode(string $json): ServerRequestInterface |
225
|
2 |
|
{ |
226
|
2 |
|
return psr7_server_request_decode(json_decode($json, true)); |
227
|
2 |
|
} |
228
|
|
|
|
229
|
2 |
|
/** |
230
|
2 |
|
* @param array{protocol_version: string, method: string, uri: string, query_params: array, cookie_params: array, server_params: array, headers: array, attributes: array, body: string, parsed_body: (array|object|null), files: array} $json |
231
|
2 |
|
* |
232
|
2 |
|
* @throws NotAnEncodedServerRequestException |
233
|
|
|
* @throws NotAnEncodedUploadedFileException |
234
|
|
|
*/ |
235
|
2 |
|
function psr7_server_request_decode(array $json): ServerRequestInterface |
236
|
2 |
|
{ |
237
|
|
|
$properties = [ |
238
|
|
|
'protocol_version' => 'string', |
239
|
2 |
|
'method' => 'string', |
240
|
2 |
|
'uri' => 'string', |
241
|
2 |
|
'query_params' => 'array', |
242
|
|
|
'cookie_params' => 'array', |
243
|
2 |
|
'server_params' => 'array', |
244
|
2 |
|
'headers' => 'array', |
245
|
|
|
'attributes' => 'array', |
246
|
|
|
'body' => 'string', |
247
|
2 |
|
'parsed_body' => ['array', 'object', 'NULL'], |
248
|
|
|
'files' => 'array', |
249
|
|
|
]; |
250
|
|
|
|
251
|
|
|
validate_array($json, $properties, NotAnEncodedServerRequestException::class); |
252
|
270 |
|
|
253
|
|
|
/** @psalm-suppress ImplicitToStringCast */ |
254
|
270 |
|
$request = (new ServerRequest( |
255
|
|
|
$json['method'], |
256
|
|
|
$json['uri'], |
257
|
|
|
$json['headers'], |
258
|
|
|
new ReadOnlyStringStream(base64_decode($json['body'], true)), |
259
|
|
|
$json['protocol_version'], |
260
|
|
|
$json['server_params'] |
261
|
|
|
))-> |
262
|
|
|
withParsedBody($json['parsed_body'])-> |
263
|
|
|
withUploadedFiles($json['files'])-> |
264
|
|
|
withQueryParams($json['query_params'])-> |
265
|
|
|
withCookieParams($json['cookie_params']); |
266
|
|
|
|
267
|
|
|
foreach ($json['attributes'] as $key => $value) { |
268
|
|
|
$request = $request->withAttribute($key, $value); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
if (count($json['files']) > 0) { |
272
|
|
|
foreach ($json['files'] as $key => $file) { |
273
|
|
|
$json['files'][$key] = psr7_uploaded_file_decode($file); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
$json['files'] = Hash::expand($json['files']); |
277
|
|
|
$request = $request->withUploadedFiles($json['files']); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
return $request; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* @param array<array<string>> $headers |
285
|
|
|
* |
286
|
|
|
* @return array<array<string>> |
287
|
|
|
*/ |
288
|
|
|
function sort_headers(array $headers): array |
289
|
|
|
{ |
290
|
|
|
ksort($headers); |
291
|
|
|
|
292
|
|
|
return $headers; |
293
|
|
|
} |
294
|
|
|
|