Skip to content

Commit b70a854

Browse files
committed
🛀 extract uploaded file normalize
1 parent 2713821 commit b70a854

File tree

5 files changed

+216
-198
lines changed

5 files changed

+216
-198
lines changed

src/Psr17/factory_helpers.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99
namespace chillerlan\HTTP\Psr17;
1010

1111
use Psr\Http\Message\ServerRequestInterface;
12-
use chillerlan\HTTP\Psr7\{ServerRequest, Stream, Uri};
12+
use chillerlan\HTTP\Psr7\{File, ServerRequest, Stream, Uri};
1313
use InvalidArgumentException;
1414
use Psr\Http\Message\StreamInterface;
1515

16-
use function chillerlan\HTTP\Psr7\normalize_files;
1716
use function explode, function_exists, getallheaders, is_scalar, method_exists, str_replace;
1817

1918
const PSR17_INCLUDES = true;
@@ -70,7 +69,7 @@ function_exists('getallheaders') ? getallheaders() : [],
7069
->withCookieParams($_COOKIE)
7170
->withQueryParams($_GET)
7271
->withParsedBody($_POST)
73-
->withUploadedFiles(normalize_files($_FILES))
72+
->withUploadedFiles(File::normalize($_FILES))
7473
;
7574
}
7675

src/Psr7/File.php

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
/**
3+
* Class File
4+
*
5+
* @created 28.03.2021
6+
* @author smiley <smiley@chillerlan.net>
7+
* @copyright 2021 smiley
8+
* @license MIT
9+
*/
10+
11+
namespace chillerlan\HTTP\Psr7;
12+
13+
use InvalidArgumentException;
14+
use Psr\Http\Message\UploadedFileInterface;
15+
use function array_keys, is_array;
16+
17+
/**
18+
*
19+
*/
20+
class File{
21+
22+
/**
23+
* @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
24+
*/
25+
public const MIMETYPES = [
26+
'3gp' => 'video/3gpp',
27+
'7z' => 'application/x-7z-compressed',
28+
'aac' => 'audio/x-aac',
29+
'ai' => 'application/postscript',
30+
'aif' => 'audio/x-aiff',
31+
'asc' => 'text/plain',
32+
'asf' => 'video/x-ms-asf',
33+
'atom' => 'application/atom+xml',
34+
'avi' => 'video/x-msvideo',
35+
'bmp' => 'image/bmp',
36+
'bz2' => 'application/x-bzip2',
37+
'cer' => 'application/pkix-cert',
38+
'crl' => 'application/pkix-crl',
39+
'crt' => 'application/x-x509-ca-cert',
40+
'css' => 'text/css',
41+
'csv' => 'text/csv',
42+
'cu' => 'application/cu-seeme',
43+
'deb' => 'application/x-debian-package',
44+
'doc' => 'application/msword',
45+
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
46+
'dvi' => 'application/x-dvi',
47+
'eot' => 'application/vnd.ms-fontobject',
48+
'eps' => 'application/postscript',
49+
'epub' => 'application/epub+zip',
50+
'etx' => 'text/x-setext',
51+
'flac' => 'audio/flac',
52+
'flv' => 'video/x-flv',
53+
'gif' => 'image/gif',
54+
'gz' => 'application/gzip',
55+
'htm' => 'text/html',
56+
'html' => 'text/html',
57+
'ico' => 'image/x-icon',
58+
'ics' => 'text/calendar',
59+
'ini' => 'text/plain',
60+
'iso' => 'application/x-iso9660-image',
61+
'jar' => 'application/java-archive',
62+
'jpe' => 'image/jpeg',
63+
'jpeg' => 'image/jpeg',
64+
'jpg' => 'image/jpeg',
65+
'js' => 'text/javascript',
66+
'json' => 'application/json',
67+
'latex' => 'application/x-latex',
68+
'log' => 'text/plain',
69+
'm4a' => 'audio/mp4',
70+
'm4v' => 'video/mp4',
71+
'mid' => 'audio/midi',
72+
'midi' => 'audio/midi',
73+
'mov' => 'video/quicktime',
74+
'mkv' => 'video/x-matroska',
75+
'mp3' => 'audio/mpeg',
76+
'mp4' => 'video/mp4',
77+
'mp4a' => 'audio/mp4',
78+
'mp4v' => 'video/mp4',
79+
'mpe' => 'video/mpeg',
80+
'mpeg' => 'video/mpeg',
81+
'mpg' => 'video/mpeg',
82+
'mpg4' => 'video/mp4',
83+
'oga' => 'audio/ogg',
84+
'ogg' => 'audio/ogg',
85+
'ogv' => 'video/ogg',
86+
'ogx' => 'application/ogg',
87+
'pbm' => 'image/x-portable-bitmap',
88+
'pdf' => 'application/pdf',
89+
'pgm' => 'image/x-portable-graymap',
90+
'png' => 'image/png',
91+
'pnm' => 'image/x-portable-anymap',
92+
'ppm' => 'image/x-portable-pixmap',
93+
'ppt' => 'application/vnd.ms-powerpoint',
94+
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
95+
'ps' => 'application/postscript',
96+
'qt' => 'video/quicktime',
97+
'rar' => 'application/x-rar-compressed',
98+
'ras' => 'image/x-cmu-raster',
99+
'rss' => 'application/rss+xml',
100+
'rtf' => 'application/rtf',
101+
'sgm' => 'text/sgml',
102+
'sgml' => 'text/sgml',
103+
'svg' => 'image/svg+xml',
104+
'swf' => 'application/x-shockwave-flash',
105+
'tar' => 'application/x-tar',
106+
'tif' => 'image/tiff',
107+
'tiff' => 'image/tiff',
108+
'torrent' => 'application/x-bittorrent',
109+
'ttf' => 'application/x-font-ttf',
110+
'txt' => 'text/plain',
111+
'wav' => 'audio/x-wav',
112+
'webm' => 'video/webm',
113+
'wma' => 'audio/x-ms-wma',
114+
'wmv' => 'video/x-ms-wmv',
115+
'woff' => 'application/x-font-woff',
116+
'wsdl' => 'application/wsdl+xml',
117+
'xbm' => 'image/x-xbitmap',
118+
'xls' => 'application/vnd.ms-excel',
119+
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
120+
'xml' => 'application/xml',
121+
'xpm' => 'image/x-xpixmap',
122+
'xwd' => 'image/x-xwindowdump',
123+
'yaml' => 'text/yaml',
124+
'yml' => 'text/yaml',
125+
'zip' => 'application/zip',
126+
];
127+
128+
/**
129+
* Return an UploadedFile instance array.
130+
*
131+
* @param array $files A array which respect $_FILES structure
132+
*
133+
* @return array
134+
* @throws \InvalidArgumentException for unrecognized values
135+
*/
136+
public static function normalize(array $files):array{
137+
$normalized = [];
138+
139+
foreach($files as $key => $value){
140+
141+
if($value instanceof UploadedFileInterface){
142+
$normalized[$key] = $value;
143+
}
144+
elseif(is_array($value) && isset($value['tmp_name'])){
145+
$normalized[$key] = self::createUploadedFileFromSpec($value);
146+
}
147+
elseif(is_array($value)){
148+
$normalized[$key] = self::normalize($value);
149+
}
150+
else{
151+
throw new InvalidArgumentException('Invalid value in files specification');
152+
}
153+
154+
}
155+
156+
return $normalized;
157+
}
158+
159+
/**
160+
* Create and return an UploadedFile instance from a $_FILES specification.
161+
*
162+
* If the specification represents an array of values, this method will
163+
* delegate to normalizeNestedFileSpec() and return that return value.
164+
*
165+
* @param array $value $_FILES struct
166+
*
167+
* @return array|\Psr\Http\Message\UploadedFileInterface
168+
*/
169+
public static function createUploadedFileFromSpec(array $value){
170+
171+
if(is_array($value['tmp_name'])){
172+
return self::normalizeNestedFileSpec($value);
173+
}
174+
175+
return new UploadedFile($value['tmp_name'], (int)$value['size'], (int)$value['error'], $value['name'], $value['type']);
176+
}
177+
178+
/**
179+
* Normalize an array of file specifications.
180+
*
181+
* Loops through all nested files and returns a normalized array of
182+
* UploadedFileInterface instances.
183+
*
184+
* @param array $files
185+
*
186+
* @return \Psr\Http\Message\UploadedFileInterface[]
187+
*/
188+
public static function normalizeNestedFileSpec(array $files):array{
189+
$normalized = [];
190+
191+
foreach(array_keys($files['tmp_name']) as $key){
192+
$spec = [
193+
'tmp_name' => $files['tmp_name'][$key],
194+
'size' => $files['size'][$key],
195+
'error' => $files['error'][$key],
196+
'name' => $files['name'][$key],
197+
'type' => $files['type'][$key],
198+
];
199+
200+
$normalized[$key] = self::createUploadedFileFromSpec($spec);
201+
}
202+
203+
return $normalized;
204+
}
205+
206+
}

src/Psr7/MultipartStream.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function addElement(array $e):MultipartStream{
106106

107107
$this->stream->write('--'.$this->boundary."\r\n");
108108

109-
foreach(normalize_message_headers($e['headers']) as $key => $value){
109+
foreach(Header::normalize($e['headers']) as $key => $value){
110110
$this->stream->write($key.': '.$value."\r\n");
111111
}
112112

@@ -139,7 +139,7 @@ private function setElementHeaders(array $e):array{
139139

140140
// Set a default Content-Type if none was supplied
141141
if(!$this->hasHeader($e['headers'], 'content-type') && $hasFilename){
142-
$type = MIMETYPES[pathinfo($e['filename'], PATHINFO_EXTENSION)] ?? null;
142+
$type = File::MIMETYPES[pathinfo($e['filename'], PATHINFO_EXTENSION)] ?? null;
143143

144144
if($type){
145145
$e['headers']['Content-Type'] = $type;

0 commit comments

Comments
 (0)