Uploading image file through API using Symfony2 &

2019-03-11 02:20发布

I have been coding an API for a photo sharing app like Instagram using Symfony2, FOSRESTBundle, and Vichuploader for file uploads.

I'm able to work around GET and POST requests, but I can't find an example of how to attach to a POST request, the actual image so that in my case, Vichuploader can grab it and help me out with the file upload.

By the way, I can upload a file without issue using the stack mentioned through the use of a normal form.

4条回答
老娘就宠你
2楼-- · 2019-03-11 02:48

You use form types for posts with the FOSRestBundle:

For example you have this form type:

    public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('facebook_id',
                'text',
                array(
                    'mapped' => FALSE
                )
            )
        ->add('profile_pic',
                'text',
                array(
                    'mapped' => FALSE
                )
            )
        ;

        $builder->addValidator(new CallbackValidator(function(FormInterface $form)
        {
            if ($form["facebook_id"]->getData() === '' || $form["facebook_id"]->getData() === NULL)
            {
                $form->get('facebook_id')->addError(new FormError('facebook_id should not be empty'));
            }
            if ($form["profile_pic"]->getData() === '' || $form["profile_pic"]->getData() === NULL)
            {
                $form->get('profile_pic')->addError(new FormError('profile_pic should not be empty'));
            }
        })
        );

}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{

    $resolver->setDefaults(array(
        // 'validation_constraint' => $collectionConstraint,
        'csrf_protection' => FALSE,
    ));
}

public function getName()
{
    return 'data';
}

Then what you can do is post JSON to the API. Don't forget to set the header as "Content-type = application/json" when you do a POST.

The JSON structure would look like this:

{
"data": {
    "facebook_id": "12345",
    "profile_pic": "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"
}

}

Why is this json wrapped in "data"? Because your form type also has "data" in getName so it will use validation and etc.

What I always do is I encode my pictures as a base64 string while sending them to the API.

Then in the post function you just convert it back:

$base64     = $form['profile_pic']->getData();
//decode back to image data and create image
$image      = imagecreatefromstring(base64_decode($base64));
imagepng($image, $path);
查看更多
萌系小妹纸
3楼-- · 2019-03-11 02:54

I have been looking for a solution about the exact same problem. Here is what I did.

First let me explain my constraints. I wanted my API to be full JSON and to take power of the HTTP protocol (headers, methods, etc.). I chose to use:

  • Symfony2 for the "everything is almost done for you, just code your business logic".
  • Doctrine2 because by default with Symfony2 and provide a way to integrate with most popular DBMS by changing one line.
  • FOSRestBundle to handle the REST part of my API (do the maximum with annotations, body listener, auto format for the response with JMSSerializer support, etc.).
  • KnpGaufretteBundle because I wanted to be allowed to change the way I store blob file quickly.

First solution envisaged: base64

My first thought, because I was thinking JSON everytime, was to encode all the incoming images in base64, then decode them inside my API and store them.

The advantage with this solution is that you can pass images along with other data. For instance upload a whole user's profile in one API call. But I read that encoding images in base64 make them grow by 33% of their initial size. I did not wanted my users to be out of mobile data after sending 3 images.

Second solution envisaged: form

Then I thought using forms as described above. But I did not know how my clients could send both JSON data (for instance {"last_name":"Litz"}) and image data (for instance image/png one). I know that you can deal with an Content-Type: multipart/form-data but nothing more.

Plus I was not using forms in my API since the beginning and I wanted it to be uniform in all my code. [mini-edit: hoho, something I just discovered, here]

Third and last solution: use HTTP..

Then, one night, the revelation. I'm using Content-Type: application/json for send JSON data. Why not use image/* to send images? So easy that I searched for days before coming with this idea. This is how I did it (simplified code). Let suppose that the user is calling PUT /api/me/image with a Content-Type: image/*

  1. UserController::getUserImageAction(Request $request) - Catching the Request

        // get the service to handle the image
        $service = $this->get('service.user_image');
        $content = $request->getContent();
        $userImage = $service->updateUserImage($user, $content);
    
        // get the response from FOSRestBundle::View
        $response = $this->view()->getResponse();
        $response->setContent($content);
        $response->headers->set('Content-Type', $userImage->getMimeType());
    
        return $response;
    
  2. UserImageService::updateUserImage($user, $content) - Business Logic (I put everything here to be simplier to read)

        // Create a temporary file on the disk
        // the temp file will be delete at the end of the script
        // see http://www.php.net/manual/en/function.tmpfile.php
        $file = tmpfile();
        if ($file === false) 
            throw new \Exception('File can not be opened.');
    
        // Put content in this file
        $path = stream_get_meta_data($file)['uri'];
        file_put_contents($path, $content);
    
        // the UploadedFile of the user image
        // referencing the temp file (used for validation only)
        $uploadedFile = new UploadedFile($path, $path, null, null, null, true);
    
        // the UserImage to return
        $userImage = $user->getUserImage();
        if (is_null($userImage))
        {
            $userImage = new UserImage();
            $userImage->setOwner($user); 
            // auto persist with my configuration
            // plus generation of a unique ID that allows
            // me to retrieve the image at anytime
            $userImage->setKey(/*random string*/);
        }
    
        // fill the UserImage properties
        $userImage->setImage($uploadedFile);
        $userImage->setMimeType($uploadedFile->getMimeType());
    
        /** @var ConstraintViolationInterface $validationError */
        if (count($this->getValidator()->validate($userImage)) > 0)
            throw new \Exception('Validation');
    
        // if no error we can write the file definitively
        // [KnpGaufretteBundle code to store on disk]
        // [use the UserImage::key to store]
        $this->getEntityManager()->flush();
    
        return $userImage;
    
查看更多
走好不送
4楼-- · 2019-03-11 03:11

This is a full upload from api code bit. This does upload the file, but I am still having trouble with validating the uploaded file. Hope this helps.

This uses fosrest bundle for REST.

private function addResource(Entity $resource) {
    $em = $this->getDoctrine()->getManager();
    $em->persist($resource);
    $em->flush();
}

private function processForm(Entity $resource)
{
    $em = $this->getDoctrine()->getManager();
    $uploadedFile = null;

    $form = $this->createForm(new EntityForm(), $resource);

    foreach ($_FILES as $file) {
        $uploadedFile = new UploadedFile(
            $file['tmp_name'], 
            $file['name'], $file['type'],
            $file['size'], $file['error'], 
            $test = false);
    }

    $submitData = array(
        "file" => $uploadedFile,
    );

    $form->submit($submitData);

    if ($form->isValid()) {
        $repository = $this->getDoctrine()
            ->getRepository('AcmeBundle:Product');

        $view = View::create();
        $resource->setFile($uploadedFile);

        // handling api requests
        if ($this->getRequest()->getMethod() == "POST") {

            $this->addResource($resource);

            // store image url
            $resource = $repository->find($resource->getId());

            if ($resource->getImage()) {
                $fs = new Filesystem();

                if ($fs->exists($resource->getWebPath())) {
                    $resource->setImagePath($resource->getWebPath());    
                }

                $this->addResource($resource);
            }

            $view->setData($resource);
        } 

        return $view;
    }

    return View::create($form);        
}
查看更多
可以哭但决不认输i
5楼-- · 2019-03-11 03:12

An example for a upload method exepting post requests:

public function uploadAction() {
    $em = $this->getDoctrine()->getManager();

    $document = new Document();

    foreach ($_FILES as $file) {

        $document->setTitle($file['name']);
        $document->file = new UploadedFile($file['tmp_name'], 
                          $file['name'], $file['type'],
                          $file['size'], $file['error'], $test = false);

        $em->persist($document);
        $em->flush();

        break;
    }

    $serializer = $this->get('jms_serializer');
    $data = $serializer->serialize(
          $document, 'json', 
          SerializationContext::create()->setGroups(array('someGroup')));

    return new Response($data);
}

So this action first stores the document on the server and returns a json response containing document meta data and path. I used the response for further processing in my web application.

I am not familiar with VichUploader, the above code is native Symfony2 code using Symfony\Component\HttpFoundation\File\UploadedFile.

Read: http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html

查看更多
登录 后发表回答