]>
Commit | Line | Data |
---|---|---|
1 | <?php | |
2 | ||
3 | /** | |
4 | * Uguu | |
5 | * | |
6 | * @copyright Copyright (c) 2022 Go Johansson (nokonoko) <neku@pomf.se> | |
7 | * | |
8 | * This program is free software: you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation, either version 3 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | namespace Pomf\Uguu\Classes; | |
23 | ||
24 | use Exception; | |
25 | ||
26 | class Upload extends Response | |
27 | { | |
28 | public array $FILE_INFO; | |
29 | public array $fingerPrintInfo; | |
30 | private mixed $Connector; | |
31 | ||
32 | ||
33 | /** | |
34 | * @throws Exception | |
35 | */ | |
36 | public function reFiles($files): array | |
37 | { | |
38 | $this->Connector = new Connector(); | |
39 | $this->Connector->setDB($this->Connector->DB); | |
40 | $result = []; | |
41 | $files = $this->diverseArray($files); | |
42 | foreach ($files as $file) { | |
43 | $hash = sha1_file($file['tmp_name']); | |
44 | $this->FILE_INFO = [ | |
45 | 'TEMP_NAME' => $file['tmp_name'], | |
46 | 'NAME' => strip_tags($file['name']), | |
47 | 'SIZE' => $file['size'], | |
48 | 'SHA1' => $hash, | |
49 | 'EXTENSION' => $this->fileExtension($file), | |
50 | 'MIME' => $this->fileMIME($file), | |
51 | 'NEW_NAME' => $this->generateName($this->fileExtension($file), $hash) | |
52 | ]; | |
53 | $result[] = [ | |
54 | $this->FILE_INFO['TEMP_NAME'], | |
55 | $this->FILE_INFO['NAME'], | |
56 | $this->FILE_INFO['SIZE'], | |
57 | $this->FILE_INFO['SHA1'], | |
58 | $this->FILE_INFO['EXTENSION'], | |
59 | $this->FILE_INFO['MIME'] | |
60 | ]; | |
61 | } | |
62 | return $result; | |
63 | } | |
64 | public function diverseArray($files): array | |
65 | { | |
66 | $result = []; | |
67 | foreach ($files as $key1 => $value1) { | |
68 | foreach ($value1 as $key2 => $value2) { | |
69 | $result[$key2][$key1] = $value2; | |
70 | } | |
71 | } | |
72 | return $result; | |
73 | } | |
74 | ||
75 | /** | |
76 | * @throws Exception | |
77 | */ | |
78 | public function uploadFile(): array | |
79 | { | |
80 | ||
81 | if ($this->Connector->CONFIG['RATE_LIMIT']) { | |
82 | $this->Connector->checkRateLimit($this->fingerPrintInfo); | |
83 | } | |
84 | ||
85 | if ($this->Connector->CONFIG['BLACKLIST_DB']) { | |
86 | $this->Connector->checkFileBlacklist($this->FILE_INFO); | |
87 | } | |
88 | ||
89 | if ($this->Connector->CONFIG['FILTER_MODE'] && empty($this->FILE_INFO['EXTENSION'])) { | |
90 | $this->checkMimeBlacklist(); | |
91 | } | |
92 | ||
93 | if ($this->Connector->CONFIG['FILTER_MODE'] && !empty($this->FILE_INFO['EXTENSION'])) { | |
94 | $this->checkMimeBlacklist(); | |
95 | $this->checkExtensionBlacklist(); | |
96 | } | |
97 | ||
98 | if (!is_dir($this->Connector->CONFIG['FILES_ROOT'])) { | |
99 | throw new Exception('File storage path not accessible.', 500); | |
100 | } | |
101 | ||
102 | if ( | |
103 | !move_uploaded_file($this->FILE_INFO['TEMP_NAME'], $this->Connector->CONFIG['FILES_ROOT'] . | |
104 | $this->FILE_INFO['NEW_NAME']) | |
105 | ) { | |
106 | throw new Exception('Failed to move file to destination', 500); | |
107 | } | |
108 | ||
109 | if (!chmod($this->Connector->CONFIG['FILES_ROOT'] . $this->FILE_INFO['NEW_NAME'], 0644)) { | |
110 | throw new Exception('Failed to change file permissions', 500); | |
111 | } | |
112 | ||
113 | if (!$this->Connector->CONFIG['LOG_IP']) { | |
114 | $this->fingerPrintInfo['ip'] = null; | |
115 | } | |
116 | ||
117 | $this->Connector->newIntoDB($this->FILE_INFO, $this->fingerPrintInfo); | |
118 | ||
119 | return [ | |
120 | 'hash' => $this->FILE_INFO['SHA1'], | |
121 | 'name' => $this->FILE_INFO['NAME'], | |
122 | 'url' => $this->Connector->CONFIG['FILES_URL'] . '/' . $this->FILE_INFO['NEW_NAME'], | |
123 | 'size' => $this->FILE_INFO['SIZE'] | |
124 | ]; | |
125 | } | |
126 | ||
127 | public function fingerPrint($files_amount): void | |
128 | { | |
129 | $this->fingerPrintInfo = [ | |
130 | 'timestamp' => time(), | |
131 | 'useragent' => $_SERVER['HTTP_USER_AGENT'], | |
132 | 'ip' => $_SERVER['REMOTE_ADDR'], | |
133 | 'ip_hash' => hash('sha1', $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']), | |
134 | 'files_amount' => $files_amount | |
135 | ]; | |
136 | } | |
137 | ||
138 | ||
139 | public function fileMIME($file): string | |
140 | { | |
141 | $finfo = finfo_open(FILEINFO_MIME_TYPE); | |
142 | return finfo_file($finfo, $file['tmp_name']); | |
143 | } | |
144 | ||
145 | public function fileExtension($file): ?string | |
146 | { | |
147 | $extension = explode('.', $file['name']); | |
148 | if (substr_count($file['name'], '.') > 0) { | |
149 | return end($extension); | |
150 | } else { | |
151 | return null; | |
152 | } | |
153 | } | |
154 | ||
155 | ||
156 | /** | |
157 | * @throws Exception | |
158 | */ | |
159 | public function checkMimeBlacklist(): void | |
160 | { | |
161 | if (in_array($this->FILE_INFO['MIME'], $this->Connector->CONFIG['BLOCKED_MIME'])) { | |
162 | throw new Exception('Filetype not allowed.', 415); | |
163 | } | |
164 | } | |
165 | ||
166 | /** | |
167 | * Check if file extension is blacklisted | |
168 | * if it does throw an exception. | |
169 | * | |
170 | * @throws Exception | |
171 | */ | |
172 | public function checkExtensionBlacklist(): void | |
173 | { | |
174 | if (in_array($this->FILE_INFO['EXTENSION'], $this->Connector->CONFIG['BLOCKED_EXTENSIONS'])) { | |
175 | throw new Exception('Filetype not allowed.', 415); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * @throws Exception | |
181 | */ | |
182 | public function generateName($extension, $hash): string | |
183 | { | |
184 | $a = $this->Connector->antiDupe($hash); | |
185 | if ($a === true) { | |
186 | do { | |
187 | if ($this->Connector->CONFIG['FILES_RETRIES'] === 0) { | |
188 | throw new Exception('Gave up trying to find an unused name!', 500); | |
189 | } | |
190 | ||
191 | $NEW_NAME = ''; | |
192 | for ($i = 0; $i < $this->Connector->CONFIG['NAME_LENGTH']; ++$i) { | |
193 | $NEW_NAME .= $this->Connector->CONFIG['ID_CHARSET'] | |
194 | [mt_rand(0, strlen($this->Connector->CONFIG['ID_CHARSET']))]; | |
195 | } | |
196 | ||
197 | if (!is_null($extension)) { | |
198 | $NEW_NAME .= '.' . $extension; | |
199 | } | |
200 | } while ($this->Connector->dbCheckNameExists($NEW_NAME) > 0); | |
201 | return $NEW_NAME; | |
202 | } else { | |
203 | return $a; | |
204 | } | |
205 | } | |
206 | } |