[FEATURE] Introduce Request/Response based on PSR-7
[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 static public function fromGlobals() {
37 $serverParameters = $_SERVER;
38 $headers = static::prepareHeaders($serverParameters);
39
40 $method = isset($serverParameters['REQUEST_METHOD']) ? $serverParameters['REQUEST_METHOD'] : 'GET';
41 $uri = new Uri(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'));
42
43 $request = new ServerRequest(
44 $uri,
45 $method,
46 'php://input',
47 $headers,
48 $serverParameters,
49 static::normalizeUploadedFiles($_FILES)
50 );
51
52 if (!empty($_COOKIE)) {
53 $request = $request->withCookieParams($_COOKIE);
54 }
55 $queryParameters = GeneralUtility::_GET();
56 if (!empty($queryParameters)) {
57 $request = $request->withQueryParams($queryParameters);
58 }
59 $parsedBody = GeneralUtility::_POST();
60 if (!empty($parsedBody)) {
61 $request = $request->withParsedBody($parsedBody);
62 }
63 return $request;
64 }
65
66 /**
67 * Fetch headers from $_SERVER variables
68 * which are only the ones starting with HTTP_* and CONTENT_*
69 *
70 * @param array $server
71 * @return array
72 */
73 protected static function prepareHeaders(array $server) {
74 $headers = array();
75 foreach ($server as $key => $value) {
76 if (strpos($key, 'HTTP_COOKIE') === 0) {
77 // Cookies are handled using the $_COOKIE superglobal
78 continue;
79 }
80 if (!empty($value)) {
81 if (strpos($key, 'HTTP_') === 0) {
82 $name = strtr(substr($key, 5), '_', ' ');
83 $name = strtr(ucwords(strtolower($name)), ' ', '-');
84 $name = strtolower($name);
85 $headers[$name] = $value;
86 } elseif (strpos($key, 'CONTENT_') === 0) {
87 $name = substr($key, 8); // Content-
88 $name = 'Content-' . (($name == 'MD5') ? $name : ucfirst(strtolower($name)));
89 $name = strtolower($name);
90 $headers[$name] = $value;
91 }
92 }
93 }
94 return $headers;
95 }
96
97 /**
98 * Normalize uploaded files
99 *
100 * Transforms each value into an UploadedFileInterface instance, and ensures that nested arrays are normalized.
101 *
102 * @param array $files
103 * @return array
104 * @throws \InvalidArgumentException for unrecognized values
105 */
106 protected static function normalizeUploadedFiles(array $files) {
107 $normalizedFileUploads = array();
108 foreach ($files as $key => $value) {
109 if ($value instanceof UploadedFileInterface) {
110 $normalizedFileUploads[$key] = $value;
111 } elseif (is_array($value)) {
112 if (isset($value['tmp_name'])) {
113 $normalizedFileUploads[$key] = self::createUploadedFile($value);
114 } else {
115 $normalizedFileUploads[$key] = self::normalizeUploadedFiles($value);
116 }
117 } else {
118 throw new \InvalidArgumentException('Invalid value in files specification.', 1436717282);
119 }
120 }
121 return $normalizedFileUploads;
122 }
123
124 /**
125 * Create and return an UploadedFile instance from a $_FILES specification.
126 *
127 * If the specification represents an array of values, this method will
128 * delegate to normalizeNestedFileSpec() and return that return value.
129 *
130 * @param array $value $_FILES structure
131 * @return UploadedFileInterface[]|UploadedFileInterface
132 */
133 protected static function createUploadedFile(array $value) {
134 if (is_array($value['tmp_name'])) {
135 $files = array();
136 foreach (array_keys($value['tmp_name']) as $key) {
137 $data = array(
138 'tmp_name' => $value['tmp_name'][$key],
139 'size' => $value['size'][$key],
140 'error' => $value['error'][$key],
141 'name' => $value['name'][$key],
142 'type' => $value['type'][$key]
143 );
144 $files[$key] = self::createUploadedFile($data);
145 }
146 return $files;
147 } else {
148 return new UploadedFile($value['tmp_name'], $value['size'], $value['error'], $value['name'], $value['type']);
149 }
150 }
151
152 }