0

I've viewed plenty of similar questions on stack overflow and have attempted the noted solutions but none has worked for me. I honestly can't figure out what i'm doing wrong.

Heres a snippet of the code...

Node.JS ServerFile

function uploadAvatar(request){
return new Promise(function(resolve){
    if(request.sessionObject.username){
        base64 = (request.postObject.data).replace(/^data:image\/png;base64,/, "");
        fpath = __dirname + "/gg/avatars/" + request.sessionObject.username + ".png";
        fs.writeFile(fpath, base64, 'base64', function(err) {
            alertObject = alertObj("success","Success","You have succesfully uploaded an avatar.", false, false, 2000);
            resolve(alertObject);
        });
    }else{
        alertObject = alertObj("danger","Error","You must be logged in in order to upload an avatar.", false, false, 2000);
        resolve(alertObject);
    }
});
}

app.post("*", function(request, response, next){
postObject = {};
for(x in request.body){
    postObject[x] = sanitizer.sanitize(request.body[x]);
}
request.postObject = postObject;

function r(html, obj){
    response.render(html, obj);
}

switch(request.originalUrl){
    case "/uploadAvatar":
    uploadAvatar(request).then(function(alertObject){ r('HTML_Alert', {alertObject}) });
    break;
}

HTML_Modal (View file)

<div class="modal fade" id="uploadAvatar" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
  <div class="modal-header background-dark">
    <img src="/upload.png" width="30px" height="30px" />
    <h5 class="modal-title">Upload Avatar</h5>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <form id="upload-avatar">
      <label class="lead w-100 text-center">Please select an Image</label>
      <p id="image-response" class="text-center"></p>
      <div id="image-container" class="mx-auto p-2 border-dark background-darkest img-thumbnail">
        <img src="/load.png" style="left: 50%; position: absolute; margin-left: -25px; top: 50%; margin-top: -50px;"/>
      </div><br/>
      <input type="file" id="avatar-image-upload" class="form-control" onchange="imageResizer(event)" accept="image/*"/>
    </form>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
    <button type="button" class="btn btn-dark" onClick="uploadAvatar();">Upload</button>
  </div>
</div>
</div>
</div>

Javascript File

function xhttpz(action, dataSTR, cb){
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
    if(this.readyState == 4 && this.status == 200){
        if(cb){
            cb(this.responseText);
        }
    }
}
xhttp.open("POST", action, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(dataSTR);    
}

function imageResizer(event){
img = document.getElementById('image-avatar');
if(img){
    img.remove();
}
document.getElementById('image-container').innerHTML = "";
if(event.target.files[0].size < 500000){
    var files = event.target.files;
    var file = files[0];
    imageAvatar = document.createElement('img');
    imageAvatar.id = "image-avatar";
    if (file) {
    var reader = new FileReader();
    reader.onload = function(e) {
        imageAvatar.src = e.target.result;
        document.getElementById('image-container').appendChild(imageAvatar);
    };
    reader.readAsDataURL(file);
    }
    if (window.File && window.FileReader && window.FileList && window.Blob) {
        var filesToUploads = document.getElementById('avatar-image-upload').files;
        var file = filesToUploads[0];
        if (file) {
            var reader = new FileReader();
            reader.onload = function(e) {
                var img = document.createElement("img");
                img.src = e.target.result;
                var canvas = document.createElement("canvas");
                var ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0);
                var MAX_WIDTH = 300;
                var MAX_HEIGHT = 225;
                var width = img.width;
                var height = img.height;
                if (width > height) {
                    if (width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                    }
                } else {
                    if (height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                    }
                }
                canvas.width = width;
                canvas.height = height;
                var ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0, width, height);
                dataurl = canvas.toDataURL();
                document.getElementById('image-avatar').src = dataurl;
                document.getElementById('image-response').innerHTML = "Please wait as we upload your image.";
                document.getElementById('image-response').classList.add('text-success');
                document.getElementById('image-response').classList.remove('text-danger');
                xhttpz("/uploadAvatar", "data="+document.getElementById('image-avatar').src, function(responseHTML){
                    console.log(responseHTML);
                });
            }
            reader.readAsDataURL(file);
        }
    }else{
        document.getElementById('image-response').innerHTML = "Your browser does not support our API. Please consider using Chrome.";
        document.getElementById('image-response').classList.add('text-danger');
        document.getElementById('image-response').classList.remove('text-success');
    }
}else{
    document.getElementById('image-response').innerHTML = "Please ensure your image is under 500KB.";
    document.getElementById('image-response').classList.add('text-danger');
    document.getElementById('image-response').classList.remove('text-success');
}
}

Note: The request.postObject.data variable is a base64 string of a png image. (If that's correct)

Most of the code is superfluous, however I kept it all in tack just to help find the issue.

So the issue that I keep running into is that the file saves perfectly into the specified file path, however the file itself is either unreadable or corrupted. Essentially all i'm trying to do is save a base64 string as a png image on the server.

Note i'm using Node.js

I know this might be close to a duplicate question, but i've attempted all the solutions that we're posted on similar topics and none has worked.

Rahh
  • 121
  • 12
  • see this https://stackoverflow.com/questions/7375635/xhr-send-base64-string-and-decode-it-in-the-server-to-a-file – Lorenzo Canavaggio Jan 22 '19 at 10:14
  • Fixed it, well worked around it, I removed the xhttpz function and used FormData(), I then appended the 'image-avatar' src to the formData and sent the formData to the post controller using xmlhttp. – Rahh Jan 22 '19 at 11:07
  • 1
    Good, no need to thanks me for putting you on the right path :) – Lorenzo Canavaggio Jan 22 '19 at 12:34

2 Answers2

0

Please ensure that your base64 variable is decoding well using a tool like https://www.base64-image.de/ and that your fpath variable is correct.

Then,

require("fs").writeFile(fpath, base64, 'base64', function(err) {
  console.log(err);
});

Should work

Edit :

Just try

xhttpz("/uploadAvatar", document.getElementById('image-avatar').src, function(responseHTML){
    console.log(responseHTML);
});

and

base64 = (request.data).replace(/^data:image\/png;base64,/, "");
  • So I uploaded the image file to convert it to base64, then copied the base64 string, and entered the string as the base64 variable and it worked perfectly fine. So that means there must be an issue with my base64 String. I'll post the code that i'm using to extrapolate the base64 string. – Rahh Jan 22 '19 at 09:01
  • sometime the base64 string can have extra artefacts in it, at the start normally. Check the string you are having issues with does not have exstra stuff in it. Sorry I can't remember off hand what that is but if you compare the "good" one with the "bad" you should be able to find it, if that is the case. – MrPickles Jan 22 '19 at 09:11
  • try this `var base64 = req.rawBody.replace(/^data:image\/png;base64,/, "");` – Lorenzo Canavaggio Jan 22 '19 at 09:12
  • I tried that, I'm using XMLHTTPRequest to send the base64 string. And i sanitize all the post data and place it in an object called postObject. So it'd look like something like request.postObject.data (data bieng the key label for the base64 String). Is the 'rawBody' part of the line specific to something? – Rahh Jan 22 '19 at 09:18
  • are you using express ? – Lorenzo Canavaggio Jan 22 '19 at 09:29
  • So this is doing my head... So the string that gets sent to the server is different to the string that appears on the image src. I copied and pasted the string in the image element and it's different from the one bieng posted. I can't figure this out. I'll post the complete code. – Rahh Jan 22 '19 at 09:29
  • Yeah i'm using express. – Rahh Jan 22 '19 at 09:29
  • It didn't work. In the xhttpz function where it states xhr.send(dataSTR) it needs to be formatted in the following key=value&. That's essentially the reason that I wrote "data="+document.getElementByID('image-avatar').src. With the changes i'm getting a TypeError: Cannot read property 'replace' of undefined. – Rahh Jan 22 '19 at 10:04
  • You are right but it's strange request.data should work. maybe try to process the request with express – Lorenzo Canavaggio Jan 22 '19 at 10:11
  • https://stackoverflow.com/questions/5710358/how-to-retrieve-post-query-parameters – Lorenzo Canavaggio Jan 22 '19 at 10:22
0

Replace the xhttpz function

xhttpz("/uploadAvatar", "data="+document.getElementById('image-avatar').src, 
function(responseHTML){
    console.log(responseHTML);
});

with

xhr.open("POST","/uploadAvatar",true);
xhr.setRequestHeader('Content-Type','x-www-form-urlencoded');
xhr.send("Filedata="+imageAvatar.src);

Then change the base64 variable to reference the newly stated 'Filedata.'

fpath = (__dirname + "/html/avatars/" + sessionObject.username + ".png");
var bodyStr = '';
request.on("data",function(chunk){
    bodyStr += chunk.toString();
});
request.on("end",function(){
    base64 = (bodyStr).replace("Filedata=data:image/png;base64,","");
    fs.writeFile(fpath, base64, 'base64', function(err){
        alertObject = alertObj("success","Success","You have successfully uploaded an avatar.", false, true, 2000);
        resolve(alertObject);
    });
});
Rahh
  • 121
  • 12
  • So what I had broke not shortly after and I can't seem to figure out how and why it broke, but I found a different work around. I'll edit my post to reflect the changes. – Rahh Jan 29 '19 at 01:12