src/Service/FileUploader/UploadService.php line 277

Open in your IDE?
  1. <?php
  2. namespace App\Service\FileUploader;
  3. use Psr\Log\LoggerInterface;
  4. use Symfony\Component\DependencyInjection\ContainerInterface;
  5. use Symfony\Component\Finder\Finder;
  6. use Symfony\Component\HttpFoundation\AcceptHeader;
  7. use Symfony\Component\HttpFoundation\AcceptHeaderItem;
  8. use Symfony\Component\HttpFoundation\File\File;
  9. use Symfony\Component\HttpFoundation\File\UploadedFile;
  10. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  11. use Symfony\Component\HttpFoundation\RedirectResponse;
  12. use Symfony\Component\HttpFoundation\RequestStack;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  15. use Symfony\Component\Filesystem\Filesystem;
  16. use App\Service\FileUploader\Exception;
  17. use App\Service\FileUploader\Result;
  18. use Intervention\Image\ImageManagerStatic as Image;
  19. class UploadService
  20. {
  21.     /**
  22.      * @var ContainerInterface
  23.      */
  24.     protected $container;
  25.     /**
  26.      * @var Filesystem
  27.      */
  28.     protected $filesystem;
  29.     protected $request;
  30.     private $logger;
  31.     public function __construct(ContainerInterface $containerLoggerInterface $loggerRequestStack $requestStack) {
  32.         $this->container $container;
  33.         $this->logger $logger;
  34.         $this->filesystem = new Filesystem();
  35.         $this->request $requestStack->getCurrentRequest();
  36.     }
  37.     /**
  38.      * EntityのUploadConfigを返す
  39.      *
  40.      * $UploadService->getUploadConfig(Entity $NewsEntity)
  41.      * $UploadService->getUploadConfig("News\Entry", "main_img")
  42.      * $UploadService->getUploadConfig("News\Entry:main_img")
  43.      *  で指定する
  44.      *
  45.      *  Entity側では App\Entity\Traits\FileConfigurationTrait を実装
  46.      *  protected $uploadConfig = [
  47.      *     "main_img" => [
  48.      *        "upload_dir" => "news/main_img/",
  49.      *        "mime" => [
  50.      *           "image/jpeg",
  51.      *           "image/png"
  52.      *        ],
  53.      *        "image_process" => [
  54.      *           "resize" => [1200, 800],
  55.      *           "thumb" => [150, 150],
  56.      *           "limit" => [1200, 1000] はみ出た場合のみトリム
  57.      *           "fit"   => [1200, 1000]
  58.      *           "thumb_resize" => [300, 300, bgcolor #fff] トリムせずに縮小して指定サイズにカンバスをセット
  59.      *        ]
  60.      *   ]
  61.      * ];
  62.      * で設定する
  63.      *
  64.      * @return array
  65.      */
  66.     public function getUploadConfig($entity$fileClass null) {
  67.         if(is_string($entity) && null === $fileClass) {
  68.             list($entity$fileClass) = explode(":"$entity);
  69.         }
  70.         if(is_string($entity)) {
  71.             $entyt "\\" $entity;
  72.             $entity = new $entity;
  73.         }
  74.         if(!method_exists($entity"getUploadConfigrations")) {
  75.             throw new \InvalidArgumentException('Entity not have method getUploadConfigrations()');
  76.         }
  77.         return $entity->getUploadConfigrations($fileClass);
  78.     }
  79.     public function upload(UploadedFile $file, array $uploadConfig) {
  80.         $uploadDir $this->getUploadDir($uploadConfig);
  81.         $result = new Result($file$uploadDir);
  82.         // Mime check
  83.         if(
  84.             isset($uploadConfig['mime']) &&
  85.             is_array($uploadConfig['mime']) &&
  86.             !in_array($result->getMime(), $uploadConfig['mime'], true)
  87.         ) {
  88.             throw new Exception('Mime type deny.');
  89.         }
  90.         // 画像MIMEであるか?
  91.         if($this->isImageMime($result->getMime())) {
  92.             if (isset($uploadConfig["image_process"])) {
  93.                 // 画像処理
  94.                 $this->imageProcessing($result$uploadConfig);
  95.                 $result->setPreviewUrl($this->getPreviewUrl($uploadConfig$result->getRemoteName()));
  96.             } else {
  97.                 // ファイル保存
  98.                 $img Image::make($file);
  99.                 $result->setImgSize($img->width(), $img->height());
  100.                 $img->destroy();
  101.                 $result->move();
  102.                 $result->setPreviewUrl($this->getPreviewUrl($uploadConfig$result->getRemoteName()));
  103.                 $result->setIsImage(true);
  104.             }
  105.         } else {
  106.             // ファイル保存
  107.             $result->move();
  108.             $result->setPreviewUrl($this->getPreviewUrl($uploadConfig$result->getRemoteName()));
  109.             $result->setIsImage(false);
  110.         }
  111.         return $result;
  112.     }
  113.     protected function getPreviewUrl(array $config$remoteFile) {
  114.         return $this->container->getParameter('image.admin.preview_url').
  115.                 str_replace("\\""-"$config['fileClass']).
  116.                 "/".
  117.                 $remoteFile;
  118.     }
  119.     public function getUploadDir(array $uploadConfig) {
  120.         if(!isset($uploadConfig['upload_dir'])) {
  121.             throw new \InvalidArgumentException('UploadDir parameter not found in Cms Upload config. check Entity property $uploadConfig');
  122.         }
  123.         // remote upload dir
  124.         $uploadDir $this->container->getParameter('cms_upload_dir');
  125.         $uploadDir .= "/"$uploadConfig['upload_dir'];
  126.         if(!preg_match("/\/$/"$uploadDir)) {
  127.             $uploadDir .= "/";
  128.         }
  129.         if(!$this->filesystem->exists($uploadDir)) {
  130.             $this->filesystem->mkdir($uploadDir0755);
  131.         }
  132.         return $uploadDir;
  133.     }
  134.     public function isImageMime($mime) {
  135.         if($mime instanceof UploadedFile) {
  136.             $mime $mime->getMimeType();
  137.         }
  138.         $imageMime $this->container->getParameter('image.mime');
  139.         return (in_array($mime$imageMimetrue));
  140.     }
  141.     public function isPdf($mime) {
  142.         return $mime === "application/pdf";
  143.     }
  144.     protected function moveFile(UploadedFile $file$dir$newName) {
  145.         $file->move($dir$newName);
  146.         return null;
  147.     }
  148.     public function imageProcessing(Result $result, array $config) {
  149.         $img Image::make($result->getfile());
  150.         foreach($config["image_process"] as $method => $value) {
  151.             switch($method) {
  152.             case "orientate":
  153.                 $img->orientate();break;
  154.             case "fit":
  155.                 $img->fit($value[0], $value[1], function($constraint) {
  156.                     $constraint->upsize();
  157.                 });break;
  158.             case "resize":
  159.                 $img->resize($value[0], $value[1], function($constraint) {
  160.                     $constraint->aspectRatio();
  161.                     $constraint->upsize();
  162.                 });
  163.                 break;
  164.             case "resize_canvas":
  165.                 $value[2] = isset($value[2])? $value[2]: "center";
  166.                 $value[3] = isset($value[3])? $value[3]: false;
  167.                 $value[4] = isset($value[4])? $value[4]: null;
  168.                 $this->logger->info(print_r($valuetrue));
  169.                 $img->resizeCanvas($value[0], $value[1], $value[2], $value[3], $value[4]);
  170.                 break;
  171.             case "limit":
  172.                 $w $img->width();
  173.                 $h $img->height();
  174.                 $doTrim false;
  175.                 // はみ出ている場合のみトリム
  176.                 if($w $value[0]) {
  177.                     $toWidth $value[0];
  178.                     $doTrim true;
  179.                 } else {
  180.                     $toWidth $w;
  181.                 }
  182.                 if($h $value[1]) {
  183.                     $toHeight $value[1];
  184.                     $doTrim true;
  185.                 } else {
  186.                     $toHeight $h;
  187.                 }
  188.                 if($doTrim) {
  189.                     $img->resizeCanvas($toWidth$toHeight);
  190.                 }
  191.                 break;
  192.             case "callback":
  193.                 call_user_func($value$img$result);break;
  194.             case "thumb":
  195.                 $thumb Image::make($result->getFile());
  196.                 $thumb->orientate();
  197.                 $thumb->fit($value[0], $value[1], function($constraint) {
  198.                     $constraint->upsize();
  199.                 });
  200.                 $thumbFilePath $result->createThumbFilename();
  201.                 $thumb->save($thumbFilePath);
  202.                 $thumb->save($result->createThumbFilename("webp"), null"webp");
  203.                 $thumb->destroy();
  204.                 $result->setThumbName($thumbFilePath);
  205.                 $result->setThumbPreviewUrl(
  206.                     $this->getPreviewUrl($config$result->getThumbName())
  207.                 );
  208.                 break;
  209.             case "thumb_resize":
  210.                 $thumb Image::make($result->getFile());
  211.                 $thumb->orientate();
  212.                 $thumb->resize($value[0], $value[1], function($constraint) {
  213.                     $constraint->aspectRatio();
  214.                 });
  215.                 $color = (isset($value[2]))? $value[2]: null;
  216.                 $thumb->resizeCanvas($value[0], $value[1], "center"false,$color);
  217.                 $thumbFilePath $result->createThumbFilename();
  218.                 $thumb->save($thumbFilePath);
  219.                 $thumb->save($result->createThumbFilename("webp"), null"webp");
  220.                 $thumb->destroy();
  221.                 $result->setThumbName($thumbFilePath);
  222.                 $result->setThumbPreviewUrl(
  223.                     $this->getPreviewUrl($config$result->getThumbName())
  224.                 );
  225.                 break;
  226.             }
  227.         }
  228.         $result->setImgSize($img->width(), $img->height());
  229.         $result->setIsImage(true);
  230.         $remoteName $result->getRemotePath();
  231.         $img->save($remoteName);
  232.         $img->save($result->getRemotePathWithoutExtension(). ".webp"null'webp');
  233.         $img->destroy();
  234.     }
  235.     protected function createPdfThumb(Result $result) {
  236.     }
  237.     /**
  238.      * ファイルを出力する
  239.      *
  240.      * @param string $filename
  241.      * @param array $config     self::getUploadedConfig()で取得した配列
  242.      * @return BinaryFileResponse
  243.      */
  244.     public function output($filename$config) {
  245.         $uploadDir $this->getUploadDir($config);
  246.         $path $uploadDir$filename;
  247.         $fs = new FileSystem;
  248.         if(!$fs->exists($path)) {
  249.             throw new NotFoundHttpException('file not found.'$path);
  250.         }
  251.         return new BinaryFileResponse($path);
  252.     }
  253.     public function outputResponseOrWebpResponse($filename$config): Response
  254.     {
  255.         $dir $this->getUploadDir($config);
  256.         $targetFile $dir $filename;
  257.         $file = new File($targetFile);
  258.         $acceptHeader AcceptHeader::fromString($this->request->headers->get('accept'));
  259.         if(!$acceptHeader->has('image/webp')) {
  260.             return new BinaryFileResponse($targetFile);
  261.         }
  262.         $guessExtension $file->guessExtension();
  263.         switch(strtolower($guessExtension)) {
  264.             case "webp":
  265.                 return new BinaryFileResponse($targetFile);
  266.             case "jpg":
  267.             case "jpeg":
  268.             case "png":
  269.                 $webpPath $dirbasename($targetFile"."$guessExtension). ".webp";
  270.                 $fs = new Filesystem();
  271.                 if($fs->exists($webpPath)) {
  272.                     return new BinaryFileResponse($webpPath);
  273.                 }
  274.                 break;
  275.         }
  276.         return new BinaryFileResponse($targetFile);
  277.     }
  278.     /**
  279.      * アップロード済のファイルのwidget用のデータを返す
  280.      *
  281.      * @param string $filename
  282.      * @param array $config     self::getUploadedConfig()で取得した配列
  283.      * @return array
  284.      */
  285.     public function getUploadedValue($filename$config) {
  286.         $uploadDir $this->getUploadDir($config);
  287.         $fs = new FileSystem();
  288.         // remote file
  289.         if(!$fs->exists($uploadDir $filename)) {
  290.             throw new \InvalidArgumentException('File not found.');
  291.         }
  292.         $file = new UploadedFile($uploadDir$filename$filename);
  293.         $isImage $this->isImageMime($file->getMimeType());
  294.         $thumb_prev null;
  295.         if($isImage) {
  296.             $thumbName preg_replace("/(.[a-z]{3,4})$/"""$filename);
  297.             if($fs->exists($uploadDir$thumbName)) {
  298.                 $thumb_prev $this->getPreviewUrl($config$thumbName);
  299.             }
  300.         }
  301.         return [
  302.             "status" => "200",
  303.             "is_image" => $isImage,
  304.             "preview_url" => $this->getPreviewUrl($config$filename),
  305.             "thumb_preview_url" => $thumb_prev,
  306.         ];
  307.     }
  308. }