vendor/pimcore/pimcore/models/Asset/Thumbnail/ImageThumbnailTrait.php line 117

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\Asset\Thumbnail;
  15. use Pimcore\Helper\TemporaryFileHelperTrait;
  16. use Pimcore\Model\Asset;
  17. use Pimcore\Model\Asset\Image;
  18. use Pimcore\Model\Asset\Image\Thumbnail\Config;
  19. use Pimcore\Tool;
  20. use Pimcore\Tool\Storage;
  21. use Symfony\Component\Mime\MimeTypes;
  22. trait ImageThumbnailTrait
  23. {
  24.     use TemporaryFileHelperTrait;
  25.     /**
  26.      * @internal
  27.      *
  28.      * @var Asset|null
  29.      */
  30.     protected $asset;
  31.     /**
  32.      * @internal
  33.      *
  34.      * @var Config|null
  35.      */
  36.     protected $config;
  37.     /**
  38.      * @internal
  39.      *
  40.      * @var array
  41.      */
  42.     protected array $pathReference = [];
  43.     /**
  44.      * @internal
  45.      *
  46.      * @var int|null
  47.      */
  48.     protected $width;
  49.     /**
  50.      * @internal
  51.      *
  52.      * @var int|null
  53.      */
  54.     protected $height;
  55.     /**
  56.      * @internal
  57.      *
  58.      * @var int|null
  59.      */
  60.     protected $realWidth;
  61.     /**
  62.      * @internal
  63.      *
  64.      * @var int|null
  65.      */
  66.     protected $realHeight;
  67.     /**
  68.      * @internal
  69.      *
  70.      * @var string
  71.      */
  72.     protected $mimetype;
  73.     /**
  74.      * @internal
  75.      *
  76.      * @var bool
  77.      */
  78.     protected $deferred true;
  79.     private static array $supportedFormats = [];
  80.     /**
  81.      * @return null|resource
  82.      */
  83.     public function getStream()
  84.     {
  85.         $pathReference $this->getPathReference(false);
  86.         if ($pathReference['type'] === 'asset') {
  87.             return $this->asset->getStream();
  88.         } elseif (isset($pathReference['storagePath'])) {
  89.             return Tool\Storage::get('thumbnail')->readStream($pathReference['storagePath']);
  90.         }
  91.         return null;
  92.     }
  93.     public function getPathReference(bool $deferredAllowed false): array
  94.     {
  95.         if (!$deferredAllowed && (($this->pathReference['type'] ?? '') === 'deferred')) {
  96.             $this->pathReference = [];
  97.         }
  98.         if (empty($this->pathReference)) {
  99.             $this->generate($deferredAllowed);
  100.         }
  101.         return $this->pathReference;
  102.     }
  103.     /**
  104.      * @internal
  105.      */
  106.     public function reset()
  107.     {
  108.         $this->pathReference = [];
  109.         $this->width null;
  110.         $this->height null;
  111.         $this->realHeight null;
  112.         $this->realWidth null;
  113.     }
  114.     /**
  115.      * @return int|null
  116.      */
  117.     public function getWidth()
  118.     {
  119.         if (!$this->width) {
  120.             $this->getDimensions();
  121.         }
  122.         return $this->width;
  123.     }
  124.     /**
  125.      * @return int|null
  126.      */
  127.     public function getHeight()
  128.     {
  129.         if (!$this->height) {
  130.             $this->getDimensions();
  131.         }
  132.         return $this->height;
  133.     }
  134.     /**
  135.      * @return int|null
  136.      */
  137.     public function getRealWidth()
  138.     {
  139.         if (!$this->realWidth) {
  140.             $this->getDimensions();
  141.         }
  142.         return $this->realWidth;
  143.     }
  144.     /**
  145.      * @return int|null
  146.      */
  147.     public function getRealHeight()
  148.     {
  149.         if (!$this->realHeight) {
  150.             $this->getDimensions();
  151.         }
  152.         return $this->realHeight;
  153.     }
  154.     /**
  155.      * @internal
  156.      *
  157.      * @return array{width?: int, height?: int}
  158.      */
  159.     public function readDimensionsFromFile(): array
  160.     {
  161.         $dimensions = [];
  162.         $pathReference $this->getPathReference();
  163.         if (in_array($pathReference['type'], ['thumbnail''asset'])) {
  164.             try {
  165.                 $localFile $this->getLocalFile();
  166.                 if (null !== $localFile && isset($pathReference['storagePath']) && $config $this->getConfig()) {
  167.                     $asset $this->getAsset();
  168.                     $filename basename($pathReference['storagePath']);
  169.                     $asset->addThumbnailFileToCache(
  170.                         $localFile,
  171.                         $filename,
  172.                         $config
  173.                     );
  174.                     $thumbnail $asset->getDao()->getCachedThumbnail($config->getName(), $filename);
  175.                     if (isset($thumbnail['width'], $thumbnail['height'])) {
  176.                         $dimensions['width'] = $thumbnail['width'];
  177.                         $dimensions['height'] = $thumbnail['height'];
  178.                     }
  179.                 }
  180.             } catch (\Exception $e) {
  181.                 // noting to do
  182.             }
  183.         }
  184.         return $dimensions;
  185.     }
  186.     /**
  187.      * @return array{width: ?int, height: ?int}
  188.      */
  189.     public function getDimensions()
  190.     {
  191.         if (!$this->width || !$this->height) {
  192.             $config $this->getConfig();
  193.             $asset $this->getAsset();
  194.             $dimensions = [];
  195.             if ($config) {
  196.                 $thumbnail $asset->getDao()->getCachedThumbnail($config->getName(), $this->getFilename());
  197.                 if (isset($thumbnail['width'], $thumbnail['height'])) {
  198.                     $dimensions['width'] = $thumbnail['width'];
  199.                     $dimensions['height'] = $thumbnail['height'];
  200.                 }
  201.             }
  202.             if (empty($dimensions) && $this->exists()) {
  203.                 $dimensions $this->readDimensionsFromFile();
  204.             }
  205.             // try to calculate the final dimensions based on the thumbnail configuration
  206.             if (empty($dimensions) && $config && $asset instanceof Image) {
  207.                 $dimensions $config->getEstimatedDimensions($asset);
  208.             }
  209.             if (empty($dimensions)) {
  210.                 // unable to calculate dimensions -> use fallback
  211.                 // generate the thumbnail and get dimensions from the thumbnail file
  212.                 $dimensions $this->readDimensionsFromFile();
  213.             }
  214.             // realWidth / realHeight is only relevant if using high-res option (retina, ...)
  215.             $this->width $this->realWidth $dimensions['width'] ?? null;
  216.             $this->height $this->realHeight $dimensions['height'] ?? null;
  217.             if ($config && $config->getHighResolution() > 1) {
  218.                 if ($this->width) {
  219.                     $this->width = (int)floor($this->realWidth $config->getHighResolution());
  220.                 }
  221.                 if ($this->height) {
  222.                     $this->height = (int)floor($this->realHeight $config->getHighResolution());
  223.                 }
  224.             }
  225.         }
  226.         return [
  227.             'width' => $this->width,
  228.             'height' => $this->height,
  229.         ];
  230.     }
  231.     /**
  232.      * @return Asset
  233.      */
  234.     public function getAsset()
  235.     {
  236.         return $this->asset;
  237.     }
  238.     /**
  239.      * @return Config|null
  240.      */
  241.     public function getConfig()
  242.     {
  243.         return $this->config;
  244.     }
  245.     /**
  246.      * @return string
  247.      */
  248.     public function getMimeType()
  249.     {
  250.         if (!$this->mimetype) {
  251.             $pathReference $this->getPathReference(true);
  252.             if ($pathReference['type'] === 'data-uri') {
  253.                 $this->mimetype substr($pathReference['src'], 5strpos($pathReference['src'], ';') - 5);
  254.             } else {
  255.                 $fileExt $this->getFileExtension();
  256.                 $mimeTypes MimeTypes::getDefault()->getMimeTypes($fileExt);
  257.                 if (!empty($mimeTypes)) {
  258.                     $this->mimetype $mimeTypes[0];
  259.                 } else {
  260.                     // unknown
  261.                     $this->mimetype 'application/octet-stream';
  262.                 }
  263.             }
  264.         }
  265.         return $this->mimetype;
  266.     }
  267.     /**
  268.      * @return string
  269.      */
  270.     public function getFileExtension()
  271.     {
  272.         return \Pimcore\File::getFileExtension($this->getPath());
  273.     }
  274.     /**
  275.      * TODO: Pimcore 11: remove convertArgsBcLayer method (BC layer)
  276.      *
  277.      * @param array $args
  278.      *
  279.      * @return array
  280.      */
  281.     protected function convertArgsBcLayer($args)
  282.     {
  283.         $totalArgs count($args);
  284.         if ($totalArgs 0) {
  285.             if (is_array($args[0])) {
  286.                 return $args[0];
  287.             }
  288.             trigger_deprecation('pimcore/pimcore''10.6',
  289.                 'Calling the getPath() method with arguments is deprecated since version 10.6 and will be removed in Pimcore 11.
  290.             Use an array with options (e.g. ->getPath(["deferredAllowed" => true, "cacheBuster" => false]))');
  291.             if ($totalArgs === 1) {
  292.                 return [
  293.                     'deferredAllowed' => $args[0],
  294.                 ];
  295.             }
  296.             return [
  297.                 'deferredAllowed' => $args[0],
  298.                 'cacheBuster' => $args[1],
  299.             ];
  300.         }
  301.         return [];
  302.     }
  303.     /**
  304.      * @internal
  305.      *
  306.      * @param array $pathReference
  307.      * @param bool $frontend
  308.      *
  309.      * @return string|null
  310.      */
  311.     protected function convertToWebPath(array $pathReferencebool $frontend): ?string
  312.     {
  313.         $type $pathReference['type'] ?? null;
  314.         $path $pathReference['src'] ?? null;
  315.         if ($frontend) {
  316.             if ($type === 'data-uri') {
  317.                 return $path;
  318.             } elseif ($type === 'deferred') {
  319.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail_deferred'];
  320.                 $path $prefix urlencode_ignore_slash($path);
  321.             } elseif ($type === 'thumbnail') {
  322.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['thumbnail'];
  323.                 $path $prefix urlencode_ignore_slash($path);
  324.             } elseif ($type === 'asset') {
  325.                 $prefix \Pimcore::getContainer()->getParameter('pimcore.config')['assets']['frontend_prefixes']['source'];
  326.                 $path $prefix urlencode_ignore_slash($path);
  327.             } else {
  328.                 $path urlencode_ignore_slash($path);
  329.             }
  330.         }
  331.         return $path;
  332.     }
  333.     /**
  334.      * @return string
  335.      */
  336.     public function getFrontendPath(): string
  337.     {
  338.         $path $this->getPath(['deferredAllowed' => true'frontend' => true]);
  339.         if (!\preg_match('@^(https?|data):@'$path)) {
  340.             $path \Pimcore\Tool::getHostUrl() . $path;
  341.         }
  342.         return $path;
  343.     }
  344.     /**
  345.      * @internal
  346.      *
  347.      * @return string|null
  348.      *
  349.      * @throws \Exception
  350.      */
  351.     public function getLocalFile()
  352.     {
  353.         $stream $this->getStream();
  354.         if (null === $stream) {
  355.             return null;
  356.         }
  357.         $localFile self::getLocalFileFromStream($stream);
  358.         @fclose($stream);
  359.         return $localFile;
  360.     }
  361.     /**
  362.      * @return bool
  363.      */
  364.     public function exists(): bool
  365.     {
  366.         $pathReference $this->getPathReference(true);
  367.         $type $pathReference['type'] ?? '';
  368.         if (
  369.             $type === 'asset' ||
  370.             $type === 'data-uri' ||
  371.             $type === 'thumbnail'
  372.         ) {
  373.             return true;
  374.         } elseif ($type === 'deferred') {
  375.             return false;
  376.         } elseif (isset($pathReference['storagePath'])) {
  377.             // this is probably redundant, but as it doesn't hurt we can keep it
  378.             return $this->existsOnStorage($pathReference);
  379.         }
  380.         return false;
  381.     }
  382.     /**
  383.      * @internal
  384.      *
  385.      * @param array|null $pathReference
  386.      *
  387.      * @return bool
  388.      *
  389.      * @throws \League\Flysystem\FilesystemException
  390.      */
  391.     public function existsOnStorage(?array $pathReference = []): bool
  392.     {
  393.         $pathReference ??= $this->getPathReference(true);
  394.         if (isset($pathReference['storagePath'])) {
  395.             // this is probably redundant, but as it doesn't hurt we can keep it
  396.             return Storage::get('thumbnail')->fileExists($pathReference['storagePath']);
  397.         }
  398.         return false;
  399.     }
  400.     public static function supportsFormat(string $format): bool
  401.     {
  402.         if (!isset(self::$supportedFormats[$format])) {
  403.             self::$supportedFormats[$format] = \Pimcore\Image::getInstance()->supportsFormat($format);
  404.         }
  405.         return self::$supportedFormats[$format];
  406.     }
  407.     public function getFileSize(): ?int
  408.     {
  409.         $thumbnail $this->getAsset()->getDao()->getCachedThumbnail($this->getConfig()->getName(), $this->getFilename());
  410.         if ($thumbnail && $thumbnail['filesize']) {
  411.             return $thumbnail['filesize'];
  412.         }
  413.         $pathReference $this->getPathReference(false);
  414.         if ($pathReference['type'] === 'asset') {
  415.             return $this->asset->getFileSize();
  416.         } elseif (isset($pathReference['storagePath'])) {
  417.             return Tool\Storage::get('thumbnail')->fileSize($pathReference['storagePath']);
  418.         }
  419.         return null;
  420.     }
  421.     private function getFilename(): string
  422.     {
  423.         $pathReference $this->getPathReference(true);
  424.         return basename($pathReference['src']);
  425.     }
  426.     /**
  427.      * Returns path for thumbnail image in a given file format
  428.      *
  429.      * @param string $format
  430.      *
  431.      * @return static
  432.      */
  433.     public function getAsFormat(string $format): static
  434.     {
  435.         $thumb = clone $this;
  436.         $config $thumb->getConfig() ? clone $thumb->getConfig() : new Config();
  437.         $config->setFormat($format);
  438.         $thumb->config $config;
  439.         $thumb->reset();
  440.         return $thumb;
  441.     }
  442. }