I have a blob data in this structure:
Blob {type: "audio/wav", size: 655404, slice: function}
size: 655404
type: "audio/wav"
__proto__: Blob
It's actually sound data recorded using the recent Chrome getUerMedia() and Recorder.js
How can I upload this blob to the server using jquery's post method? I've tried this without any luck:
$.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob },
function(responseText) {
console.log(responseText);
});
You can use the FormData API.
If you're using jquery.ajax, you need to set processData: false and contentType: false.
var fd = new FormData();
fd.append('fname', 'test.wav');
fd.append('data', soundBlob);
$.ajax({
type: 'POST',
url: '/upload.php',
data: fd,
processData: false,
contentType: false
}).done(function(data) {
console.log(data);
});
2019 Update
This updates the answers with the latest Fetch API and doesn't need jQuery.
Disclaimer: doesn't work on IE, Opera Mini and older browsers. See caniuse.
Basic Fetch
It could be as simple as:
fetch(`https://example.com/upload.php`, {method:"POST", body:blobData})
.then(response => console.log(response.text()))
Fetch with Error Handling
After adding error handling, it could look like:
fetch(`https://example.com/upload.php`, {method:"POST", body:blobData})
.then(response => {
if (response.ok) return response;
else throw Error(`Server returned ${response.status}: ${response.statusText}`)
})
.then(response => console.log(response.text()))
.catch(err => {
alert(err);
});
PHP Code
This is the server-side code in upload.php.
<?php
// gets entire POST body
$data = file_get_contents('php://input');
// write the data out to the file
$fp = fopen("path/to/file", "wb");
fwrite($fp, $data);
fclose($fp);
?>
You actually don't have to use FormData to send a Blob to the server from JavaScript (and a File is also a Blob).
jQuery example:
var file = $('#fileInput').get(0).files.item(0); // instance of File
$.ajax({
type: 'POST',
url: 'upload.php',
data: file,
contentType: 'application/my-binary-type', // set accordingly
processData: false
});
Vanilla JavaScript example:
var file = $('#fileInput').get(0).files.item(0); // instance of File
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload.php', true);
xhr.onload = function(e) { ... };
xhr.send(file);
Granted, if you are replacing a traditional HTML multipart form with an "AJAX" implementation (that is, your back-end consumes multipart form data), you want to use the FormData object as described in another answer.
Source: New Tricks in XMLHttpRequest2 | HTML5 Rocks
I could not get the above example to work with blobs and I wanted to know what exactly is in upload.php. So here you go:
(tested only in Chrome 28.0.1500.95)
// javascript function that uploads a blob to upload.php
function uploadBlob(){
// create a blob here for testing
var blob = new Blob(["i am a blob"]);
//var blob = yourAudioBlobCapturedFromWebAudioAPI;// for example
var reader = new FileReader();
// this function is triggered once a call to readAsDataURL returns
reader.onload = function(event){
var fd = new FormData();
fd.append('fname', 'test.txt');
fd.append('data', event.target.result);
$.ajax({
type: 'POST',
url: 'upload.php',
data: fd,
processData: false,
contentType: false
}).done(function(data) {
// print the output from the upload.php script
console.log(data);
});
};
// trigger the read from the reader...
reader.readAsDataURL(blob);
}
The contents of upload.php:
<?
// pull the raw binary data from the POST array
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
// decode it
$decodedData = base64_decode($data);
// print out the raw data,
echo ($decodedData);
$filename = "test.txt";
// write the data out to the file
$fp = fopen($filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?>
I was able to get #yeeking example to work by not using FormData but using javascript object to transfer the blob. Works with a sound blob created using recorder.js. Tested in Chrome version 32.0.1700.107
function uploadAudio( blob ) {
var reader = new FileReader();
reader.onload = function(event){
var fd = {};
fd["fname"] = "test.wav";
fd["data"] = event.target.result;
$.ajax({
type: 'POST',
url: 'upload.php',
data: fd,
dataType: 'text'
}).done(function(data) {
console.log(data);
});
};
reader.readAsDataURL(blob);
}
Contents of upload.php
<?
// pull the raw binary data from the POST array
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
// decode it
$decodedData = base64_decode($data);
// print out the raw data,
$filename = $_POST['fname'];
echo $filename;
// write the data out to the file
$fp = fopen($filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?>
I tried all the solutions above and in addition, those in related answers as well. Solutions including but not limited to passing the blob manually to a HTMLInputElement's file property, calling all the readAs* methods on FileReader, using a File instance as second argument for a FormData.append call, trying to get the blob data as a string by getting the values at URL.createObjectURL(myBlob) which turned out nasty and crashed my machine.
Now, if you happen to attempt those or more and still find you're unable to upload your blob, it could mean the problem is server-side. In my case, my blob exceeded the http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize and post_max_size limit in PHP.INI so the file was leaving the front end form but getting rejected by the server. You could either increase this value directly in PHP.INI or via .htaccess
For some reason, when I don't use Ajax, the image file in the form being processed comes through just fine, but not when using the Ajax script below.
Can't figure out why...
Note: Not all form fields are image files (there are some text fields).
jQuery.ajax({
method: 'POST',
url: 'actions/listings-add.php',
data: $('#form').serialize(),
dataType:'json',
success: function(msg){
if(parseInt(msg.status)==1)
{
window.location=msg.txt;
}
else if(parseInt(msg.status)==0)
{
error(1,msg.txt);
}
}
});
JSON does not work with "file" inputs, because they need to be transfered with multipart/form-data.
To upload files using AJAX, you can either use FormData to also transfer the file input or if you have a normal rest api that follows a standard endpoint use javascript to base64 encode the image into a string and then transfer it using your ajax request.
To convert the image, you have to use the browsers file api:
// Convert file to base64 string
export const fileToBase64 = (filename, filepath) => {
return new Promise(resolve => {
var file = new File([filename], filepath);
var reader = new FileReader();
// Read file content on file loaded event
reader.onload = function(event) {
resolve(event.target.result);
};
// Convert data to base64
reader.readAsDataURL(file);
});
};
// Example call:
fileToBase64("test.pdf", "../files/test.pdf").then(result = {
console.log(result);
// ##### PUT YOUR AJAX CALL HERE
});
I'm using keditor for my document. My problem here is that the images are generated as blob and I have no way of knowing where they are being stored thus when converting the file to another format the images are lost.
Sample image tag with blob:
<img src="blob:http://localhost/7b0e82ab-445b-4866-b8b5-09b4881a0544" width="100%" height="" style="display: inline-block;">
I was hoping I can find a way to convert this to blob either using PHP or JS.
I also found this post but no solution was provided:
JS convert blob url to Base64 file
Somewhere in your code you have a reference to the blob that you had to get your blob url, take it an pass it to the FileReader like so:
// Just an example file
var blob = new Blob(['abc'], {type: 'text/plain'})
var reader = new FileReader()
reader.onload = function() {
var base64data = reader.result
console.log(base64data)
}
reader.readAsDataURL(blob)
Using AJAX:
$.ajax({
method: "GET",
url: "blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc",
dataType: "binary",
}).done(function( data ) {
var reader = new FileReader();
reader.readAsDataURL(data);
reader.onloadend = function() {
var base64data = reader.result;
console.log(base64data)
}
});
Have not tested this, but should point you in the right direction though.
I generate a pdf with text and images using javascript jsPDF library. Then I want to send the file to server in order to send an email with it. The problem is that the file that arrives on server is corrupted and can't be opened or I can't see the images on the pdf.
My code:
var pdf = btoa(doc.output());
- this gives an error: Uncaught InvalidCharacterError: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
var pdf = btoa(encodeURIComponent(doc.output()));
var data = new FormData();
data.append("data" , pdf);
var xhr = new XMLHttpRequest();
xhr.open( 'post', '/url', true );
xhr.send(data);
I also tried other things like:
var pdf = btoa(encodeURIComponent(doc.output('blob'))); - the file can't be opened
var pdf = btoa(doc.output('blob')); - the file can't be opened
var pdf = btoa(unescape(encodeURIComponent(doc.output()))); - the file will open but the images are some grey lines
PS: I am using Laravel 5. Server code:
$data = base64_decode($_POST['data']);
$fname = "test.pdf";
$file = fopen("pdf/" .$fname, 'w');
fwrite($file, $data);
fclose($file);
SOLUTION:
js code:
var blob = doc.output('blob');
var fd = new FormData();
fd.append('data', blob);
$.ajax({
type: 'POST',
url: '/url',
data: fd,
processData: false,
contentType: false
}).done(function(data) {
console.log(data);
});
server code:
if(!empty($_FILES['data'])){
move_uploaded_file(
$_FILES['data']['tmp_name'],
public_path() . '/test.pdf'
);
return "Pdf was successfully saved.";
} else {
return "No Data Sent";
}
btoa is messed up with the ascii byte range... javascript can't hold all character. That's the reason for why you shouldn't use FileReader's readAsBinaryString either... Handle binary the right way, not as string or ~3x larger base64 string, but as a blob, ArrayBuffer or a typed array and it will turn out fine
var blob = doc.output('blob')
xhr.send(blob)
I am receiving an error trying to upload large than 50kB file via jQuery Ajax POST request.
I am sending the request to OData service ( ASP.Net MVC application)
The error I am receiving in browser console is " 413 Request Entity Too Large "
Below is the code I am using to upload
var fileData =
{
fileBinaryData: encodedData //file data in encoded format ( 64 bit),
Description: "my first file"
};
fileData = JSON.stringify(fileData);
$.ajax({
url: // some odata url ,
type: "POST",
data: fileData,
success: function (res) {
// do something
},
contentType: "application/json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
});
a) Is code above the correct way to upload file data via jQuery ajax to a service
b) I have modified my web.config to accept large requests.
c) I do not want to use plugin's like uploadify etc
EDIT 1:
I used javascripts' FileReader() to read the file.
var reader = new FileReader();
//then applied reader.onloadend method etc
if (file.webkitSlice) {
var blob = file.slice(start, stop + 1);
} else if (file.mozSlice) {
var blob = file.mozSlice(start, stop + 1);
}
reader.readAsBinaryString(blob);
Finally settled with using jQuery fileUpload plugin