Search code examples
javascriptformssymfonybase64symfony4

VichUploader and CroppieJS : how to send a base64 cropped image to persist in Symfony 4


I have a small symfony 4 application with a cropper using CroppieJS. When i crop and hit the save button, croppie sends me a base64 image :

 $( "#cropSave" ).click(function() {
    basic.croppie('result','canvas'
    ).then(function (result) {}

how to send this result to my controller and persist the image with VichUploader and Doctrine ?

Here is my controller :

public function updateProfilePicture(Request $request): Response
{
    $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
    $user = $this->getUser();
    $entityManager = $this->getDoctrine()->getManager();
    $user->setImageFile($request->files->get('image'));
    $entityManager->flush();
    return new Response("ok");
}

I tried a lot of things but I must lack experience because it don't work :

var form = document.getElementById("myAwesomeForm");
var ImageURL = result;
// Split the base64 string in data and contentType
var block = ImageURL.split(";");
// Get the content type of the image
var contentType = block[0].split(":")[1];
// get the real base64 content of the file
var realData = block[1].split(",")[1];
// Convert it to a blob to upload
var blob = b64toBlob(realData, contentType);
// Create a FormData and append the file with "image" as parameter name
var formDataToUpload = new FormData(form);
formDataToUpload.append("image", blob);

or

function urltoFile(url, filename, mimeType){
return (fetch(url)
    .then(function(res){return res.arrayBuffer();})
    .then(function(buf){return new File([buf], filename, {type:mimeType});})
);
}

here is one of my ajax request :

$.ajax({
    type : "POST",
    data: formDataToUpload,
    url : $('#updateProfilePictureLink').val(),
    contentType:false,
    processData:false,
    cache:false,
    dataType:"json",
    success : function(response) {
        $('#profilePicture').attr('src', result);
        alert(response);
    },
    error : function (response) {
        alert("error !");
    }
});

I was thinking maybe "Simulate" a file upload in JS from the base64 using VichUploader formType input field, but I want to know if there are simpler ways.

Thanks


Solution

  • I managed to work around it thanks to Ronnie Hint. You have to :

    • use JS FormData
    • put the blob inside
    • retrieve it in Symfony controller as an image
    • save it as is

    But you have to implement serializable on your image's entity (serialize and unserialize all fields, unless it will break your other features).

    Here is the working code sample :

    // JS
    $( "#cropSave" ).click(function() {
        alert("click !");
        basic.croppie('result','blob'
        ).then(function (result) {
            var fd = new FormData();
            //Third parameter is the blob name
            fd.append('data', 
            result,$('#userId').val()+"."+result.type.split("/")[1]);
                $.ajax({
                type: 'POST',
                url : $('#updateProfilePictureLink').val(),
                data: fd,
                processData: false,
                contentType: false
            }).done(function(data) {
                // your things
            });
    
    // PHP
    
    // Controller
    try {
        $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
        $user = $this->getUser();
        $entityManager = $this->getDoctrine()->getManager();
        $user->setImageFile($request->files->get('data'));
        $entityManager->flush();
    }
    catch (exception $e) {
    }
    
    // Entity
    class User implements UserInterface, \Serializable
    {
    
    /** @see \Serializable::serialize() */
    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->profilePicture,
            $this->email,
            $this->password
        ));
    }
    /** @see \Serializable::unserialize() */
    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->profilePicture,
            $this->email,
            $this->password
            ) = unserialize($serialized);
    }