1
  1. Having an HTML Form that is submittet via POST (user clicking the submit button).

  2. 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!

Tim Schmidt
  • 654
  • 6
  • 14

1 Answers1

3

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);
    }
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Works - thanks. I added example code to show the response in the browser like a normal form. – eddyparkinson Nov 30 '17 at 03:47
  • @eddyparkinson glad it helped, but I rolled back your edit: there is already a `callback` parameter that you can use if you want to display the response in browser, but that should in no way be the default behavior of this function. – Kaiido Nov 30 '17 at 03:53
  • Any idea how to make this work on ms Edge - it gives error Object doesn't support property or method 'toBlob' – eddyparkinson Nov 30 '17 at 06:37
  • 1
    @eddyparkinson use the polyfill I linked to: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill – Kaiido Nov 30 '17 at 06:51