Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
79 / 79
100.00% covered (success)
100.00%
31 / 31
CRAP
100.00% covered (success)
100.00%
1 / 1
File
100.00% covered (success)
100.00%
79 / 79
100.00% covered (success)
100.00%
31 / 31
53
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
7
 getMimeTypes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFileMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 formatFileSize
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 setBasename
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getBasename
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasBasename
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setFilename
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getFilename
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasFilename
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setExtension
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getExtension
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasExtension
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPath
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getPath
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasPath
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSize
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasSize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 formatSize
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
13
 setMimeType
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDefaultMimeType
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isDefaultMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllMimeTypes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 exists
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getContents
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 toArray
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Pop PHP Framework (https://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@noladev.com>
7 * @copyright  Copyright (c) 2009-2025 NOLA Interactive, LLC.
8 * @license    https://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Utils;
15
16/**
17 * Pop utils file helper class
18 *
19 * @category   Pop
20 * @package    Pop\Utils
21 * @author     Nick Sagona, III <dev@noladev.com>
22 * @copyright  Copyright (c) 2009-2025 NOLA Interactive, LLC.
23 * @license    https://www.popphp.org/license     New BSD License
24 * @version    2.1.0
25 */
26class File
27{
28
29    /**
30     * Basename (filename.ext)
31     * @var ?string
32     */
33    protected ?string $basename = null;
34
35    /**
36     * Filename (filename)
37     * @var ?string
38     */
39    protected ?string $filename = null;
40
41    /**
42     * Extension (.ext)
43     * @var ?string
44     */
45    protected ?string $extension = null;
46
47    /**
48     * Path (/some/path)
49     * @var ?string
50     */
51    protected ?string $path = null;
52
53    /**
54     * Size
55     * @var int
56     */
57    protected int $size = 0;
58
59    /**
60     * Mime type
61     * @var ?string
62     */
63    protected ?string $mimeType = null;
64
65    /**
66     * Mime types
67     * @var array
68     */
69    protected static array $mimeTypes = [
70        'avi'   => 'video/x-msvideo',
71        'bin'   => 'application/octet-stream',
72        'bmp'   => 'image/bmp',
73        'bz'    => 'application/x-bzip',
74        'bz2'   => 'application/x-bzip2',
75        'css'   => 'text/css',
76        'csv'   => 'text/csv',
77        'doc'   => 'application/msword',
78        'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
79        'gz'    => 'application/gzip',
80        'gif'   => 'image/gif',
81        'htm'   => 'text/html',
82        'html'  => 'text/html',
83        'ico'   => 'image/vnd.microsoft.icon',
84        'ics'   => 'text/calendar',
85        'jar'   => 'application/java-archive',
86        'jpe'   => 'image/jpeg',
87        'jpg'   => 'image/jpeg',
88        'jpeg'  => 'image/jpeg',
89        'js'    => 'text/javascript',
90        'json'  => 'application/json',
91        'jwt'   => 'application/jwt',
92        'log'   => 'text/plain',
93        'mid'   => 'audio/midi',
94        'midi'  => 'audio/midi',
95        'mp3'   => 'audio/mpeg',
96        'mp4'   => 'video/mp4',
97        'mpeg'  => 'video/mpeg',
98        'odp'   => 'application/vnd.oasis.opendocument.presentation',
99        'ods'   => 'application/vnd.oasis.opendocument.spreadsheet',
100        'odt'   => 'application/vnd.oasis.opendocument.text',
101        'oga'   => 'audio/ogg',
102        'ogv'   => 'video/ogg',
103        'ogx'   => 'application/ogg',
104        'otf'   => 'font/otf',
105        'png'   => 'image/png',
106        'pdf'   => 'application/pdf',
107        'php'   => 'application/x-httpd-php',
108        'ppt'   => 'application/vnd.ms-powerpoint',
109        'pptx'  => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
110        'psd'   => 'image/vnd.adobe.photoshop',
111        'rar'   => 'application/vnd.rar',
112        'rtf'   => 'application/rtf',
113        'sgml'  => 'application/sgml',
114        'sql'   => 'application/sql',
115        'svg'   => 'image/svg+xml',
116        'tar'   => 'application/x-tar',
117        'tif'   => 'image/tiff',
118        'tiff'  => 'image/tiff',
119        'ttf'   => 'font/ttf',
120        'tsv'   => 'text/tsv',
121        'txt'   => 'text/plain',
122        'wav'   => 'audio/wav',
123        'xhtml' => 'application/xhtml+xml',
124        'xls'   => 'application/vnd.ms-excel',
125        'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
126        'xml'   => 'application/xml',
127        'yaml'  => 'application/yaml',
128        'zip'   => 'application/zip',
129    ];
130
131    /**
132     * Default mime types
133     * @var string
134     */
135    protected static string $defaultMimeType = 'application/octet-stream';
136
137    /**
138     * Constructor
139     *
140     * Instantiate the file object
141     *
142     * @param  ?string $filename
143     */
144    public function __construct(?string $filename = null)
145    {
146        $info = [];
147
148        if (!empty($filename)) {
149            $info = pathinfo($filename);
150            if (file_exists($filename)) {
151                $this->setSize(filesize($filename));
152            }
153        }
154
155        if (!empty($info['basename'])) {
156            $this->setBasename($info['basename']);
157        }
158        if (!empty($info['filename'])) {
159            $this->setFilename($info['filename']);
160        }
161        if (!empty($info['dirname'])) {
162            $this->setPath($info['dirname']);
163        }
164        if (!empty($info['extension'])) {
165            $this->setExtension($info['extension']);
166        }
167    }
168
169    /**
170     * Get common mime types
171     *
172     * @return array
173     */
174    public static function getMimeTypes(): array
175    {
176        return (new self())->getAllMimeTypes();
177    }
178
179    /**
180     * Get file's mime type
181     *
182     * @param  string $filename
183     * @return ?string
184     */
185    public static function getFileMimeType(string $filename): ?string
186    {
187        return (new self($filename))->getMimeType();
188    }
189
190    /**
191     * Format file size
192     *
193     * @param  int    $filesize
194     * @param  int    $round
195     * @param  ?bool  $case null = UPPER (MB); true = Title (Mb); false = lower (mb)
196     * @param  string $space
197     * @return string
198     */
199    public static function formatFileSize(int $filesize, int $round = 2, ?bool $case = null, string $space = ' '): string
200    {
201        $file = new self();
202        $file->setSize($filesize);
203        return $file->formatSize();
204    }
205
206    /**
207     * Set the basename
208     *
209     * @param  string $basename
210     * @return File
211     */
212    public function setBasename(string $basename): File
213    {
214        $this->basename = $basename;
215        return $this;
216    }
217
218    /**
219     * Get the basename
220     *
221     * @return ?string
222     */
223    public function getBasename(): ?string
224    {
225        return $this->basename;
226    }
227
228    /**
229     * Has the basename
230     *
231     * @return bool
232     */
233    public function hasBasename(): bool
234    {
235        return ($this->basename !== null);
236    }
237
238    /**
239     * Set the filename
240     *
241     * @param  string $filename
242     * @return File
243     */
244    public function setFilename(string $filename): File
245    {
246        $this->filename = $filename;
247        return $this;
248    }
249
250    /**
251     * Get the filename
252     *
253     * @return ?string
254     */
255    public function getFilename(): ?string
256    {
257        return $this->filename;
258    }
259
260    /**
261     * Has the filename
262     *
263     * @return bool
264     */
265    public function hasFilename(): bool
266    {
267        return ($this->filename !== null);
268    }
269
270    /**
271     * Set the extension
272     *
273     * @param  string $extension
274     * @return File
275     */
276    public function setExtension(string $extension): File
277    {
278        $this->extension = $extension;
279        if (array_key_exists(strtolower($extension), self::$mimeTypes)) {
280            $this->setMimeType(self::$mimeTypes[strtolower($extension)]);
281        } else {
282            $this->setDefaultMimeType();
283        }
284        return $this;
285    }
286
287    /**
288     * Get the extension
289     *
290     * @return ?string
291     */
292    public function getExtension(): ?string
293    {
294        return $this->extension;
295    }
296
297    /**
298     * Has the extension
299     *
300     * @return bool
301     */
302    public function hasExtension(): bool
303    {
304        return ($this->extension !== null);
305    }
306
307    /**
308     * Set the path
309     *
310     * @param  string $path
311     * @return File
312     */
313    public function setPath(string $path): File
314    {
315        $this->path = $path;
316        return $this;
317    }
318
319    /**
320     * Get the path
321     *
322     * @return ?string
323     */
324    public function getPath(): ?string
325    {
326        return $this->path;
327    }
328
329    /**
330     * Has the path
331     *
332     * @return bool
333     */
334    public function hasPath(): bool
335    {
336        return ($this->path !== null);
337    }
338
339    /**
340     * Set the size
341     *
342     * @param  int $size
343     * @return File
344     */
345    public function setSize(int $size): File
346    {
347        $this->size = $size;
348        return $this;
349    }
350
351    /**
352     * Get the size
353     *
354     * @return int
355     */
356    public function getSize(): int
357    {
358        return $this->size;
359    }
360
361    /**
362     * Has the size
363     *
364     * @return bool
365     */
366    public function hasSize(): bool
367    {
368        return ($this->size > 0);
369    }
370
371    /**
372     * Format size into human-readable string
373     *
374     * @param  int    $round
375     * @param  ?bool  $case null = UPPER (MB); true = Title (Mb); false = lower (mb)
376     * @param  string $space
377     * @return string
378     */
379    public function formatSize(int $round = 2, ?bool $case = null, string $space = ' '): string
380    {
381        $prefix = '';
382        $byte   = ($case !== null) ? 'b' : 'B';
383
384        if ($this->size >= 1000000000000) {
385            $prefix    = ($case !== false) ? 'T' : 't';
386            $formatted = round($this->size / 1000000000000, $round);
387        } else if (($this->size < 1000000000000) && ($this->size >= 1000000000)) {
388            $prefix    = ($case !== false) ? 'G' : 'g';
389            $formatted = round($this->size / 1000000000, $round);
390        } else if (($this->size < 1000000000) && ($this->size >= 1000000)) {
391            $prefix    = ($case !== false) ? 'M' : 'm';
392            $formatted = round($this->size / 1000000, $round);
393        } else if (($this->size < 1000000) && ($this->size >= 1000)) {
394            $prefix    = ($case !== false) ? 'K' : 'k';
395            $formatted = round($this->size / 1000, $round);
396        } else {
397            $formatted = $this->size;
398        }
399
400        return $formatted . $space . $prefix . $byte;
401    }
402
403    /**
404     * Set the mime type
405     *
406     * @param  string $mimeType
407     * @return File
408     */
409    public function setMimeType(string $mimeType): File
410    {
411        $this->mimeType = $mimeType;
412        return $this;
413    }
414
415    /**
416     * Get the mime type
417     *
418     * @return ?string
419     */
420    public function getMimeType(): ?string
421    {
422        return $this->mimeType;
423    }
424
425    /**
426     * Has the mime type
427     *
428     * @return bool
429     */
430    public function hasMimeType(): bool
431    {
432        return ($this->mimeType !== null);
433    }
434
435    /**
436     * Set the mime type to default mime type
437     *
438     * @return File
439     */
440    public function setDefaultMimeType(): File
441    {
442        $this->mimeType = self::$defaultMimeType;
443        return $this;
444    }
445
446    /**
447     * Get the default mime type
448     *
449     * @return string
450     */
451    public function getDefaultMimeType(): string
452    {
453        return self::$defaultMimeType;
454    }
455
456    /**
457     * Set the default mime type
458     *
459     * @return bool
460     */
461    public function isDefaultMimeType(): bool
462    {
463        return ($this->mimeType == self::$defaultMimeType);
464    }
465
466    /**
467     * Get the all common mime types
468     *
469     * @return array
470     */
471    public function getAllMimeTypes(): array
472    {
473        return self::$mimeTypes;
474    }
475
476    /**
477     * Does the file exist
478     *
479     * @return bool
480     */
481    public function exists(): bool
482    {
483        $fullPath = ($this->hasPath()) ? $this->path . DIRECTORY_SEPARATOR . $this->basename : $this->basename;
484        return file_exists($fullPath);
485    }
486
487    /**
488     * Get the file contents
489     *
490     * @return mixed
491     */
492    public function getContents(): mixed
493    {
494        $fullPath = ($this->hasPath()) ? $this->path . DIRECTORY_SEPARATOR . $this->basename : $this->basename;
495        return file_get_contents($fullPath);
496    }
497
498    /**
499     * Convert file to an array
500     *
501     * @return array
502     */
503    public function toArray(): array
504    {
505        return [
506            'basename'  => $this->basename,
507            'filename'  => $this->filename,
508            'extension' => $this->extension,
509            'path'      => $this->path,
510            'size'      => $this->size,
511            'mime_type' => $this->mimeType,
512        ];
513    }
514
515    /**
516     * To string
517     *
518     * @return string
519     */
520    public function __toString(): string
521    {
522        return ($this->hasPath()) ? $this->path . DIRECTORY_SEPARATOR . $this->basename : $this->basename;
523    }
524
525}