]> jfr.im git - uguu.git/blob - static/php/includes/Core.namespace.php
major code cleanup and more error checking added.
[uguu.git] / static / php / includes / Core.namespace.php
1 <?php
2
3 /*
4 * Uguu
5 *
6 * @copyright Copyright (c) 2022 Go Johansson (nekunekus) <neku@pomf.se> <github.com/nokonoko>
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
23 namespace Core {
24
25 require_once 'Upload.class.php';
26
27 use PDO;
28 use Upload as Upload;
29
30 class Settings
31 {
32
33 public static mixed $DB;
34
35 public static string $DB_MODE;
36 public static string $DB_PATH;
37 public static string $DB_USER;
38 public static string $DB_PASS;
39
40 public static bool $LOG_IP;
41 public static bool $ANTI_DUPE;
42 public static bool $BLACKLIST_DB;
43 public static bool $FILTER_MODE;
44
45 public static string $FILES_ROOT;
46 public static int $FILES_RETRIES;
47
48 public static bool $SSL;
49 public static string $URL;
50
51 public static int $NAME_LENGTH;
52 public static string $ID_CHARSET;
53 public static array $DOUBLE_DOTS;
54 public static array $BLOCKED_EXTENSIONS;
55 public static array $BLOCKED_MIME;
56
57
58 public static function loadConfig()
59 {
60 if (!file_exists('/Users/go.johansson/PERSONAL_REPOS/Uguu/dist.json')) {
61 throw new \Exception('Cant read settings file.', 500);
62 }
63 try {
64 $settings_array = json_decode(
65 file_get_contents('/Users/go.johansson/PERSONAL_REPOS/Uguu/dist.json'),
66 true
67 );
68 self::$DB_MODE = $settings_array['DB_MODE'];
69 self::$DB_PATH = $settings_array['DB_PATH'];
70 self::$DB_USER = $settings_array['DB_USER'];
71 self::$DB_PASS = $settings_array['DB_PASS'];
72 self::$LOG_IP = $settings_array['LOG_IP'];
73 self::$ANTI_DUPE = $settings_array['ANTI_DUPE'];
74 self::$BLACKLIST_DB = $settings_array['BLACKLIST_DB'];
75 self::$FILTER_MODE = $settings_array['FILTER_MODE'];
76 self::$FILES_ROOT = $settings_array['FILES_ROOT'];
77 self::$FILES_RETRIES = $settings_array['FILES_RETRIES'];
78 self::$SSL = $settings_array['SSL'];
79 self::$URL = $settings_array['URL'];
80 self::$NAME_LENGTH = $settings_array['NAME_LENGTH'];
81 self::$ID_CHARSET = $settings_array['ID_CHARSET'];
82 self::$BLOCKED_EXTENSIONS = $settings_array['BLOCKED_EXTENSIONS'];
83 self::$BLOCKED_MIME = $settings_array['BLOCKED_MIME'];
84 self::$DOUBLE_DOTS = $settings_array['DOUBLE_DOTS'];
85 } catch (\Exception $e) {
86 throw new \Exception('Cant populate settings.', 500);
87 }
88 (new Database())->assemblePDO();
89 }
90 }
91
92 class cuteGrills
93 {
94 public static array $GRILLS;
95
96 public static function showGrills()
97 {
98 self::loadGrills();
99 if (!headers_sent()) {
100 header(
101 'Location: /img/grills/' .
102 self::$GRILLS[array_rand(self::$GRILLS)],
103 true,
104 303
105 );
106 }
107 }
108
109 public static function loadGrills()
110 {
111 self::$GRILLS = array_slice(scandir('img/grills/'), 2);
112 }
113 }
114
115 /**
116 * The Response class is a do-it-all for getting responses out in different
117 * formats.
118 *
119 * @todo Create sub-classes to split and extend this god object.
120 */
121 class Response
122 {
123 /**
124 * Indicates response type used for routing.
125 *
126 * Valid strings are 'csv', 'html', 'json' and 'text'.
127 *
128 * @var string Response type
129 */
130 private $type;
131
132 /**
133 * Indicates requested response type.
134 *
135 * Valid strings are 'csv', 'html', 'json', 'gyazo' and 'text'.
136 *
137 * @param string|null $response_type Response type
138 */
139 public function __construct($response_type = null)
140 {
141 switch ($response_type) {
142 case 'csv':
143 header('Content-Type: text/csv; charset=UTF-8');
144 $this->type = $response_type;
145 break;
146 case 'html':
147 header('Content-Type: text/html; charset=UTF-8');
148 $this->type = $response_type;
149 break;
150 case 'json':
151 header('Content-Type: application/json; charset=UTF-8');
152 $this->type = $response_type;
153 break;
154 case 'gyazo':
155 header('Content-Type: text/plain; charset=UTF-8');
156 $this->type = 'text';
157 break;
158 case 'text':
159 header('Content-Type: text/plain; charset=UTF-8');
160 $this->type = $response_type;
161 break;
162 default:
163 header('Content-Type: application/json; charset=UTF-8');
164 $this->type = 'json';
165 $this->error(400, 'Invalid response type. Valid options are: csv, html, json, text.');
166 break;
167 }
168 }
169
170 /**
171 * Routes error messages depending on response type.
172 *
173 * @param int $code HTTP status code number
174 * @param int $desc descriptive error message
175 *
176 * @return void
177 */
178 public function error($code, $desc)
179 {
180 $response = null;
181
182 switch ($this->type) {
183 case 'csv':
184 $response = $this->csvError($desc);
185 break;
186 case 'html':
187 $response = $this->htmlError($code, $desc);
188 break;
189 case 'json':
190 $response = $this->jsonError($code, $desc);
191 break;
192 case 'text':
193 $response = $this->textError($code, $desc);
194 break;
195 }
196 http_response_code($code);
197 echo $response;
198 }
199
200 /**
201 * Indicates with CSV body the request was invalid.
202 *
203 * @param int $description descriptive error message
204 *
205 * @return string error message in CSV format
206 * @deprecated 2.1.0 Will be renamed to camelCase format.
207 *
208 */
209 private static function csvError($description)
210 {
211 return '"error"' . "\r\n" . "\"$description\"" . "\r\n";
212 }
213
214 /**
215 * Indicates with HTML body the request was invalid.
216 *
217 * @param int $code HTTP status code number
218 * @param int $description descriptive error message
219 *
220 * @return string error message in HTML format
221 * @deprecated 2.1.0 Will be renamed to camelCase format.
222 *
223 */
224 private static function htmlError($code, $description)
225 {
226 return '<p>ERROR: (' . $code . ') ' . $description . '</p>';
227 }
228
229 /**
230 * Indicates with JSON body the request was invalid.
231 *
232 * @param int $code HTTP status code number
233 * @param int $description descriptive error message
234 *
235 * @return string error message in pretty-printed JSON format
236 * @deprecated 2.1.0 Will be renamed to camelCase format.
237 *
238 */
239 private static function jsonError($code, $description)
240 {
241 return json_encode([
242 'success' => false,
243 'errorcode' => $code,
244 'description' => $description,
245 ], JSON_PRETTY_PRINT);
246 }
247
248 /**
249 * Indicates with plain text body the request was invalid.
250 *
251 * @param int $code HTTP status code number
252 * @param int $description descriptive error message
253 *
254 * @return string error message in plain text format
255 * @deprecated 2.1.0 Will be renamed to camelCase format.
256 *
257 */
258 private static function textError($code, $description)
259 {
260 return 'ERROR: (' . $code . ') ' . $description;
261 }
262
263 /**
264 * Routes success messages depending on response type.
265 *
266 * @param mixed[] $files
267 *
268 * @return void
269 */
270 public function send($files)
271 {
272 $response = null;
273
274 switch ($this->type) {
275 case 'csv':
276 $response = $this->csvSuccess($files);
277 break;
278 case 'html':
279 $response = $this->htmlSuccess($files);
280 break;
281 case 'json':
282 $response = $this->jsonSuccess($files);
283 break;
284 case 'text':
285 $response = $this->textSuccess($files);
286 break;
287 }
288
289 http_response_code(200); // "200 OK". Success.
290 echo $response;
291 }
292
293 /**
294 * Indicates with CSV body the request was successful.
295 *
296 * @param mixed[] $files
297 *
298 * @return string success message in CSV format
299 * @deprecated 2.1.0 Will be renamed to camelCase format.
300 *
301 */
302 private static function csvSuccess($files)
303 {
304 $result = '"name","url","hash","size"' . "\r\n";
305 foreach ($files as $file) {
306 $result .= '"' . $file['name'] . '"' . ',' .
307 '"' . $file['url'] . '"' . ',' .
308 '"' . $file['hash'] . '"' . ',' .
309 '"' . $file['size'] . '"' . "\r\n";
310 }
311
312 return $result;
313 }
314
315 /**
316 * Indicates with HTML body the request was successful.
317 *
318 * @param mixed[] $files
319 *
320 * @return string success message in HTML format
321 * @deprecated 2.1.0 Will be renamed to camelCase format.
322 *
323 */
324 private static function htmlSuccess($files)
325 {
326 $result = '';
327
328 foreach ($files as $file) {
329 $result .= '<a href="' . $file['url'] . '">' . $file['url'] . '</a><br>';
330 }
331
332 return $result;
333 }
334
335 /**
336 * Indicates with JSON body the request was successful.
337 *
338 * @param mixed[] $files
339 *
340 * @return string success message in pretty-printed JSON format
341 * @deprecated 2.1.0 Will be renamed to camelCase format.
342 *
343 */
344 private static function jsonSuccess($files)
345 {
346 return json_encode([
347 'success' => true,
348 'files' => $files,
349 ], JSON_PRETTY_PRINT);
350 }
351
352 /**
353 * Indicates with plain text body the request was successful.
354 *
355 * @param mixed[] $files
356 *
357 * @return string success message in plain text format
358 * @deprecated 2.1.0 Will be renamed to camelCase format.
359 *
360 */
361 private static function textSuccess($files)
362 {
363 $result = '';
364
365 foreach ($files as $file) {
366 $result .= $file['url'] . "\n";
367 }
368
369 return $result;
370 }
371 }
372
373
374 class Database
375 {
376 public static function assemblePDO()
377 {
378 try {
379 Settings::$DB = new PDO(
380 Settings::$DB_MODE . ':' . Settings::$DB_PATH, Settings::$DB_USER,
381 Settings::$DB_PASS
382 );
383 } catch (\Exception $e) {
384 throw new \Exception('Cant connect to DB.', 500);
385 }
386 }
387
388 public function dbCheckNameExists()
389 {
390 try {
391 $q = Settings::$DB->prepare('SELECT COUNT(filename) FROM files WHERE filename = (:name)');
392 $q->bindValue(':name', Upload::$NEW_NAME_FULL);
393 $q->execute();
394 return $q->fetchColumn();
395 } catch (\Exception $e) {
396 throw new \Exception('Cant check if name exists in DB.', 500);
397 }
398 }
399
400 public function checkFileBlacklist()
401 {
402 try {
403 $q = Settings::$DB->prepare('SELECT hash, COUNT(*) AS count FROM blacklist WHERE hash = (:hash)');
404 $q->bindValue(':hash', Upload::$SHA1, PDO::PARAM_STR);
405 $q->execute();
406 $result = $q->fetch();
407 if ($result['count'] > 0) {
408 throw new \Exception('File blacklisted!', 415);
409 }
410 } catch (\Exception $e) {
411 throw new \Exception('Cant check blacklist DB.', 500);
412 }
413 }
414
415 public function antiDupe()
416 {
417 try {
418 $q = Settings::$DB->prepare(
419 'SELECT filename, COUNT(*) AS count FROM files WHERE hash = (:hash) AND size = (:size)'
420 );
421 $q->bindValue(':hash', Upload::$SHA1, PDO::PARAM_STR);
422 $q->bindValue(':size', Upload::$FILE_SIZE, PDO::PARAM_INT);
423 $q->execute();
424 $result = $q->fetch();
425 if ($result['count'] > 0) {
426 Upload::$NEW_NAME_FULL = $result['filename'];
427 }
428 } catch (\Exception $e) {
429 throw new \Exception('Cant check for dupes in DB.', 500);
430 }
431 }
432
433 public function newIntoDB()
434 {
435 try {
436 $q = Settings::$DB->prepare(
437 'INSERT INTO files (hash, originalname, filename, size, date, ip)' .
438 'VALUES (:hash, :orig, :name, :size, :date, :ip)'
439 );
440 $q->bindValue(':hash', Upload::$SHA1, PDO::PARAM_STR);
441 $q->bindValue(':orig', strip_tags(Upload::$FILE_NAME), PDO::PARAM_STR);
442 $q->bindValue(':name', Upload::$NEW_NAME_FULL, PDO::PARAM_STR);
443 $q->bindValue(':size', Upload::$FILE_SIZE, PDO::PARAM_INT);
444 $q->bindValue(':date', time(), PDO::PARAM_STR);
445 $q->bindValue(':ip', Upload::$IP, PDO::PARAM_STR);
446 $q->execute();
447 } catch (\Exception $e) {
448 throw new \Exception('Cant insert into DB.', 500);
449 }
450 }
451 }
452 }
453
454
455