I have a FileUpload control where I upload PDF files and they get saved to a folder, the file path gets saved to the database.
The problem is when I upload a file which contains parenthesis () as part of the file name, it returns undefined. This only happens if the file name has parenthesis () , if it does not have parenthesis () it uploads fine.
This is my code
var filePaths;
function UploadFile() {
var fileUpload = document.getElementById("fuPDFupload");
var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.pdf)$");
if (regex.test(fileUpload.value.toLowerCase())) {
//Check whether HTML5 is supported.
if (typeof (fileUpload.files) != "undefined") {
//Initiate the FileReader object.
var reader = new FileReader();
//Read the contents of Image File.
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {
//Initiate the JavaScript Image object.
var image = new Image();
//Set the Base64 string return from FileReader as source.
image.src = e.target.result;
var fileUpload = $("#fuPDFupload").get(0);
var files = fileUpload.files;
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append(files[i].name, files[i]);
}
$.ajax({
url: "FileUploadHandler.ashx",
type: "POST",
data: data,
contentType: false,
processData: false,
success: function (result) {
filePaths = result;
//Save to DB
UpdateSchedule();
},
error: function (err) {
}
});
return true;
};
} else {
alert("This browser does not support HTML5.");
return false;
}
} else {
return false;
}
}
FileUploadHandler Code:
public class FileUploadHandler : IHttpHandler {
public void ProcessRequest(HttpContext context)
{
if (context.Request.Files.Count > 0)
{
string filePaths = Guid.NewGuid().ToString() + ".pdf";
HttpPostedFile file = context.Request.Files[0];
string path = context.Server.MapPath("~/QfrencyInvoices/" + filePaths);
file.SaveAs(path);
context.Response.ContentType = "text/plain";
context.Response.Write(filePaths);
}
}
public bool IsReusable {
get {
return false;
}
}
}
I believe that the problem might be happening because the Regex expression is incorrect but I have not been able to fix it.
Please assist me how I can upload files that have parenthesis () as part of the file name. Thank you.
Just leave next regex new RegExp("(\.(jpg|png|pdf)$", "i");. It checks that filename has extension jpg, png or pdf. Text case does not matter so "i" was added as the second parameter.
You can learn regular expressions on https://regexone.com/
Related
I am trying to POST a .tgz file using XHR as part of a file upload.
The file itself is valid and I have tested it via manual upload. The issue I am having (I think) is when I encode the file into base64 and upload it, it is being corrupted and not not being picked up as valid.
The file itself is a plugin module for Atmail, which I have tested manually like I said.
This is my upload function with the base64 truncated.
I am encoding the target file initially with:
cat myfile.tgz | base64 > base64_file
and shortening/removing new lines with:
sed ':a;N;$!ba;s/\n/ /g' plugin.base64 > t
My question is, is this the correct way to encode a compressed file for use in my POST request? And if so what is wrong with my implementation?
function uploadPlugin()
{
var uri = "/index.php/admin/plugins/preinstall";
var name = "newPlugin";
filename = "RCE.tgz";
// Comments and extra lines removed to reduce payload size
// Remove new lines: sed ':a;N;$!ba;s/\n/ /g' plugin.base64 > t
var content = "H4sIAAAAAAAAA+0aa2/bOLJfk1/BFYJaLvyIs0m6TZpss30Awe22vabXA65XqLREx2xkSSWppNlu ...";
var formData = new FormData();
var blob = new Blob([atob(content)],
{
type: "application/x-gtar-compressed"
}
)
formData.append(name, blob, filename);
var request = new XMLHttpRequest();
request.open("POST", uri);
request.send(formData);
}
This is the ATMail plugin class I am using.
<?php
class Atmail_Test_Plugin extends Atmail_Controller_Plugin
{
protected $_pluginFullName = 'rce';
protected $_pluginModule = 'mail';
private $_loginPage = false;
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$request = $this->getRequest();
if (($request->getControllerName() == 'index' && $request->getActionName() == 'index') ||
($request->getControllerName() == 'auth' && $request->getActionName() == 'logout')) {
$this->_loginPage = true;
}
}
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
if ($this->_loginPage) {
$page = $this->getResponse()->getBody();
$page = str_replace("</body>", "<!-- plugins working -->\n</body>", $page);
$this->getResponse()->setBody($page);
}
}
public function setup()
{
$db = zend_Registry::get("dbAdapter");
$db->query("drop table if exists `TestPluginSettings`");
$db->query("create table `TestPluginSettings` (`id` int auto_increment primary key, `keyName` varchar(12), `keyValue` text, index `keyName` (`keyName`))");
}
public function setViewRenderScript()
{
//return "/path/to/nothing.phtml";
}
public function setViewRenderAction()
{
}
}
I eventually found out what was going wrong. I was trying to post binary data incorrectly. Below is the working solution.
function uploadPlugin()
{
var uri = "/index.php/admin/plugins/preinstall";
var name = "newPlugin";
filename = "Upload.tgz";
var body = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xed\x1a\x6b\x6f\xdb" +
"\x38\xb2\x5f\x93\x5f\xc1\x15\x82\x5a\x2e\xfc\x88\xb3\x49\xba" +
"..." +
"...";
var formData = new FormData();
var payload = new Uint8Array(body.length);
for (var i = 0; i < payload.length; i++)
{
payload[i] = body.charCodeAt(i);
}
var blob = new Blob([payload])
formData.append(name, blob, filename);
var xhr = new XMLHttpRequest();
xhr.open("POST", uri);
xhr.send(formData);
}
Using the sapui5 uploadcollection to upload files in the frontend and then sending them through ajax with a post request...
I need to know how to convert te returned object from the uploadcollection control into a xstring, so then I can send that xstring (that contains the file content) To a sap gateway by using ajax post method.
Any idea how could I do this?
Right now I'm sending files by using the uploadcollection, once I upload an attachment, the control returns an object that represents the file content.
I'm trying to make this object a xstring by using filereader:
//obtiene archivo
var file = files[i];
//Convierte archivo en binario
var reader = new FileReader();
reader.onload = function(readerEvt) {
var binaryString = readerEvt.target.result;
var base64 = btoa(binaryString);
var base64file;
if(typeof base64file == "undefined" || typeof base64file == null){
base64file = base64;
}else{
base64file = base64file +'new'+base64;
}
};
reader.readAsBinaryString(file);
console.log(file)
But this work only with files of type image, the others like pdf, .doc etc etc give the following error when I try to send them with ajax.
"The Data Services Request could not be understood due to malformed syntax".
Any idea how can I send convert these files into a xstring data?
Take a look at this example. Hope this helps.
View
<u:FileUploader change="onChange" fileType="pdf" mimeType="pdf" buttonText="Upload" />
Controller
convertBinaryToHex: function(buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), function(x) {
return ("00" + x.toString(16)).slice(-2);
}).join("");
},
onChange: function(oEvent){
var that = this;
var reader = new FileReader();
var file = oEvent.getParameter("files")[0];
reader.onload = function(e) {
var raw = e.target.result;
var hexString = that.convertBinaryToHex(raw).toUpperCase();
// DO YOUR THING HERE
};
reader.onerror = function() {
sap.m.MessageToast.show("Error occured when uploading file");
};
reader.readAsArrayBuffer(file);
},
I figured it out by filling an array everytime that a file was uploaded through the control,
change: function(oEvent) {
//Get file content
file = oEvent.getParameter("files")[0];
//Prepare data for slug
fixname = file.name;
filename = fixname.substring(0, fixname.indexOf("."));
extension = fixname.substring(fixname.indexOf(".") + 1);
//fill array with uploaded file
var fileData = {
file: file,
filename: filename,
extension: extension
}
fileArray.push(fileData);
},
and then I did a loop over that array to post every single file I keept there by using ajax method post.
$.each(fileArray, function(j, valor) {
//get file
file = fileArray[j].file;
//get file lenght
var numfiles = fileArray.length;
//Convert file to binary
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(evt) {
fileString = evt.target.result;
//get and make slug
filename = fileArray[j].filename;
extension = fileArray[j].extension;
slug = documento + '/' + filename + '/' + extension;
//User url service
var sUrlUpload = "sap url";
runs++;
//Post files
jQuery.ajax({});
}
});
download any file using ResponseEntity with angular does not work
I need to download a file using angular in client side,
this file can have any format it could be a pdf or excel or image or txt ...
my method works just for txt files and gives me a fail format for excel and image and for the pdf it gives an empty pdf.
so in my controller here is the function that calles the service method:
vm.downloadFile = downloadFile;
function downloadFile(file){
var urlDir = "C://STCI//"+idpeticion;
return VerDocServices.downloadFile(file,urlDir)
.then(function(response) {
var data = response.data;
var filename = file;
var contentType = 'application/octet-stream';//octet-stream
var linkElement = document.createElement('a');
try {
var blob = new Blob([ data ], {
type : contentType
});
var url = window.URL.createObjectURL(blob);
linkElement.setAttribute('href', url);
linkElement.setAttribute("download", filename);
var clickEvent = new MouseEvent("click", {
"view" : window,
"bubbles" : true,
"cancelable" : false
});
linkElement.dispatchEvent(clickEvent);
} catch (ex) {
console.log(ex);
throw ex;
}
}).catch(function(response) {
alert('Se ha producido un error al exportar del documento');
console.log(response.status);
throw response;
});
}
and my service.js has:
angular.module('mecenzApp').service('VerDocServices',['$http',function($http) {
this.downloadFile = function(file,urlDir) {
return $http.get('api/downloadFile', {
params : {
file : file,
urlDir : urlDir
}
}); }} ]);
And my service method is this:
#GetMapping("/downloadFile")
#Timed
public ResponseEntity<byte[]> downloadFile(#RequestParam(value = "file") String file, #RequestParam(value = "urlDir") String urlDir) {
log.debug("GET ---------------- DOWNLOAD FILE : {}", file);
log.debug("GET ---------------- From the DIRECTORY: {}",urlDir);
InputStream fileStream;
String filepath = urlDir+File.separator+file;
try {
File f = new File(filepath);
log.debug("GET ---------------- FILE: {}",f.getPath());
fileStream = new FileInputStream(f);
byte[] contents = IOUtils.toByteArray(fileStream);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/octet-stream"));
String filename = file;
headers.setContentDispositionFormData(filename, filename);
ResponseEntity<byte[]> response2 = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
fileStream.close();
return response2;
} catch (FileNotFoundException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
return null;
}
could you plz take a look and tell me what did I have missed??
Thank youuu :)
How to Download Binary Files with AngularJS
When downloading binary files, it is important to set the responseType:
app.service('VerDocServices',['$http',function($http) {
this.downloadFile = function(url, file, urlDir) {
var config = {
//SET responseType
responseType: 'blob',
params : {
file : file,
urlDir : urlDir
}
};
return $http.get(url, config)
.then(function(response) {
return response.data;
}).catch(function(response) {
console.log("ERROR: ", response.status);
throw response;
});
};
}]);
If the responseType is omitted the XHR API defaults to converting UTF-8 encoded text to DOMString (UTF-16) which will corrupt PDF, image, and other binary files.
For more information, see MDN Web API Reference - XHR ResponseType
I don't know much about the backend, but I'll provide what i have used may be it will help, so On the Java Script File:
//your $http(request...)
.success(function (data, status, headers, config) {
//Recieves base64 String data
var fileName = 'My Awesome File Name'+'.'+'pdf';
//Parsing base64 String...
var binaryString = window.atob(data);
var binaryLen = binaryString.length;
var fileContent = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
fileContent[i] = ascii;
}
var blob = new Blob([fileContent], { type: 'application/octet-stream' }); //octet-stream
var fileURL = window.URL.createObjectURL(blob);
$sce.trustAsResourceUrl(fileURL); //allow angular to trust this url
//Creating the anchor download link
var anchor = angular.element('<a/>');
anchor.css({display: 'none'}); // Make sure it's not visible
angular.element(document.body).append(anchor); // Attach it to the document
anchor.attr({
href: fileURL,
target: '_blank',
download: fileName
})[0].click();
anchor.remove(); // Clean it up afterwards
})
//.error(function(...
And On your backend, make sure that your webservice produces octet-stream and returning the file in base64 data format, i did this using Java JAX-RS like this:
#POST
#Path("/downloadfile")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(...){
String base64String = Base64.getEncoder().encodeToString(/*here you pass your file in byte[] format*/);
return Response.ok(base64String).build();
}
I want to get the image file stream and pass them to the background like asp.net,but every time I try to fire the onload event ,it always accomplish after the programming passed.
I tried to use setTimeout to prevent it and let it processing and waiting it Success ,but it failed .
the comment of below explains which step I failed.thanks.
$("#goodsImage").change(function (e) {
if ($("#goodsImage").val() == "")
{
alert("please choose the image you want to upload");
return;
}
var filepath = $("#goodsImage").val();
//$("#goodsImage").val();
var extStart=filepath.lastIndexOf(".");
var ext=filepath.substring(extStart,filepath.length).toUpperCase();
if(ext!=".BMP"&&ext!=".PNG"&&ext!=".GIF"&&ext!=".JPG"&&ext!=".JPEG"){
alert("only images could be uploaded");
return;
}
readFile(e.target.files[0]);
setTimeout(function () {
//I want to use setTimeOut to delay it
}, 1000);
//always undefined!!!
if ($("#hidImageStream").val() != "")
{
$.post("#Url.Action("UploadGoodImage")", { localPath: readerRs }, function (e)
{
if (e) {
$("#ImagePreviewUrl").val(e.data);
}
else {
}
});
}
});
function readFile(file) {
var reader = new FileReader();
reader.onload = readSuccess;
//always success after post request accomplished.
function readSuccess(evt) {
document.getElementById("hidImageStream").
value = evt.target.result;
};
reader.readAsText(file);
}
here is a few tips
<-- use accept and only allow image mimetype. It can accept extension to -->
<input type="file" name="pic" accept="image/*">
Also reading the file as readAsText is a horrible idea for binary. (All doe i saw you change to base64).
readAsDataURL isn't that grate either since it's ~3x larger upload and needs more cpu/memory.
Spoofing the filename is very easy so best is to actually test if it's a image
$("#goodsImage").change(function() {
// We use `this` to access the DOM element instead of target
for (let file of this.files) {
// Test if it's a image instead of looking at the filename
let img = new image
img.onload = () => {
// Success it's a image
// upload file
let fd = new FormData
fd.append('file', file)
$.ajax({
url: 'http://example.com',
data: fd,
processData: false, // so jquery can handle FormData
type: 'POST',
success: function( data ) {
alert( data )
}
})
}
img.onerror = () => {
// only images dude
}
img.src = URL.createObjectURL(file)
}
})
I have solved the question ,just put the post request into the onloaded funciton .
function readFile(file) {
var reader = new FileReader();
reader.onloadend = readSuccess;
//reader.onloadend = function (e) {
// console.log(e.target.result);
//};
function readSuccess(evt) {
$.post("#Url.Action("UploadGoodImage")", { localPath: evt.target.result}, function (e) {
if (e.IsSuccess) {
$("#ImagePreviewUrl").val(e.data);
}
else {
alert("Fail!");
}
});
}
reader.readAsDataURL(file);
}
I have some code in an MVC project that creates a zip file and sends it to the browser. Everything works when I manually enter the URL in the browser, but if I click on the link in the page to get the download, I get a file of a different size and Windows cannot open it.
So, if I manually enter something like this:
http://localhost/fms-ui/File/DownloadZipFile/?id=10&filename=DST-2015-11-14_04_04_04
I get a zip file of 167 bytes and it open fine.
If I click on the link in the page, I get a file of 180 bytes and Windows says the file is corrupted. Hun?
My one stipulation is that I cannot use an external library. Due to politics I must use the library provided with .Net Framework 4.5 (static ZipFile class).
Code:
public FileContentResult DownloadZipFile(int id, string filename)
{
/*
* 1 - get fileset info
* 2 - get temp file name
* 3 - create zip file under temp name
* 4- return file
*/
QuesterTangent.Wayside.FileServices.FileSet sInfo = new QuesterTangent.Wayside.FileServices.FileSet(id);
string path = Path.Combine(sInfo.BasePath);
string tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".zip");
ZipFile.CreateFromDirectory(path, tempPath);
byte[] fileBytes = System.IO.File.ReadAllBytes(tempPath);
//System.IO.File.Delete(tempPath); Commented so I can compare the files
filename = filename + ".zip";
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileBytes, "application/zip");
}
I've tried this with and without AppendHeader and with various contentTypes, but it doesn't seem to effect the outcome.
Here is the JavaScript that calls the controller (I inherited this code but it works for other things).
function GetFile(url) {
//spin a wheel for friendly buffering time
var buffer = $('.MiddleRightDiv').spinBuffer();
$.ajax({
url: url,
type: "POST",
cache: false,
async: true,
data: {},
success: function (response, status, xhr) {
// check for a filename
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = new Blob([response], { type: type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
},
complete: function (result) {
if (typeof $('.MiddleRightDiv').spinBuffer !== 'undefined' && $.isFunction($('.MiddleRightDiv').spinBuffer)) {
$('.MiddleRightDiv').spinBuffer("destroy");
}
}
});
Any input would be a great help. I have gone over other similar postings but non of them seems to address the core problem I am having.
Thanks,
dinsdale
jQuery.ajax cannot read bytestreams correctly (check SO for many topics about this), so we have to use old and good XMLHttpRequest. Here is your function refactored to work with blobs. Extened it with fallbacks for other browsers while saveAs(blob,filename) is the draft.
function GetFile(url) {
if (window.navigator.msSaveBlob) {
var req = new XMLHttpRequest();
req.open('GET', url);
req.responseType = 'arraybuffer';
req.onload = function (e) {
if (req.response) {
var filename = 'archive.zip';
var disposition = req.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
var type = req.getResponseHeader('Content-Type');
var blob = new Blob([req.response], { type: type ? type : 'application/octet' });
window.navigator.msSaveBlob(blob, filename);
} else {
throw 'Empty or invalid response';
}
}
req.send();
} else {
//fallback for browsers without blob saver
throw 'Not implemented';
}
}