Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
namespace GuzzleHttp\Psr7;
6
 
7
use InvalidArgumentException;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Message\StreamInterface;
10
use Psr\Http\Message\UploadedFileInterface;
11
use Psr\Http\Message\UriInterface;
12
 
13
/**
14
 * Server-side HTTP request
15
 *
16
 * Extends the Request definition to add methods for accessing incoming data,
17
 * specifically server parameters, cookies, matched path parameters, query
18
 * string arguments, body parameters, and upload file information.
19
 *
20
 * "Attributes" are discovered via decomposing the request (and usually
21
 * specifically the URI path), and typically will be injected by the application.
22
 *
23
 * Requests are considered immutable; all methods that might change state are
24
 * implemented such that they retain the internal state of the current
25
 * message and return a new instance that contains the changed state.
26
 */
27
class ServerRequest extends Request implements ServerRequestInterface
28
{
29
    /**
30
     * @var array
31
     */
32
    private $attributes = [];
33
 
34
    /**
35
     * @var array
36
     */
37
    private $cookieParams = [];
38
 
39
    /**
40
     * @var array|object|null
41
     */
42
    private $parsedBody;
43
 
44
    /**
45
     * @var array
46
     */
47
    private $queryParams = [];
48
 
49
    /**
50
     * @var array
51
     */
52
    private $serverParams;
53
 
54
    /**
55
     * @var array
56
     */
57
    private $uploadedFiles = [];
58
 
59
    /**
60
     * @param string                               $method       HTTP method
61
     * @param string|UriInterface                  $uri          URI
62
     * @param array<string, string|string[]>       $headers      Request headers
63
     * @param string|resource|StreamInterface|null $body         Request body
64
     * @param string                               $version      Protocol version
65
     * @param array                                $serverParams Typically the $_SERVER superglobal
66
     */
67
    public function __construct(
68
        string $method,
69
        $uri,
70
        array $headers = [],
71
        $body = null,
72
        string $version = '1.1',
73
        array $serverParams = []
74
    ) {
75
        $this->serverParams = $serverParams;
76
 
77
        parent::__construct($method, $uri, $headers, $body, $version);
78
    }
79
 
80
    /**
81
     * Return an UploadedFile instance array.
82
     *
83
     * @param array $files An array which respect $_FILES structure
84
     *
85
     * @throws InvalidArgumentException for unrecognized values
86
     */
87
    public static function normalizeFiles(array $files): array
88
    {
89
        $normalized = [];
90
 
91
        foreach ($files as $key => $value) {
92
            if ($value instanceof UploadedFileInterface) {
93
                $normalized[$key] = $value;
94
            } elseif (is_array($value) && isset($value['tmp_name'])) {
95
                $normalized[$key] = self::createUploadedFileFromSpec($value);
96
            } elseif (is_array($value)) {
97
                $normalized[$key] = self::normalizeFiles($value);
98
                continue;
99
            } else {
100
                throw new InvalidArgumentException('Invalid value in files specification');
101
            }
102
        }
103
 
104
        return $normalized;
105
    }
106
 
107
    /**
108
     * Create and return an UploadedFile instance from a $_FILES specification.
109
     *
110
     * If the specification represents an array of values, this method will
111
     * delegate to normalizeNestedFileSpec() and return that return value.
112
     *
113
     * @param array $value $_FILES struct
114
     *
115
     * @return UploadedFileInterface|UploadedFileInterface[]
116
     */
117
    private static function createUploadedFileFromSpec(array $value)
118
    {
119
        if (is_array($value['tmp_name'])) {
120
            return self::normalizeNestedFileSpec($value);
121
        }
122
 
123
        return new UploadedFile(
124
            $value['tmp_name'],
125
            (int) $value['size'],
126
            (int) $value['error'],
127
            $value['name'],
128
            $value['type']
129
        );
130
    }
131
 
132
    /**
133
     * Normalize an array of file specifications.
134
     *
135
     * Loops through all nested files and returns a normalized array of
136
     * UploadedFileInterface instances.
137
     *
138
     * @return UploadedFileInterface[]
139
     */
140
    private static function normalizeNestedFileSpec(array $files = []): array
141
    {
142
        $normalizedFiles = [];
143
 
144
        foreach (array_keys($files['tmp_name']) as $key) {
145
            $spec = [
146
                'tmp_name' => $files['tmp_name'][$key],
147
                'size'     => $files['size'][$key],
148
                'error'    => $files['error'][$key],
149
                'name'     => $files['name'][$key],
150
                'type'     => $files['type'][$key],
151
            ];
152
            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
153
        }
154
 
155
        return $normalizedFiles;
156
    }
157
 
158
    /**
159
     * Return a ServerRequest populated with superglobals:
160
     * $_GET
161
     * $_POST
162
     * $_COOKIE
163
     * $_FILES
164
     * $_SERVER
165
     */
166
    public static function fromGlobals(): ServerRequestInterface
167
    {
168
        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
169
        $headers = getallheaders();
170
        $uri = self::getUriFromGlobals();
171
        $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
172
        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
173
 
174
        $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
175
 
176
        return $serverRequest
177
            ->withCookieParams($_COOKIE)
178
            ->withQueryParams($_GET)
179
            ->withParsedBody($_POST)
180
            ->withUploadedFiles(self::normalizeFiles($_FILES));
181
    }
182
 
183
    private static function extractHostAndPortFromAuthority(string $authority): array
184
    {
185
        $uri = 'http://' . $authority;
186
        $parts = parse_url($uri);
187
        if (false === $parts) {
188
            return [null, null];
189
        }
190
 
191
        $host = $parts['host'] ?? null;
192
        $port = $parts['port'] ?? null;
193
 
194
        return [$host, $port];
195
    }
196
 
197
    /**
198
     * Get a Uri populated with values from $_SERVER.
199
     */
200
    public static function getUriFromGlobals(): UriInterface
201
    {
202
        $uri = new Uri('');
203
 
204
        $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
205
 
206
        $hasPort = false;
207
        if (isset($_SERVER['HTTP_HOST'])) {
208
            [$host, $port] = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
209
            if ($host !== null) {
210
                $uri = $uri->withHost($host);
211
            }
212
 
213
            if ($port !== null) {
214
                $hasPort = true;
215
                $uri = $uri->withPort($port);
216
            }
217
        } elseif (isset($_SERVER['SERVER_NAME'])) {
218
            $uri = $uri->withHost($_SERVER['SERVER_NAME']);
219
        } elseif (isset($_SERVER['SERVER_ADDR'])) {
220
            $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
221
        }
222
 
223
        if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
224
            $uri = $uri->withPort($_SERVER['SERVER_PORT']);
225
        }
226
 
227
        $hasQuery = false;
228
        if (isset($_SERVER['REQUEST_URI'])) {
229
            $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
230
            $uri = $uri->withPath($requestUriParts[0]);
231
            if (isset($requestUriParts[1])) {
232
                $hasQuery = true;
233
                $uri = $uri->withQuery($requestUriParts[1]);
234
            }
235
        }
236
 
237
        if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
238
            $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
239
        }
240
 
241
        return $uri;
242
    }
243
 
244
    public function getServerParams(): array
245
    {
246
        return $this->serverParams;
247
    }
248
 
249
    public function getUploadedFiles(): array
250
    {
251
        return $this->uploadedFiles;
252
    }
253
 
254
    public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
255
    {
256
        $new = clone $this;
257
        $new->uploadedFiles = $uploadedFiles;
258
 
259
        return $new;
260
    }
261
 
262
    public function getCookieParams(): array
263
    {
264
        return $this->cookieParams;
265
    }
266
 
267
    public function withCookieParams(array $cookies): ServerRequestInterface
268
    {
269
        $new = clone $this;
270
        $new->cookieParams = $cookies;
271
 
272
        return $new;
273
    }
274
 
275
    public function getQueryParams(): array
276
    {
277
        return $this->queryParams;
278
    }
279
 
280
    public function withQueryParams(array $query): ServerRequestInterface
281
    {
282
        $new = clone $this;
283
        $new->queryParams = $query;
284
 
285
        return $new;
286
    }
287
 
288
    /**
289
     * {@inheritdoc}
290
     *
291
     * @return array|object|null
292
     */
293
    public function getParsedBody()
294
    {
295
        return $this->parsedBody;
296
    }
297
 
298
    public function withParsedBody($data): ServerRequestInterface
299
    {
300
        $new = clone $this;
301
        $new->parsedBody = $data;
302
 
303
        return $new;
304
    }
305
 
306
    public function getAttributes(): array
307
    {
308
        return $this->attributes;
309
    }
310
 
311
    /**
312
     * {@inheritdoc}
313
     *
314
     * @return mixed
315
     */
316
    public function getAttribute($attribute, $default = null)
317
    {
318
        if (false === array_key_exists($attribute, $this->attributes)) {
319
            return $default;
320
        }
321
 
322
        return $this->attributes[$attribute];
323
    }
324
 
325
    public function withAttribute($attribute, $value): ServerRequestInterface
326
    {
327
        $new = clone $this;
328
        $new->attributes[$attribute] = $value;
329
 
330
        return $new;
331
    }
332
 
333
    public function withoutAttribute($attribute): ServerRequestInterface
334
    {
335
        if (false === array_key_exists($attribute, $this->attributes)) {
336
            return $this;
337
        }
338
 
339
        $new = clone $this;
340
        unset($new->attributes[$attribute]);
341
 
342
        return $new;
343
    }
344
}