]> Raphaël G. Git Repositories - packbundle/blob - Util/FileUtil.php
Version 0.5.7
[packbundle] / Util / FileUtil.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys PackBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\PackBundle\Util;
13
14 use Psr\Container\ContainerInterface;
15
16 use Rapsys\PackBundle\RapsysPackBundle;
17 use Rapsys\PackBundle\Util\ImageUtil;
18 use Rapsys\PackBundle\Util\IntlUtil;
19 use Rapsys\PackBundle\Util\SluggerUtil;
20
21 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
22 use Symfony\Component\Routing\RouterInterface;
23 use Symfony\Contracts\Translation\TranslatorInterface;
24
25 /**
26 * Manages file informations
27 */
28 class FileUtil {
29 /**
30 * Alias string
31 */
32 protected string $alias;
33
34 /**
35 * Config array
36 */
37 protected array $config;
38
39 /**
40 * Creates a new file util
41 *
42 * @param ContainerInterface $container The container instance
43 * @param ImageUtil $image The ImageUtil instance
44 * @param IntlUtil $intl The IntlUtil instance
45 * @param RouterInterface $router The router instance
46 * @param SluggerUtil $slugger The SluggerUtil instance
47 * @param TranslatorInterface $translator The translator instance
48 */
49 public function __construct(protected ContainerInterface $container, protected ImageUtil $image, protected IntlUtil $intl, protected RouterInterface $router, protected SluggerUtil $slugger, protected TranslatorInterface $translator) {
50 //Retrieve config
51 $this->config = $container->getParameter($this->alias = RapsysPackBundle::getAlias());
52 }
53
54 /**
55 * Get file infos
56 *
57 * @param string $path The base path
58 * @param string $realpath The real path
59 * @param string $name The route name
60 * @param array $parameters The route parameters
61 * @param bool $si Use si unit
62 */
63 public function getFile(string $path, string $realpath, string $name, array $parameters = [], bool $si = true): array {
64 //Set file
65 $file = new \SplFileObject($realpath);
66
67 //Set size
68 $size = $file->getSize();
69
70 //Set unit
71 $unit = $si ? 1000 : 1024;
72
73 //Set index
74 $index = [ '', $si ? 'k' : 'K', 'M', 'G', 'T', 'P', 'E' ];
75
76 //Get exp
77 $exp = intval((log($size) / log($unit)));
78
79 //Rebase number
80 $number = round($size / pow($unit, $exp), 2);
81
82 //Set ext, height, image, mime, preview, thumb and width
83 $ext = $height = $image = $mime = $preview = $thumb = $width = false;
84
85 //With supporter format extension
86 if (($pos = strrpos($realpath, '.')) && ($ext = substr($realpath, $pos + 1)) && in_array($ext, $this->config['formats'])) {
87 //With mime type
88 //XXX: getimagesize is too slow to run against all files
89 if (($image = getimagesize($realpath)) !== false) {
90 //Set ext
91 if (($ext = image_type_to_extension($image[2], false)) === false) {
92 //Throw error
93 throw new \Exception(sprintf('Unable to get "%s" file image extension', $realpath));
94 }
95
96 //Set height
97 $height = $image[1];
98
99 //Set mime
100 $mime = image_type_to_mime_type($image[2]);
101
102 //Set width
103 $width = $image[0];
104
105 //Set preview
106 $preview = $this->image->getThumb($realpath, $height, $width, $ext);
107
108 //Set preview
109 $thumb = $this->image->getThumb($realpath, $this->config['thumb']['height'], $this->config['thumb']['weight'], $ext);
110 }
111 }
112
113 //Return file infos
114 return [
115 'created' => (new \DateTime())->setTimestamp($file->getCTime()),
116 'height' => $height,
117 'intlsize' => $intlsize = $this->intl->number($number),
118 'intlunit' => $intlunit = $this->translator->trans($index[$exp].($si ? '' : 'i').'B'),
119 'link' => $this->router->generate($name, ['path' => substr($realpath, strlen($path) + 1)] + $parameters),
120 'download' => $this->router->generate('rapsyspack_download', ['path' => $short = $this->slugger->short($realpath), 'hash' => $this->slugger->hash($short), 'u' => $mtime = $file->getMTime()]),
121 'mime' => $mime,
122 'modified' => (new \DateTime())->setTimestamp($mtime),
123 'name' => basename($realpath).' ('.$intlsize.' '.$intlunit.')',
124 'preview' => $preview,
125 'size' => $size,
126 'thumb' => $thumb,
127 'width' => $width,
128 //TODO: preview for images ?
129 //TODO: extra fields ? (preview, miniature, etc ?)
130 //TODO: mimetype decided extra fields ? (.pdf for doc, webm preview, img preview, etc ?)
131 //TODO: XXX: finish this !!!
132 ];
133 }
134
135 /**
136 * Get path infos
137 *
138 * @param string $path The base path
139 * @param string $realpath The real path
140 * @param string $name The route name
141 * @param array $parameters The route parameters
142 * @param bool $si Use si unit
143 */
144 //Route object instead of shitty array ?
145 public function getInfos(string $path, string $realpath, string $slug, string $name, array $parameters = []) {
146 //Set result
147 $result = [
148 'breadcrumbs' => [/*$breadcrumb*/],
149 'directories' => [],
150 'file' => [],
151 'files' => [],
152 ];
153
154 //Set base
155 $base = '';
156
157 //Iterate on breadcrumbs
158 foreach (explode('/', substr($realpath, strlen($path))) as $value) {
159 $result['breadcrumbs'][] = [
160 'name' => $value ? '/ '.$value : $slug,
161 'link' => $this->router->generate($name, ['path' => ($base .= ($base == '' ? '' : '/').$value)] + $parameters)
162 ];
163 }
164
165 //With file
166 if (is_file($realpath)) {
167 //Set file
168 $result['file'] = $this->getFile($path, $realpath, $name, $parameters);
169 //With directory
170 //TODO: for pagination, files and directories are to be placed in a single array
171 //TODO: only get informations on files and directories inside the pagination window !
172 } elseif (is_dir($realpath)) {
173 //Set dir
174 $dir = dir($realpath);
175
176 //Iterate on directory
177 while (($item = $dir->read()) !== false) {
178 //Skip ., .., .git, .svn, .htpasswd, .htgroup and .*.un~ items
179 //TODO: set this regexp in config ?
180 if (preg_match('/^(\.|\.\.|\.git|\.svn|\.ht(access|passwd|group)|\..*\.un~)$/', $item)) {
181 //Skip it
182 continue;
183 }
184
185 //Check item
186 if (
187 //Without item realpath
188 !($itempath = realpath($realpath.'/'.$item)) ||
189 //Item realpath not matching album path
190 //XXX: skip files outside of album/element path (symlink outside of tree)
191 //TODO: make it configurable ? by album/element/admin ?
192 $path !== substr($itempath, 0, strlen($path))
193 ) {
194 //Skip it
195 continue;
196 }
197
198 //With directory
199 if (is_dir($itempath)) {
200 //Append directory
201 //TODO: use this structure or revert to old $item.'/' => $link form
202 $result['directories'][] = [
203 'name' => $item.'/',
204 'link' => $this->router->generate($name, ['path' => substr($itempath, strlen($path) + 1)] + $parameters)
205 //TODO: add stats here ? like number of files ?
206 ];
207 //With file
208 } elseif (is_file($itempath)) {
209 //Set file
210 $result['files'][] = $this->getFile($path, $itempath, $name, $parameters);
211 //With unknown type
212 } else {
213 //Throw 404
214 throw new \Exception(sprintf('Unknown file "%s" type', $itempath));
215 }
216 }
217 //With unknown type
218 } else {
219 //Throw 404
220 throw new \Exception(sprintf('Unknown file "%s" type', $realpath));
221 }
222
223 //Return result
224 return $result;
225 }
226
227 /**
228 * Get file infos
229 *
230 * @param string $path The file path
231 * @param bool $si Use si units
232 * @return array The file infos
233 * /
234 public function infos(string $path, bool $si = true): array {
235 //Stat file
236 $stat = stat($path);
237
238 //Set unit
239 $unit = $si ? 1000 : 1024;
240
241 //Set index
242 $index = [ '', $si ? 'k' : 'K', 'M', 'G', 'T', 'P', 'E' ];
243
244 //Get exp
245 $exp = intval((log($stat['size']) / log($unit)));
246
247 //Rebase number
248 $number = round($stat['size'] / pow($unit, $exp), 2);
249
250 //Set file infos
251 $fileinfos = [
252 'intlsize' => $intlsize = $this->intl->number($number),
253 'intlunit' => $intlunit = $this->translator->trans($index[$exp].($si ? '' : 'i').'B'),
254 'name' => basename($path).' ('.$intlsize.' '.$intlunit.')',
255 'size' => $stat['size'],
256 'ctime' => $stat['ctime'],
257 'mtime' => $stat['mtime'],
258 //TODO: preview for images ?
259 //TODO: extra fields ? (preview, miniature, etc ?)
260 //TODO: mimetype decided extra fields ? (.pdf for doc, webm preview, img preview, etc ?)
261 //TODO: XXX: finish this !!!
262 ];
263
264 //With mimetype
265 if (($mimetype = mime_content_type($path)) !== false) {
266 //Set file mimetype
267 $fileinfos['mimetype'] = $mimetype;
268
269 //TODO: with image preview, movie webm preview, others a imagemagick file with format initials ?
270
271 //With image
272 if (
273 $mimetype == 'image/jpeg' ||
274 $mimetype == 'image/png' ||
275 $mimetype == 'image/bmp' ||
276 $mimetype == 'image/tiff' ||
277 $mimetype == 'image/svg+xml'
278 ) {
279 //Get image width and height
280 if (($fileinfos['image'] = getimagesize($path)) === false) {
281 //Throw error
282 throw new \Exception(sprintf('Unable to get "%s" file image size', $path));
283 }
284
285 //Set thumb
286 $fileinfos['thumb'] = $this->image->getThumb($path, 64, 64);
287 }
288 }
289 /*
290 'src' =>
291 //With location user source image
292 if (($isFile = is_file($source = $this->config['path'].'/location/'.$location['id'].'/'.$id.'.png')) && ($mtime = stat($source)['mtime'])) {
293 //Set location image
294 $this->context['locations'][$locationId]['image'] = $this->image->getThumb($location['miniature'], $mtime, $source);
295
296 //With image mimetype
297 if (in_array($fileinfos['mimetype'], [ 'image/jpeg', 'image/png', 'image/webp' ])) {
298 header('Content-Type: text/plain');
299 var_dump($fileinfos);
300 exit;
301 $file['thumb'] = $this->router->generate('rapsyspack_thumb', [ 'hash' => $this->slugger->hash(''), 'path' => $path, 'slug' => $slug ]);
302 #public function thumb(Request $request, string $hash, int $updated, string $path, int $width, int $height): Response {
303 }
304 * /
305
306 //Return file infos
307 return $fileinfos;
308 }*/
309 }