src/EventSubscriber/FileUploadSubscriber.php line 97

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by simpson <simpsonwork@gmail.com>
  4.  * Date: 2019-05-02
  5.  * Time: 13:27
  6.  */
  7. namespace App\EventSubscriber;
  8. use App\Service\Features;
  9. use Intervention\Image\ImageManagerStatic as Image;
  10. use League\Flysystem\FilesystemOperator;
  11. use Oneup\UploaderBundle\Event\PostUploadEvent;
  12. use Oneup\UploaderBundle\Event\PreUploadEvent;
  13. use Oneup\UploaderBundle\Event\ValidationEvent;
  14. use Oneup\UploaderBundle\Uploader\Exception\ValidationException;
  15. use Oneup\UploaderBundle\Uploader\File\FileInterface;
  16. use Oneup\UploaderBundle\UploadEvents;
  17. use Symfony\Component\Asset\Packages;
  18. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\HttpFoundation\File\File;
  21. class FileUploadSubscriber implements EventSubscriberInterface
  22. {
  23.     private static array $allowedPhotoExtensions = ['jpg''jpeg''png'];
  24.     private static array $allowedFacePhotoExtensions = ['jpg''jpeg''png''heic'];
  25.     private static array $allowedVideoExtensions = ['mp4''flv''mov'];
  26.     private int $minAvatarWidth;
  27.     private int $minAvatarHeight;
  28.     private int $maxImageSideSize;
  29.     public function __construct(
  30.         private Packages $assetPackage,
  31.         ParameterBagInterface $parameterBag,
  32.         private Features $features,
  33.         private FilesystemOperator $tmpFilesystem
  34.     )
  35.     {
  36.         $this->minAvatarWidth = (int)$parameterBag->get('app.profile.avatar.min_width');
  37.         $this->minAvatarHeight = (int)$parameterBag->get('app.profile.avatar.min_height');
  38.         $this->maxImageSideSize = (int)$parameterBag->get('app.profile.image.max_side_size');
  39.     }
  40.     public function returnFilename(PostUploadEvent $event)
  41.     {
  42.         /** @var File $file */
  43.         $file $event->getFile();
  44.         $response $event->getResponse();
  45.         /*
  46.         // Path manipulations for orphanage
  47.         $fullPath = $file->getPath();
  48.         $firstLevelDirectory = basename($fullPath);
  49.         $secondLevelDirectory = basename(dirname($fullPath));
  50.         $filename = $file->getFilename();
  51.         $response['filename'] = "$secondLevelDirectory/$firstLevelDirectory/$filename";
  52.         */
  53.         $response['filename'] = $this->getPathname($file);
  54.         return $response['filename'];
  55.     }
  56.     protected function getPathname(FileInterface $file)
  57.     {
  58.         $filename $file->getPathname();
  59.         if(in_array(strtolower($file->getExtension()), ['png''heic'], true)) {
  60.             $filename preg_replace('/\.[^.]+$/''.jpg'$filename);
  61.         }
  62.         return $filename;
  63.     }
  64.     public function validateAvatar(ValidationEvent $event): void
  65.     {
  66.         $file $event->getFile();
  67.         list($width$height) = getimagesize($file->getPathname());
  68.         if($width $this->minAvatarWidth || $height $this->minAvatarHeight)
  69.             throw new ValidationException('Image too small.');
  70.         $this->validatePhotoFile($event);
  71.     }
  72.     public function validatePhotoFile(ValidationEvent $event): void
  73.     {
  74.         $file $event->getFile();
  75.         $extension strtolower($file->getExtension());
  76.         if (!in_array($extensionself::$allowedPhotoExtensionstrue)) {
  77.             throw new ValidationException('This kind of files is not allowed.');
  78.         }
  79.     }
  80.     public function validateVideoFile(ValidationEvent $event): void
  81.     {
  82.         $file $event->getFile();
  83.         $extension strtolower($file->getExtension());
  84.         if (!in_array($extensionself::$allowedVideoExtensionstrue)) {
  85.             throw new ValidationException('This kind of files is not allowed.');
  86.         }
  87.     }
  88.     public function validateFacePhotoFile(ValidationEvent $event): void
  89.     {
  90.         $file $event->getFile();
  91.         $extension strtolower($file->getExtension());
  92.         if (!in_array($extensionself::$allowedFacePhotoExtensionstrue)) {
  93.             throw new ValidationException('This kind of files is not allowed.');
  94.         }
  95.         if ('heic' === $extension && false === $this->isHeicConversionSupported()) {
  96.             throw new ValidationException('HEIC files are not supported by the server.');
  97.         }
  98.     }
  99.     public function validateApprovalMediaFile(ValidationEvent $event): void
  100.     {
  101.         $file $event->getFile();
  102.         $extension strtolower($file->getExtension());
  103.         if (!in_array($extensiontrue === $this->features->approval_by_video() ? self::$allowedVideoExtensions self::$allowedPhotoExtensionstrue)) {
  104.             throw new ValidationException('This kind of files is not allowed.');
  105.         }
  106.         if($event->getFile()->getSize() > 209715200) {
  107.             throw new ValidationException('Video is too big.');
  108.         }
  109.     }
  110.     public function postUploadUserAvatar(PostUploadEvent $event): void
  111.     {
  112.         $response $event->getResponse();
  113.         $pathname $this->returnFilename($event);
  114.         $response['path'] = $this->assetPackage->getUrl($pathname'user_media');
  115.     }
  116.     public function postUploadProfileAvatar(PostUploadEvent $event): void
  117.     {
  118.         $response $event->getResponse();
  119.         $pathname $this->returnFilename($event);
  120.         $response['path'] = $this->assetPackage->getUrl($pathname'profile_media_avatar');
  121.     }
  122.     public function postUploadSaloonThumb(PostUploadEvent $event): void
  123.     {
  124.         $response $event->getResponse();
  125.         $pathname $this->returnFilename($event);
  126.         $response['path'] = $this->assetPackage->getUrl($pathname'saloon_media_thumb');
  127.     }
  128.     protected function processFileParameters(File $file)
  129.     {
  130.         if(str_starts_with($file->getMimeType(), 'video/'))
  131.             return;
  132.         $image Image::make($this->tmpFilesystem->read($file->getFilename()));
  133.         $maxSideSize max($image->width(), $image->height());
  134.         if($maxSideSize $this->maxImageSideSize) {
  135.             if ($maxSideSize == $image->width()) {
  136.                 $newWidth $this->maxImageSideSize;
  137.                 $newHeight $newWidth $image->height() / $image->width();
  138.             } else {
  139.                 $newHeight $this->maxImageSideSize;
  140.                 $newWidth $newHeight $image->width() / $image->height();
  141.             }
  142.             $image->resize($newWidth$newHeight);
  143.         }
  144.         $this->tmpFilesystem->write($file->getFilename(), $image->encode('jpg'));
  145.     }
  146.     protected function processHeicFile(File $file): void
  147.     {
  148.         if (false === $this->isHeicConversionSupported()) {
  149.             throw new ValidationException('HEIC files are not supported by the server.');
  150.         }
  151.         $image = new \Imagick();
  152.         $image->readImageBlob($this->tmpFilesystem->read($file->getFilename()));
  153.         $image->setIteratorIndex(0);
  154.         $maxSideSize max($image->getImageWidth(), $image->getImageHeight());
  155.         if($maxSideSize $this->maxImageSideSize) {
  156.             if ($maxSideSize == $image->getImageWidth()) {
  157.                 $newWidth $this->maxImageSideSize;
  158.                 $newHeight $newWidth $image->getImageHeight() / $image->getImageWidth();
  159.             } else {
  160.                 $newHeight $this->maxImageSideSize;
  161.                 $newWidth $newHeight $image->getImageWidth() / $image->getImageHeight();
  162.             }
  163.             $image->resizeImage((int)$newWidth, (int)$newHeight\Imagick::FILTER_LANCZOS1);
  164.         }
  165.         $image->setImageFormat('jpg');
  166.         $this->tmpFilesystem->write($file->getFilename(), $image->getImagesBlob());
  167.         $image->clear();
  168.     }
  169.     protected function isHeicConversionSupported(): bool
  170.     {
  171.         return extension_loaded('imagick') && in_array('HEIC'\Imagick::queryFormats('HEIC'), true);
  172.     }
  173.     public function preUpload(PreUploadEvent $event): void
  174.     {
  175.         /** @var File $file */
  176.         $file $event->getFile();
  177.         if ('profile_face_photo' === $event->getType() && 'heic' === strtolower($file->getExtension())) {
  178.             $this->processHeicFile($file);
  179.             return;
  180.         }
  181.         $this->processFileParameters($file);
  182.     }
  183.     /**
  184.      * @inheritDoc
  185.      */
  186.     public static function getSubscribedEvents()
  187.     {
  188.         return [
  189.             PreUploadEvent::NAME => 'preUpload',
  190.             UploadEvents::postUpload('profile_media_avatar') => 'postUploadProfileAvatar',
  191.             UploadEvents::postUpload('profile_photo') => 'returnFilename',
  192.             UploadEvents::postUpload('profile_selfie') => 'returnFilename',
  193.             UploadEvents::postUpload('profile_video') => 'returnFilename',
  194.             UploadEvents::postUpload('profile_media_approval') => 'returnFilename',
  195.             UploadEvents::postUpload('profile_face_photo') => 'returnFilename',
  196.             UploadEvents::postUpload('saloon_media') => 'returnFilename',
  197.             UploadEvents::postUpload('saloon_media_thumb') => 'postUploadSaloonThumb',
  198.             UploadEvents::postUpload('saloon_media_video') => 'returnFilename',
  199.             UploadEvents::postUpload('user_media') => 'postUploadUserAvatar',
  200.             UploadEvents::postUpload('tmp_media') => 'returnFilename',
  201.             UploadEvents::postUpload('process_queue') => 'returnFilename',
  202.             UploadEvents::validation('profile_media_avatar') => 'validateAvatar',
  203.             UploadEvents::validation('profile_photo') => 'validatePhotoFile',
  204.             UploadEvents::validation('profile_selfie') => 'validatePhotoFile',
  205.             UploadEvents::validation('profile_video') => 'validateVideoFile',
  206.             UploadEvents::validation('profile_media_approval') => 'validateApprovalMediaFile',
  207.             UploadEvents::validation('profile_face_photo') => 'validateFacePhotoFile',
  208.             UploadEvents::validation('saloon_media') => 'validatePhotoFile',
  209.             UploadEvents::validation('saloon_media_thumb') => 'validateAvatar',
  210.             UploadEvents::validation('saloon_media_video') => 'validateVideoFile',
  211.             UploadEvents::validation('user_media') => 'validateAvatar',
  212.             UploadEvents::validation('tmp_media') => 'validateVideoFile',
  213.             UploadEvents::validation('process_queue') => 'validateVideoFile',
  214.         ];
  215.     }
  216. }