* * 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; }*/ }