|
@@ -2,138 +2,221 @@
|
|
|
|
|
|
namespace App\Controllers;
|
|
namespace App\Controllers;
|
|
|
|
|
|
|
|
+use App\Exceptions\ValidationException;
|
|
use Exception;
|
|
use Exception;
|
|
use Psr\Http\Message\ResponseInterface as Response;
|
|
use Psr\Http\Message\ResponseInterface as Response;
|
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
|
|
+use Psr\Http\Message\UploadedFileInterface;
|
|
|
|
|
|
class UploadController extends Controller
|
|
class UploadController extends Controller
|
|
{
|
|
{
|
|
|
|
+ private $json = [
|
|
|
|
+ 'message' => null,
|
|
|
|
+ 'version' => PLATFORM_VERSION,
|
|
|
|
+ ];
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * @param Request $request
|
|
|
|
* @param Response $response
|
|
* @param Response $response
|
|
*
|
|
*
|
|
* @return Response
|
|
* @return Response
|
|
|
|
+ * @throws \Twig\Error\LoaderError
|
|
* @throws \Twig\Error\RuntimeError
|
|
* @throws \Twig\Error\RuntimeError
|
|
* @throws \Twig\Error\SyntaxError
|
|
* @throws \Twig\Error\SyntaxError
|
|
- *
|
|
|
|
- * @throws \Twig\Error\LoaderError
|
|
|
|
*/
|
|
*/
|
|
- public function webUpload(Request $request, Response $response): Response
|
|
|
|
|
|
+ public function uploadWebPage(Response $response): Response
|
|
{
|
|
{
|
|
- $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $this->session->get('user_id'))->fetch();
|
|
|
|
-
|
|
|
|
- if ($user->token === null || $user->token === '') {
|
|
|
|
- $this->session->alert(lang('no_upload_token'), 'danger');
|
|
|
|
-
|
|
|
|
- return redirect($response, $request->getHeaderLine('Referer'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return view()->render($response, 'upload/web.twig', [
|
|
|
|
- 'user' => $user,
|
|
|
|
- ]);
|
|
|
|
|
|
+ return view()->render($response, 'upload/web.twig');
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* @param Request $request
|
|
* @param Request $request
|
|
* @param Response $response
|
|
* @param Response $response
|
|
- *
|
|
|
|
* @return Response
|
|
* @return Response
|
|
* @throws \Slim\Exception\HttpNotFoundException
|
|
* @throws \Slim\Exception\HttpNotFoundException
|
|
* @throws \Slim\Exception\HttpUnauthorizedException
|
|
* @throws \Slim\Exception\HttpUnauthorizedException
|
|
|
|
+ * @throws Exception
|
|
*/
|
|
*/
|
|
- public function upload(Request $request, Response $response): Response
|
|
|
|
|
|
+ public function uploadWeb(Request $request, Response $response): Response
|
|
{
|
|
{
|
|
- $json = [
|
|
|
|
- 'message' => null,
|
|
|
|
- 'version' => PLATFORM_VERSION,
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
if ($this->config['maintenance']) {
|
|
if ($this->config['maintenance']) {
|
|
- $json['message'] = 'Endpoint under maintenance.';
|
|
|
|
|
|
+ $this->json['message'] = 'Endpoint under maintenance.';
|
|
|
|
|
|
- return json($response, $json, 503);
|
|
|
|
|
|
+ return json($response, $this->json, 503);
|
|
}
|
|
}
|
|
|
|
|
|
- if ($request->getServerParams()['CONTENT_LENGTH'] > stringToBytes(ini_get('post_max_size'))) {
|
|
|
|
- $json['message'] = 'File too large (post_max_size too low?).';
|
|
|
|
|
|
+ try {
|
|
|
|
+ $file = $this->validateFile($request, $response);
|
|
|
|
+
|
|
|
|
+ $user = $this->getUser($request, $this->session->get('user_id'));
|
|
|
|
|
|
- return json($response, $json, 400);
|
|
|
|
|
|
+ $this->validateUser($request, $response, $file, $user);
|
|
|
|
+ } catch (ValidationException $e) {
|
|
|
|
+ return $e->response();
|
|
}
|
|
}
|
|
|
|
|
|
- $file = array_values($request->getUploadedFiles());
|
|
|
|
- /** @var \Psr\Http\Message\UploadedFileInterface|null $file */
|
|
|
|
- $file = $file[0] ?? null;
|
|
|
|
|
|
+ if (!$this->updateUserQuota($request, $user->id, $file->getSize())) {
|
|
|
|
+ $this->json['message'] = 'User disk quota exceeded.';
|
|
|
|
|
|
- if ($file === null) {
|
|
|
|
- $json['message'] = 'Request without file attached.';
|
|
|
|
|
|
+ return json($response, $this->json, 507);
|
|
|
|
+ }
|
|
|
|
|
|
- return json($response, $json, 400);
|
|
|
|
|
|
+ try {
|
|
|
|
+ $response = $this->saveMedia($response, $file, $user);
|
|
|
|
+ $this->setSessionQuotaInfo($user->current_disk_quota + $file->getSize(), $user->max_disk_quota);
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
+ $this->updateUserQuota($request, $user->id, $file->getSize(), true);
|
|
|
|
+ throw $e;
|
|
}
|
|
}
|
|
|
|
|
|
- if ($file->getError() === UPLOAD_ERR_INI_SIZE) {
|
|
|
|
- $json['message'] = 'File too large (upload_max_filesize too low?).';
|
|
|
|
|
|
+ return $response;
|
|
|
|
+ }
|
|
|
|
|
|
- return json($response, $json, 400);
|
|
|
|
|
|
+ /**
|
|
|
|
+ * @param Request $request
|
|
|
|
+ * @param Response $response
|
|
|
|
+ *
|
|
|
|
+ * @return Response
|
|
|
|
+ * @throws \Slim\Exception\HttpNotFoundException
|
|
|
|
+ * @throws \Slim\Exception\HttpUnauthorizedException
|
|
|
|
+ * @throws Exception
|
|
|
|
+ */
|
|
|
|
+ public function uploadEndpoint(Request $request, Response $response): Response
|
|
|
|
+ {
|
|
|
|
+ if ($this->config['maintenance']) {
|
|
|
|
+ $this->json['message'] = 'Endpoint under maintenance.';
|
|
|
|
+
|
|
|
|
+ return json($response, $this->json, 503);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ $file = $this->validateFile($request, $response);
|
|
|
|
+ } catch (ValidationException $e) {
|
|
|
|
+ return $e->response();
|
|
}
|
|
}
|
|
|
|
|
|
if (param($request, 'token') === null) {
|
|
if (param($request, 'token') === null) {
|
|
- $json['message'] = 'Token not specified.';
|
|
|
|
|
|
+ $this->json['message'] = 'Token not specified.';
|
|
|
|
|
|
- return json($response, $json, 400);
|
|
|
|
|
|
+ return json($response, $this->json, 400);
|
|
}
|
|
}
|
|
|
|
|
|
$user = $this->database->query('SELECT * FROM `users` WHERE `token` = ? LIMIT 1', param($request, 'token'))->fetch();
|
|
$user = $this->database->query('SELECT * FROM `users` WHERE `token` = ? LIMIT 1', param($request, 'token'))->fetch();
|
|
|
|
|
|
if (!$user) {
|
|
if (!$user) {
|
|
- $json['message'] = 'Token specified not found.';
|
|
|
|
|
|
+ $this->json['message'] = 'Token specified not found.';
|
|
|
|
|
|
- return json($response, $json, 404);
|
|
|
|
|
|
+ return json($response, $this->json, 404);
|
|
}
|
|
}
|
|
|
|
|
|
- if (!$user->active) {
|
|
|
|
- $json['message'] = 'Account disabled.';
|
|
|
|
-
|
|
|
|
- return json($response, $json, 401);
|
|
|
|
|
|
+ try {
|
|
|
|
+ $this->validateUser($request, $response, $file, $user);
|
|
|
|
+ } catch (ValidationException $e) {
|
|
|
|
+ return $e->response();
|
|
}
|
|
}
|
|
|
|
|
|
if (!$this->updateUserQuota($request, $user->id, $file->getSize())) {
|
|
if (!$this->updateUserQuota($request, $user->id, $file->getSize())) {
|
|
- $json['message'] = 'User disk quota exceeded.';
|
|
|
|
|
|
+ $this->json['message'] = 'User disk quota exceeded.';
|
|
|
|
|
|
- return json($response, $json, 507);
|
|
|
|
|
|
+ return json($response, $this->json, 507);
|
|
}
|
|
}
|
|
|
|
|
|
try {
|
|
try {
|
|
- do {
|
|
|
|
- $code = humanRandomString();
|
|
|
|
- } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `code` = ?', $code)->fetch()->count > 0);
|
|
|
|
|
|
+ $response = $this->saveMedia($response, $file, $user);
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
+ $this->updateUserQuota($request, $user->id, $file->getSize(), true);
|
|
|
|
+ throw $e;
|
|
|
|
+ }
|
|
|
|
+ return $response;
|
|
|
|
+ }
|
|
|
|
|
|
- $published = 1;
|
|
|
|
- if ($this->getSetting('hide_by_default') === 'on') {
|
|
|
|
- $published = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ /**
|
|
|
|
+ * @param Request $request
|
|
|
|
+ * @param Response $response
|
|
|
|
+ * @return UploadedFileInterface
|
|
|
|
+ * @throws ValidationException
|
|
|
|
+ */
|
|
|
|
+ protected function validateFile(Request $request, Response $response)
|
|
|
|
+ {
|
|
|
|
+ if ($request->getServerParams()['CONTENT_LENGTH'] > stringToBytes(ini_get('post_max_size'))) {
|
|
|
|
+ $this->json['message'] = 'File too large (post_max_size too low?).';
|
|
|
|
|
|
- $fileInfo = pathinfo($file->getClientFilename());
|
|
|
|
- $storagePath = "$user->user_code/$code.$fileInfo[extension]";
|
|
|
|
|
|
+ throw new ValidationException(json($response, $this->json, 400));
|
|
|
|
+ }
|
|
|
|
|
|
- $this->storage->writeStream($storagePath, $file->getStream()->detach());
|
|
|
|
|
|
+ $file = array_values($request->getUploadedFiles());
|
|
|
|
+ /** @var UploadedFileInterface|null $file */
|
|
|
|
+ $file = $file[0] ?? null;
|
|
|
|
|
|
- $this->database->query('INSERT INTO `uploads`(`user_id`, `code`, `filename`, `storage_path`, `published`) VALUES (?, ?, ?, ?, ?)', [
|
|
|
|
- $user->id,
|
|
|
|
- $code,
|
|
|
|
- $file->getClientFilename(),
|
|
|
|
- $storagePath,
|
|
|
|
- $published,
|
|
|
|
- ]);
|
|
|
|
|
|
+ if ($file === null) {
|
|
|
|
+ $this->json['message'] = 'Request without file attached.';
|
|
|
|
|
|
- $json['message'] = 'OK';
|
|
|
|
- $json['url'] = urlFor("/{$user->user_code}/{$code}.{$fileInfo['extension']}");
|
|
|
|
|
|
+ throw new ValidationException(json($response, $this->json, 400));
|
|
|
|
+ }
|
|
|
|
|
|
- $this->logger->info("User $user->username uploaded new media.", [$this->database->getPdo()->lastInsertId()]);
|
|
|
|
|
|
+ if ($file->getError() === UPLOAD_ERR_INI_SIZE) {
|
|
|
|
+ $this->json['message'] = 'File too large (upload_max_filesize too low?).';
|
|
|
|
|
|
- return json($response, $json, 201);
|
|
|
|
- } catch (Exception $e) {
|
|
|
|
- $this->updateUserQuota($request, $user->id, $file->getSize(), true);
|
|
|
|
- throw $e;
|
|
|
|
|
|
+ throw new ValidationException(json($response, $this->json, 400));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return $file;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param Request $request
|
|
|
|
+ * @param Response $response
|
|
|
|
+ * @param UploadedFileInterface $file
|
|
|
|
+ * @param $user
|
|
|
|
+ * @return void
|
|
|
|
+ * @throws ValidationException
|
|
|
|
+ */
|
|
|
|
+ protected function validateUser(Request $request, Response $response, UploadedFileInterface $file, $user)
|
|
|
|
+ {
|
|
|
|
+ if (!$user->active) {
|
|
|
|
+ $this->json['message'] = 'Account disabled.';
|
|
|
|
+
|
|
|
|
+ throw new ValidationException(json($response, $this->json, 401));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param Request $request
|
|
|
|
+ * @param Response $response
|
|
|
|
+ * @param UploadedFileInterface $file
|
|
|
|
+ * @param $user
|
|
|
|
+ * @return Response
|
|
|
|
+ * @throws \League\Flysystem\FileExistsException
|
|
|
|
+ */
|
|
|
|
+ protected function saveMedia(Response $response, UploadedFileInterface $file, $user)
|
|
|
|
+ {
|
|
|
|
+ do {
|
|
|
|
+ $code = humanRandomString();
|
|
|
|
+ } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `code` = ?', $code)->fetch()->count > 0);
|
|
|
|
+
|
|
|
|
+ $published = 1;
|
|
|
|
+ if ($this->getSetting('hide_by_default') === 'on') {
|
|
|
|
+ $published = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $fileInfo = pathinfo($file->getClientFilename());
|
|
|
|
+ $storagePath = "$user->user_code/$code.$fileInfo[extension]";
|
|
|
|
+
|
|
|
|
+ $this->storage->writeStream($storagePath, $file->getStream()->detach());
|
|
|
|
+
|
|
|
|
+ $this->database->query('INSERT INTO `uploads`(`user_id`, `code`, `filename`, `storage_path`, `published`) VALUES (?, ?, ?, ?, ?)', [
|
|
|
|
+ $user->id,
|
|
|
|
+ $code,
|
|
|
|
+ $file->getClientFilename(),
|
|
|
|
+ $storagePath,
|
|
|
|
+ $published,
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ $this->json['message'] = 'OK';
|
|
|
|
+ $this->json['url'] = urlFor("/{$user->user_code}/{$code}.{$fileInfo['extension']}");
|
|
|
|
+
|
|
|
|
+ $this->logger->info("User $user->username uploaded new media.", [$this->database->getPdo()->lastInsertId()]);
|
|
|
|
+
|
|
|
|
+ return json($response, $this->json, 201);
|
|
|
|
+ }
|
|
}
|
|
}
|