Selaa lähdekoodia

Refactoring and improvements

Sergio Brighenti 6 vuotta sitten
vanhempi
commit
ca361c8eef

+ 4 - 0
CHANGELOG.md

@@ -1,3 +1,7 @@
+## v2.4
++ Added function to remove orphaned files.
++ Internal refactoring and improvements
+
 ## v2.3.1
 ## v2.3.1
 + Fixed en lang.
 + Fixed en lang.
 + Fixed forced background with dark themes.
 + Fixed forced background with dark themes.

+ 68 - 0
app/Controllers/AdminController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Controllers;
+
+
+use League\Flysystem\FileNotFoundException;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class AdminController extends Controller
+{
+
+	/**
+	 * @param Request $request
+	 * @param Response $response
+	 * @return Response
+	 * @throws FileNotFoundException
+	 */
+	public function system(Request $request, Response $response): Response
+	{
+		$usersCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count;
+		$mediasCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count;
+		$orphanFilesCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` IS NULL')->fetch()->count;
+
+		$medias = $this->database->query('SELECT `users`.`user_code`, `uploads`.`code`, `uploads`.`storage_path` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id`')->fetchAll();
+
+		$totalSize = 0;
+
+		$filesystem = storage();
+		foreach ($medias as $media) {
+			$totalSize += $filesystem->getSize($media->storage_path);
+		}
+
+		return $this->view->render($response, 'dashboard/system.twig', [
+			'usersCount' => $usersCount,
+			'mediasCount' => $mediasCount,
+			'orphanFilesCount' => $orphanFilesCount,
+			'totalSize' => humanFileSize($totalSize),
+			'post_max_size' => ini_get('post_max_size'),
+			'upload_max_filesize' => ini_get('upload_max_filesize'),
+		]);
+	}
+
+	/**
+	 * @param Request $request
+	 * @param Response $response
+	 * @return Response
+	 */
+	public function deleteOrphanFiles(Request $request, Response $response): Response
+	{
+		$orphans = $this->database->query('SELECT * FROM `uploads` WHERE `user_id` IS NULL')->fetchAll();
+
+		$filesystem = storage();
+		$deleted = 0;
+
+		foreach ($orphans as $orphan) {
+			try {
+				$filesystem->delete($orphan->storage_path);
+				$deleted++;
+			} catch (FileNotFoundException $e) {
+			}
+		}
+
+		$this->session->alert(lang('deleted_orphans', [$deleted]));
+
+		return redirect($response, 'system');
+	}
+}

+ 9 - 3
app/Controllers/Controller.php

@@ -2,12 +2,18 @@
 
 
 namespace App\Controllers;
 namespace App\Controllers;
 
 
-
-use League\Flysystem\Adapter\Local;
+use App\Database\DB;
+use App\Web\Session;
 use League\Flysystem\FileNotFoundException;
 use League\Flysystem\FileNotFoundException;
-use League\Flysystem\Filesystem;
+use Monolog\Logger;
 use Slim\Container;
 use Slim\Container;
 
 
+/**
+ * @property Session|null session
+ * @property mixed|null view
+ * @property DB|null database
+ * @property Logger|null logger
+ */
 abstract class Controller
 abstract class Controller
 {
 {
 
 

+ 9 - 77
app/Controllers/DashboardController.php

@@ -2,8 +2,6 @@
 
 
 namespace App\Controllers;
 namespace App\Controllers;
 
 
-
-use App\Web\Session;
 use League\Flysystem\FileNotFoundException;
 use League\Flysystem\FileNotFoundException;
 use Slim\Http\Request;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Response;
@@ -23,7 +21,7 @@ class DashboardController extends Controller
 	{
 	{
 
 
 		if ($request->getParam('afterInstall') !== null && is_dir('install')) {
 		if ($request->getParam('afterInstall') !== null && is_dir('install')) {
-			Session::alert(lang('installed'), 'success');
+			$this->session->alert(lang('installed'), 'success');
 			removeDirectory('install');
 			removeDirectory('install');
 		}
 		}
 
 
@@ -41,31 +39,30 @@ class DashboardController extends Controller
 		$page = isset($args['page']) ? (int)$args['page'] : 0;
 		$page = isset($args['page']) ? (int)$args['page'] : 0;
 		$page = max(0, --$page);
 		$page = max(0, --$page);
 
 
-		if (Session::get('admin', false)) {
+		if ($this->session->get('admin', false)) {
 			$medias = $this->database->query('SELECT `uploads`.*, `users`.`user_code`, `users`.`username` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id` ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [self::PER_PAGE_ADMIN, $page * self::PER_PAGE_ADMIN])->fetchAll();
 			$medias = $this->database->query('SELECT `uploads`.*, `users`.`user_code`, `users`.`username` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id` ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [self::PER_PAGE_ADMIN, $page * self::PER_PAGE_ADMIN])->fetchAll();
 			$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count / self::PER_PAGE_ADMIN;
 			$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count / self::PER_PAGE_ADMIN;
 		} else {
 		} else {
-			$medias = $this->database->query('SELECT `uploads`.*,`users`.`user_code`, `users`.`username` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_id` = ? ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [Session::get('user_id'), self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
-			$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` = ?', Session::get('user_id'))->fetch()->count / self::PER_PAGE;
+			$medias = $this->database->query('SELECT `uploads`.*,`users`.`user_code`, `users`.`username` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_id` = ? ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [$this->session->get('user_id'), self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
+			$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` = ?', $this->session->get('user_id'))->fetch()->count / self::PER_PAGE;
 		}
 		}
 
 
 		$filesystem = storage();
 		$filesystem = storage();
 
 
 		foreach ($medias as $media) {
 		foreach ($medias as $media) {
-			$extension = pathinfo($media->filename, PATHINFO_EXTENSION);
 			try {
 			try {
 				$media->size = humanFileSize($filesystem->getSize($media->storage_path));
 				$media->size = humanFileSize($filesystem->getSize($media->storage_path));
-				$mime = $filesystem->getMimetype($media->storage_path);
+				$media->mimetype = $filesystem->getMimetype($media->storage_path);
 			} catch (FileNotFoundException $e) {
 			} catch (FileNotFoundException $e) {
-				$mime = null;
+				$media->size = null;
+				$media->mimetype = null;
 			}
 			}
-			$media->extension = $extension;
-			$media->mimetype = $mime;
+			$media->extension = pathinfo($media->filename, PATHINFO_EXTENSION);
 		}
 		}
 
 
 		return $this->view->render(
 		return $this->view->render(
 			$response,
 			$response,
-			Session::get('admin', false) ? 'dashboard/admin.twig' : 'dashboard/home.twig',
+			$this->session->get('admin', false) ? 'dashboard/admin.twig' : 'dashboard/home.twig',
 			[
 			[
 				'medias' => $medias,
 				'medias' => $medias,
 				'next' => $page < floor($pages),
 				'next' => $page < floor($pages),
@@ -74,69 +71,4 @@ class DashboardController extends Controller
 			]
 			]
 		);
 		);
 	}
 	}
-
-	/**
-	 * @param Request $request
-	 * @param Response $response
-	 * @return Response
-	 * @throws FileNotFoundException
-	 */
-	public function system(Request $request, Response $response): Response
-	{
-		$usersCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count;
-		$mediasCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count;
-		$orphanFilesCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` IS NULL')->fetch()->count;
-
-		$medias = $this->database->query('SELECT `users`.`user_code`, `uploads`.`code`, `uploads`.`storage_path` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id`')->fetchAll();
-
-		$totalSize = 0;
-
-		$filesystem = storage();
-		foreach ($medias as $media) {
-			$totalSize += $filesystem->getSize($media->storage_path);
-		}
-
-		return $this->view->render($response, 'dashboard/system.twig', [
-			'usersCount' => $usersCount,
-			'mediasCount' => $mediasCount,
-			'orphanFilesCount' => $orphanFilesCount,
-			'totalSize' => humanFileSize($totalSize),
-			'post_max_size' => ini_get('post_max_size'),
-			'upload_max_filesize' => ini_get('upload_max_filesize'),
-		]);
-	}
-
-	/**
-	 * @param Request $request
-	 * @param Response $response
-	 * @return Response
-	 */
-	public function getThemes(Request $request, Response $response): Response
-	{
-		$apiJson = json_decode(file_get_contents('https://bootswatch.com/api/4.json'));
-
-		$out = [];
-
-		$out['Default - Bootstrap 4 default theme'] = 'https://bootswatch.com/_vendor/bootstrap/dist/css/bootstrap.min.css';
-		foreach ($apiJson->themes as $theme) {
-			$out["{$theme->name} - {$theme->description}"] = $theme->cssMin;
-		}
-
-		return $response->withJson($out);
-	}
-
-
-	public function applyTheme(Request $request, Response $response): Response
-	{
-		if (!is_writable('static/bootstrap/css/bootstrap.min.css')) {
-			Session::alert(lang('cannot_write_file'), 'danger');
-			return redirect($response, route('system'));
-		}
-
-		file_put_contents('static/bootstrap/css/bootstrap.min.css', file_get_contents($request->getParam('css')));
-		return redirect($response, 'system')
-			->withAddedHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
-			->withAddedHeader('Pragma', 'no-cache')
-			->withAddedHeader('Expire', '0');
-	}
 }
 }

+ 15 - 17
app/Controllers/LoginController.php

@@ -3,8 +3,6 @@
 namespace App\Controllers;
 namespace App\Controllers;
 
 
 
 
-use App\Database\DB;
-use App\Web\Session;
 use Slim\Http\Request;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Response;
 
 
@@ -18,7 +16,7 @@ class LoginController extends Controller
 	 */
 	 */
 	public function show(Request $request, Response $response): Response
 	public function show(Request $request, Response $response): Response
 	{
 	{
-		if (Session::get('logged', false)) {
+		if ($this->session->get('logged', false)) {
 			return redirect($response, 'home');
 			return redirect($response, 'home');
 		}
 		}
 		return $this->view->render($response, 'auth/login.twig');
 		return $this->view->render($response, 'auth/login.twig');
@@ -32,29 +30,29 @@ class LoginController extends Controller
 	public function login(Request $request, Response $response): Response
 	public function login(Request $request, Response $response): Response
 	{
 	{
 
 
-		$result = DB::query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$request->getParam('username'), $request->getParam('username')])->fetch();
+		$result = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$request->getParam('username'), $request->getParam('username')])->fetch();
 
 
 		if (!$result || !password_verify($request->getParam('password'), $result->password)) {
 		if (!$result || !password_verify($request->getParam('password'), $result->password)) {
-			Session::alert(lang('bad_login'), 'danger');
+			$this->session->alert(lang('bad_login'), 'danger');
 			return redirect($response, 'login');
 			return redirect($response, 'login');
 		}
 		}
 
 
 		if (!$result->active) {
 		if (!$result->active) {
-			Session::alert(lang('account_disabled'), 'danger');
+			$this->session->alert(lang('account_disabled'), 'danger');
 			return redirect($response, 'login');
 			return redirect($response, 'login');
 		}
 		}
 
 
-		Session::set('logged', true);
-		Session::set('user_id', $result->id);
-		Session::set('username', $result->username);
-		Session::set('admin', $result->is_admin);
-		Session::set('used_space', humanFileSize($this->getUsedSpaceByUser($result->id)));
+		$this->session->set('logged', true);
+		$this->session->set('user_id', $result->id);
+		$this->session->set('username', $result->username);
+		$this->session->set('admin', $result->is_admin);
+		$this->session->set('used_space', humanFileSize($this->getUsedSpaceByUser($result->id)));
 
 
-		Session::alert(lang('welcome', [$result->username]), 'info');
+		$this->session->alert(lang('welcome', [$result->username]), 'info');
 		$this->logger->info("User $result->username logged in.");
 		$this->logger->info("User $result->username logged in.");
 
 
-		if (Session::has('redirectTo')) {
-			return $response->withRedirect(Session::get('redirectTo'));
+		if ($this->session->has('redirectTo')) {
+			return $response->withRedirect($this->session->get('redirectTo'));
 		}
 		}
 
 
 		return redirect($response, 'home');
 		return redirect($response, 'home');
@@ -67,9 +65,9 @@ class LoginController extends Controller
 	 */
 	 */
 	public function logout(Request $request, Response $response): Response
 	public function logout(Request $request, Response $response): Response
 	{
 	{
-		Session::clear();
-		Session::set('logged', false);
-		Session::alert(lang('goodbye'), 'warning');
+		$this->session->clear();
+		$this->session->set('logged', false);
+		$this->session->alert(lang('goodbye'), 'warning');
 		return redirect($response, 'login.show');
 		return redirect($response, 'login.show');
 	}
 	}
 
 

+ 44 - 0
app/Controllers/ThemeController.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Controllers;
+
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+class ThemeController extends Controller
+{
+	/**
+	 * @param Request $request
+	 * @param Response $response
+	 * @return Response
+	 */
+	public function getThemes(Request $request, Response $response): Response
+	{
+		$apiJson = json_decode(file_get_contents('https://bootswatch.com/api/4.json'));
+
+		$out = [];
+
+		$out['Default - Bootstrap 4 default theme'] = 'https://bootswatch.com/_vendor/bootstrap/dist/css/bootstrap.min.css';
+		foreach ($apiJson->themes as $theme) {
+			$out["{$theme->name} - {$theme->description}"] = $theme->cssMin;
+		}
+
+		return $response->withJson($out);
+	}
+
+
+	public function applyTheme(Request $request, Response $response): Response
+	{
+		if (!is_writable('static/bootstrap/css/bootstrap.min.css')) {
+			$this->session->alert(lang('cannot_write_file'), 'danger');
+			return redirect($response, route('system'));
+		}
+
+		file_put_contents('static/bootstrap/css/bootstrap.min.css', file_get_contents($request->getParam('css')));
+		return redirect($response, 'system')
+			->withAddedHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
+			->withAddedHeader('Pragma', 'no-cache')
+			->withAddedHeader('Expire', '0');
+	}
+
+}

+ 12 - 15
app/Controllers/UploadController.php

@@ -2,9 +2,7 @@
 
 
 namespace App\Controllers;
 namespace App\Controllers;
 
 
-
 use App\Exceptions\UnauthorizedException;
 use App\Exceptions\UnauthorizedException;
-use App\Web\Session;
 use Intervention\Image\ImageManagerStatic as Image;
 use Intervention\Image\ImageManagerStatic as Image;
 use League\Flysystem\FileExistsException;
 use League\Flysystem\FileExistsException;
 use League\Flysystem\FileNotFoundException;
 use League\Flysystem\FileNotFoundException;
@@ -84,7 +82,7 @@ class UploadController extends Controller
 	{
 	{
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 
 
-		if (!$media || (!$media->published && Session::get('user_id') !== $media->user_id && !Session::get('admin', false))) {
+		if (!$media || (!$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false))) {
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
@@ -102,7 +100,7 @@ class UploadController extends Controller
 				} else if (in_array($type, ['image', 'video'])) {
 				} else if (in_array($type, ['image', 'video'])) {
 					$url = urlFor("/$args[userCode]/$args[mediaCode]/raw");
 					$url = urlFor("/$args[userCode]/$args[mediaCode]/raw");
 					$header = "<{$url}>; rel=preload; as={$type}";
 					$header = "<{$url}>; rel=preload; as={$type}";
-					if (Session::get('logged', false)) {
+					if ($this->session->get('logged', false)) {
 						$header .= '; nopush';
 						$header .= '; nopush';
 					}
 					}
 					$response = $response->withHeader('Link', $header);
 					$response = $response->withHeader('Link', $header);
@@ -139,16 +137,16 @@ class UploadController extends Controller
 		$user = $this->database->query('SELECT `id`, `active` FROM `users` WHERE `token` = ? LIMIT 1', $args['token'])->fetch();
 		$user = $this->database->query('SELECT `id`, `active` FROM `users` WHERE `token` = ? LIMIT 1', $args['token'])->fetch();
 
 
 		if (!$user) {
 		if (!$user) {
-			Session::alert(lang('token_not_found'), 'danger');
+			$this->session->alert(lang('token_not_found'), 'danger');
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 		}
 		}
 
 
 		if (!$user->active) {
 		if (!$user->active) {
-			Session::alert(lang('account_disabled'), 'danger');
+			$this->session->alert(lang('account_disabled'), 'danger');
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 		}
 		}
 
 
-		if (Session::get('admin', false) || $user->id === $media->user_id) {
+		if ($this->session->get('admin', false) || $user->id === $media->user_id) {
 
 
 			try {
 			try {
 				storage()->delete($media->storage_path);
 				storage()->delete($media->storage_path);
@@ -197,7 +195,7 @@ class UploadController extends Controller
 	{
 	{
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 
 
-		if (!$media || !$media->published && Session::get('user_id') !== $media->user_id && !Session::get('admin', false)) {
+		if (!$media || !$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false)) {
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 		return $this->streamMedia($request, $response, storage(), $media);
 		return $this->streamMedia($request, $response, storage(), $media);
@@ -216,7 +214,7 @@ class UploadController extends Controller
 	{
 	{
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 		$media = $this->getMedia($args['userCode'], $args['mediaCode']);
 
 
-		if (!$media || !$media->published && Session::get('user_id') !== $media->user_id && !Session::get('admin', false)) {
+		if (!$media || !$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false)) {
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 		return $this->streamMedia($request, $response, storage(), $media, 'attachment');
 		return $this->streamMedia($request, $response, storage(), $media, 'attachment');
@@ -231,10 +229,10 @@ class UploadController extends Controller
 	 */
 	 */
 	public function togglePublish(Request $request, Response $response, $args): Response
 	public function togglePublish(Request $request, Response $response, $args): Response
 	{
 	{
-		if (Session::get('admin')) {
+		if ($this->session->get('admin')) {
 			$media = $this->database->query('SELECT * FROM `uploads` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
 			$media = $this->database->query('SELECT * FROM `uploads` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
 		} else {
 		} else {
-			$media = $this->database->query('SELECT * FROM `uploads` WHERE `id` = ? AND `user_id` = ? LIMIT 1', [$args['id'], Session::get('user_id')])->fetch();
+			$media = $this->database->query('SELECT * FROM `uploads` WHERE `id` = ? AND `user_id` = ? LIMIT 1', [$args['id'], $this->session->get('user_id')])->fetch();
 		}
 		}
 
 
 		if (!$media) {
 		if (!$media) {
@@ -262,7 +260,7 @@ class UploadController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if (Session::get('admin', false) || $media->user_id === Session::get('user_id')) {
+		if ($this->session->get('admin', false) || $media->user_id === $this->session->get('user_id')) {
 
 
 			try {
 			try {
 				storage()->delete($media->storage_path);
 				storage()->delete($media->storage_path);
@@ -270,8 +268,8 @@ class UploadController extends Controller
 				throw new NotFoundException($request, $response);
 				throw new NotFoundException($request, $response);
 			} finally {
 			} finally {
 				$this->database->query('DELETE FROM `uploads` WHERE `id` = ?', $args['id']);
 				$this->database->query('DELETE FROM `uploads` WHERE `id` = ?', $args['id']);
-				$this->logger->info('User ' . Session::get('username') . ' deleted a media.', [$args['id']]);
-				Session::set('used_space', humanFileSize($this->getUsedSpaceByUser(Session::get('user_id'))));
+				$this->logger->info('User ' . $this->session->get('username') . ' deleted a media.', [$args['id']]);
+				$this->session->set('used_space', humanFileSize($this->getUsedSpaceByUser($this->session->get('user_id'))));
 			}
 			}
 		} else {
 		} else {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
@@ -324,7 +322,6 @@ class UploadController extends Controller
 				->withHeader('Content-Disposition', $disposition . ';filename="scaled-' . pathinfo($media->filename)['filename'] . '.png"')
 				->withHeader('Content-Disposition', $disposition . ';filename="scaled-' . pathinfo($media->filename)['filename'] . '.png"')
 				->write($image);
 				->write($image);
 		} else {
 		} else {
-			ob_end_clean();
 			return $response
 			return $response
 				->withHeader('Content-Type', $mime)
 				->withHeader('Content-Type', $mime)
 				->withHeader('Content-Disposition', $disposition . '; filename="' . $media->filename . '"')
 				->withHeader('Content-Disposition', $disposition . '; filename="' . $media->filename . '"')

+ 32 - 33
app/Controllers/UserController.php

@@ -4,7 +4,6 @@ namespace App\Controllers;
 
 
 
 
 use App\Exceptions\UnauthorizedException;
 use App\Exceptions\UnauthorizedException;
-use App\Web\Session;
 use Slim\Exception\NotFoundException;
 use Slim\Exception\NotFoundException;
 use Slim\Http\Request;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Response;
@@ -57,27 +56,27 @@ class UserController extends Controller
 	public function store(Request $request, Response $response): Response
 	public function store(Request $request, Response $response): Response
 	{
 	{
 		if ($request->getParam('email') === null) {
 		if ($request->getParam('email') === null) {
-			Session::alert(lang('email_required'), 'danger');
+			$this->session->alert(lang('email_required'), 'danger');
 			return redirect($response, 'user.create');
 			return redirect($response, 'user.create');
 		}
 		}
 
 
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ?', $request->getParam('email'))->fetch()->count > 0) {
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ?', $request->getParam('email'))->fetch()->count > 0) {
-			Session::alert(lang('email_taken'), 'danger');
+			$this->session->alert(lang('email_taken'), 'danger');
 			return redirect($response, 'user.create');
 			return redirect($response, 'user.create');
 		}
 		}
 
 
 		if ($request->getParam('username') === null) {
 		if ($request->getParam('username') === null) {
-			Session::alert(lang('username_required'), 'danger');
+			$this->session->alert(lang('username_required'), 'danger');
 			return redirect($response, 'user.create');
 			return redirect($response, 'user.create');
 		}
 		}
 
 
 		if ($request->getParam('password') === null) {
 		if ($request->getParam('password') === null) {
-			Session::alert(lang('password_required'), 'danger');
+			$this->session->alert(lang('password_required'), 'danger');
 			return redirect($response, 'user.create');
 			return redirect($response, 'user.create');
 		}
 		}
 
 
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ?', $request->getParam('username'))->fetch()->count > 0) {
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ?', $request->getParam('username'))->fetch()->count > 0) {
-			Session::alert(lang('username_taken'), 'danger');
+			$this->session->alert(lang('username_taken'), 'danger');
 			return redirect($response, 'user.create');
 			return redirect($response, 'user.create');
 		}
 		}
 
 
@@ -97,8 +96,8 @@ class UserController extends Controller
 			$token,
 			$token,
 		]);
 		]);
 
 
-		Session::alert(lang('user_created', [$request->getParam('username')]), 'success');
-		$this->logger->info('User ' . Session::get('username') . ' created a new user.', [array_diff($request->getParams(), ['password'])]);
+		$this->session->alert(lang('user_created', [$request->getParam('username')]), 'success');
+		$this->logger->info('User ' . $this->session->get('username') . ' created a new user.', [array_diff($request->getParams(), ['password'])]);
 
 
 		return redirect($response, 'user.index');
 		return redirect($response, 'user.index');
 	}
 	}
@@ -140,27 +139,27 @@ class UserController extends Controller
 		}
 		}
 
 
 		if ($request->getParam('email') === null) {
 		if ($request->getParam('email') === null) {
-			Session::alert(lang('email_required'), 'danger');
+			$this->session->alert(lang('email_required'), 'danger');
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 		}
 		}
 
 
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
-			Session::alert(lang('email_taken'), 'danger');
+			$this->session->alert(lang('email_taken'), 'danger');
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 		}
 		}
 
 
 		if ($request->getParam('username') === null) {
 		if ($request->getParam('username') === null) {
-			Session::alert(lang('username_required'), 'danger');
+			$this->session->alert(lang('username_required'), 'danger');
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 		}
 		}
 
 
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ? AND `username` <> ?', [$request->getParam('username'), $user->username])->fetch()->count > 0) {
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ? AND `username` <> ?', [$request->getParam('username'), $user->username])->fetch()->count > 0) {
-			Session::alert(lang('username_taken'), 'danger');
+			$this->session->alert(lang('username_taken'), 'danger');
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 		}
 		}
 
 
-		if ($user->id === Session::get('user_id') && $request->getParam('is_admin') === null) {
-			Session::alert(lang('cannot_demote'), 'danger');
+		if ($user->id === $this->session->get('user_id') && $request->getParam('is_admin') === null) {
+			$this->session->alert(lang('cannot_demote'), 'danger');
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 			return redirect($response, 'user.edit', ['id' => $args['id']]);
 		}
 		}
 
 
@@ -183,8 +182,8 @@ class UserController extends Controller
 			]);
 			]);
 		}
 		}
 
 
-		Session::alert(lang('user_updated', [$request->getParam('username')]), 'success');
-		$this->logger->info('User ' . Session::get('username') . " updated $user->id.", [$user, array_diff($request->getParams(), ['password'])]);
+		$this->session->alert(lang('user_updated', [$request->getParam('username')]), 'success');
+		$this->logger->info('User ' . $this->session->get('username') . " updated $user->id.", [$user, array_diff($request->getParams(), ['password'])]);
 
 
 		return redirect($response, 'user.index');
 		return redirect($response, 'user.index');
 
 
@@ -205,15 +204,15 @@ class UserController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id === Session::get('user_id')) {
-			Session::alert(lang('cannot_delete'), 'danger');
+		if ($user->id === $this->session->get('user_id')) {
+			$this->session->alert(lang('cannot_delete'), 'danger');
 			return redirect($response, 'user.index');
 			return redirect($response, 'user.index');
 		}
 		}
 
 
 		$this->database->query('DELETE FROM `users` WHERE `id` = ?', $user->id);
 		$this->database->query('DELETE FROM `users` WHERE `id` = ?', $user->id);
 
 
-		Session::alert(lang('user_deleted'), 'success');
-		$this->logger->info('User ' . Session::get('username') . " deleted $user->id.");
+		$this->session->alert(lang('user_deleted'), 'success');
+		$this->logger->info('User ' . $this->session->get('username') . " deleted $user->id.");
 
 
 		return redirect($response, 'user.index');
 		return redirect($response, 'user.index');
 	}
 	}
@@ -227,13 +226,13 @@ class UserController extends Controller
 	 */
 	 */
 	public function profile(Request $request, Response $response): Response
 	public function profile(Request $request, Response $response): Response
 	{
 	{
-		$user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', Session::get('user_id'))->fetch();
+		$user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $this->session->get('user_id'))->fetch();
 
 
 		if (!$user) {
 		if (!$user) {
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
+		if ($user->id !== $this->session->get('user_id') && !$this->session->get('admin', false)) {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 
@@ -259,17 +258,17 @@ class UserController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
+		if ($user->id !== $this->session->get('user_id') && !$this->session->get('admin', false)) {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 
 		if ($request->getParam('email') === null) {
 		if ($request->getParam('email') === null) {
-			Session::alert(lang('email_required'), 'danger');
+			$this->session->alert(lang('email_required'), 'danger');
 			return redirect($response, 'profile');
 			return redirect($response, 'profile');
 		}
 		}
 
 
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
 		if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
-			Session::alert(lang('email_taken'), 'danger');
+			$this->session->alert(lang('email_taken'), 'danger');
 			return redirect($response, 'profile');
 			return redirect($response, 'profile');
 		}
 		}
 
 
@@ -286,8 +285,8 @@ class UserController extends Controller
 			]);
 			]);
 		}
 		}
 
 
-		Session::alert(lang('profile_updated'), 'success');
-		$this->logger->info('User ' . Session::get('username') . " updated profile of $user->id.");
+		$this->session->alert(lang('profile_updated'), 'success');
+		$this->logger->info('User ' . $this->session->get('username') . " updated profile of $user->id.");
 
 
 		return redirect($response, 'profile');
 		return redirect($response, 'profile');
 	}
 	}
@@ -308,7 +307,7 @@ class UserController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
+		if ($user->id !== $this->session->get('user_id') && !$this->session->get('admin', false)) {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 
@@ -319,7 +318,7 @@ class UserController extends Controller
 			$user->id,
 			$user->id,
 		]);
 		]);
 
 
-		$this->logger->info('User ' . Session::get('username') . " refreshed token of user $user->id.");
+		$this->logger->info('User ' . $this->session->get('username') . " refreshed token of user $user->id.");
 
 
 		$response->getBody()->write($token);
 		$response->getBody()->write($token);
 
 
@@ -342,12 +341,12 @@ class UserController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
+		if ($user->id !== $this->session->get('user_id') && !$this->session->get('admin', false)) {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 
 		if ($user->token === null || $user->token === '') {
 		if ($user->token === null || $user->token === '') {
-			Session::alert('You don\'t have a personal upload token. (Click the update token button and try again)', 'danger');
+			$this->session->alert('You don\'t have a personal upload token. (Click the update token button and try again)', 'danger');
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 		}
 		}
 
 
@@ -386,12 +385,12 @@ class UserController extends Controller
 			throw new NotFoundException($request, $response);
 			throw new NotFoundException($request, $response);
 		}
 		}
 
 
-		if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
+		if ($user->id !== $this->session->get('user_id') && !$this->session->get('admin', false)) {
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 
 		if ($user->token === null || $user->token === '') {
 		if ($user->token === null || $user->token === '') {
-			Session::alert('You don\'t have a personal upload token. (Click the update token button and try again)', 'danger');
+			$this->session->alert('You don\'t have a personal upload token. (Click the update token button and try again)', 'danger');
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 			return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
 		}
 		}
 
 

+ 2 - 2
app/Database/DB.php

@@ -39,7 +39,7 @@ class DB
 		}
 		}
 	}
 	}
 
 
-	public function doQuery(string $query, $parameters = [])
+	public function query(string $query, $parameters = [])
 	{
 	{
 		if (!is_array($parameters)) {
 		if (!is_array($parameters)) {
 			$parameters = [$parameters];
 			$parameters = [$parameters];
@@ -87,7 +87,7 @@ class DB
 	 * @param array $parameters
 	 * @param array $parameters
 	 * @return bool|\PDOStatement|string
 	 * @return bool|\PDOStatement|string
 	 */
 	 */
-	public static function query(string $query, $parameters = [])
+	public static function doQuery(string $query, $parameters = [])
 	{
 	{
 
 
 		return self::getInstance()->doQuery($query, $parameters);
 		return self::getInstance()->doQuery($query, $parameters);

+ 5 - 14
app/Middleware/AdminMiddleware.php

@@ -3,20 +3,11 @@
 namespace App\Middleware;
 namespace App\Middleware;
 
 
 use App\Exceptions\UnauthorizedException;
 use App\Exceptions\UnauthorizedException;
-use App\Web\Session;
 use Slim\Http\Request;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Response;
 
 
-class AdminMiddleware
+class AdminMiddleware extends Middleware
 {
 {
-	/** @var \Slim\Container */
-	private $container;
-
-	public function __construct($container)
-	{
-		$this->container = $container;
-	}
-
 	/**
 	/**
 	 * @param Request $request
 	 * @param Request $request
 	 * @param Response $response
 	 * @param Response $response
@@ -26,10 +17,10 @@ class AdminMiddleware
 	 */
 	 */
 	public function __invoke(Request $request, Response $response, callable $next)
 	public function __invoke(Request $request, Response $response, callable $next)
 	{
 	{
-		if (!$this->container->database->query('SELECT `id`, `is_admin` FROM `users` WHERE `id` = ? LIMIT 1', [Session::get('user_id')])->fetch()->is_admin) {
-			Session::alert('Your account is not admin anymore.', 'danger');
-			Session::set('admin', false);
-			Session::set('redirectTo', (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+		if (!$this->database->query('SELECT `id`, `is_admin` FROM `users` WHERE `id` = ? LIMIT 1', [$this->session->get('user_id')])->fetch()->is_admin) {
+			$this->session->alert('Your account is not admin anymore.', 'danger');
+			$this->session->set('admin', false);
+			$this->session->set('redirectTo', (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
 			throw new UnauthorizedException();
 			throw new UnauthorizedException();
 		}
 		}
 
 

+ 7 - 16
app/Middleware/AuthMiddleware.php

@@ -2,21 +2,12 @@
 
 
 namespace App\Middleware;
 namespace App\Middleware;
 
 
-use App\Web\Session;
 use Slim\Http\Request;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Response;
 
 
-class AuthMiddleware
+class AuthMiddleware extends Middleware
 {
 {
 
 
-	/** @var \Slim\Container */
-	private $container;
-
-	public function __construct($container)
-	{
-		$this->container = $container;
-	}
-
 	/**
 	/**
 	 * @param Request $request
 	 * @param Request $request
 	 * @param Response $response
 	 * @param Response $response
@@ -25,15 +16,15 @@ class AuthMiddleware
 	 */
 	 */
 	public function __invoke(Request $request, Response $response, callable $next)
 	public function __invoke(Request $request, Response $response, callable $next)
 	{
 	{
-		if (!Session::get('logged', false)) {
-			Session::set('redirectTo', (isset($_SERVER['HTTPS']) ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+		if (!$this->session->get('logged', false)) {
+			$this->session->set('redirectTo', (isset($_SERVER['HTTPS']) ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
 			return redirect($response, 'login.show');
 			return redirect($response, 'login.show');
 		}
 		}
 
 
-		if (!$this->container->database->query('SELECT `id`, `active` FROM `users` WHERE `id` = ? LIMIT 1', [Session::get('user_id')])->fetch()->active) {
-			Session::alert('Your account is not active anymore.', 'danger');
-			Session::set('logged', false);
-			Session::set('redirectTo', (isset($_SERVER['HTTPS']) ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
+		if (!$this->database->query('SELECT `id`, `active` FROM `users` WHERE `id` = ? LIMIT 1', [$this->session->get('user_id')])->fetch()->active) {
+			$this->session->alert('Your account is not active anymore.', 'danger');
+			$this->session->set('logged', false);
+			$this->session->set('redirectTo', (isset($_SERVER['HTTPS']) ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
 			return redirect($response, 'login.show');
 			return redirect($response, 'login.show');
 		}
 		}
 
 

+ 38 - 0
app/Middleware/Middleware.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Middleware;
+
+use Slim\Container;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+abstract class Middleware
+{
+	/** @var Container */
+	protected $container;
+
+	public function __construct(Container $container)
+	{
+		$this->container = $container;
+	}
+
+	/**
+	 * @param $name
+	 * @return mixed|null
+	 * @throws \Interop\Container\Exception\ContainerException
+	 */
+	public function __get($name)
+	{
+		if ($this->container->has($name)) {
+			return $this->container->get($name);
+		}
+		return null;
+	}
+
+	/**
+	 * @param Request $request
+	 * @param Response $response
+	 * @param callable $next
+	 */
+	public abstract function __invoke(Request $request, Response $response, callable $next);
+}

+ 10 - 10
app/Web/Session.php

@@ -7,12 +7,12 @@ class Session
 {
 {
 
 
 	/**
 	/**
-	 * Start a session if is not already started in the current context
+	 * Session constructor.
 	 * @param string $name
 	 * @param string $name
 	 * @param string $path
 	 * @param string $path
 	 * @throws \Exception
 	 * @throws \Exception
 	 */
 	 */
-	public static function init(string $name, $path = ''): void
+	public function __construct(string $name, $path = '')
 	{
 	{
 		if (session_status() === PHP_SESSION_NONE) {
 		if (session_status() === PHP_SESSION_NONE) {
 			if (!is_writable($path) && $path !== '') {
 			if (!is_writable($path) && $path !== '') {
@@ -30,7 +30,7 @@ class Session
 	 * Destroy the current session
 	 * Destroy the current session
 	 * @return bool
 	 * @return bool
 	 */
 	 */
-	public static function destroy(): bool
+	public function destroy(): bool
 	{
 	{
 		return session_destroy();
 		return session_destroy();
 	}
 	}
@@ -38,7 +38,7 @@ class Session
 	/**
 	/**
 	 * Clear all session stored values
 	 * Clear all session stored values
 	 */
 	 */
-	public static function clear(): void
+	public function clear(): void
 	{
 	{
 		$_SESSION = [];
 		$_SESSION = [];
 	}
 	}
@@ -48,7 +48,7 @@ class Session
 	 * @param $key
 	 * @param $key
 	 * @return bool
 	 * @return bool
 	 */
 	 */
-	public static function has($key): bool
+	public function has($key): bool
 	{
 	{
 		return isset($_SESSION[$key]);
 		return isset($_SESSION[$key]);
 	}
 	}
@@ -57,7 +57,7 @@ class Session
 	 * Get the content of the current session
 	 * Get the content of the current session
 	 * @return array
 	 * @return array
 	 */
 	 */
-	public static function all(): array
+	public function all(): array
 	{
 	{
 		return $_SESSION;
 		return $_SESSION;
 	}
 	}
@@ -68,7 +68,7 @@ class Session
 	 * @param null $default
 	 * @param null $default
 	 * @return mixed
 	 * @return mixed
 	 */
 	 */
-	public static function get($key, $default = null)
+	public function get($key, $default = null)
 	{
 	{
 		return self::has($key) ? $_SESSION[$key] : $default;
 		return self::has($key) ? $_SESSION[$key] : $default;
 	}
 	}
@@ -78,7 +78,7 @@ class Session
 	 * @param $key
 	 * @param $key
 	 * @param $value
 	 * @param $value
 	 */
 	 */
-	public static function set($key, $value): void
+	public function set($key, $value): void
 	{
 	{
 		$_SESSION[$key] = $value;
 		$_SESSION[$key] = $value;
 	}
 	}
@@ -88,7 +88,7 @@ class Session
 	 * @param $message
 	 * @param $message
 	 * @param string $type
 	 * @param string $type
 	 */
 	 */
-	public static function alert($message, string $type = 'info'): void
+	public function alert($message, string $type = 'info'): void
 	{
 	{
 		$_SESSION['_flash'][] = [$type => $message];
 		$_SESSION['_flash'][] = [$type => $message];
 	}
 	}
@@ -98,7 +98,7 @@ class Session
 	 * Retrieve flash alerts
 	 * Retrieve flash alerts
 	 * @return array
 	 * @return array
 	 */
 	 */
-	public static function getAlert()
+	public function getAlert()
 	{
 	{
 		$flash = self::get('_flash');
 		$flash = self::get('_flash');
 		self::set('_flash', []);
 		self::set('_flash', []);

+ 2 - 1
app/helpers.php

@@ -125,7 +125,8 @@ if (!function_exists('lang')) {
 	 */
 	 */
 	function lang(string $key, $args = []): string
 	function lang(string $key, $args = []): string
 	{
 	{
-		return \App\Web\Lang::getInstance()->get($key, $args);
+		global $app;
+		return $app->getContainer()->get('lang')->get($key, $args);
 	}
 	}
 }
 }
 
 

+ 6 - 5
app/routes.php

@@ -2,9 +2,10 @@
 // Auth routes
 // Auth routes
 $app->group('', function () {
 $app->group('', function () {
 	$this->get('/home[/page/{page}]', \App\Controllers\DashboardController::class . ':home')->setName('home');
 	$this->get('/home[/page/{page}]', \App\Controllers\DashboardController::class . ':home')->setName('home');
-	$this->get('/system', \App\Controllers\DashboardController::class . ':system')->add(\App\Middleware\AdminMiddleware::class)->setName('system');
-	$this->get('/system/themes', \App\Controllers\DashboardController::class . ':getThemes')->add(\App\Middleware\AdminMiddleware::class)->setName('theme');
-	$this->post('/system/theme/apply', \App\Controllers\DashboardController::class . ':applyTheme')->add(\App\Middleware\AdminMiddleware::class)->setName('theme.apply');
+	$this->get('/system/deleteOrphanFiles', \App\Controllers\AdminController::class . ':deleteOrphanFiles')->add(\App\Middleware\AdminMiddleware::class)->setName('system.deleteOrphanFiles');
+	$this->get('/system/themes', \App\Controllers\ThemeController::class . ':getThemes')->add(\App\Middleware\AdminMiddleware::class)->setName('theme');
+	$this->post('/system/theme/apply', \App\Controllers\ThemeController::class . ':applyTheme')->add(\App\Middleware\AdminMiddleware::class)->setName('theme.apply');
+	$this->get('/system', \App\Controllers\AdminController::class . ':system')->add(\App\Middleware\AdminMiddleware::class)->setName('system');
 
 
 	$this->group('', function () {
 	$this->group('', function () {
 		$this->get('/users[/page/{page}]', \App\Controllers\UserController::class . ':index')->setName('user.index');
 		$this->get('/users[/page/{page}]', \App\Controllers\UserController::class . ':index')->setName('user.index');
@@ -38,5 +39,5 @@ $app->post('/upload', \App\Controllers\UploadController::class . ':upload')->set
 $app->get('/{userCode}/{mediaCode}', \App\Controllers\UploadController::class . ':show')->setName('public');
 $app->get('/{userCode}/{mediaCode}', \App\Controllers\UploadController::class . ':show')->setName('public');
 $app->get('/{userCode}/{mediaCode}/delete/{token}', \App\Controllers\UploadController::class . ':show')->setName('public.delete.show');
 $app->get('/{userCode}/{mediaCode}/delete/{token}', \App\Controllers\UploadController::class . ':show')->setName('public.delete.show');
 $app->post('/{userCode}/{mediaCode}/delete/{token}', \App\Controllers\UploadController::class . ':deleteByToken')->setName('public.delete');
 $app->post('/{userCode}/{mediaCode}/delete/{token}', \App\Controllers\UploadController::class . ':deleteByToken')->setName('public.delete');
-$app->get('/{userCode}/{mediaCode}/raw', \App\Controllers\UploadController::class . ':showRaw')->setName('public.raw');
-$app->get('/{userCode}/{mediaCode}/download', \App\Controllers\UploadController::class . ':download')->setName('public.download');
+$app->get('/{userCode}/{mediaCode}/raw', \App\Controllers\UploadController::class . ':showRaw')->setName('public.raw')->setOutputBuffering(false);
+$app->get('/{userCode}/{mediaCode}/download', \App\Controllers\UploadController::class . ':download')->setName('public.download')->setOutputBuffering(false);

+ 6 - 6
bin/migrate

@@ -24,7 +24,7 @@ if (!file_exists($config['db']['dsn']) && DB::driver() === 'sqlite') {
 }
 }
 
 
 try {
 try {
-	DB::query('SELECT 1 FROM `migrations` LIMIT 1');
+	DB::doQuery('SELECT 1 FROM `migrations` LIMIT 1');
 } catch (PDOException $exception) {
 } catch (PDOException $exception) {
 	$firstMigrate = true;
 	$firstMigrate = true;
 }
 }
@@ -44,7 +44,7 @@ $names = array_map(function ($path) {
 
 
 $in = str_repeat('?, ', count($names) - 1) . '?';
 $in = str_repeat('?, ', count($names) - 1) . '?';
 
 
-$inMigrationsTable = DB::query("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
+$inMigrationsTable = DB::doQuery("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
 
 
 
 
 foreach ($files as $file) {
 foreach ($files as $file) {
@@ -67,14 +67,14 @@ foreach ($files as $file) {
 	try {
 	try {
 		DB::raw()->exec($sql);
 		DB::raw()->exec($sql);
 		if (!$exists) {
 		if (!$exists) {
-			DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
+			DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
 		} else {
 		} else {
-			DB::query('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
+			DB::doQuery('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
 		}
 		}
 		echo "Migrated '$file'" . PHP_EOL;
 		echo "Migrated '$file'" . PHP_EOL;
 	} catch (PDOException $exception) {
 	} catch (PDOException $exception) {
 		if (!$exists) {
 		if (!$exists) {
-			DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
+			DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
 		}
 		}
 		echo "Error migrating '$file' (" . $exception->getMessage() . ')' . PHP_EOL;
 		echo "Error migrating '$file' (" . $exception->getMessage() . ')' . PHP_EOL;
 		echo $exception->getTraceAsString() . PHP_EOL;
 		echo $exception->getTraceAsString() . PHP_EOL;
@@ -83,7 +83,7 @@ foreach ($files as $file) {
 }
 }
 
 
 if (isset($argv[1]) && $argv[1] === '--install') {
 if (isset($argv[1]) && $argv[1] === '--install') {
-	DB::query("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES ('admin@example.com', 'admin', ?, 1, ?)", [password_hash('admin', PASSWORD_DEFAULT), substr(md5(microtime()), rand(0, 26), 5)]);
+	DB::doQuery("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES ('admin@example.com', 'admin', ?, 1, ?)", [password_hash('admin', PASSWORD_DEFAULT), substr(md5(microtime()), rand(0, 26), 5)]);
 }
 }
 
 
 echo 'Done.' . PHP_EOL;
 echo 'Done.' . PHP_EOL;

+ 11 - 11
bootstrap/app.php

@@ -47,18 +47,18 @@ $container['logger'] = function ($container) {
 	return $logger;
 	return $logger;
 };
 };
 
 
-// Session init
-Session::init('xbackbone_session', __DIR__ . '/../resources/sessions');
-
-// Set the database dsn
-$dsn = $config['db']['connection'] === 'sqlite' ? __DIR__ . '/../' . $config['db']['dsn'] : $config['db']['dsn'];
-DB::setDsn($config['db']['connection'] . ':' . $dsn, $config['db']['username'], $config['db']['password']);
+$container['session'] = function ($container) {
+	return new Session('xbackbone_session', __DIR__ . '/../resources/sessions');
+};
 
 
 $container['database'] = function ($container) use (&$config) {
 $container['database'] = function ($container) use (&$config) {
-	return DB::getInstance();
+	$dsn = $config['db']['connection'] === 'sqlite' ? __DIR__ . '/../' . $config['db']['dsn'] : $config['db']['dsn'];
+	return new DB($config['db']['connection'] . ':' . $dsn, $config['db']['username'], $config['db']['password']);
 };
 };
 
 
-Lang::build(Lang::recognize(), __DIR__. '/../resources/lang/');
+$container['lang'] = function ($container) {
+	return Lang::build(Lang::recognize(), __DIR__ . '/../resources/lang/');
+};
 
 
 $container['view'] = function ($container) use (&$config) {
 $container['view'] = function ($container) use (&$config) {
 	$view = new \Slim\Views\Twig(__DIR__ . '/../resources/templates', [
 	$view = new \Slim\Views\Twig(__DIR__ . '/../resources/templates', [
@@ -75,9 +75,9 @@ $container['view'] = function ($container) use (&$config) {
 
 
 	$view->getEnvironment()->addGlobal('config', $config);
 	$view->getEnvironment()->addGlobal('config', $config);
 	$view->getEnvironment()->addGlobal('request', $container->get('request'));
 	$view->getEnvironment()->addGlobal('request', $container->get('request'));
-	$view->getEnvironment()->addGlobal('alerts', Session::getAlert());
-	$view->getEnvironment()->addGlobal('session', Session::all());
-	$view->getEnvironment()->addGlobal('current_lang', Lang::getInstance()->getLang());
+	$view->getEnvironment()->addGlobal('alerts', $container->get('session')->getAlert());
+	$view->getEnvironment()->addGlobal('session', $container->get('session')->all());
+	$view->getEnvironment()->addGlobal('current_lang', $container->get('lang')->getLang());
 	$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
 	$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
 
 
 	$view->getEnvironment()->addFunction(new Twig_Function('route', 'route'));
 	$view->getEnvironment()->addFunction(new Twig_Function('route', 'route'));

+ 1 - 1
composer.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "sergix44/xbackbone",
   "name": "sergix44/xbackbone",
-  "version": "2.3.1",
+  "version": "2.4",
   "description": "A lightweight ShareX PHP backend",
   "description": "A lightweight ShareX PHP backend",
   "type": "project",
   "type": "project",
   "require": {
   "require": {

+ 18 - 16
install/index.php

@@ -24,7 +24,9 @@ $config = [
 
 
 $container = new Container(['settings' => $config]);
 $container = new Container(['settings' => $config]);
 
 
-Session::init('xbackbone_session');
+$container['session'] = function ($container) {
+	return new Session('xbackbone_session');
+};
 
 
 $container['view'] = function ($container) use (&$config) {
 $container['view'] = function ($container) use (&$config) {
 	$view = new \Slim\Views\Twig([__DIR__ . '/templates', __DIR__ . '/../resources/templates'], [
 	$view = new \Slim\Views\Twig([__DIR__ . '/templates', __DIR__ . '/../resources/templates'], [
@@ -41,8 +43,8 @@ $container['view'] = function ($container) use (&$config) {
 
 
 	$view->getEnvironment()->addGlobal('config', $config);
 	$view->getEnvironment()->addGlobal('config', $config);
 	$view->getEnvironment()->addGlobal('request', $container->get('request'));
 	$view->getEnvironment()->addGlobal('request', $container->get('request'));
-	$view->getEnvironment()->addGlobal('alerts', Session::getAlert());
-	$view->getEnvironment()->addGlobal('session', Session::all());
+	$view->getEnvironment()->addGlobal('alerts', $container->get('session')->getAlert());
+	$view->getEnvironment()->addGlobal('session', $container->get('session')->all());
 	$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
 	$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
 	return $view;
 	return $view;
 };
 };
@@ -56,7 +58,7 @@ function migrate($config)
 	}
 	}
 
 
 	try {
 	try {
-		DB::query('SELECT 1 FROM `migrations` LIMIT 1');
+		DB::doQuery('SELECT 1 FROM `migrations` LIMIT 1');
 	} catch (PDOException $exception) {
 	} catch (PDOException $exception) {
 		$firstMigrate = true;
 		$firstMigrate = true;
 	}
 	}
@@ -73,7 +75,7 @@ function migrate($config)
 
 
 	$in = str_repeat('?, ', count($names) - 1) . '?';
 	$in = str_repeat('?, ', count($names) - 1) . '?';
 
 
-	$inMigrationsTable = DB::query("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
+	$inMigrationsTable = DB::doQuery("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
 
 
 
 
 	foreach ($files as $file) {
 	foreach ($files as $file) {
@@ -96,13 +98,13 @@ function migrate($config)
 		try {
 		try {
 			DB::raw()->exec($sql);
 			DB::raw()->exec($sql);
 			if (!$exists) {
 			if (!$exists) {
-				DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
+				DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
 			} else {
 			} else {
-				DB::query('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
+				DB::doQuery('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
 			}
 			}
 		} catch (PDOException $exception) {
 		} catch (PDOException $exception) {
 			if (!$exists) {
 			if (!$exists) {
-				DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
+				DB::doQuery('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
 			}
 			}
 			throw $exception;
 			throw $exception;
 		}
 		}
@@ -114,15 +116,15 @@ $app = new App($container);
 $app->get('/', function (Request $request, Response $response) {
 $app->get('/', function (Request $request, Response $response) {
 
 
 	if (!is_writable(__DIR__ . '/../resources/cache')) {
 	if (!is_writable(__DIR__ . '/../resources/cache')) {
-		Session::alert('The cache folder is not writable (' . __DIR__ . '/../resources/cache' . ')', 'danger');
+		$this->session->alert('The cache folder is not writable (' . __DIR__ . '/../resources/cache' . ')', 'danger');
 	}
 	}
 
 
 	if (!is_writable(__DIR__ . '/../resources/database')) {
 	if (!is_writable(__DIR__ . '/../resources/database')) {
-		Session::alert('The database folder is not writable (' . __DIR__ . '/../resources/database' . ')', 'danger');
+		$this->session->alert('The database folder is not writable (' . __DIR__ . '/../resources/database' . ')', 'danger');
 	}
 	}
 
 
 	if (!is_writable(__DIR__ . '/../resources/sessions')) {
 	if (!is_writable(__DIR__ . '/../resources/sessions')) {
-		Session::alert('The sessions folder is not writable (' . __DIR__ . '/../resources/sessions' . ')', 'danger');
+		$this->session->alert('The sessions folder is not writable (' . __DIR__ . '/../resources/sessions' . ')', 'danger');
 	}
 	}
 
 
 	$installed = file_exists(__DIR__ . '/../config.php');
 	$installed = file_exists(__DIR__ . '/../config.php');
@@ -146,18 +148,18 @@ $app->post('/', function (Request $request, Response $response) use (&$config) {
 		try {
 		try {
 			storage($config['storage_dir']);
 			storage($config['storage_dir']);
 		} catch (LogicException $exception) {
 		} catch (LogicException $exception) {
-			Session::alert('The storage folder is not readable (' . $config['storage_dir'] . ')', 'danger');
+			$this->session->alert('The storage folder is not readable (' . $config['storage_dir'] . ')', 'danger');
 			return redirect($response, './');
 			return redirect($response, './');
 		} finally {
 		} finally {
 			if (!is_writable($config['storage_dir'])) {
 			if (!is_writable($config['storage_dir'])) {
-				Session::alert('The storage folder is not writable (' . $config['storage_dir'] . ')', 'danger');
+				$this->session->alert('The storage folder is not writable (' . $config['storage_dir'] . ')', 'danger');
 				return redirect($response, './');
 				return redirect($response, './');
 			}
 			}
 		}
 		}
 
 
 		$ret = file_put_contents(__DIR__ . '/../config.php', '<?php' . PHP_EOL . 'return ' . var_export($config, true) . ';');
 		$ret = file_put_contents(__DIR__ . '/../config.php', '<?php' . PHP_EOL . 'return ' . var_export($config, true) . ';');
 		if ($ret === false) {
 		if ($ret === false) {
-			Session::alert('The config folder is not writable (' . __DIR__ . '/../config.php' . ')', 'danger');
+			$this->session->alert('The config folder is not writable (' . __DIR__ . '/../config.php' . ')', 'danger');
 			return redirect($response, './');
 			return redirect($response, './');
 		}
 		}
 	}
 	}
@@ -169,12 +171,12 @@ $app->post('/', function (Request $request, Response $response) use (&$config) {
 
 
 		migrate($config);
 		migrate($config);
 	} catch (PDOException $exception) {
 	} catch (PDOException $exception) {
-		Session::alert("Cannot connect to the database: {$exception->getMessage()} [{$exception->getCode()}]", 'danger');
+		$this->session->alert("Cannot connect to the database: {$exception->getMessage()} [{$exception->getCode()}]", 'danger');
 		return redirect($response, './');
 		return redirect($response, './');
 	}
 	}
 
 
 	if (!$installed) {
 	if (!$installed) {
-		DB::query("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES (?, 'admin', ?, 1, ?)", [$request->getParam('email'), password_hash($request->getParam('password'), PASSWORD_DEFAULT), substr(md5(microtime()), rand(0, 26), 5)]);
+		DB::doQuery("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES (?, 'admin', ?, 1, ?)", [$request->getParam('email'), password_hash($request->getParam('password'), PASSWORD_DEFAULT), substr(md5(microtime()), rand(0, 26), 5)]);
 	}
 	}
 
 
 	cleanDirectory(__DIR__ . '/../resources/cache');
 	cleanDirectory(__DIR__ . '/../resources/cache');

+ 1 - 0
resources/lang/en.lang.php

@@ -85,4 +85,5 @@ return [
 	'cannot_delete' => 'You cannot delete yourself.',
 	'cannot_delete' => 'You cannot delete yourself.',
 	'cannot_demote' => 'You cannot demote yourself.',
 	'cannot_demote' => 'You cannot demote yourself.',
 	'cannot_write_file' => 'The destination path is not writable.',
 	'cannot_write_file' => 'The destination path is not writable.',
+	'deleted_orphans' => 'Successfully deleted %d orphaned files.',
 ];
 ];

+ 1 - 0
resources/lang/it.lang.php

@@ -85,4 +85,5 @@ return [
 	'cannot_delete' => 'Non puoi eliminare te stesso.',
 	'cannot_delete' => 'Non puoi eliminare te stesso.',
 	'cannot_demote' => 'Non puoi degradare te stesso. ',
 	'cannot_demote' => 'Non puoi degradare te stesso. ',
 	'cannot_write_file' => 'Il percorso di destinazione non è scrivibile.',
 	'cannot_write_file' => 'Il percorso di destinazione non è scrivibile.',
+	'deleted_orphans' => 'Eliminati %d file orfani.',
 ];
 ];

+ 1 - 1
resources/templates/comp/footer.twig

@@ -1,5 +1,5 @@
 <footer class="footer">
 <footer class="footer">
     <div class="container-fluid">
     <div class="container-fluid">
-        <div class="text-muted">Proudly powered by <a href="https://github.com/SergiX44/XBackBone" target="_blank">XBackBone{% if session.logged %} v{{ PLATFORM_VERSION }}{% endif %}</a></div>
+        <div class="text-muted">Proudly powered by <a href="https://github.com/SergiX44/XBackBone">XBackBone{% if session.logged %} v{{ PLATFORM_VERSION }}{% endif %}</a></div>
     </div>
     </div>
 </footer>
 </footer>

+ 1 - 0
resources/templates/dashboard/system.twig

@@ -5,6 +5,7 @@
 {% block content %}
 {% block content %}
     {% include 'comp/navbar.twig' %}
     {% include 'comp/navbar.twig' %}
     <div class="container">
     <div class="container">
+        {% include 'comp/alert.twig' %}
         <div class="row">
         <div class="row">
             <div class="col-xl-3 col-sm-6 mb-3">
             <div class="col-xl-3 col-sm-6 mb-3">
                 <div class="card bg-success text-white h-100 shadow-sm">
                 <div class="card bg-success text-white h-100 shadow-sm">