Allow user to download a generated pdf file after uploading a file - ajax

I'm trying to allow a user to upload a 15 MB file to my web, from there that file should be posted to a web service of mine, receive the response (a pdf file) and serve that to the user so he can download it.
However, I'm ending in a URL like this with no prompt to download anything, just a 404 error: http://localhost:10080/Download?file=%PDF-1.4%%EF%BF%BD%EF%B (etc)
Some points:
First I will compress the file
Because of the previous point, I'm using Ajax to post the file
Ajax code
$("#file").on("change", function(evt) {
var files = evt.target.files;
/* Create zip file representation */
var zip = new JSZip();
/* Name, content */
zip.file("data.zip", files[0]);
zip.generateAsync({
compression: 'DEFLATE',
type: 'blob'
}).then(function(zc) { // Function called when the generation is complete
/* Create file object to upload */
var fileObj = new File([zc], "compressed-data");
/* form data oject */
var formData = new FormData();
/* $('#file')[0].files[0] */
formData.append('attachments', fileObj);
$.ajax({
type: "POST",
url: $("form#data").attr("action"),
data: formData,
contentType: false,
processData: false,
success: function (returnValue, textStatus, jqXHR ) {
window.location = '/Download?file=' + returnValue;
}
})
Python Web Code
def post(self):
attachments = self.request.POST.getall('attachments')
#handle the attachment
_attachments = [{'content': f.file.read(),
'filename': f.filename} for f in attachments]
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
#web service url
url = 'http://localhost:8080'
files = {'attachments': _attachments[0]["content"]}
resp = requests.post(url, files=files)
self.response.headers[b'Content-Type'] = b'application/pdf; charset=utf-8'
self.response.headers[b'Content-Disposition'] = b'attachment; filename=report.pdf'
self.response.out.write(resp.content)
Python Web Service Code
#app.route('/', methods=['POST'])
def hello():
#the attached ZIPPED raw data
f = request.files["attachments"]
#to unzip it
input_zip = ZipFile(f)
#unzip
data = [input_zip.read(name) for name in input_zip.namelist()]
generator = pdfGenerator(io.BytesIO(data[0]))
return generator.analyzeDocument()
The pdf generator uses Reportlab, writes the pdf over a
io.BytesIO() and returns it with output = self.buff.getvalue()
1.- What am I doing wrong with the window location thing?
2.- Am I doing something wrong with the file type?
I'm two days into this, now I need help.
Thanks.

However, I'm ending in a URL like this with no prompt to download anything, just a 404 error: http://localhost:10080/Download?file=%PDF-1.4%%EF%BF%BD%EF%B (etc)
That's what you're asking in window.location = '/Download?file=' + returnValue;, you redirect the user to /Download.
When you call your service, you should ask for a Blob response. Then, use saveAs (or FileSaver.js, a polyfill) to trigger the download.
As far as I know, $.ajax doesn't let you download binary content out of the box (it will try to decode your binary from UTF-8 and corrupt it). Either use a jQuery plugin (like jquery.binarytransport.js) or use a xhr directly.
$.ajax({
type: "POST",
url: $("form#data").attr("action"),
data: formData,
contentType: false,
processData: false,
dataType: 'binary', // using jquery.binarytransport.js
success: function (returnValue, textStatus, jqXHR ) {
// Default response type is blob
saveAs(returnValue, "result.pdf"); // using FileSaver.js
}
})

Related

Receive file with request.files vs request.form in Flask

I'm using ajax to send file via POST request to the server (my Flask app), but I can only retrieve this file (binary data) in Flask using request.form, not request.files, and request.files is desired. Code as below.
How can I get file with request.files ? (Conversely, with Postman and other tools, I can get the file with request.files. In request.form case, info such as content-type is missing)
// "file_content" is read previously
var formData = new FormData();
formData.append("file", file_content); // "file_content" is binary data
.ajax({
type:"POST",
async: false,
url: ...,
data: formData,
dataType:"json",
processData: false,
contentType: false,
});
The tricky thing is send a local file, and most relevant answers are using document.getElementById().

SummerNote onImageUpload converting server request to C# BASE64?

I have a C# MVC project where I will need to both use Summernote v0.8.2 as my WYSIWYG editor, along with exporting a PDF with jsPDF. I know that there are examples to make this work. My issue is that I need to custom resize/process the image that's inserted with summernote. Again, I know that you can capture this event using the onImageUpload callback. I'm having trouble correctly handing the incoming Request on the server to get the image and convert it into a BASE64 string. I would think this should be pretty easy, but I can't figure out what to do with the incoming Request to extract the Image. I've give you the whole process just to make sure you have enough info to help.
Here's my Summernote setup:
$('.summernote').summernote(
{
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']]
, ['fontname', ['fontname']]
, ['fontsize', ['fontsize']]
, ['color', ['color']]
, ['insert', ['picture']]
]
, callbacks: {
onImageUpload: function (image) {
uploadImage(image[0]);
}
}
}
);
Here's the AJAX call: FYI - I did change the data appended from image to file. Didn't change outcome.
function uploadImage(file, editor, welEditb) {
var data = new FormData();
//data.append("image", image);
data.append("file", file);
$.ajax({
url: '/home/UploadSummerNoteFile',
cache: false,
contentType: false,
processData: false,
data: data,
type: "post",
success: function (data) {
alert('display base64 data: ' + data);
//editor.insertImage(welEditable, url);
},
error: function (data) {
console.log(data);
}
});
}
My server method doesn't have any parameters, and I'm not sure how to extract just the FILE (IMAGE?) content. Once I get the actual file, I need to modify and change it (size, resolution, etc., which I can do), then convert it into BASE64 and send it back to the UI. So, my questions here this:
How do I get the file (image) from the request stream?
How do convert whatever this 'thing' is from above into BASE64?
I've used an online BASE64 converter for the image that I've been testing with so I know that my attempts haven't created a valid string.
Here's a partial example that I've found online, modified it (poorly) in an attempt to make work, which it doesn't:
byte[] buffer = new byte[Request.InputStream.Length];
Request.InputStream.Read(buffer, 0, buffer.Length);
string data = Encoding.Default.GetString(buffer);
string[] tokens = data.Split(',');
if (tokens.Length > 1)
{
// not sure what I'm doing, trying stuff. BOOOOM!
image = Convert.FromBase64String(tokens[1]);
base64 = Convert.ToBase64String(image);
//string fileName = DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".png";
//string path = Path.Combine(#"D:\www\images", fileName);
//File.WriteAllBytes(path, image);
}
What do I need to do with the buffer or the data object? Where does the content of the file live in the request? Is it already converted when it was serialized for transport to the server? Also, assuming everything else gets completed, do I need to save the file to the server so it can be placed within Summernote's editor.insertImage(welEditable, url)? Thanks for your time and help!
Seems that I made this much harder than it needed to be. It's just a regular request, so extract the file from the request, and copy it to a memory stream. In this case I send back the BASE64 string to the calling function. Hopefully this helps others.
[HttpPost]
public JsonResult UploadFile()
{
var fileName = Request.Files[0].FileName;
var base64 = string.Empty;
using (var memoryStream = new MemoryStream())
{
Request.Files[0].InputStream.CopyTo(memoryStream);
var fileContent = memoryStream.ToArray();
base64 = Convert.ToBase64String(fileContent);
}
return Json(base64);
}
Here's the uploadImage ajax method changes: I create an instance of an IMG, and change the src to be the BASE64 value.
function uploadImage(file, editor, welEditb) {
var data = new FormData();
data.append("file", file);
$.ajax({
url: '/home/UploadSummerNoteFile',
cache: false,
contentType: false,
processData: false,
data: data,
type: "post",
success: function (data) {
var image = $('<img>').attr('src', 'data:' + file.type + ';base64,' + data);
$('.summernote').summernote("insertNode", image[0]);
},
error: function (data) {
console.log(data);
}
});
}

Ajax file upload to Parse Express JS get 500 server error for files more than 2 MB size

I am getting 500 internal server error issue when uploding file having size more than 2MB to parse.com through an ajax.The application is hosted on parse.com and written using Cloud code plus Express JS. Files (images+videos) used to be
uploaded without any problem but recently application is getting 500 error for big files. Files less than 1 MB are still uploaded successfully. Let me show the code.
1. Express JS controller to upload file (Server-Side)
Note1: Upload file is not send to url, https://api.parse.com/1/files/filename but to custom url created in
Express JS, https://example.com/file?name=filename
Note2: File data is send to custom Express JS url and the controller method "file", mention below, make use of Cloud Code Buffer Module to create parse file and send response back to client(Browser).
exports.file = function(req, res) {
var buf = new Buffer(req.body, 'base64');
var fileType = req.get("Content-Type");
var fileName = decodeURIComponent(common.trim(req.query.name));
var file = new Parse.File(fileName, {base64: buf.toString('base64')}, fileType);
file.save().then(function() {
res.json({url: file.url(), name: file.name()});
}, function(error) {
var message = "";
if(req.app.settings._gs.debug === true) {
message = error.code + ' - ' + error.message;
}
else {
message = 'Failed uploading file.';
}
res.json(message);
});
};
2. Jquery ajax method (Client-Side)
//file change handler
$('.upload').on('change', function(e) {
var files = e.target.files || e.dataTransfer.files;
uploadVideo(files[0]);
});
//Video upload handler
var uploadVideo = function(file) {
$.ajax({
async: false,
cache: false,
type: "POST",
dataType: 'json',
url: "https://example.com/file?name=fileNameWithExtension",
data: file, //file binary data
processData: false,
contentType: false,
beforeSend: function(jqXHR, settings) {
//set content type
jqXHR.setRequestHeader('Content-Type', file.type);
},
success: function(data, textStatus, jqXHR) {
//success callback
},
error: function(jqXHR, textStatus, exception) {
//error callback
}
});
}
Code working absolutely fine with file less than 1 MB but more than 1MB size gives 500 internal server error.
I had tried to debug the problem and i found an interesting thing, which is, the control never reaches to controller method, controller does not execute " exports.file = function(req, res) {....}" but breaks before at some point and send 500 error. There is no entry in parse.com log for an error. There is no way i can find the real problem which causes the 500 code. Any idea please ?
Found out the problem. Parse.com does not allow more than 1MB of post data.

Create file from AJAX response data and force download

I need to make an AJAX call from a page, sending some JavaScript data to a PHP file, which creates a file based on that data. I then want this file to be downloaded by the user.
So is it an option, to make a force download of a file created by PHP (specifically PHPExcel in my case) via an AJAX request?
The code shown below does not yet send any JavaScript data, but does generate a file.
This is my PHP script, which creates a file using PHPExcel:
public function renderTasksToExcel($tasksData){
$objPHPExcel = new PHPExcel();
// Set properties
$objPHPExcel->getProperties()->setCreator("TRW");
// ...
// Add some data
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Hello');
// ...
// Rename sheet
$objPHPExcel->getActiveSheet()->setTitle('Simple');
// Save Excel 2007 file
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$file = '/export.' . date('Y-m-d-H-i-s').'.xlsx';
$objWriter->save($file);
// hotovo
return $this->sendResponse(new FileResponse($file));
}
And this is AJAX call:
$.ajax({
type: "POST",
url: {plink Tasks:tasksToExcel},
data: ajaxData,
success:function(data){
$('#download').html(data);
}
})
same with mine. but i already solve this problem,try this:
use this in your php:
$objWriter->save('export/FileName.xls');
and use this in your ajax call:
$.ajax({
type: "POST",
url: {plink Tasks:tasksToExcel},
data: ajaxData,
success:function(data){
$('#download').html(data);
var zz=document.createElement('a');
var data_type = 'data:application/vnd.ms-excel';
zz.href ='htp://localhost/bengkel/backend/export/FileName.xls';
zz.download='FileName'+'.xls';
zz.click();
}
})
simple concept,ajax cant download. then,save *xls file,and then download that file with JS.
sorry im junior programmer and my bad english..
hope this help you,good luck :)

RecorderJS uploading recorded blob via AJAX

I'm using Matt Diamond's recorder.js to navigate the HTML5 audio API, and feel this question probably has an apparent answer, but i'm unable to find any specific documentation.
Question: After recording a wav file, how can I send that wav to the server via ajax? Any suggestions???
If you have the blob you'll need to turn it into a url and run the url through an ajax call.
// might be nice to set up a boolean somewhere if you have a handler object
object = new Object();
object.sendToServer = true;
// You can create a callback and set it in the config object.
var config = {
callback : myCallback
}
// in the callback, send the blob to the server if you set the property to true
function myCallback(blob){
if( object.sendToServer ){
// create an object url
// Matt actually uses this line when he creates Recorder.forceDownload()
var url = (window.URL || window.webkitURL).createObjectURL(blob);
// create a new request and send it via the objectUrl
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "blob";
request.onload = function(){
// send the blob somewhere else or handle it here
// use request.response
}
request.send();
}
}
// very important! run the following exportWAV method to trigger the callback
rec.exportWAV();
Let me know if this works.. haven't tested it but it should work. Cheers!
#jeff Skee's answer really helped but I couldn't grasps it at first, so i made something simpler with this little javascript function.
Function parameters
#blob : Blob file to send to server
#url : server side code url e.g. upload.php
#name : File index to reference at the server side file array
jQuery ajax function
function sendToServer(blob,url,name='audio'){
var formData = new FormData();
formData.append(name,blob);
$.ajax({
url:url,
type:'post',
data: formData,
contentType:false,
processData:false,
cache:false,
success: function(data){
console.log(data);
}
}); }
Server side code (upload.php)
$input = $_FILES['audio']['tmp_name'];
$output = time().'.wav';
if(move_uploaded_file($input, $output))
exit('Audio file Uploaded');
/*Display the file array if upload failed*/
exit(print_r($_FILES));
I also spent many hours trying to achieve what you are trying to do here. I was able to successfully upload the audio blob data only after implementing a FileReader and calling readAsDataURL() to convert the blob to a data: URL representing the file's data (check out MDN FileReader). Also you must POST, not GET the FormData. Here's a scoped snippet of my working code. Enjoy!
function uploadAudioFromBlob(assetID, blob)
{
var reader = new FileReader();
// this is triggered once the blob is read and readAsDataURL returns
reader.onload = function (event)
{
var formData = new FormData();
formData.append('assetID', assetID);
formData.append('audio', event.target.result);
$.ajax({
type: 'POST'
, url: 'MyMvcController/MyUploadAudioMethod'
, data: formData
, processData: false
, contentType: false
, dataType: 'json'
, cache: false
, success: function (json)
{
if (json.Success)
{
// do successful audio upload stuff
}
else
{
// handle audio upload failure reported
// back from server (I have a json.Error.Msg)
}
}
, error: function (jqXHR, textStatus, errorThrown)
{
alert('Error! '+ textStatus + ' - ' + errorThrown + '\n\n' + jqXHR.responseText);
// handle audio upload failure
}
});
}
reader.readAsDataURL(blob);
}
Both solutions above use jQuery and $.ajax()
Here's a native XMLHttpRequest solution. Just run this code wherever you have access to the blob element:
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("audio_data",blob, "filename");
xhr.open("POST","upload.php",true);
xhr.send(fd);
Server-side, upload.php is as simple as:
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = $_FILES['audio_data']['name'].".wav"; //letting the client control the filename is a rather bad idea
//move the file from temp name to local folder using $output name
move_uploaded_file($input, $output)
source | live demo

Resources