Skip to content

Instantly share code, notes, and snippets.

@thibaut-decherit
Created February 20, 2020 17:21
Show Gist options
  • Save thibaut-decherit/bdee40ab0c32f27d36bfcbbb604848b4 to your computer and use it in GitHub Desktop.
Save thibaut-decherit/bdee40ab0c32f27d36bfcbbb604848b4 to your computer and use it in GitHub Desktop.
Symfony - Serve Private File

Symfony - Serve Private File

Following example demonstrates how to:

  • display a private file download prompt to the user (here for a PDF file)
  • serve a private image or PDF which will be displayed on a webpage

See https://symfony.com/doc/4.4/components/http_foundation.html#serving-files

Host these files in a directory outside of /public, so they can be accessed only through the controller and its @Security() authorization. For example you could create a /private-uploads directory at the root of your project.

templates/template.html.twig

<a href="{{ path('download_private_pdf', {'name': privatePdfExample.name}) }}">Download</a>

<object data="{{ path('serve_private_pdf', {'name': privatePdfExample.name}) }}" type="application/pdf"></object>

<img src="{{ path('serve_private_image', {'name': privateImageExample.name}) }}">

src/Controller/ServePrivateFileController.php

<?php

namespace App\Controller;

use App\Entity\PrivatePdfExample;
use App\Entity\PrivateImageExample;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class ServePrivateFileController
 * @package App\Controller
 */
class ServePrivateFileController extends DefaultController
{
    /**
     * Returns a PrivatePdfExample file for download.
     *
     * @param PrivatePdfExample $privatePdfExample
     * @Route("/serve-private-file/pdf/{name}", name="download_private_pdf", methods="GET")
     * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED') and user.getId() === privatePdfExample.getUser().getId()")
     * @return BinaryFileResponse
     */
    public function privatePdfExampleDownload(PrivatePdfExample $privatePdfExample): BinaryFileResponse
    {
        $name = $privateImageExample->getOriginalName() . '.' . $privateImageExample->getFileExtension();

        return $this->fileDownload($privatePdfExample->getPath(), $name);
    }

    /**
     * Returns a PrivatePdfExample file for display.
     *
     * @param PrivatePdfExample $privatePdfExample
     * @Route("/serve-private-file/pdf/{name}", name="serve_private_pdf", methods="GET")
     * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED') and user.getId() === privatePdfExample.getUser().getId()")
     * @return BinaryFileResponse
     */
    public function privatePdfExampleServe(PrivateImageExample $privatePdfExample): BinaryFileResponse
    {
        return $this->fileServe($privatePdfExample->getPath());
    }

    /**
     * Returns a PrivateImageExample file for display.
     *
     * @param PrivateImageExample $privateImageExample
     * @Route("/serve-private-file/image/{name}", name="serve_private_image", methods="GET")
     * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED') and user.getId() === privateImageExample.getUser().getId()")
     * @return BinaryFileResponse
     */
    public function privateImageExampleServe(PrivateImageExample $privateImageExample): BinaryFileResponse
    {
        return $this->fileServe($privateImageExample->getPath());
    }

    /**
     * Returns a private file for download.
     *
     * @param string $path
     * @param string $name
     * @return BinaryFileResponse
     */
    private function fileDownload(string $path, string $name): BinaryFileResponse
    {
        $absolutePath = $this->getParameter('kernel.root_dir') . '/..' . $path;

        $response = new BinaryFileResponse($absolutePath);

        $disposition = HeaderUtils::makeDisposition(
            HeaderUtils::DISPOSITION_ATTACHMENT,
            $name
        );

        $response->headers->set('Content-Disposition', $disposition);

        return $response;
    }

    /**
     * Returns a private file for display.
     *
     * @param string $path
     * @return BinaryFileResponse
     */
    private function fileServe(string $path): BinaryFileResponse
    {
        $absolutePath = $this->getParameter('kernel.root_dir') . '/..' . $path;

        return new BinaryFileResponse($absolutePath);
    }
}
@arvodia
Copy link

arvodia commented Jun 4, 2021

thank you so much

@LaurieReinette
Copy link

You saved your life! Thank you sooooo(...) much

@nfacciolo
Copy link

Thanks for this piece of code !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment