[TASK] Use strict comparison for strings
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Http / ServerRequestFactory.php
1 <?php
2 namespace TYPO3\CMS\Core\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\UploadedFileInterface;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Class ServerRequestFactory to create ServerRequest objects
22 *
23 * Highly inspired by https://github.com/phly/http/
24 *
25 * @internal Note that this is not public API yet.
26 */
27 class ServerRequestFactory
28 {
29 /**
30 * Create a request from the original superglobal variables.
31 *
32 * @return ServerRequest
33 * @throws \InvalidArgumentException when invalid file values given
34 * @internal Note that this is not public API yet.
35 */
36 public static function fromGlobals()
37 {
38 $serverParameters = $_SERVER;
39 $headers = static::prepareHeaders($serverParameters);
40
41 $method = isset($serverParameters['REQUEST_METHOD']) ? $serverParameters['REQUEST_METHOD'] : 'GET';
42 $uri = new Uri(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'));
43
44 $request = new ServerRequest(
45 $uri,
46 $method,
47 'php://input',
48 $headers,
49 $serverParameters,
50 static::normalizeUploadedFiles($_FILES)
51 );
52
53 if (!empty($_COOKIE)) {
54 $request = $request->withCookieParams($_COOKIE);
55 }
56 $queryParameters = GeneralUtility::_GET();
57 if (!empty($queryParameters)) {
58 $request = $request->withQueryParams($queryParameters);
59 }
60 $parsedBody = GeneralUtility::_POST();
61 if (empty($parsedBody) && in_array($method, ['PUT', 'PATCH', 'DELETE'])) {
62 parse_str(file_get_contents('php://input'), $parsedBody);
63 }
64 if (!empty($parsedBody)) {
65 $request = $request->withParsedBody($parsedBody);
66 }
67 return $request;
68 }
69
70 /**
71 * Fetch headers from $_SERVER variables
72 * which are only the ones starting with HTTP_* and CONTENT_*
73 *
74 * @param array $server
75 * @return array
76 */
77 protected static function prepareHeaders(array $server)
78 {
79 $headers = [];
80 foreach ($server as $key => $value) {
81 if (strpos($key, 'HTTP_COOKIE') === 0) {
82 // Cookies are handled using the $_COOKIE superglobal
83 continue;
84 }
85 if (!empty($value)) {
86 if (strpos($key, 'HTTP_') === 0) {
87 $name = strtr(substr($key, 5), '_', ' ');
88 $name = strtr(ucwords(strtolower($name)), ' ', '-');
89 $name = strtolower($name);
90 $headers[$name] = $value;
91 } elseif (strpos($key, 'CONTENT_') === 0) {
92 $name = substr($key, 8); // Content-
93 $name = 'Content-' . (($name === 'MD5') ? $name : ucfirst(strtolower($name)));
94 $name = strtolower($name);
95 $headers[$name] = $value;
96 }
97 }
98 }
99 return $headers;
100 }
101
102 /**
103 * Normalize uploaded files
104 *
105 * Transforms each value into an UploadedFileInterface instance, and ensures that nested arrays are normalized.
106 *
107 * @param array $files
108 * @return array
109 * @throws \InvalidArgumentException for unrecognized values
110 */
111 protected static function normalizeUploadedFiles(array $files)
112 {
113 $normalizedFileUploads = [];
114 foreach ($files as $key => $value) {
115 if ($value instanceof UploadedFileInterface) {
116 $normalizedFileUploads[$key] = $value;
117 } elseif (is_array($value)) {
118 if (isset($value['tmp_name'])) {
119 $uploadedFiles = self::createUploadedFile($value);
120 if ($uploadedFiles) {
121 $normalizedFileUploads[$key] = $uploadedFiles;
122 }
123 } else {
124 $normalizedFileUploads[$key] = self::normalizeUploadedFiles($value);
125 }
126 } else {
127 throw new \InvalidArgumentException('Invalid value in files specification.', 1436717282);
128 }
129 }
130 return $normalizedFileUploads;
131 }
132
133 /**
134 * Create and return an UploadedFile instance from a $_FILES specification.
135 *
136 * If the specification represents an array of values, this method will
137 * recursively resolve uploaded files.
138 *
139 * @param array $value $_FILES structure
140 * @return UploadedFileInterface[]|UploadedFileInterface|NULL
141 */
142 protected static function createUploadedFile(array $value)
143 {
144 if (is_array($value['tmp_name'])) {
145 $files = [];
146 foreach (array_keys($value['tmp_name']) as $key) {
147 $data = [
148 'tmp_name' => $value['tmp_name'][$key],
149 'size' => $value['size'][$key],
150 'error' => $value['error'][$key],
151 'name' => $value['name'][$key],
152 'type' => $value['type'][$key]
153 ];
154 $result = self::createUploadedFile($data);
155 if ($result) {
156 $files[$key] = $result;
157 }
158 }
159 return $files;
160 } elseif (!empty($value['tmp_name'])) {
161 return new UploadedFile($value['tmp_name'], $value['size'], $value['error'], $value['name'], $value['type']);
162 }
163 return null;
164 }
165 }