]> Raphaël G. Git Repositories - packbundle/commitdiff
Add file util class
authorRaphaël Gertz <git@rapsys.eu>
Mon, 13 Oct 2025 13:28:59 +0000 (15:28 +0200)
committerRaphaël Gertz <git@rapsys.eu>
Mon, 13 Oct 2025 13:28:59 +0000 (15:28 +0200)
Util/FileUtil.php [new file with mode: 0644]

diff --git a/Util/FileUtil.php b/Util/FileUtil.php
new file mode 100644 (file)
index 0000000..814892e
--- /dev/null
@@ -0,0 +1,309 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Rapsys PackBundle package.
+ *
+ * (c) Raphaël Gertz <symfony@rapsys.eu>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Rapsys\PackBundle\Util;
+
+use Psr\Container\ContainerInterface;
+
+use Rapsys\PackBundle\RapsysPackBundle;
+use Rapsys\PackBundle\Util\ImageUtil;
+use Rapsys\PackBundle\Util\IntlUtil;
+use Rapsys\PackBundle\Util\SluggerUtil;
+
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+/**
+ * Manages file informations
+ */
+class FileUtil {
+       /**
+        * Alias string
+        */
+       protected string $alias;
+
+       /**
+        * Config array
+        */
+       protected array $config;
+
+       /**
+        * Creates a new file util
+        *
+        * @param ContainerInterface $container The container instance
+        * @param ImageUtil $image The ImageUtil instance
+        * @param IntlUtil $intl The IntlUtil instance
+        * @param RouterInterface $router The router instance
+        * @param SluggerUtil $slugger The SluggerUtil instance
+        * @param TranslatorInterface $translator The translator instance
+        */
+       public function __construct(protected ContainerInterface $container, protected ImageUtil $image, protected IntlUtil $intl, protected RouterInterface $router, protected SluggerUtil $slugger, protected TranslatorInterface $translator) {
+               //Retrieve config
+               $this->config = $container->getParameter($this->alias = RapsysPackBundle::getAlias());
+       }
+
+       /**
+        * Get file infos
+        *
+        * @param string $path The base path
+        * @param string $realpath The real path
+        * @param string $name The route name
+        * @param array $parameters The route parameters
+        * @param bool $si Use si unit
+        */
+       public function getFile(string $path, string $realpath, string $name, array $parameters = [], bool $si = true): array {
+               //Set file
+               $file = new \SplFileObject($realpath);
+
+               //Set size
+               $size = $file->getSize();
+
+               //Set unit
+               $unit = $si ? 1000 : 1024;
+
+               //Set index
+               $index = [ '', $si ? 'k' : 'K', 'M', 'G', 'T', 'P', 'E' ];
+
+               //Get exp
+               $exp = intval((log($size) / log($unit)));
+
+               //Rebase number
+               $number = round($size / pow($unit, $exp), 2);
+
+               //Set ext, height, image, mime, preview, thumb and width
+               $ext = $height = $image = $mime = $preview = $thumb = $width = false;
+
+               //With supporter format extension
+               if (($pos = strrpos($realpath, '.')) && ($ext = substr($realpath, $pos + 1)) && in_array($ext, $this->config['formats'])) {
+                       //With mime type
+                       //XXX: getimagesize is too slow to run against all files
+                       if (($image = getimagesize($realpath)) !== false) {
+                               //Set ext
+                               if (($ext = image_type_to_extension($image[2], false)) === false) {
+                                       //Throw error
+                                       throw new \Exception(sprintf('Unable to get "%s" file image extension', $realpath));
+                               }
+
+                               //Set height
+                               $height = $image[1];
+
+                               //Set mime
+                               $mime = image_type_to_mime_type($image[2]);
+
+                               //Set width
+                               $width = $image[0];
+
+                               //Set preview
+                               $preview = $this->image->getThumb($realpath, $height, $width, $ext);
+
+                               //Set preview
+                               $thumb = $this->image->getThumb($realpath, $this->config['thumb']['height'], $this->config['thumb']['weight'], $ext);
+                       }
+               }
+
+               //Return file infos
+               return [
+                       'created' => (new \DateTime())->setTimestamp($file->getCTime()),
+                       'height' => $height,
+                       'intlsize' => $intlsize = $this->intl->number($number),
+                       'intlunit' => $intlunit = $this->translator->trans($index[$exp].($si ? '' : 'i').'B'),
+                       'link' => $this->router->generate($name, ['path' => substr($realpath, strlen($path) + 1)] + $parameters),
+                       'download' => $this->router->generate('rapsyspack_download', ['path' => $short = $this->slugger->short($realpath), 'hash' => $this->slugger->hash($short), 'u' => $mtime = $file->getMTime()]),
+                       'mime' => $mime,
+                       'modified' => (new \DateTime())->setTimestamp($mtime),
+                       'name' => basename($realpath).' ('.$intlsize.' '.$intlunit.')',
+                       'preview' => $preview,
+                       'size' => $size,
+                       'thumb' => $thumb,
+                       'width' => $width,
+                       //TODO: preview for images ?
+                       //TODO: extra fields ? (preview, miniature, etc ?)
+                       //TODO: mimetype decided extra fields ? (.pdf for doc, webm preview, img preview, etc ?)
+                       //TODO: XXX: finish this !!!
+               ];
+       }
+
+       /**
+        * Get path infos
+        *
+        * @param string $path The base path
+        * @param string $realpath The real path
+        * @param string $name The route name
+        * @param array $parameters The route parameters
+        * @param bool $si Use si unit
+        */
+       //Route object instead of shitty array ?
+       public function getInfos(string $path, string $realpath, string $slug, string $name, array $parameters = []) {
+               //Set result
+               $result = [
+                       'breadcrumbs' => [/*$breadcrumb*/],
+                       'directories' => [],
+                       'file' => [],
+                       'files' => [],
+               ];
+
+               //Set base
+               $base = '';
+
+               //Iterate on breadcrumbs
+               foreach (explode('/', substr($realpath, strlen($path))) as $value) {
+                       $result['breadcrumbs'][] = [
+                               'name' => $value ? '/ '.$value : $slug,
+                               'link' => $this->router->generate($name, ['path' => ($base .= ($base == '' ? '' : '/').$value)] + $parameters)
+                       ];
+               }
+
+               //With file
+               if (is_file($realpath)) {
+                       //Set file
+                       $result['file'] = $this->getFile($path, $realpath, $name, $parameters);
+               //With directory
+               //TODO: for pagination, files and directories are to be placed in a single array
+               //TODO: only get informations on files and directories inside the pagination window !
+               } elseif (is_dir($realpath)) {
+                       //Set dir
+                       $dir = dir($realpath);
+
+                       //Iterate on directory
+                       while (($item = $dir->read()) !== false) {
+                               //Skip ., .., .git, .svn, .htpasswd, .htgroup and .*.un~ items
+                               //TODO: set this regexp in config ?
+                               if (preg_match('/^(\.|\.\.|\.git|\.svn|\.ht(access|passwd|group)|\..*\.un~)$/', $item)) {
+                                       //Skip it
+                                       continue;
+                               }
+
+                               //Check item
+                               if (
+                                       //Without item realpath
+                                       !($itempath = realpath($realpath.'/'.$item)) ||
+                                       //Item realpath not matching album path
+                                       //XXX: skip files outside of album/element path (symlink outside of tree)
+                                       //TODO: make it configurable ? by album/element/admin ?
+                                       $path !== substr($itempath, 0, strlen($path))
+                               ) {
+                                       //Skip it
+                                       continue;
+                               }
+
+                               //With directory
+                               if (is_dir($itempath)) {
+                                       //Append directory
+                                       //TODO: use this structure or revert to old $item.'/' => $link form
+                                       $result['directories'][] = [
+                                               'name' => $item.'/',
+                                               'link' => $this->router->generate($name, ['path' => substr($itempath, strlen($path) + 1)] + $parameters)
+                                               //TODO: add stats here ? like number of files ?
+                                       ];
+                               //With file
+                               } elseif (is_file($itempath)) {
+                                       //Set file
+                                       $result['files'][] = $this->getFile($path, $itempath, $name, $parameters);
+                               //With unknown type
+                               } else {
+                                       //Throw 404
+                                       throw new \Exception(sprintf('Unknown file "%s" type', $itempath));
+                               }
+                       }
+               //With unknown type
+               } else {
+                       //Throw 404
+                       throw new \Exception(sprintf('Unknown file "%s" type', $realpath));
+               }
+
+               //Return result
+               return $result;
+       }
+
+       /**
+        * Get file infos
+        *
+        * @param string $path The file path
+        * @param bool $si Use si units
+        * @return array The file infos
+        * /
+       public function infos(string $path, bool $si = true): array {
+               //Stat file
+               $stat = stat($path);
+
+               //Set unit
+               $unit = $si ? 1000 : 1024;
+
+               //Set index
+               $index = [ '', $si ? 'k' : 'K', 'M', 'G', 'T', 'P', 'E' ];
+
+               //Get exp
+               $exp = intval((log($stat['size']) / log($unit)));
+
+               //Rebase number
+               $number = round($stat['size'] / pow($unit, $exp), 2);
+
+               //Set file infos
+               $fileinfos = [
+                       'intlsize' => $intlsize = $this->intl->number($number),
+                       'intlunit' => $intlunit = $this->translator->trans($index[$exp].($si ? '' : 'i').'B'),
+                       'name' => basename($path).' ('.$intlsize.' '.$intlunit.')',
+                       'size' => $stat['size'],
+                       'ctime' => $stat['ctime'],
+                       'mtime' => $stat['mtime'],
+                       //TODO: preview for images ?
+                       //TODO: extra fields ? (preview, miniature, etc ?)
+                       //TODO: mimetype decided extra fields ? (.pdf for doc, webm preview, img preview, etc ?)
+                       //TODO: XXX: finish this !!!
+               ];
+
+               //With mimetype
+               if (($mimetype = mime_content_type($path)) !== false) {
+                       //Set file mimetype
+                       $fileinfos['mimetype'] = $mimetype;
+
+                       //TODO: with image preview, movie webm preview, others a imagemagick file with format initials ?
+
+                       //With image
+                       if (
+                               $mimetype == 'image/jpeg' ||
+                               $mimetype == 'image/png' ||
+                               $mimetype == 'image/bmp' ||
+                               $mimetype == 'image/tiff' ||
+                               $mimetype == 'image/svg+xml'
+                       ) {
+                               //Get image width and height
+                               if (($fileinfos['image'] = getimagesize($path)) === false) {
+                                       //Throw error
+                                       throw new \Exception(sprintf('Unable to get "%s" file image size', $path));
+                               }
+
+                               //Set thumb
+                               $fileinfos['thumb'] = $this->image->getThumb($path, 64, 64);
+                       }
+               }
+               /*
+                       'src' => 
+                               //With location user source image
+                               if (($isFile = is_file($source = $this->config['path'].'/location/'.$location['id'].'/'.$id.'.png')) && ($mtime = stat($source)['mtime'])) {
+                                       //Set location image
+                                       $this->context['locations'][$locationId]['image'] = $this->image->getThumb($location['miniature'], $mtime, $source);
+
+                       //With image mimetype
+                       if (in_array($fileinfos['mimetype'], [ 'image/jpeg', 'image/png', 'image/webp' ])) {
+                               header('Content-Type: text/plain');
+                               var_dump($fileinfos);
+                               exit;
+                               $file['thumb'] = $this->router->generate('rapsyspack_thumb', [ 'hash' => $this->slugger->hash(''), 'path' => $path, 'slug' => $slug ]);
+                               #public function thumb(Request $request, string $hash, int $updated, string $path, int $width, int $height): Response {
+                       }
+                * /
+
+               //Return file infos
+               return $fileinfos;
+       }*/
+}