Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

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