Blueimp multiple chunk upload with form data - javascript

I want to chunk upload multiple files with form data. Save form data to database and image to a perticualr folder.
I'm using blueimp upload here is my Fiddle.
The JavaScript codde i'm using
$(function () {
$('#fileupload').fileupload({
maxChunkSize: 5000,
previewMaxHeight: 210,
previewMaxWidth: 210,
url: '/echo/json'
});
$('#fileupload').bind('fileuploadsubmit', function (e, data) {
var inputs = data.context.find(':input');
if (inputs.filter('[required][value=""]').first().focus().length) {
return false;
}
data.formData = inputs.serializeArray();
});
});
Chunk upload is working fine, but if I save data to database multiple entries are created.
The number of entries created in database is equal to number chunk uploaded.
The PHP code that i'm using is ( taking help of blueimp PHP class https://github.com/blueimp/jQuery-File-Upload/blob/master/server/php/UploadHandler.php )
public function postUpload()
{
$upload_handler = new UploadHandler(); // Blueimp class
$this->file->create(Input::all()); // This code is executed multiple times
}
So main trouble is $this->file->create(Input::all()); code is execute multiple times as the number of chunks uploaded, where as I want it to be executed once when file is uploaded successfully.
Also want to name file of the file that is uploaded to save it to database.

You need to first upload all the chunks and on the last chunk execute your own logic. So here is how you can do this.
You should first extract the range info from http header Content-Range. You can look at this answer for how to. Then you should check if that's the last chunk.
And if it is the last chunk you simly execute your business logic there.
Even if it is a late answer, it might help someone.

Related

Save Multiple Canvas Created Images to Server via AJAX with JavaScript

I am working on a form set for a client. In a nutshell:
The forms are filled out by my client’s customers by selecting different options on each form.
Each form can have multiple instances, depending on the customer.
At the end of the process, the customer can opt to either sign one or all the forms digitally or decline to sign them digitally and at the end of the process the forms are printed out and signed manually.
To accomplish this, I’ve created a signature plugin written in jQuery. Once the customer fills out the forms, they are presented each form separately. To sign the form digitally they simply tap (click) the signature block, a dialog with a canvas element appears, they sign the form and save it, the signature appears in the form, and they move on to the next form.
Here is the portion of the code that stores the completed signature and adds the image to the form:
$.sig = {
signatures: {},
}
function signatureSave() {
var canvas = document.getElementById("sigcanvas"),
dataURL = canvas.toDataURL("image/png");
document.getElementById($.sig.target).src = dataURL;
$.sig.signatures[$.sig.target].url = dataURL;
$.sig.signatures[$.sig.target].hasSignature = true;
};
The function is only called if the signature is saved, if there is no signature, the $.sig.signatures[$.sig.target].hasSignature remains false and the system skips the object.
This all works as intended, almost.
My problem lies in the process used to save the form information. If the customer does not sign any forms digitally the form information is simply saved and the forms are printed out, no need to save any signatures.
If the customer signs at least one form, though, the signatures must be sent to the server using the FormData() object.
I’ve used the FormData object in other projects for the client successfully, but only when the customer uploads one or more images to the browser using the input file element. It’s a pretty simple process because the resulting images have a img.file property that I send to the server.
Not so with a canvas object. All I get is the .src property, an any attempt to use anything from the resulting .png image that is created in the function above results in either a “cannot use a blob” or some other error.
Now I know if I have a single image, I can send it using AJAX with the following:
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
})
Problem is that I am sending from one to x number of signatures.
Edit: I forgot to add this in. This is the function that is supposed to create the FormData object used to send the signatures to the server (and where my problem lies):
function getUploadData() {
var upl = new FormData();
$.each($.sig.signatures, function (e, u) {
if (u.hasSignature == true && u.url != null) {
var im = new Image();
im.src = u.url;
upl.append(u.target, im, u.target + '.png');
}
})
return upl;
}
I've tried all the tricks and nothing is working. The var im = new Image(); as well as the following line are just my latest ill fated attempt.
Picture perfect would be the ability to save the image information in the $.sig.signatures object so I can simply loop through any signatures that are signed, add them as elements of the FormData object, and then send the FormData object as the data for the AJAX call. As stated before, I use this method in other projects and works fine.
Does anyone know a way to do this?
Please note:
The server-side AJAX processor functions correctly.
The signature process works correctly (customer signs canvas, signature is displayed, signature information is stored).
All I need is how to send multiple images created using the canvas element in a FormData object to the server.
I know the answer is staring me right in the face, but I am just not getting it. Any hints or suggestions would be greatly appreciated!
Edit: Just a note. I've searched the entire afternoon for this and have found entries that either deal with sending multiple files using FormData and AJAX - but the files are uploaded to the browser (not created using Canvas), or single files sent to the server that are created using Canvas, but nothing about sending multiple files sent using FormData and AJAX that are created using Canvas. Oje!
As stated, the answer was staring me in the face, but I didn't see it because was looking behind the wrong door. FormData has nothing to do with it (Homer Dope Slap!).
Since I already have the data stored in $.sig.signature for each signature, I just need to send the information to the server as the data in the AJAX function. I updated my function above as shown:
function getUploadData() {
var upl = {};
$.each($.sig.signatures, function (e, u) {
if (u.hasSignature == true && u.url != null) {
upl[e] = u.url;
}
})
return upl;
}
Since the form information is sent as JSON I just add the signature info to the object that contains the form information, JSON.stringify it and send it on its way. This should work because the information retrieved above are strings.
Server side will look something like this:
$info = json_decode( $_POST['info'] );
// Various validation routines and checks
foreach( $info->signatures as $sig=>$data ):
$data = str_replace('data:image/png;base64,', '', $data);
$data = str_replace(' ', '+', $data);
$img = base64_decode($data);
// Do some processing, file naming, database saving and other general dodads
$success = file_put_contents( $file, $img );
endforeach;
The above function is still concept, I am reworking some of the code but this should work.
Credit is given to this post for opening my eyes:
post sending base64 image with ajaxpost sending base64 image with ajax
So question answered and yeah, I deserve a dope slap, but all comes out right in the end.
CAVEAT: Works like a charm.

How to maintain state of file field in ExtJs

I have file upload control using which i uploading image file on server. In this operation I am going submitting form two times. Issue is that after submitting form first time file upload filed giving value null at second submit.
lets see my code as below.
this.userPhoto = new Ext.create('Ext.form.field.File', {
xtype: 'filefield',
padding: '5 5 5',
cls: 'p-photo-upload',
emptyText: 'Photo',
buttonOnly: true,
fieldLabel: fleet.Language.get('_FLEET_USER_USERDETAIL_PHOTO_'),
name: 'photo',
labelWidth: 200,
width: '26%',
msgTarget: 'under',
listeners: {
scope: this,
change: function (t, value) {
var data = {};
data.userPhoto = t.value;
data.imageType = 'userPhoto';
var postdata = Ext.encode(data);
postdata = Base64.encode(postdata);
this.UserDetailform.getForm().submit({
scope: this,
url: FLEET_PROXY_URL + 'index.php?c=user&a=uploadphoto',
params: { postData: postdata },
success: function (form, action) {
this.setLoading(false);
var b = Ext.decode(action.response.responseText);
console.log(b);
if (b && b.data && b.success === "S") {
var img = '<img src="' + FLEET_SERVER_URL + 'images/temporary/' + b.data.photoname + '" />';
this.userimage.setValue(img);
} else {
this.UserDetailform.getForm().findField('photo').markInvalid(fleet.Language.get(b.errors[0].photo));
}
}
});
}
}
});
this.userPhoto is the object of Ext.form.field.File, after the browse file I am uploading it by submitting form (you can see code in listeners change event of this.userPhoto) this form submit method I used for save temporary file at server side. Next I am going to save same file and other user details on second submit, but on second submit I got nothing from This.userPhoto.
Please see below screen shot you can get better idea about this.
in image you can see there is BROWSE and SAVE button
first form submit method done on after select the file and second on SAVE button click.
The sencha file upload field cannot retain its state because the underlying HTML field is a file upload field which is not intended to keep its state across form submission.
There are so many drawbacks when using file upload fields in your forms, that I have switched to a different approach for image upload.
In my app, where image uploads are required, the file upload field is not connected to the actual form, but submitted on its own, and the backend then returns a data URL of the image to the client. The client then usually puts this data URL into a hiddenfield in the form. An xtype:'image', bound to the hidden field, displays the content of the hidden field (= the image) in the frontend.
That way,
the data URL can be more easily handled in a database because it is a "readable" string, not a blob,
the data URL is loaded and saved together with all the other data in the form,
the data URL can be loaded and saved infinitely often,
I only need one backend endpoint that handles image uploads, and can work with data URLs (strings) from there on,
all forms can be submitted as JSON (a file upload field enforces standard submission, so when a file upload field is added to an existing form, I would have to throw away all backend code I already have for that endpoint).
The main drawback is that the image goes over the wire more often than with a simple file upload, but at least for me, this is a minor issue.

How to write path to files in Magento? File is not found, even when I set the absolute path

everyone!
I try to create custom application sending (to emails) form the site on Magento.
For doing it, I call post.php file in this way:
$('form#send-profile').submit(function(event) {
event.preventDefault();
var output = true,
array = $(this).serialize();
if (output) {
$.post('post.php', array, function(data) {
$('input[type="text"], textarea').val('');
});
};
});
I`ve placed post.php into the root folder (and tried it with different folders too).
But I had this result in any conditions:
POST http://vescorte.com/post.php 404 (Not Found)
Maybe Magento has some special way to set paths? Tell me please, if you know how to cope with this problem.
First of all , which version of magento do you use ?
Next, if you want to development any new function , you need create a module
try this link magento-2-module-development
In the template file in which you mentioned JS code, you can mention the Magento base URL function to get full base URL like below:
$.post('<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB); ?>post.php', array, function(data) {
$('input[type="text"], textarea').val('');
});
Still if you face issue then try to remove all the code from post.php and run with simple text to check file request complete or not.

Kendo UI multiple files upload issue

I am using a Kendo File Upload control to upload multiple files. Only few of the files are getting uploaded (especially first and last) or some random ones. Is there any solution for this ?
Index.cshtml :
<input name="files" id="files" type="file" multiple="multiple" />
JS File :
$("#files").kendoUpload
({
async: {
saveUrl: "/Controller/GetUserUploadedFiles",
removeUrl: "/Controller/Remove",
autoUpload: false,
allowmultiple: true
},
select: function (e) {
onSelect(e);
},
success: function (e) {
},
error: function (e) {
}
});
//Controller Method
[HttpPost]
public void GetUserUploadedFiles(IEnumerable<HttpPostedFileBase> files)
{
//Custom logic here
}
Also, it would be great if i can get all the files as Enumerable in one controller method call rather than having it called multiple times for multiple files.
Is there anything i am missing or doing wrong ?
Thanks,
Srini
This code will upload all the files that were selected in Kendo Upload, and then run code on each.
[HttpPost]
public void GetUserUploadedFiles()
{
Request.Content.LoadIntoBufferAsync().Wait();
var result = Task.Factory
.StartNew(() => Request.Content.ReadAsMultipartAsync().Result,
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).Result;
var contents = result.Contents;
HttpContent httpContent = contents.First();
Stream file = httpContent.ReadAsStreamAsync().Result;
if (file.CanRead)
{
// Code that will be executed on each file
}
}
You can get the filename by using:
string filename = httpContent.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
You can get the uploaded file media type by using:
string uploadedFileMediaType = httpContent.Headers.ContentType.MediaType;
IIRC, the kendo batch option will only upload the files as a collection if selected at the same time (browse, then select more than one file). Once you select additional file(s) they will be sent in another request. The only way you can force the files to be posted during the same request is to use the synchronous mode rather than async. Good luck.

Forcing Backbone to save an attribute as a file

Is there a way to use Model.set and Model.save in a way that will force Backbone to send the data to the server as a file (as if you were submitting a form with an <input type="file"> tag?
The short answer is no. The long answer is, sort of.
This doesn't really have anything to do with Backbone and instead is about being able to AJAX a file in the browser. The solution is to use the File API from HTML 5. Below is an example of how you would do that with a Backbone model.
Let's assume we have a User model and we want to save an avatar file on that model.
// Backbone Model JS
User = Backbone.Model.extend({
readAvatar : function (file, callback) {
var reader = new FileReader(); // File API object for reading a file locally
reader.onload = (function (theFile, self) {
return function (e) {
// Set the file data correctly on the Backbone model
self.set({avatar_file_name : theFile.name, avatar_data : fileEvent.target.result});
// Handle anything else you want to do after parsing the file and setting up the model.
callback();
};
})(file, this);
reader.readAsDataURL(file); // Reads file into memory Base64 encoded
}
});
// Somewhere in your view JS
this.$("input[type='file']").change(function (event) {
var file = e.originalEvent.target.files[0];
userModel.readAvatar(file, userModel.save);
});
// HTML
<form><input type="file" name="avatar"/></form>
Now on your back end you need to handle the file coming through as Base64 encoded data.
A couple of warnings:
If you need extensive browser support then this solution probably won't work for you.
Base64 encoding a file is going to increase the amount of data sent over the wire by about 30%.

Categories

Resources