0

I have this simple program that saves canvas into blob file, I am trying to retrieve it in php, but I can't manage to access it.

My console.log(FormData) does show the blob file content properly.

HTML:

<form id="formId">
    <button id="click-photo" type="submit" value="submit">Click Photo</button>
    <canvas id="canvas" width="320" height="240"></canvas>
</form>

JavaScript:

form.addEventListener('submit', function(e) {

    e.preventDefault();
    
    var xhr = new XMLHttpRequest();
    var image_data_url = "";
    xhr.open('POST', 'image.php', true);
    if(xhr.readyState === XMLHttpRequest.DONE) {
        var status = xhr.status;
        if (status === 0 || (status >= 200 && status < 400)) {
            alert(xhr.reponseText);
        };
    };
    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
    image_data_url = canvas.toDataURL('image/jpeg');
    var file = dataURLtoBlob( canvas.toDataURL('image/jpeg') );;
    
    const fd = new FormData;
    fd.append('image', file);
    xhr.send(fd);
});

PHP:

<?php
    if (isset($_FILES['image'])){
        print_r ($_FILES['image']);
    };
?>

Alsakka
  • 155
  • 10
  • The problem isn't the retrieving in PHP, the problem is that you are not processing PHP's response to your XMLHttpRequest. You need to do `xhr.onreadystatechange = ...` to assign a handler that displays / logs the response. The browser does not navigate to the result of an AJAX request. –  May 12 '22 at 12:25
  • `multipart/form-data` requests need a boundary, but you did not specify one. Remove that header; based on what the FormData actually contains, browsers should be able to set the correct Content-Type header on their own. – CBroe May 12 '22 at 12:26
  • @ChrisG If you may explain more of what should be appended from the code inside ```onreadystatechange``` I am a bit new to ```Ajax``` so I am confusing things a little bit. Thanks! – Alsakka May 12 '22 at 12:32
  • May I point you to the docs: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readystatechange_event#examples –  May 12 '22 at 12:35
  • @ChrisG after appending starting from ```canvas.getContext``` now my ```formData``` is **null** outside the state. – Alsakka May 12 '22 at 12:50
  • Please edit the question to reflect your code changes. And formData being null is probably just this: https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron –  May 12 '22 at 12:53
  • @ChrisG the new edits are there now :) – Alsakka May 12 '22 at 13:00
  • Right, you completely misunderstood how onreadystatechange works. Move the code back outside where it used to be, it was fine there. Now inside the `if (status == ...` block, just do this: `alert(xhr.reponseText);`. That is whatever your PHP code sends back as response to your request. –  May 12 '22 at 13:05
  • @ChrisG fixed that, and now actually after checking my network tab, I am receiving from **php** the right respond, but it's not being echoed into the **HTML** – Alsakka May 12 '22 at 13:14
  • Like I said almost an hour ago: "The browser does not navigate to the result of an AJAX request.". If you want to display the result in your HTML somewhere you need to actually write code that does that. Something like `document.getElementById('result').innerText = xhr.reponseText;` –  May 12 '22 at 13:19
  • @ChrisG I have tried all those ways, and yet seems not to be working :) except if you are really busy, It would be nice to see a full written solution. But thanks anyway for your words – Alsakka May 12 '22 at 13:34
  • 1
    To trivially solve this problem, use `
    `. Now add a submit event listener to the form, and inside turn the canvas content into a base64 string and put the result as .value of an ``. Submitting the form will now populate the hidden input first, and your PHP code can simply read `$_POST['base64image']` and output HTML as usual. (i.e. you can get rid of all the xhr code)
    –  May 12 '22 at 13:35
  • Also, regarding my previous comment, you obviously need a `
    ` for that to work.
    –  May 12 '22 at 13:42
  • @ChrisG This solution you wrote was quite great and works now, I have implemented it, I was only trying to do so Async so the page wouldn't refresh, but I guess I will try to read more still about that first and for now use this solution. – Alsakka May 12 '22 at 14:15
  • If you don't want the page to refresh, then AJAX/xhr/fetch is the way to go, but displaying the result will require manually inserting it into the DOM in that case. That's a really basic thing to do, so if that was all that didn't work I encourage you to go back to ajax. And use fetch(). –  May 12 '22 at 14:25

1 Answers1

0

You are adding the image with a different name than the one you are trying to retrieve.

form.addEventListener('submit', function(e) {

    e.preventDefault();
    
    var xhr = new XMLHttpRequest();
    var image_data_url = "";
    xhr.open('POST', 'image.php', true);
    xhr.onreadystatechange = function ()
    {
        if(xhr.readyState === XMLHttpRequest.DONE) {
            var status = xhr.status;
            if (status === 0 || (status >= 200 && status < 400)) {
                alert(xhr.reponseText);
            };
        };
    }

    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
    image_data_url = canvas.toDataURL('image/jpeg');
    var file = dataURLtoBlob( canvas.toDataURL('image/jpeg') );;
    
    const fd = new FormData;
    fd.append('image', file);
    xhr.send(fd);
});
// ...
if (isset($_FILES['file'])){
// Up here it should be: if (isset($_FILES['image'])){
// ...
Lucas
  • 394
  • 2
  • 13
  • Tried with image still not receiving anything – Alsakka May 12 '22 at 12:46
  • I've never worked with canvas, but I think `$_FILES` is more for uploading files coming from ``. Try changing it to `$_POST['image']`. – Lucas May 12 '22 at 12:48
  • Changed both sir and yet not reacting at all – Alsakka May 12 '22 at 12:51
  • Did you see in the browser console network requests if this data is being sent normally? – Lucas May 12 '22 at 13:01
  • Actually I didn't, but now going back to the old code, I am actually able to see in my network response the right data, it's only not being echoed for the HTML for some reason! – Alsakka May 12 '22 at 13:11
  • This is just a typo; the actual issue is OP not handling the response of their AJAX request. –  May 12 '22 at 13:22
  • To work with the response coming from the server you need to do as @ChrisG said and implement `XMLHttpRequest.onreadystatechange`. I will edit my answer. – Lucas May 12 '22 at 13:24
  • You're just rehashing the docs though? And OP should use fetch() instead anyway. –  May 12 '22 at 13:31