Reputation: 808
I am using:
"@uppy/core": "^3.12.0"
"@uppy/dashboard": "^3.8.3"
"@uppy/golden-retriever": "^3.2.0"
"@uppy/locales": "^3.5.3"
"@uppy/xhr-upload": "^3.6.7"
As of time of writing there is no official OneUpUploaderBundle
integration with UPPY
.
Luckily, developers of OneUpUploaderBundle
are forward thinking and added support for a custom Uploader!
So I choose to implement it.
Firstly, I chose to set up upload with Blueimp jQuery File Uploader as it is supported by bundle.
After success I moved to setting up upload with UPPY
and Custom uploader
.
For my CustomUploader
I chose BlueimpController
- from a bunch of other uploaders that bundle supports.
At the moment upload works with custom uploader (for UPPY).
For security reasons I do not allow upload of files where extension
does not correspond with its mime type
. I check this (on server, after file is received) with Symfony in UploadValidationListener
. In this case I need to show error to the user, but do not know how to pass it to UPPY Dashboard
.
Status is: file is uploaded successfully, but such a file is not kept - as it failed validation. Without a message, user would be left wondering: where does phantom files are, as they saw them uploading successfully!
here is how
UPPY
is set up
'use strict';
import Translator from 'bazinga-translator';
import Uppy from '@uppy/core';
import Dashboard from '@uppy/dashboard';
import GoldenRetriever from '@uppy/golden-retriever';
import XHR from '@uppy/xhr-upload';
import '@uppy/core/dist/style.css';
import '@uppy/dashboard/dist/style.css';
import en_US from "@uppy/locales/lib/en_US";
const js_data = document.querySelector('#js-data');
let data_allowed_file_types_str = js_data.dataset.allowedFileTypes;
const data_allowed_file_types = data_allowed_file_types_str.split('|');
const data_allowed_file_size_min = js_data.dataset.allowedFileSizeMin;
const data_allowed_file_size_max = js_data.dataset.allowedFileSizeMax;
const data_upload_endpoint = js_data.dataset.uploadEndpoint;
const uppy = new Uppy({
debug: false,
locale: en_US,
onBeforeFileAdded: (currentFile, files) =>
{
const do_not_allow_arr = ['do_not_allow_me_1.txt', 'do_not_allow_me_2.txt', 'do_not_allow_me_3.txt'];
let allowed = true;
do_not_allow_arr.forEach((element) =>
{
if (currentFile.name === element)
{
allowed = false;
uppy.log(Translator.trans('upload.error.skipFilesFromBlockList'));
uppy.info((Translator.trans('upload.error.skipFilesFromBlockList')), 'error', 5000);
return allowed;
}
});
return allowed;
},
});
uppy.use(GoldenRetriever);
uppy.use(Dashboard, {
inline: true,
target: '#uppy-dashboard',
id: 'uppy',
width: '100%',
proudlyDisplayPoweredByUppy: false,
showProgressDetails: true,
});
uppy.use(XHR, {
endpoint: data_upload_endpoint
});
uppy.setOptions({
restrictions:
{
minNumberOfFiles: 1,
maxNumberOfFiles: 1,
minFileSize: data_allowed_file_size_min,
minTotalFileSize: data_allowed_file_size_min,
maxTotalFileSize: data_allowed_file_size_max,
allowedFileTypes: data_allowed_file_types
},
//autoProceed: true
});
uppy.on('file-added', (file) => {
console.log('Added file', file);
});
uppy.on('upload-success', (file, responseObject) => {
// (depending on the uploader plugin used, it might contain
// less info, the example is for @uppy/xhr-upload)
// responseObject = {
// status, // HTTP status code (0, 200, 300)
// body, // response body
// uploadURL // the file url, if it was returned
// }
console.log('after upload success');
});
uppy.on('upload-error', (file, responseObject) => {
// responseObject = {
// status, // HTTP status code (0, 200, 300)
// body // response body
// }
console.log('after upload error');
});
here is validator code
<?php
namespace App\EventListener;
use App\Entity\FileType;
use App\UltraHelpers\UltraHelpers;
use Doctrine\Persistence\ManagerRegistry;
use Oneup\UploaderBundle\Event\ValidationEvent;
use Oneup\UploaderBundle\Uploader\Exception\ValidationException;
use Symfony\Component\Mime\MimeTypes;
class UploadValidationListener
{
/**
* @var ManagerRegistry
*/
private ManagerRegistry $doctrine;
/**
* @var UltraHelpers
*/
private UltraHelpers $ultraHelpers;
public function __construct(
ManagerRegistry $doctrine,
UltraHelpers $ultraHelpers
)
{
$this->doctrine = $doctrine;
$this->ultraHelpers = $ultraHelpers;
}
public function onValidate(ValidationEvent $event): void
{
$repo_file_Type = $this->doctrine->getRepository(FileType::class);
$file_extensions_allowed = $repo_file_Type->getActivatedFileTypeOnlyListArray();
$mimeTypes = new MimeTypes();
$errors = [];
$file_list_banned = [];
$file_list_banned[] = 'do_not_allow_me_1.txt';
$file_list_banned[] = 'do_not_allow_me_2.txt';
$file_list_banned[] = 'do_not_allow_me_3.txt';
$config = $event->getConfig();
$file = $event->getFile();
$filtered_file_info = $this->ultraHelpers->filterFileInfoFromFileName($file->getClientOriginalName());
$transliterated_file_name = $filtered_file_info['name'];
$full_file_name = $transliterated_file_name .'.'. $filtered_file_info['extension'];
$file_extension = $filtered_file_info['extension'];
$file_mime_type_from_file = $mimeTypes->guessMimeType($file);
$file_mime_types_from_extension = $mimeTypes->getMimeTypes($file_extension);
// process forbidden_files
if (in_array($full_file_name, $file_list_banned, true))
{
$errors[] = 'error.file_banned';
}
// If mime type of current file does not correspond to extensions mime type
// Damaged file or specially prepared for research / hacking
if (!in_array($file_mime_type_from_file, $file_mime_types_from_extension, true))
{
$errors[] = 'error.mime_type_mismatch';
}
if (!empty($errors))
{
throw new ValidationException(implode(', ', $errors));
}
}
}
I added UploadExceptionListener
yet it did not change anything. Files that are not corresponding to declared type (by extension) are still silently removed (on server) and UI shows it was a sucessful upload.
services.yaml
App\EventListener\UploadExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
ExceptionListener
<?php
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class UploadExceptionListener
{
public function __invoke(ExceptionEvent $event): void
{
// You get the exception object from the received event
$exception = $event->getThrowable();
$message = sprintf(
'My Error says: %s with code: %s',
$exception->getMessage(),
$exception->getCode()
);
// Customize your response object to display the exception details
$response = new Response();
$response->setContent($message);
// HttpExceptionInterface is a special type of exception that
// holds status code and header details
if ($exception instanceof HttpExceptionInterface)
{
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
}
else
{
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
// sends the modified response object to the event
$event->setResponse($response);
}
}
Tried suggestions in the comments:
Trying 1 and 2 conditions with malformed file (mimetype does not correspond extension):
Trying 1 and 2 conditions with normal file:
Wrote a second EventListener and added EventSubscriber in place of first EventListener:
Did similar as exlained here:
Still can not get error form server showing in Uppy UI!
Upvotes: 0
Views: 571
Reputation: 61
can use a ExceptionListener
, checkout an example here https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-listener
services.yaml
services:
App\Listener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
Upvotes: 0