Chargement du fichier image via L'API en utilisant Symfony2 & FOSRESTBundle

j'ai codé une API pour une application de partage de photos comme Instagram en utilisant Symfony2, FOSRESTBundle, et Vichuploader pour le téléchargement de fichiers.

je suis capable de travailler autour des requêtes GET et POST, mais je ne peux pas trouver un exemple de la façon d'attacher à une requête POST, l'image réelle de sorte que dans mon cas, Vichuploader peut l'attraper et m'aider avec le téléchargement de fichier.

soit dit en passant, je peux télécharger un fichier sans problème en utilisant la pile mentionnée à l'aide d'un formulaire normal.

16
demandé sur vaxquis 2013-06-16 07:18:39

4 réponses

j'ai cherché une solution à propos du même problème. Voici ce que j'ai fait.

Permettez-moi D'abord d'expliquer mes contraintes. Je voulais que mon API soit JSON complet et prenne le pouvoir du protocole HTTP (en-têtes, méthodes, etc.). J'ai choisi d'utiliser:

  • Symfony2 pour le "tout est presque fait pour vous, il suffit de coder votre logique d'entreprise".
  • Doctrine2 parce que par défaut avec Symfony2 et fournir un moyen d'intégrer avec les SGBD les plus populaires par changer une ligne.
  • FOSRestBundle pour traiter le RESTE de la partie de mon API (faire le maximum avec les annotations, le corps de l'auditeur, auto format de la réponse avec JMSSerializer de soutien, etc.).
  • KnpGaufretteBundle parce que je voulais être autorisé à changer la façon dont je stocke le fichier blob rapidement.

première solution envisagée: base64

ma première pensée, parce que je pensais JSON à chaque fois, était de coder tous les entrants images dans base64, puis les décoder dans mon API et les stocker.

L'avantage de cette solution est que vous pouvez passer des images avec d'autres données. Par exemple, téléchargez le profil d'un utilisateur entier dans un appel API. Mais j'ai lu que le codage des images dans base64 les fait croître de 33% de leur taille initiale. Je ne voulais pas que mes utilisateurs soient hors de données mobiles après avoir envoyé 3 images.

deuxième solution envisagée: forme

alors j'ai pensé utiliser les formes décrites ci-dessus. Mais je ne savais pas comment mes clients pouvaient envoyer les deux données JSON (par exemple {"last_name":"Litz"}) et des données d'image (par exemple image/png). Je sais que vous pouvez traiter avec un Content-Type: multipart/form-data mais rien de plus.

de plus, je n'utilisais pas de formulaires dans mon API depuis le début et je voulais qu'elle soit uniforme dans tout mon code. [mini-edit: hoho, quelque chose que je viens de découvrir, ici]

Troisième et dernière solution: utiliser HTTP..

Puis, une nuit, la révélation. Je suis à l'aide de Content-Type: application/json pour envoyer les données JSON. Pourquoi ne pas utiliser image/* pour envoyer des images? Tellement facile que j'ai cherché pendant des jours avant de venir avec cette idée. C'est comme ça que je l'ai fait (code simplifié). Supposons que l'utilisateur appelle PUT /api/me/image avec un Content-Type: image/*

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

        // 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($utilisateur, $contenu) - de la Logique Métier (j'ai tout mis ici pour être plus simple à lire)

        // 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;
    
16
répondu AlixB 2017-05-23 12:02:17

vous utilisez les types de formulaires pour les messages avec le FOSRestBundle:

Par exemple, vous avez ce type de formulaire:

    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';
}

alors ce que vous pouvez faire est de poster JSON à L'API. N'oubliez pas de définir l'en-tête comme "Content-type = application/json" lorsque vous faites un POST.

la structure JSON ressemblerait à ceci:

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

}

pourquoi ce json est-il enveloppé dans des "données"? Parce que votre type de formulaire a aussi des "données" dans getName donc il utilisera la validation et etc.

ce que je fais toujours, c'est encoder mes photos comme une chaîne base64 tout en les envoyant à L'API.

puis dans la fonction post vous le convertissez juste en arrière:

$base64     = $form['profile_pic']->getData();
//decode back to image data and create image
$image      = imagecreatefromstring(base64_decode($base64));
imagepng($image, $path);
2
répondu NoScope 2013-07-29 13:48:35

il s'agit d'un téléchargement complet à partir d'un bit de code api. Cela permet de télécharger le fichier, mais j'ai encore du mal à valider le fichier téléchargé. Espérons que cette aide.

ceci utilise le faisceau de fossests pour le repos.

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);        
}
1
répondu Chathushka 2013-10-31 05:57:55

un exemple pour une méthode de téléchargement 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);
}

cette action stocke d'abord le document sur le serveur et renvoie une réponse json contenant les méta-données du document et le chemin. J'ai utilisé la réponse pour un traitement ultérieur dans mon application web.

Je ne suis pas familier avec VichUploader, le code ci-dessus est natif Symfony2 code en utilisant Symfony\Component\HttpFoundation\File\UploadedFile.

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

0
répondu Artjom Zabelin 2013-06-29 03:47:22