I'm in need of some javascript guru. I have this code:
handleImage(new File([blob], blob.name, {type: blob.type})).done(/* something */)
and
handleImage = function (image) {
// create some fake form data
var formData = new FormData();
formData.append("attachment", image);
formData.append("auto", true);
formData.append("_csrf", "xxxxxxxxx");
// post to the server.
return $.ajax({
url: "/some/url",
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
error: function () {
console.log("error");
}
});
This works fine with Chrome and Firefox, but when using Safari (10.1.1), the server (java / spring mvc) receive in the MultipartHttpServletRequest an empty file for "attachment". So it seems to me that new File([blob], blob.name, {type: blob.type}) is somehow failing.
Any idea of what's wrong here?
This is probably a bug in safari's young implementation.
But why do you even convert it to a File object ?
A File object is a Blob, the only difference being that it has a name and a lastModified properties. But since you already seem to extend your blob, it leaves only this lastModifiedproperty that you could add too anyway.
The only API I can think of, where it makes a difference if your object is a Blob or a File is FormData.append method ; where if you pass a File object, it will be able to set the filename automatically. But this method has a third parameter, allowing you to set this filename.
So if you change your code to include formData.append("attachment", image, image.name); and call it with handleImage(blob) directly, it will do exactly the same request as the one you're doing, except that it will work on Safari and every other browser that don't support the File constructor (looking at you IE).
Related
Issue : While uploading large image files i recognized that while uploading on my AWS server having 1gb memory uses it's full capacity, it goes upto 932 mb usage which causes crash to the process. I was saving that image in the form of DataURI and then I read somewhere that saving it in the form of blob can solve my problem. So i want to append that blob to formData and send to server and this is the reason i come up with this question. However if any else suggestion regarding the same problem to save image more efficient way when memory is concerned, will be appreciated.
Motive
I want to send an image to the server side as in the form of a blob.
What I have done
I am currently having a dataURI which I have converted into a blob. Further, i append that blob to formData and try to send it to server side/php using ajax.
JAVASCRIPT:
function convertURIToImageData(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
//
const dataURIconverter = () =>{
let img;
var image = new Image();
image.crossOrigin = 'anonymous'; // cross domain
// create an empty canvas element
var canvas = document.createElement("canvas"),
canvasContext = canvas.getContext("2d");
image.onload = function () {
//Set canvas size is same as the picture
canvas.width = image.width;
canvas.height = image.height;
// draw image into canvas element
canvasContext.drawImage(image, 0, 0, image.width, image.height);
// get canvas contents as a data URL (returns png format by default)
var dataURL = canvas.toDataURL();
// console.log(dataURL)
let blob = convertURIToImageData(dataURL)
console.log(blob)
var formData = new FormData();
formData.append('blobImage',blob)
$.ajax({
type: 'POST',
url: 'check.php',
data: formData,
processData: false
}).done(function(data) {
console.log(data);
})
}
image.src = "https://static.pexels.com/photos/248797/pexels-photo-248797.jpeg"
}
dataURIconverter()
PHP
<?php
var_dump($_POST['blobImage'])
var_dump($_POST);
//var_dump($_FILES['image']);
//$name = $_FILES['image']['tmp_name'];
//echo $name;
//echo $_FILES['image']['tmp_name'];
//$status = move_uploaded_file($name, $_FILES['image']['name']);
//echo 'successfully stored at '.$_SERVER['HTTP_HOST'];
?>
Error
I am receiving null as in console and i also checked the headers where i see formData with the name
As you can see, $_POST showing the blob but $_POST['blobImage'] is showing null.
Solution I require:
i am not that quick to php so i am not sure if i am sending the blob in the right way or receiving it.
I have provided my all possible efforts i have taken to achieve my motive.
Thanks to the community for help.
Add the following three properties on your jQuery Ajax call , they are required for blobs :
cache: false,
contentType: false,
processData: false
Then do not use formData in the data property of your Ajax Call , you simply need to add your created blob.
Also add a small rendering callback (apart from the console.log you already use) to print the Image. Your AJAX call gets like this :
$.ajax({
type: 'POST',
url: 'check.php',
data: blob,
cache: false,
contentType: false,
processData: false
}).done(function(data) {
document.write("<img src='"+data+"'></img>");
})
Change your PHP code to the following :
<?php
$res = file_get_contents("php://input");
echo "data:image/jpg;base64,".base64_encode($res);
?>
As far as the "php://input" use is concerned. It returns all the raw data that come after the headers of your request and it does not care what type they are which is pretty handy in most cases. Whereas $_POST will only wrap the data that have been passed with the following Content-Types :
application/x-www-form-urlencoded
multipart/form-data
If you really want to use FormData then you can change the request to the following :
$.ajax({
type: 'POST',
url: 'check.php',
data: formData,
cache: false,
contentType: false,
processData: false
}).done(function(data) {
console.log(data);
})
And you should also change your PHP file to get the $_FILE. Sending data this way , the Content-Type of the Request will be "multipart/form-data" which will have blobs , images and generally files on the $_FILES and the rest on the $_POST so the "php://input" will not be helpful.
<?php
var_dump($_FILES);
?>
Also keep in mind that when uploading blobs this way , they will get a random name , if you are not going to be generating filenames on the Server-Side (which you probably should in most cases) and want a specific name designated by the uploader , then you can pass it along with the FormData like :
formData.append('blobImage',blob, "MyBloBName");
If you set contentType: false in your jQuery Ajax call , you can still use the same code with formData and then access the file on the server through $_FILES['blobImage']
The problem is that $_REQUEST, and therefore $_GET and $_POST objects have a limitation to the number of characters available to them.
post_max_size
in PHP.ini controls the maximum size of post.
Browsers and their implementations of $_GET control the limit of a $_GET request. As it appears in their URL bar. For example IE9's limit is 2000 characters so if your blob ends up as anything more than 2000 characters in the $_GET Request. The general consensus is that $_GET requests should be much less than 255 bytes. And if you approach this limit be careful because older browsers and protocols are completely unprepared for this.
I am a little new when it comes to JSON and Javascript , so please excuse me if if this is a stupid question, but I have run into a problem that is starting to drive me insane.
On a webpage I am including two scripts; jQuery and a file called "scripts2.js". In the same directory as scripts2.js, I have a JSON file; "settings.json". From within my "scripts2.js" file I am running he following code inside of a function.
var settingsPath = settings.json;
jQuery.getJSON(settingsPath, function (data){
jQuery.each(data, function(index){
console.log("!"+data[index].name);
/*unrelated other stuff */
});
});
Previously the settings.json file looked like this
[
{"name":"Standard Black"},
{"name":"Gold"},
{"name":"Silver"}
]
So naturally when I looked in the Chrome Dev Console the log would print out
!Standard Black
!Gold
!Silver
However, when testing what would happen upon editing my settings.json file I changed "name":"Gold" to "name":"Test".
[
{"name":"Standard Black"},
{"name":"Test"},
{"name":"Silver"}
]
After the json updates I tried refreshing the page but my console log is still printing out
!Standard Black
!Gold
!Silver
...
I am at a loss. I have no idea why the data being retrieved with jQuery.getJSON() is sending the data of my old settings.json even after the changes has been saved. I have perused my .php file (which is generating the HTML) , as well as my included javascript and there is no other mention of another json file or any sort of clone of my json file in any related directory.
I really have no idea what is going on and I am starting to go insane. Does anyone have an idea of what the issue might be?
I dont know if it matters but I am running a XAMPP stack on my localhost. All files (index.php, scripts2.js, and settings.json) are in a directory located inside XAMPP's htdocs folder.
EDIT: Thank you all for the speedy and thorough answers, many of you answered the question I was a bout to ask next. I really appreciate it!
This is because the browser is caching the file from your first request. Simply clear the cache and run it again and the new data will be retrieved.
UPDATE:
To prevent the browser from caching this file, change your AJAX settings like so:
jQuery.ajaxSetup({ cache: false });
Before you make the getJSON call
Try clearing web cache and restart local servers if you have not already
When using jQuery.ajax() instead of the shorthand method, you can disable caching like this:
jQuery.ajax(settingsPath, {cache: false})
jQuery will append a timestamp parameter to your request URL which changes with every request and therefore keeps the browser from caching the response.
To force the browser to get a new version each time you can use cache: false in jQuery.ajax()
$.ajax({
dataType: "json",
url: settingsPath,
cache: false,
success: function (data){
$.each(data, function(index){
console.log("!"+data[index].name);
});
}
});
Pass additional parameter to your requested url which value will change with every request.So,your browser will consider it as new request every time and will not cache the data.
var random = Math.round(new Date().getTime())
var settingsPath = 'settings.json&time=' + random;
jQuery.getJSON(settingsPath, function(data) {
});
});
You can use any algoritham that generate random new value everytime for random for every request.
OR
you can have same things with jQuery#Ajax method
jQuery.getJSON is a shorthand Ajax function, which is equivalent to:
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
So, set the optional parameter cache to false (this value by default is always true):
$.ajax({
dataType: "json",
url: url,
data: data,
cache: false, // If set to false, it will force requested pages not to be cached by the browser
success: success
});
Therefore, your getJson becomes:
var settingsPath = settings.json;
jQuery.ajax({
dataType: "json",
url: settingsPath,
data: data,
cache: false,
success: function(data) {
jQuery.each(data, function (index) {
console.log("!" + data[index].name);
/*unrelated other stuff */
});
}
});
I'm trying to make a ajax request to upload a image. My problem is when I create the FormData. My console is saying "dataForm is not a constructor".
How can I solve this ?
here is my script
$("#new-broadcast-image-static").on("change", function(formData) {
var formData = new formData();
// line that console point the error //
var file = $("#new-broadcast-image-static")[0].files[0];
formData.set("image", file);
$.ajax({
url: apiUrl + "image/upload",
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
xhrFields: {
withCredentials: true
},
success: function(data) {
hashNewBroadcastImage = data.data.identifier;
$("#hash-new-broadcast-image-static").val(hashNewBroadcastImage);
}
});
});
Capitalize it: var formData = new FormData();
But what are you trying to acomplish anyways? You are reasigning a variable you are getting as parameter:
$("#new-broadcast-image-static").on("change", function(formData) {
var formData = new formData();
You probably want to change it to something like
$("#new-broadcast-image-static").on("change", function(e) {
var formData = new FormData();
Not totally sure about it, but I think you have a capital letter mistake, you've write formData() instead of FormData()
The correct way:
var formData = new FormData();
Please Check this Possibility it will definitely solve your problem
Anywhere in your JS Code if you are assigning a value to FormData like below
FormData={"PersonID":1,"PersonName":"Test"};
and if you use like this
var a = new FormData();
Then it will throw an error like "FormData is not a constructor as it is already declared as an Object".
as my experience sometime because of in javascript function is debugger mode.
I tried all of the solutions for this and none worked. After hours of pulling my hair out, I discovered it was because I had a filed named FormData, which was a partial Vue Pinia State. I changed the name of that file to formData and it worked. So if you run into this problem and can't solve it and you have FormData used as a variable or file name anywhere in your project - change it and see if that fixes it.
I have the following data both in my js file or as a param in rails. Togther there is an image that is to be sent to server, what I want to achieve is to crop the image based on the data such as below. I am not allowed to use gems :) just using ruby/js code if I can manipulate the image already in js side. I am using cropper js which generated the output to me. What should I do to achieve cropping ?
{"x":552.697358490566,"y":-72.49509433962258,"width":696.9599999999999,"height":696.9599999999999,"rotate":0,"scaleX":1,"scaleY":1}
Check out the fiddle: Link
This is the code you should be using, since your JSON is already formatted the same way Cropper takes its input:
//get the data from your rails framework and save it in a variable, below I just pasted the same data you put in your question
var data = {"x":552.697358490566,"y":-72.49509433962258,"width":696.9599999999999,"height":696.9599999999999,"rotate":0,"scaleX":1,"scaleY":1};
//remember to change my-picture to the id of your img
$('#my-picture').cropper('setData', data);
//also make sure to bind this to your own button
$('#crop-button').click(function(e){
//this will transform the image into a blob, so you can submit it in form data
$(this).href = $('#my-picture').cropper("getCroppedCanvas").toBlob(function (blob) {
var formData = new FormData();
formData.append('croppedImage', blob);
//this is where you put your Rails path to upload
//it's going to be a POST, so you should know how to handle it
$.ajax('/path/to/upload', {
method: "POST",
data: formData,
processData: false,
contentType: false,
success: function () {
console.log('Upload success');
},
error: function () {
console.log('Upload error');
}
});
});
});
I really have no prior knowledge to Blob objects in JavaScript aside from what I've read here but need to use them to convert a string of binary data into a .xls file which I then make available to the user. The catch is when I construct a blob, get the location, and open up the file to look at it, it opens up saying
The file you are trying to open is in a different format that
specified by the file extension. Verify that the file is not
corrupted and is from a trusted source before opening the file.
(I know this data is incorrect because when I submit the form normally I get the file correctly and don't have this issue)
This is done in an ajax call and the success functions parameter data is the binary data.
$("#fileForm").submit(function(){
var fileData = $("#fileInputElmt").prop("files")[0];
var data = new FormData();
data.append("upload",fileData);
var url = "process.action?" + $("#fileForm").serialize();
$.ajax({
type: "POST",
url:url,
data:data,
cache:false,
contentType:false,
processData:false,
success:function(data){
var bb = new Blob([data],
{ type: 'application/vnd.ms-excel',endings:'native'});
var bUrl = URL.createObjectURL(bb);
window.open(bUrl,"_self");
hideProgressBar();
},error:function(data){
hideProgressBar();
}
});
return false;
});
Am I doing something wrong? or is there a better way of doing this?