Home > Software engineering >  How to append a file to a FormData() from an url or file on server rather than a file input
How to append a file to a FormData() from an url or file on server rather than a file input

Time:12-21

)

I'm working on a piece of code using the Stripe Connect API where the user can send a visual from an input type="file" to an ajax call via jQuery, this way:

var form_file = new FormData();
form_file.append('file', document.querySelector('input#file_to_send').files[0]);

When the user submits the form, I copy the visual in a folder on my server via PHP and keep its name in a session variable. If something is incorrect or missing in the form, the user goes back to the same page, where the visual is shown in a img element under the input type="file" one, so the user knows that their visual has been taken into consideration.

After that, I need to do send the file in an ajax call again... except that this time, the file cannot be selected from the input type="file" anymore, the only accessible source I have would be to take it's name from the img element in javascript.

Now, if I do this:

var form_file = new FormData();
form_file.append('file', $('img#visual').attr('src'));

And send this via the same ajax call :

$.ajax({
    url: 'https://uploads.stripe.com/v1/files',
    type: 'POST',
    processData: false,
    contentType: false,
    headers: {'Authorization': 'Bearer xxxxxxxxxxxxxxxxx' },
    data: form_file
}).fail(function(e) {
    console.log('fail: '   e);
}).done(function(e) {
    console.log('file uploaded: '   e.id);
});

My question, you guessed it, is: is there a way to/how should I do to send a file not from an input element as a source, but a defined path taken from an img element?

Thanks in advance for the help!! :-)

CodePudding user response:

I read your question a second time. If I understand correctly you need to send a cross-domain AJAX request to stripe.com, so you are not controlling the PHP code on the server side, right?

SHORT ANSWER:

The easiest way would be to do your form check in Javascript instead of PHP, so you won't need to go back and "lose" the selected input file.


... BUT if you really need/want to send a cross-domain file using only its URL,

then you'll need to convert Data URI to File then append to FormData :

1/ Get you image base64 value

function toDataUrl(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
            callback(reader.result);
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.responseType = 'blob';
    xhr.send();
}

2/ Convert the base64 image to Blob :

function DataURIToBlob(dataURI: string) {
    const splitDataURI = dataURI.split(',')
    const byteString = splitDataURI[0].indexOf('base64') >= 0 ? atob(splitDataURI[1]) : decodeURI(splitDataURI[1])
    const mimeString = splitDataURI[0].split(':')[1].split(';')[0]

    const ia = new Uint8Array(byteString.length)
    for (let i = 0; i < byteString.length; i  )
       ia[i] = byteString.charCodeAt(i)

    return new Blob([ia], {
       type: mimeString
    })
 }

3/ Send you Blob with FormData :

const file = DataURIToBlob(imgBase64)
const formData = new FormData();
formData.append('upload', file, 'image.jpg')

Sources :


Edit:

You could speed up phase 1 and 2 by using the Fetch API to get the image Blob directly.

(WARNING: not compatible with IE)

Source : How to get a File() or Blob() from an URL in javascript?

CodePudding user response:

Thank you @e-telier! After combining your samples of code with what's on the links you suggested, I was able to achieve what I wanted! Here is the code I ended up with:

var visual_source = 'upload/file-source.png';
var visual_ext = visual_source.split('.').pop();
var visual = await fetch(visual_source);
console.log(visual);
var visual_as_blob = await visual.blob();
console.log(visual_as_blob);
var visual_as_file = new File([visual_as_blob], 'file-name-renamed.'   visual_ext, { lastModified: new Date().getTime(), type: visual_as_blob.type });
console.log(visual_as_file);
form_file.append('file', visual_as_file);

I added a console.log() at each step of this if anyone needs this code and wants to see the result of what is happening step by step. The steps being:

  • We fetch the file from a given url (here, a file on the server in a "upload" folder)
  • We set the fetched data as a blob
  • We transform the blob as a file
  • We are then able to append() the file to the FormData() element

After that, it can be sent via ajax to the Stripe API.

Thanks again for your help!! :))

  • Related