vendor/sulu/sulu/src/Sulu/Bundle/MediaBundle/Controller/MediaStreamController.php line 129

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Sulu.
  4.  *
  5.  * (c) Sulu GmbH
  6.  *
  7.  * This source file is subject to the MIT license that is bundled
  8.  * with this source code in the file LICENSE.
  9.  */
  10. namespace Sulu\Bundle\MediaBundle\Controller;
  11. use Sulu\Bundle\MediaBundle\Admin\MediaAdmin;
  12. use Sulu\Bundle\MediaBundle\Entity\Collection;
  13. use Sulu\Bundle\MediaBundle\Entity\FileVersion;
  14. use Sulu\Bundle\MediaBundle\Entity\MediaInterface;
  15. use Sulu\Bundle\MediaBundle\Entity\MediaRepositoryInterface;
  16. use Sulu\Bundle\MediaBundle\Media\DispositionType\DispositionTypeResolver;
  17. use Sulu\Bundle\MediaBundle\Media\Exception\FileVersionNotFoundException;
  18. use Sulu\Bundle\MediaBundle\Media\Exception\ImageProxyException;
  19. use Sulu\Bundle\MediaBundle\Media\Exception\MediaException;
  20. use Sulu\Bundle\MediaBundle\Media\FormatCache\FormatCacheInterface;
  21. use Sulu\Bundle\MediaBundle\Media\FormatManager\FormatManagerInterface;
  22. use Sulu\Bundle\MediaBundle\Media\Manager\MediaManagerInterface;
  23. use Sulu\Bundle\MediaBundle\Media\Storage\StorageInterface;
  24. use Sulu\Component\PHPCR\PathCleanupInterface;
  25. use Sulu\Component\Security\Authorization\PermissionTypes;
  26. use Sulu\Component\Security\Authorization\SecurityCheckerInterface;
  27. use Sulu\Component\Security\Authorization\SecurityCondition;
  28. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  29. use Symfony\Component\HttpFoundation\RedirectResponse;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  33. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  34. class MediaStreamController
  35. {
  36.     /**
  37.      * @var FormatManagerInterface
  38.      */
  39.     protected $formatManager;
  40.     /**
  41.      * @var FormatCacheInterface
  42.      */
  43.     protected $formatCache;
  44.     /**
  45.      * @var MediaManagerInterface
  46.      */
  47.     protected $mediaManager;
  48.     /**
  49.      * @var StorageInterface
  50.      */
  51.     protected $storage;
  52.     /**
  53.      * @var DispositionTypeResolver
  54.      */
  55.     protected $dispositionTypeResolver;
  56.     /**
  57.      * @var MediaRepositoryInterface
  58.      */
  59.     protected $mediaRepository;
  60.     /**
  61.      * @var PathCleanupInterface
  62.      */
  63.     protected $pathCleaner;
  64.     /**
  65.      * @var SecurityCheckerInterface|null
  66.      */
  67.     protected $securityChecker;
  68.     public function __construct(
  69.         DispositionTypeResolver $dispositionTypeResolver,
  70.         MediaRepositoryInterface $mediaRepository,
  71.         PathCleanupInterface $pathCleaner,
  72.         FormatManagerInterface $formatManager,
  73.         FormatCacheInterface $formatCache,
  74.         MediaManagerInterface $mediaManager,
  75.         StorageInterface $storage,
  76.         ?SecurityCheckerInterface $securityChecker null
  77.     ) {
  78.         $this->dispositionTypeResolver $dispositionTypeResolver;
  79.         $this->mediaRepository $mediaRepository;
  80.         $this->pathCleaner $pathCleaner;
  81.         $this->formatManager $formatManager;
  82.         $this->formatCache $formatCache;
  83.         $this->mediaManager $mediaManager;
  84.         $this->storage $storage;
  85.         $this->securityChecker $securityChecker;
  86.     }
  87.     /**
  88.      * @return Response
  89.      */
  90.     public function getImageAction(Request $request)
  91.     {
  92.         try {
  93.             if (\ob_get_length()) {
  94.                 \ob_end_clean();
  95.             }
  96.             $url $request->getPathInfo();
  97.             $mediaProperties $this->formatCache->analyzedMediaUrl($url);
  98.             return $this->formatManager->returnImage(
  99.                 $mediaProperties['id'],
  100.                 $mediaProperties['format'],
  101.                 $mediaProperties['fileName']
  102.             );
  103.         } catch (ImageProxyException $e) {
  104.             throw new NotFoundHttpException('Image create error. Code: ' $e->getCode());
  105.         }
  106.     }
  107.     /**
  108.      * @param int $id
  109.      *
  110.      * @return Response
  111.      */
  112.     public function downloadAction(Request $request$id)
  113.     {
  114.         try {
  115.             if (\ob_get_length()) {
  116.                 \ob_end_clean();
  117.             }
  118.             $version $request->get('v'null);
  119.             $noCount $request->get('no-count'false);
  120.             $fileVersion $this->getFileVersion($id$version);
  121.             if (!$fileVersion) {
  122.                 return new Response(null404);
  123.             }
  124.             if ($this->securityChecker) {
  125.                 $this->securityChecker->checkPermission(
  126.                     new SecurityCondition(
  127.                         MediaAdmin::SECURITY_CONTEXT,
  128.                         null,
  129.                         Collection::class,
  130.                         $fileVersion->getFile()->getMedia()->getCollection()->getId()
  131.                     ),
  132.                     PermissionTypes::VIEW
  133.                 );
  134.             }
  135.             if ($request->query->has('inline')) {
  136.                 $forceInline = (bool) $request->get('inline'false);
  137.                 $dispositionType $forceInline ResponseHeaderBag::DISPOSITION_INLINE ResponseHeaderBag::DISPOSITION_ATTACHMENT;
  138.             } else {
  139.                 $dispositionType $this->dispositionTypeResolver->getByMimeType($fileVersion->getMimeType());
  140.             }
  141.             if (!$noCount) {
  142.                 $this->mediaManager->increaseDownloadCounter($fileVersion->getId());
  143.             }
  144.             $response $this->getFileResponse($fileVersion$request->getLocale(), $dispositionType);
  145.             return $response;
  146.         } catch (MediaException $e) {
  147.             throw new NotFoundHttpException('File not found: ' $e->getCode() . ' ' $e->getMessage());
  148.         }
  149.     }
  150.     protected function getFileResponse(
  151.         FileVersion $fileVersion,
  152.         string $locale,
  153.         string $dispositionType ResponseHeaderBag::DISPOSITION_ATTACHMENT
  154.     ): Response {
  155.         $storageOptions $fileVersion->getStorageOptions();
  156.         $storageType $this->storage->getType($storageOptions);
  157.         if (StorageInterface::TYPE_REMOTE === $storageType) {
  158.             $response = new RedirectResponse($this->storage->getPath($storageOptions), 302);
  159.             $response->setPrivate();
  160.             return $response;
  161.         } elseif (StorageInterface::TYPE_LOCAL === $storageType) {
  162.             return $this->createBinaryFileResponse($fileVersion$this->storage$locale$dispositionType);
  163.         }
  164.         throw new \RuntimeException(\sprintf('Storage type "%s" not supported.'$storageType));
  165.     }
  166.     private function createBinaryFileResponse(
  167.         FileVersion $fileVersion,
  168.         StorageInterface $storage,
  169.         string $locale,
  170.         string $dispositionType
  171.     ): BinaryFileResponse {
  172.         $fileName $fileVersion->getName();
  173.         $fileSize $fileVersion->getSize();
  174.         $storageOptions $fileVersion->getStorageOptions();
  175.         $mimeType $fileVersion->getMimeType();
  176.         $lastModified $fileVersion->getCreated(); // use created as file itself is not changed when entity is changed
  177.         $response = new BinaryFileResponse($storage->getPath($storageOptions));
  178.         // Prepare headers
  179.         $disposition $response->headers->makeDisposition(
  180.             $dispositionType,
  181.             $fileName,
  182.             $this->cleanUpFileName($fileName$locale$fileVersion->getExtension())
  183.         );
  184.         // Set headers for
  185.         $file $fileVersion->getFile();
  186.         if ($fileVersion->getVersion() !== $file->getVersion()) {
  187.             $latestFileVersion $file->getLatestFileVersion();
  188.             $response->headers->set(
  189.                 'Link',
  190.                 \sprintf(
  191.                     '<%s>; rel="canonical"',
  192.                     $this->mediaManager->getUrl(
  193.                         $file->getMedia()->getId(),
  194.                         $latestFileVersion->getName(),
  195.                         $latestFileVersion->getVersion()
  196.                     )
  197.                 )
  198.             );
  199.             $response->headers->set('X-Robots-Tag''noindex, follow');
  200.         }
  201.         // Set headers
  202.         $response->headers->set('Content-Type', !empty($mimeType) ? $mimeType 'application/octet-stream');
  203.         $response->headers->set('Content-Disposition'$disposition);
  204.         $response->headers->set('Content-length'$fileSize);
  205.         $response->headers->set('Last-Modified'$lastModified->format('D, d M Y H:i:s \G\M\T'));
  206.         return $response;
  207.     }
  208.     /**
  209.      * @param int $id
  210.      * @param int $version
  211.      *
  212.      * @return FileVersion|null
  213.      *
  214.      * @throws FileVersionNotFoundException
  215.      */
  216.     protected function getFileVersion($id$version)
  217.     {
  218.         /** @var MediaInterface $mediaEntity */
  219.         $mediaEntity $this->mediaRepository->findMediaById($id);
  220.         if (!$mediaEntity) {
  221.             return null;
  222.         }
  223.         $file $mediaEntity->getFiles()[0];
  224.         if (!$file) {
  225.             return null;
  226.         }
  227.         if (!$version) {
  228.             $version $mediaEntity->getFiles()[0]->getVersion();
  229.         }
  230.         $fileVersion $file->getFileVersion((int) $version);
  231.         if (!$fileVersion) {
  232.             throw new FileVersionNotFoundException($id$version);
  233.         }
  234.         return $fileVersion;
  235.     }
  236.     /**
  237.      * Cleaned up filename.
  238.      *
  239.      * @param string $fileName
  240.      * @param string $locale
  241.      * @param string $extension
  242.      *
  243.      * @return string
  244.      */
  245.     private function cleanUpFileName($fileName$locale$extension)
  246.     {
  247.         $pathInfo \pathinfo($fileName);
  248.         $cleanedFileName $this->pathCleaner->cleanup($pathInfo['filename'], $locale);
  249.         if ($extension) {
  250.             $cleanedFileName .= '.' $extension;
  251.         }
  252.         return $cleanedFileName;
  253.     }
  254. }