base64 image to image file with Symfony and VichUploader

10,647

An attempt of solution is to transform first the base64 file into a symfony uploadedFile.

  • You define this service
<?php

    namespace App\Utils;

    use Symfony\Component\HttpFoundation\File\UploadedFile;

    class UploadedBase64File extends UploadedFile
    {

        public function __construct(string $base64String, string $originalName)
        {
            $filePath = tempnam(sys_get_temp_dir(), 'UploadedFile');
            $data = base64_decode($base64String);
            file_put_contents($filePath, $data);
            $error = null;
            $mimeType = null;
            $test = true;

            parent::__construct($filePath, $originalName, $mimeType, $error, $test);
        }

    }

And then this another service to extract the pur base64 string image

<?php

    namespace App\Utils;

    class Base64FileExtractor    
    {

        public function extractBase64String(string $base64Content)
        {

            $data = explode( ';base64,', $base64Content);
            return $data[1];

        }

    }
  • And in your controller, you can do something like :
    <?php

    namespace App\Controller\Api;

    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Routing\Annotation\Route;
    use App\Utils\UploadedBase64File;
    use App\Utils\Base64FileExtractor;

    class CoreController extends AbstractController
    {
       /**
         * @Route("/images", methods={"POST"}, name="app_add_image")
         */
         public function addImage(Request $request, Base64FileExtractor $base64FileExtractor) 
         {

             //...

             if($form->isSubmitted() && $form->isValid()) {

                  $base64Image = $request->request->get('base64Image');
                  $base64Image = $base64FileExtractor->extractBase64String($base64Image);
                  $imageFile = new UploadedBase64File($base64Image, "blabla");
                  $program->setImage($imageFile);

                  //... 
                  // Do thing you want to do
             }
             // Do thing you want to do

         }
   }
  • The method setImage in your Program entity can be something like
       /**
         * @param null|File $image
         * @return Program
         */
        public function setImage(?File $image): Program
        {
            $this->image = $image;

            if($this->image instanceof UploadedFile) {
                $this->updatedAt = new \DateTime('now');
            }

            return $this;
        }

If you want to validate the image, you should set it directly after handling form and the validation will be done habitually. I hope this idea can help you.

Share:
10,647
Dirk J. Faber
Author by

Dirk J. Faber

Updated on June 05, 2022

Comments

  • Dirk J. Faber
    Dirk J. Faber almost 2 years

    In symfony, I have an entity Program, which has the attribute image. Uploading images, naming them and putting them in the right directory is done with the VichUploaderBundle. The entity looks like this:

    //...
    
    /**
     * NOTE: This is not a mapped field of entity metadata, just a simple property.
     *
     * @Assert\Image(
     *     maxSize="5M",
     *     mimeTypesMessage="The file you tried to upload is not a recognized image file"
     *    )
     * @Vich\UploadableField(mapping="program_image", fileNameProperty="imageName")
     *
     * @var File
     */
    private $image;
    
    /**
     * @ORM\Column(type="string", length=191, nullable=true)
     */
    private $imageName; 
    
    //...
    

    Now I wish for images to be processed before they are uploaded, which I have done with some JS that returns a base64 string. I put this string in a hidden input field, base64Image. I then retrieve this string in my controller and try to make it into an image that I can save to my entity like so:

    if ($form->isSubmitted() && $form->isValid()) {
        $program = $form->getData();
    
        $base64String = $request->request->get('base64Image');
        $decodedImageString = base64_decode($base64String);
    
        $program->setImage($decodedImageString);
    
    //etc.....
    

    The program occurs with the last line. $decodedImageString is actually another string that first needs to be created into a file. I have looked into file_put_contents to create a file as describer here, but with no luck.

    The filename cannot be empty

    Is the error I receive. Also I don't know if this would work with the VichUploaderBundle and perhaps the answer in that question is also outdated. Any suggestions on what I could do?

    Edit: Got the converting and uploading working with the following code:

    define('UPLOAD_DIR', 'images/');
    $img = $request->request->get('base64Image');
    $img = str_replace('data:image/jpeg;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    $data = base64_decode($img);
    $file = UPLOAD_DIR . uniqid() . '.jpeg';
    $success = file_put_contents($file, $data);
    print $success ? $file : 'Unable to save the file.';
    

    Now I just need to load the VichUploaderBundle config somehow, or maybe not use that altogether perhaps.

    • William Bridge
      William Bridge about 5 years
      I posted an answer here in this topic converting-any-base64-file-to-a-file-and-moving-to-the-targe‌​ted-path-in-php-symf‌​ony. I hope this can give you an idea to how to manage it with vichuploaderbundle.
    • William Bridge
      William Bridge about 5 years
      And then you also have this answer through this topic convert-base64-string-to-an-image-file. This can help you extract pur base64 image and you combine with my answer above to manage it with vichuploaderbundle.
    • Dirk J. Faber
      Dirk J. Faber about 5 years
      @williambridge, I tried everything you wrote down. I still have a problem when I try to save the image using $program->saveImage(). The temporary file that is created with tempnam() won't be recognised as file, but as a string. I tried changing the extensions to .jpeg, but that didn't work either.
  • Dirk J. Faber
    Dirk J. Faber about 5 years
    I get a bunch of errors when using this. Firstly the method uuid1 is not recognized. but even when I manually give the file a name, I get an error the ' ul_path' is not defined.
  • Dirk J. Faber
    Dirk J. Faber about 5 years
    Appreciate it. I managed with some similar method (see the edit). Now I just need to figure out how to use the VichUploaderBundle with this.
  • Dirk J. Faber
    Dirk J. Faber about 5 years
    Very helpful indeed. A crucial part turns out to be $test = true; when using the UploadedFile. I am not completely where I want to be yet, but this is getting me on the right track.