Ticket #2531876 (closed enhancement)

Reporter


Brad Kusnir
Opened: 03/9/12
Last modified: 08/1/12
Status: closed
Type: enhancement
Resolution: fixed

Owner


Allen Rabinovich
Target Release: 3.6.0
Priority: P3 (normal)
Summary: More Robust File FIlters
Description:

Only basic allowed extension file filters are supported in the Flash Uploader, this does not seem to be supported in the HTML5 uploader. Wondering if this feature is being abandoned or if it is on
the roadmap for the HTML5 Uploader as well. If so I think it would make good sense to also offer disallowed extensions, and also a max/min file size. I find I am building this functionality now in
my implementation but it occured to me that this may be something that is desirable for all.

Type: enhancement Observed in Version: 3.5.0pr2
Component: Uploader Severity: S3 (normal)
Assigned To: Allen Rabinovich Target Release: 3.6.0
Location: Priority: P3 (normal)
Tags: uploader, file filters Relates To:
Browsers: N/A
URL:
Test Information:

This works only for UploaderFlash (not UploaderHTML5):

// allowed file filters (if setting "fileFilters" attribute below)
var ff = new Array({description:"Images", extensions:"*.jpg;*.png;*.gif"}, {description:"Videos", extensions:"*.avi;*.mov;*.mpg"});

// An array indicating what fileFilters should be applied to the file (Flash control only)
myuploader.set("fileFilters", ff);

Change History

Allen Rabinovich

YUI Developer

Posted: 03/27/12
  • priority changed to P3 (normal)
  • status changed from new to accepted

I haven't added the file extension filtering to HTML5 layer because it's not standard across all browsers that support HTML5 just yet. I will in 3.6 though. It works differently from Flash though; it's not by file extension, but rather by mime type.

Great idea about max/min file size control. I think I would just allow an option custom file filter function.

Allen Rabinovich

YUI Developer

Posted: 03/30/12
  • milestone changed to 3.6.0

Brad Kusnir

Posted: 04/7/12

I think I see the problem here is with the file dialogue box. Not sure how this behaves across different operating systems as well...

If you can build the functionality outside of the dialogue box (perhaps immediately after the file is selected). Right now I don't see how to intervene before the file actually gets added to the list, by which time it is too late. We need a function that runs immediately after a list updated, but then the problem is if we remove the file we are also updating the list which fires the listener. It would be nice to have the ability to not allow users to add illegal files, having some facility to profile files with regex expressions, file size, number of files in the list would be awesome.

John Mizliso

Posted: 05/2/12

I am looking forward to having working HTML5 filters as well :)

Allen Rabinovich

YUI Developer

Posted: 05/8/12

Custom filter function it is. Files will be run through it when the fileList is getting updated, and the "bad" ones will get rejected.

Allen Rabinovich

YUI Developer

Posted: 05/8/12
  • estimated changed from 0 to 1.5
  • remaining changed from 0 to 1.5
  • sprint changed to sprint 2

Brad Kusnir

Posted: 05/10/12

Here is what I ended up doing would be nice to see support for whitelisting and blacklisting filenames and extensions via regex:

// validation variables

// illegal file extensions list
var dis_ext = "com|exe|vbs|js|htm|html|dll|ocx|asp|jsp|bat|app|asf|avi|cda|ceo|eml|fxp|grp|hlp|lnk|m1v|mdb|mde|mid|midi|mov|mp2|mp3|mpa|mpe|mpeg|mpg|otf|prg|rmi|swf|url|vbe|wav|wm|wma|wmv",
// maximum number of files
max_nf = 5,
// minimum file size (bytes) - must be greater than
min_size = 1,
// maximum file size (bytes) - must be less than
max_size = 26214400,
// maximum aggregate upload size (bytes) - must be less than
maxUploadSize = 26214400,

// perform file validations
// NOTE: these checks are also performed on the backend - this is just a first line of defense to conserve resources
function validateFiles() {
nf = 0;
error = "";
uploadSize = 0;
validations = [];
Y.each(myuploader.get("fileList"), function (value) {
// count number of files
nf = nf + 1;
filename = value.get("name");
// get filesize (bytes)
filesize = Math.floor(value.get("size"));
// keep track of combined file size total
uploadSize = uploadSize + filesize;
// check for 0 byte file size
if (filesize >= min_size) {
// do nothing
} else {
error = error + "The file is empty. You tried to upload a blank file. Please send a completed file." + "n";
clearFile(nf - 1);
}

// check for maximum file size
if (filesize > max_size) {
error = error + filename + " (" + (Math.floor(filesize / 1024 / 1024)) + "MB) exceeds maximum file size limit (" + (Math.floor(max_size / 1024 / 1024)) + "MB)" + "n";
clearFile(nf - 1);
}
// check for illegal extensions
regex_ext = new RegExp(dis_ext, "i");
parse_ext = regex_ext;
test_ext = parse_ext.test(filename);

if (test_ext) {
extension = filename.substring(filename.lastIndexOf("."));
error = error + 'Cannot upload files with extension"' + extension + '".' + "n";
clearFile(nf - 1);
}
});
// no files selected
if (nf === 0) {
//error = error + ("No files selected!" + "n");
}

// TO:DO do a duplicate file check
// maximum number of files exceeded
if (nf > max_nf) {
error = error + ("The file(s) exceed the maximum limit of " + max_nf + " files per request." + "n");
}
// maximum upload size exceeded
if (uploadSize > maxUploadSize) {
error = error + "The file(s) exceed the maximum limit of " + (Math.floor(maxUploadSize / 1024 / 1024)) + " MB per request." + "n";
Y.one("#uploadBtn").hide();
}

// if there is error output, display it to the user
if (error !== "") {
alert(error);
} else {
// validation passed, show upload button if files exist
if (nf > 0) {
Y.one("#uploadBtn").show();
Y.one("#clearAllButton").show();
Y.one("#clearAllBtn").show();
} else {
Y.one("#uploadBtn").hide();
Y.one("#clearAllButton").hide();
Y.one("#clearAllBtn").hide();
}
}
validations = [nf, uploadSize, error];
return validations;
}

Y.one("#uploadButton").on("click", function () {
// get validation info
var validations = [];
validations = validateFiles();
// get number of files in file list
nf = validations[0];
// get total upload size
uploadSize = validations[1];
// get error info
error = validations[2];
// check if file list passes validations
if (nf === 0 || (nf > max_nf) || error !== "") {
// error - do not start uploading, user has been informed by validateFiles()
} else { // start uploading
// show legacy progress DIV
Y.one("#ProgressDiv").show();
// hide legacy upload header
Y.one("#UploadPageHeader").hide();
// hide choose file button
Y.one("#chooseFileBtn").hide();
// hide upload button
Y.one("#uploadBtn").hide();
// hide clear all button
Y.one("#clearAllBtn").hide();
// show cancel button div
Y.one("#cancelBtn").show();
// show "File Detail" header
Y.one("#pageTitle").setContent("File Name(s):");

// remove clear links
bodyNode = Y.one(document.body);
bodyNode.all('.clearLink').hide();

// record start time for calculating xfer rate and eta in progress bar
startTime = new Date().getTime();

// inititate upload
myuploader.uploadAll("upload.php");
}
});

Allen Rabinovich

YUI Developer

Posted: 06/9/12
  • status changed from accepted to checkedin

fileFilters are now implemented in HTML5 Uploader (for browsers in which it's supported), and there's a new attribute, filterFunction, which allows filtering files as they are added to the fileList. Furthermore, the fileList attribute is now shadowing the private _fileList property which, if very necessary, can be modified directly.

Jenny Donnelly

YUI Developer

Posted: 08/1/12
  • resolution changed to fixed
  • status changed from checkedin to closed

Shipped in 3.6.0. Marking closed/fixed.