I tried multiple approaches and followed quite a lot questions in StkOvfl, and W3 Specifications, but still no idea.
I have a form input:
<input type="file" multiple accept="image/*" id="item-image-upload" >
Then in my Javascript (prepareFormData method): [See full gist class here]:
var files = this.getFiles();
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type.match('image.*')) {
continue;
}
formData.append(this.uploadEntityName, file);
}
When I console.log(files), I get all the files all fine. But, formData is not working. I also tried adding an arbitrary item as:
formData.append("Apple", 1);
The response I get is empty. The server does repose in php as:
public function uploadImage(){
return json_encode(array_merge($_REQUEST, $_FILES));
}
I'm 99% sure now that it's your header, and that if you look in your logs, or turn on PHP Warnings you'll see Warning: Missing boundary in multipart/form-data POST data in Unknown on line 0
I copied this (and added your header line and removed the input file) from MDN and ran it on a script on my dev box that is set to shout all errors and I got that error, followed by an empty array
var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456); // number 123456 is immediately converted to a string "123456"
// JavaScript file-like object
var content = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file...
var blob = new Blob([content], { type: "text/xml"});
formData.append("somefiles[]", blob);
var request = new XMLHttpRequest();
request.open("POST", "MYDEVBOX/testpost.php");
// remove the line below and it works
request.setRequestHeader("Content-Type", "multipart/form-data");
request.responseType = "json";
request.send(formData);
Back a few minutes later after deciding to look into why. It has to do with the boundary of the multi-part data. The XHR is automatically setting the header with matching boundary when you do xhr.send(formData) (or somewhere along the way). When you set that header, the request uses that instead, wiping out the boundary and PHP doesn't know where to split the input. Here's a quick screen cap that points it out much better.
Related
This question already has answers here:
Uploading multiple files using formData()
(18 answers)
Closed 5 years ago.
What I want
People click add image button, they select an image, image is added to gallery.
They can delete images by clicking cross sign and re click add image button to add more images.
This all works, I've a reference to all File elements.
However, I can't figure out how to send the files in post request of form.
Problem the problem is that You can't create FileList out array of file, or set array of files as input.files = arrOfFiles.
Input element itself doesn't let you add more files, or remove files... it simply replaces old file with new file(s).
which is not what i want therefore i'm keep reference to file objects in js, and letting user remove images or add more.
I know i can send individual file as XHR, but I want to send them through form that already exists.
I wanted to know a way to send files through form not js, but apparently that's not possible
That's exactly what the FormData API is for: create from scratch a form's data that you will be able to upload to your server as if it were created from a <form> object, except that you can control what goes there or not.
So to append a File or a Blob in a FormData, the code is
var fd = new FormData();
fd.append(field_name, blob, file_name);
To append multiple files, you can call again fd.append, but note that backend often need to have the field_name formatted in such a way they can know multiple values are expected here.
Usually this is done by adding [] after your fieldname.
var fd = new FormData();
fd.append('files[]', blob_1, file_name_1);
fd.append('files[]', blob_2, file_name_2);
And then you can send it through an AJAX request to your server, which won't make the difference between this request and a real one made froma single <input multiple name="files[]">.
Note that in case of File, file_name is optional and will default to the File's name if not set. However, it is needed for Blobs if you don't want a random name to be set.
var file_1 = new File(['foo'], 'file1.txt',{type:'text/plain'});
var file_2 = new File(['bar'], 'file2.txt', {type:'text/plain'});
var fd = new FormData();
fd.append('files[]', file_1);
fd.append('files[]', file_2);
console.log(...fd.entries());
// and to send it to your server
var xhr = new XMLHttpRequest();
xhr.open('POST', 'your_server_url');
xhr.send(fd);
If you are just going to upload images. Consider using base64 encoding. That is what I did. Assign base64 encoded URL to stringify JSON, or whatever you wish that is easier for you.
When the data is POST-ed, do the conversion there, to get back your files for saving them. Decoding base64 will be dependent on your backend language though of which you did not mention in your question.
In JavaScript, you can use this function to load up the image in preview state like you mentioned.
function previewImage (inputId, eleId) {
if (window.FileReader) {
var oPreviewImg = null, oFReader = new window.FileReader(),
rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
oFReader.onload = function (oFREvent) {
if (!oPreviewImg) {
var newPreview = document.getElementById(eleId);
oPreviewImg = new Image();
oPreviewImg.style.width = (newPreview.offsetWidth).toString() + "px";
oPreviewImg.style.height = (newPreview.offsetHeight).toString() + "px";
if(newPreview.children.length > 0)
newPreview.replaceChild(oPreviewImg, newPreview.children[0]);
else
newPreview.appendChild(oPreviewImg);
}
oPreviewImg.src = oFREvent.target.result;
// Add Bootstrap's img-thumbnail class to the image frame
oPreviewImg.classList.add("img-thumbnail");
};
return function () {
var aFiles = document.getElementById(inputId).files;
if (aFiles.length === 0) { return; }
if (!rFilter.test(aFiles[0].type)) { alert("You must select a valid image file!"); return; }
oFReader.readAsDataURL(aFiles[0]);
}
}
if (navigator.appName === "Microsoft Internet Explorer") {
return function () {
document.getElementById(eleId).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = document.getElementById(inputId).value;
}
}
};
Then you can extract the base64 URL from the src attribute of the img element.
You may come out with your own preferred method of "cancelling" your upload by maybe destroying the img element.
Having an HTML Form that is submittet via POST (user clicking the
submit button).
Furthermore having an image that is read via Javascript of a canvas
object (getImageData()).
Question:
How to "inject" this image data into the HTML Form, so that it gets uploaded as Content-Type:multipart/form-data and can be processed via the existing PHP Frameworks Data Extraction Logic?
Example from a <input type="file" upload captured with CHrome in a POST request => it should look like this
------WebKitFormBoundaryBBAQ5B4Ax1NgxFmD
Content-Disposition: form-data; name="images"; filename="fooimage.png"
Content-Type: image/png
Problem:
I know how to uploed it in a seperate request (via ajax, seperate from the form). I know how to upload it as base64 Data an process it manually in the form.
But I do not know how to send the Image Data along the exiting Form so that it looks for the PHP Serverside Scripts exactly the same as an image that is send via <input type="file"...
Reason: Symphony (FileUpload Object) checks if a file is uploaded via the POST Form and fails if I manulally instanciate the object with the data.
So the best solution would be (in regards to a lot of other things, like testing, avoiding unnecessary logik), if the data would be passed the same as a regular form upload. How to do this?
Thanks!
You can use a FormData object to get the values of your form, and then append a blob version of your canvas into the FormData.
This blob will be seen as a file by the server.
Unfortunately, all browsers still don't support the native canvas.toBlob() method, and even worth, all implementations are not the same.
All major browsers now support the toBlob method, and you can find a polyfill on mdn for older browsers.
// the function to create and send our FormData
var send = function(form, url, canvas, filename, type, quality, callback) {
canvas.toBlob(function(blob){
var formData = form ? new FormData(form) : new FormData();
formData.append('file', blob, filename);
var xhr = new XMLHttpRequest();
xhr.onload = callback;
xhr.open('POST', url);
xhr.send(formData);
}, type, quality);
};
// How to use it //
var form = document.querySelector('form'), // the form to construct the FormData, can be null or undefined to send only the image
url = 'http://example.com/upload.php', // required, the url where we'll send it
canvas = document.querySelector('canvas'), // required, the canvas to send
filename = (new Date()).getTime() + '.jpg',// required, a filename
type = 'image/jpeg', // optional, the algorithm to encode the canvas. If omitted defaults to 'image/png'
quality = .5, // optional, if the type is set to jpeg, 0-1 parameter that sets the quality of the encoding
callback = function(e) {console.log(this.response);}; // optional, a callback once the xhr finished
send(form, url, canvas, filename, type, quality, callback);
PHP side would then be :
if ( isset( $_FILES["file"] ) ){
$dir = 'some/dir/';
$blob = file_get_contents($_FILES["file"]['tmp_name']);
file_put_contents($dir.$_FILES["file"]["name"], $blob);
}
Sorry I have a problem , I need to save a database file , but can not find how to send it via Ajax.
I 'm taking control input krajee but I spend with if an object to the controller , either make the js into an array of bytes or , if really help me or suggest somehow agradeceria
$('input[type=file]').change(function (event) {
//Here, get the size of file
var x = document.getElementById("file-1");
var txt = "";
for (var i = 0; i < x.files.length; i++) {
var file = x.files[i];
if ('size' in file) {
txt = file.size;// bites of file
}
}
//
});
and send my object to the controller , which receives a class that contains a property called Document type byte [ ]
var evidencia = {
observaciones: observacion,
extension: extension,
archivo: filename,
Documento: extDocument, //not like sending the file , this is property byte [ ]
}
$.ajax({
type: "POST",
url: 'GuardarEvidencia',
contentType: "application/json;charset=utf-8",
dataType: "json",
data: "{objEvidencia:" + JSON.stringify(evidencia) +"}",
async: false,
success: function (response) {
$('#modal-ConfAgregado').modal("show");
},
error: function (ex) {
$('#modal-Error').modal("show");
}
});
First of all you need to create three variables that hold references to the <form>, <input>, and <button> elements in your HTML markup.
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
Next you need to attach an event listener to the form’s onsubmit event.
form.onsubmit = function(event) {
event.preventDefault();
// Update button text.
uploadButton.innerHTML = 'Uploading...';
// The rest of the code will go here...
}
Inside the event listener you start by calling preventDefault() on the event object passed into the handler. This will prevent the browser from submitting the form, allowing us to handle the file upload using AJAX instead.
Next you update the innerHTML property on the uploadButton to Uploading.... This just provides a bit of feedback to the user so they know the files are uploading.
Your next job is to retrieve the FileList from the <input> element and store this in a variable. You can do this by accessing the files property.
// Get the selected files from the input.
var files = fileSelect.files;
You then create a new FormData object. This is used to construct the key/value pairs which form the data payload for the AJAX request.
// Create a new FormData object.
var formData = new FormData();
Your next job is to loop through each of the files in the files array and add them to the formData object you just created. You’ll also want to check that the user has selected the type of file you’re expecting.
// Loop through each of the selected files.
for (var i = 0; i < files.length; i++) {
var file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
// Add the file to the request.
formData.append('photos[]', file, file.name);
}
Here you’re first fetching the current file from the files array and then checking to make sure it’s an image. The file’s type property will return the file type as a string. You can therefore use the JavaScript match() method to ensure that this string matches the desired type. If the file type does not match, you skip the file by calling continue.
You then use the append method on the formData object to add this file to the data payload.
The FormData.append() method is used to handle Files, Blobs, or Strings.
// Files
formData.append(name, file, filename);
// Blobs
formData.append(name, blob, filename);
// Strings
formData.append(name, value);
Next you need to set up the XMLHttpRequest that is responsible for communicating with the server. To do this you first need to create a new XMLHttpRequest object.
// Set up the request.
var xhr = new XMLHttpRequest();
You now need to create a new connection to the server. You do this using the open method. This method takes three parameters. The HTTP method, the url that will handle the request, and a boolean value that determines whether the request should be dealt with asynchronously.
// Open the connection.
xhr.open('POST', 'handler.php', true);
Next you need to set up an event listener that will be triggered when the onload event is fired. Examining the status property of the xhr object will tell you if the request completed successfully.
// Set up a handler for when the request finishes.
xhr.onload = function () {
if (xhr.status === 200) {
// File(s) uploaded.
uploadButton.innerHTML = 'Upload';
} else {
alert('An error occurred!');
}
};
All that’s left to do now is send the request. Pass the formData object to the send method which is available on the xhr object.
// Send the Data.
xhr.send(formData);
I am trying to create form data to send within a post request (to a PHP script) with FormData.
However, the FormData object is always empty:
var oReq = new XMLHttpRequest();
var url = "http://www.test.com/test.php";
oReq.open("POST", url, true);
oReq.setRequestHeader("Content-Type","multipart/form-data");
var myFormData = new FormData();
myFormData.append("formType","PDF");
myFormData.append("pdf", pdf.output(),"thisPDF.pdf");
oReq.send(myFormData);
the 'pdf' variable is a jsPDF object (I've checked that it is a valid object and I have tried to remove that line and only have the "test" form data element sent. Yet, myFormData is always an empty object. Hoping I'm just missing something simple here.
In addition, when I try to check for the existence of the form elements in the PHP script, it shows no $_POST and no $_FILE elements at all.
ADDITIONAL INFO:
When I try this code:
var oReq = new XMLHttpRequest();
var url = "http://www.test.com/test.php";
oReq.open("POST", url, true);
oReq.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
var myFormData = new FormData();
myFormData.append("formType","PDF");
alert(JSON.stringify(myFormData));
oReq.send(myFormData);
I can then access the "formType" $_POST variable in the php script. But if I add in the File append statement to the myFormData object (and keep the same 'Content-Type', the PHP script errors returning a "not allowed access" error.
However, the $_POST is set according to isset($_POST) in both cases and with the file inserted the $_FILE variable is set according to isset($_FILE).
Remove the oReq.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); from the code. Browser automatically set multipart/form-data header, if you add file in FormData.
Quite simply, is there anyway to detect what file type a source file is?
Context:I have an HTML5 audio element and depending on what button someone clicks I want to randomly change the source of that audio element using JavaScript (please, no jQuery solutions) so that different songs will play. I have several hundred sound files, so I really don't want to have to convert them all to one file type.
I currently have a method that gets a random but always correct file name via a RNG but no way of knowing the file extension this file is (it could be .ogg, .wav, .m4a or .mp3). It just tries every possible extension until one works but am having a bit of trouble with the error handling which is causing other issues to occur so it would be really great if you could help me out here with a better solution. Thanks!
// fileInput is an HTML input element: <input type="file" id="myfileinput" multiple>
var fileInput = document.getElementById("myfileinput");
// files is a FileList object (similar to NodeList)
var files = fileInput.files;
var file;
// loop trough files
for (var i = 0; i < files.length; i++) {
// get item
file = files.item(i);
//or
file = files[i];
alert(file.type);
}
developer.mozilla link
You can use a mixture of the new XMLHttpRequest Level 2 API and File API to check the file type of a server resource.
For example, to get the type of an image:
url = '/favicon.ico';
xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var file = this.response;
alert(file.type);
}
};
xhr.send();
JSFIDDLE demo