FileHelper::getModifiedDate()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * File containing the {@see AppUtils\FileHelper} class.
4
 * 
5
 * @package Application Utils
6
 * @subpackage FileHelper
7
 * @see FileHelper
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
use AppUtils\FileHelper\AbstractPathInfo;
15
use AppUtils\FileHelper\CLICommandChecker;
16
use AppUtils\FileHelper\FileDownloader;
17
use AppUtils\FileHelper\FileFinder;
18
use AppUtils\FileHelper\FileInfo\NameFixer;
19
use AppUtils\FileHelper\PathRelativizer;
20
use AppUtils\FileHelper\PathsReducer;
21
use AppUtils\FileHelper\FolderInfo;
22
use AppUtils\FileHelper\FolderTree;
23
use AppUtils\FileHelper\FileInfo;
24
use AppUtils\FileHelper\JSONFile;
25
use AppUtils\FileHelper\PathInfoInterface;
26
use AppUtils\FileHelper\PHPFile;
27
use AppUtils\FileHelper\SerializedFile;
28
use AppUtils\FileHelper\UnicodeHandling;
29
use AppUtils\FileHelper\UploadFileSizeInfo;
30
use DateTime;
31
use JsonException;
32
use SplFileInfo;
33
34
/**
35
 * Collection of file system related methods.
36
 * 
37
 * @package Application Utils
38
 * @subpackage FileHelper
39
 * @author Sebastian Mordziol <[email protected]>
40
 */
41
class FileHelper
42
{
43
    public const ERROR_CANNOT_FIND_JSON_FILE = 340001;
44
    public const ERROR_CANNOT_DECODE_JSON_FILE = 340003;
45
    public const ERROR_JSON_ENCODE_ERROR = 340005;
46
    public const ERROR_CANNOT_OPEN_URL = 340008;
47
    public const ERROR_CANNOT_CREATE_FOLDER = 340009;
48
    public const ERROR_FILE_NOT_READABLE = 340010;
49
    public const ERROR_CANNOT_COPY_FILE = 340011;
50
    public const ERROR_CANNOT_DELETE_FILE = 340012;
51
    public const ERROR_FIND_SUBFOLDERS_FOLDER_DOES_NOT_EXIST = 340014;
52
    public const ERROR_UNKNOWN_FILE_MIME_TYPE = 340015;
53
    public const ERROR_SERIALIZED_FILE_CANNOT_BE_READ = 340017;
54
    public const ERROR_SERIALIZED_FILE_UNSERIALZE_FAILED = 340018;
55
    public const ERROR_UNSUPPORTED_OS_CLI_COMMAND = 340019;
56
    public const ERROR_SOURCE_FILE_NOT_FOUND = 340020;
57
    public const ERROR_SOURCE_FILE_NOT_READABLE = 340021;
58
    public const ERROR_TARGET_COPY_FOLDER_NOT_WRITABLE = 340022;
59
    public const ERROR_SAVE_FOLDER_NOT_WRITABLE = 340023;
60
    public const ERROR_SAVE_FILE_NOT_WRITABLE = 340024;
61
    public const ERROR_SAVE_FILE_WRITE_FAILED = 340025;
62
    public const ERROR_FILE_DOES_NOT_EXIST = 340026;
63
    public const ERROR_CANNOT_OPEN_FILE_TO_READ_LINES = 340027;
64
    public const ERROR_CANNOT_READ_FILE_CONTENTS = 340028;
65
    public const ERROR_CURL_OUTPUT_NOT_STRING = 340031;
66
    public const ERROR_CANNOT_OPEN_FILE_TO_DETECT_BOM = 340032;
67
    public const ERROR_FOLDER_DOES_NOT_EXIST = 340033;
68
    public const ERROR_PATH_IS_NOT_A_FOLDER = 340034;
69
    public const ERROR_CANNOT_DELETE_FOLDER = 340036;
70
    public const ERROR_REAL_PATH_NOT_FOUND = 340037;
71
    public const ERROR_PATH_IS_NOT_A_FILE = 340038;
72
    public const ERROR_PATH_NOT_WRITABLE = 340039;
73
    public const ERROR_PATH_INVALID = 340040;
74
    public const ERROR_CANNOT_COPY_FILE_TO_FOLDER = 340041;
75
76
   /**
77
    * Opens a serialized file and returns the unserialized data.
78
    *
79
    * @param string|PathInfoInterface|SplFileInfo $file
80
    * @throws FileHelper_Exception
81
    * @return array<int|string,mixed>
82
    * @see SerializedFile::parse()
83
    * 
84
    * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
85
    * @see FileHelper::ERROR_SERIALIZED_FILE_CANNOT_BE_READ
86
    * @see FileHelper::ERROR_SERIALIZED_FILE_UNSERIALZE_FAILED
87
    */
88
    public static function parseSerializedFile($file) : array
89
    {
90
        return SerializedFile::factory($file)->parse();
91
    }
92
93
    /**
94
     * Deletes a folder tree with all files therein, including
95
     * the specified folder itself.
96
     *
97
     * @param string|PathInfoInterface|SplFileInfo $rootFolder
98
     * @return bool
99
     * @throws FileHelper_Exception
100
     */
101
    public static function deleteTree($rootFolder) : bool
102
    {
103
        return FolderTree::delete($rootFolder);
104
    }
105
    
106
   /**
107
    * Create a folder, if it does not exist yet.
108
    *  
109
    * @param string|PathInfoInterface $path
110
    * @throws FileHelper_Exception
111
    * @see FileHelper::ERROR_CANNOT_CREATE_FOLDER
112
    */
113
    public static function createFolder($path) : FolderInfo
114
    {
115
        return self::getFolderInfo($path)->create();
116
    }
117
118
    /**
119
     * @param string|PathInfoInterface|SplFileInfo $path
120
     * @return FolderInfo
121
     * @throws FileHelper_Exception
122
     */
123
    public static function getFolderInfo($path) : FolderInfo
124
    {
125
        return FolderInfo::factory($path);
126
    }
127
128
    /**
129
     * Copies a folder tree to the target folder.
130
     *
131
     * @param string|PathInfoInterface|SplFileInfo $source
132
     * @param string|PathInfoInterface|SplFileInfo $target
133
     * @throws FileHelper_Exception
134
     * @see FolderTree
135
     */
136
    public static function copyTree($source, $target) : void
137
    {
138
        FolderTree::copy($source, $target);
139
    }
140
    
141
   /**
142
    * Copies a file to the target location. Includes checks
143
    * for most error sources, like the source file not being
144
    * readable. Automatically creates the target folder if it
145
    * does not exist yet.
146
    * 
147
    * @param string|PathInfoInterface|SplFileInfo $sourcePath
148
    * @param string|PathInfoInterface|SplFileInfo $targetPath
149
    * @throws FileHelper_Exception
150
    * 
151
    * @see FileHelper::ERROR_CANNOT_CREATE_FOLDER
152
    * @see FileHelper::ERROR_SOURCE_FILE_NOT_FOUND
153
    * @see FileHelper::ERROR_SOURCE_FILE_NOT_READABLE
154
    * @see FileHelper::ERROR_TARGET_COPY_FOLDER_NOT_WRITABLE
155
    * @see FileHelper::ERROR_CANNOT_COPY_FILE
156
    */
157
    public static function copyFile($sourcePath, $targetPath) : void
158
    {
159
        self::getFileInfo($sourcePath)->copyTo($targetPath);
160
    }
161
    
162
   /**
163
    * Deletes the target file. Ignored if it cannot be found,
164
    * and throws an exception if it fails.
165
    * 
166
    * @param string|PathInfoInterface|SplFileInfo $filePath
167
    * @throws FileHelper_Exception
168
    * 
169
    * @see FileHelper::ERROR_CANNOT_DELETE_FILE
170
    */
171
    public static function deleteFile($filePath) : void
172
    {
173
        self::getFileInfo($filePath)->delete();
174
    }
175
176
    /**
177
     * Retrieves an instance of the file info class, which
178
     * allows file operations and accessing information on
179
     * the file.
180
     *
181
     * @param string|PathInfoInterface|SplFileInfo $path
182
     * @return FileInfo
183
     * @throws FileHelper_Exception
184
     */
185
    public static function getFileInfo($path) : FileInfo
186
    {
187
        return FileInfo::factory($path);
188
    }
189
190
    /**
191
     * @param string|PathInfoInterface|SplFileInfo $path
192
     * @return PathInfoInterface
193
     * @throws FileHelper_Exception
194
     */
195
    public static function getPathInfo($path) : PathInfoInterface
196
    {
197
        return AbstractPathInfo::resolveType($path);
198
    }
199
200
    /**
201
     * Detects the mime type for the specified file name/path.
202
     * Returns null if it is not a known file extension.
203
     *
204
     * @param string|PathInfoInterface|SplFileInfo $fileName
205
     * @return string|NULL
206
     * @throws FileHelper_Exception
207
     */
208
    public static function detectMimeType($fileName) : ?string
209
    {
210
        $ext = self::getExtension($fileName);
211
        if(empty($ext)) {
212
            return null;
213
        }
214
215
        return FileHelper_MimeTypes::getMime($ext);
216
    }
217
218
    /**
219
     * Like `sendFile()`, but automatically determines whether
220
     * the browser can open the target file type, to either
221
     * send it directly to the browser, or force downloading
222
     * it instead.
223
     *
224
     * @param string|PathInfoInterface|SplFileInfo $filePath
225
     * @param string $fileName
226
     * @throws FileHelper_Exception
227
     */
228
    public static function sendFileAuto($filePath, string $fileName = '') : void
229
    {
230
        $file = FileInfo::factory($filePath)
231
            ->requireExists()
232
            ->requireReadable();
233
234
        self::sendFile(
235
            $file,
236
            $fileName,
237
            !FileHelper_MimeTypes::canBrowserDisplay($file->getExtension())
238
        );
239
    }
240
241
    /**
242
     * Detects the mime type of the target file automatically,
243
     * sends the required headers to trigger a download and
244
     * outputs the file. Returns false if the mime type could
245
     * not be determined.
246
     * 
247
     * @param string|PathInfoInterface|SplFileInfo $filePath
248
     * @param string|null $fileName The name of the file for the client.
249
     * @param bool $asAttachment Whether to force the client to download the file.
250
     * @throws FileHelper_Exception
251
     * 
252
     * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
253
     * @see FileHelper::ERROR_UNKNOWN_FILE_MIME_TYPE
254
     */
255
    public static function sendFile($filePath, ?string $fileName = null, bool $asAttachment=true) : void
256
    {
257
        self::getFileInfo($filePath)->getDownloader()->send($fileName, $asAttachment);
258
    }
259
260
    /**
261
     * Uses cURL to download the contents of the specified URL,
262
     * returns the content.
263
     *
264
     * @param string $url
265
     * @param int $timeout In seconds. Set to 0 to use the default.
266
     * @param bool $SSLEnabled Whether to enable HTTPs host verification.
267
     * @return string
268
     *
269
     * @throws FileHelper_Exception
270
     * @see FileHelper::ERROR_CANNOT_OPEN_URL
271
     */
272
    public static function downloadFile(string $url, int $timeout=0, bool $SSLEnabled=false) : string
273
    {
274
        return FileDownloader::factory($url)
275
            ->setTimeout($timeout)
276
            ->setSSLEnabled($SSLEnabled)
277
            ->download();
278
    }
279
280
    /**
281
     * Verifies whether the target file is a PHP file. The path
282
     * to the file can be a path to a file as a string, or a
283
     * {@see SplFileInfo} object instance.
284
     *
285
     * @param string|PathInfoInterface|SplFileInfo $filePath
286
     * @return boolean
287
     * @throws FileHelper_Exception
288
     */
289
    public static function isPHPFile($filePath) : bool
290
    {
291
    	return self::getExtension($filePath) === 'php';
292
    }
293
294
    /**
295
     * Retrieves the extension of the specified file. Can be a path
296
     * to a file as a string, or a {@see SplFileInfo} object instance.
297
     *
298
     * NOTE: A folder will return an empty string.
299
     *
300
     * @param string|PathInfoInterface|SplFileInfo $fileName
301
     * @param bool $lowercase
302
     * @return string
303
     * @throws FileHelper_Exception
304
     */
305
    public static function getExtension($fileName, bool $lowercase = true) : string
306
    {
307
        return self::getPathInfo($fileName)->getExtension($lowercase);
308
    }
309
310
    /**
311
     * Retrieves the file name from a path, with or without extension.
312
     * The path to the file can be a string, or a {@see SplFileInfo}
313
     * object instance.
314
     *
315
     * In case of folders, behaves like the "pathinfo" function: returns
316
     * the name of the folder.
317
     *
318
     * @param string|PathInfoInterface|SplFileInfo $pathOrDirIterator
319
     * @param bool $extension
320
     * @return string
321
     * @throws FileHelper_Exception
322
     */
323
    public static function getFilename($pathOrDirIterator, bool $extension = true) : string
324
    {
325
        $info = self::getPathInfo($pathOrDirIterator);
326
327
        if($extension === true || $info instanceof FolderInfo)
328
        {
329
            return $info->getName();
330
        }
331
332
        return $info->requireIsFile()->removeExtension();
333
    }
334
335
    /**
336
     * Tries to read the contents of the target file and
337
     * treat it as JSON to return the decoded JSON data.
338
     *
339
     * @param string|PathInfoInterface|SplFileInfo $file
340
     * @param string $targetEncoding
341
     * @param string|string[]|null $sourceEncoding
342
     * @return array<int|string,mixed>
343
     *
344
     * @throws FileHelper_Exception
345
     * @throws JsonException
346
     * @see FileHelper::ERROR_CANNOT_FIND_JSON_FILE
347
     * @see FileHelper::ERROR_CANNOT_DECODE_JSON_FILE
348
     */
349
    public static function parseJSONFile($file, string $targetEncoding='', $sourceEncoding=null) : array
350
    {
351
        return JSONFile::factory($file)
352
            ->setTargetEncoding($targetEncoding)
353
            ->setSourceEncodings($sourceEncoding)
354
            ->parse();
355
    }
356
    
357
   /**
358
    * Corrects common formatting mistakes when users enter
359
    * file names, like too many spaces, dots and the like.
360
    * 
361
    * NOTE: if the file name contains a path, the path is
362
    * stripped, leaving only the file name.
363
    * 
364
    * @param string $name
365
    * @return string
366
    */
367
    public static function fixFileName(string $name) : string
368
    {
369
        return NameFixer::fixName($name);
370
    }
371
372
    /**
373
     * Creates an instance of the file finder, which is an easier
374
     * alternative to the other manual findFile methods, since all
375
     * options can be set by chaining.
376
     *
377
     * @param string|AbstractPathInfo|SplFileInfo $path
378
     * @return FileFinder
379
     * @throws FileHelper_Exception
380
     *
381
     * @see FileFinder::ERROR_PATH_DOES_NOT_EXIST
382
     */
383
    public static function createFileFinder($path) : FileFinder
384
    {
385
        return new FileFinder($path);
386
    }
387
388
    /**
389
     * Searches for all HTML files in the target folder.
390
     *
391
     * NOTE: This method only exists for backwards compatibility.
392
     * Use the {@see FileHelper::createFileFinder()} method instead,
393
     * which offers an object-oriented interface that is much easier
394
     * to use.
395
     *
396
     * @param string|PathInfoInterface|SplFileInfo $targetFolder
397
     * @param array<string,mixed> $options
398
     * @return string[] An indexed array with files.
399
     * @throws FileHelper_Exception
400
     * @see FileHelper::createFileFinder()
401
     */
402
    public static function findHTMLFiles($targetFolder, array $options=array()) : array
403
    {
404
        return self::findFiles($targetFolder, array('html'), $options);
0 ignored issues
show
Deprecated Code introduced by
The function AppUtils\FileHelper::findFiles() has been deprecated: Use the file finder instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

404
        return /** @scrutinizer ignore-deprecated */ self::findFiles($targetFolder, array('html'), $options);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
405
    }
406
407
    /**
408
     * Searches for all PHP files in the target folder.
409
     *
410
     * NOTE: This method only exists for backwards compatibility.
411
     * Use the {@see FileHelper::createFileFinder()} method instead,
412
     * which offers an object-oriented interface that is much easier
413
     * to use.
414
     *
415
     * @param string|PathInfoInterface|SplFileInfo $targetFolder
416
     * @param array<string,mixed> $options
417
     * @return string[] An indexed array of PHP files.
418
     * @throws FileHelper_Exception
419
     * @see FileHelper::createFileFinder()
420
     */
421
    public static function findPHPFiles($targetFolder, array $options=array()) : array
422
    {
423
        return self::findFiles($targetFolder, array('php'), $options);
0 ignored issues
show
Deprecated Code introduced by
The function AppUtils\FileHelper::findFiles() has been deprecated: Use the file finder instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

423
        return /** @scrutinizer ignore-deprecated */ self::findFiles($targetFolder, array('php'), $options);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
424
    }
425
    
426
   /**
427
    * Finds files according to the specified options.
428
    * 
429
    * NOTE: This method only exists for backwards compatibility.
430
    * Use the {@see FileHelper::createFileFinder()} method instead,
431
    * which offers an object-oriented interface that is much easier
432
    * to use.
433
    *  
434
    * @param string|PathInfoInterface|SplFileInfo $targetFolder
435
    * @param string[] $extensions
436
    * @param array<string,mixed> $options
437
    * @throws FileHelper_Exception
438
    * @return string[]
439
    *
440
    * @see FileHelper::createFileFinder()
441
    * @deprecated Use the file finder instead.
442
    */
443
    public static function findFiles($targetFolder, array $extensions=array(), array $options=array()) : array
444
    {
445
        $finder = self::createFileFinder($targetFolder);
446
447
        foreach ($extensions as $extension) {
448
            $finder->includeExtension($extension);
449
        }
450
451
        $finder->setPathmodeStrip();
452
        
453
        if(isset($options['relative-path']) && $options['relative-path'] === true) 
454
        {
455
            $finder->setPathmodeRelative();
456
        } 
457
        else if(isset($options['absolute-path']) && $options['absolute-path'] === true)
458
        {
459
            $finder->setPathmodeAbsolute();
460
        }
461
        
462
        if(isset($options['strip-extension'])) 
463
        {
464
            $finder->stripExtensions();
465
        }
466
        
467
        $finder->setOptions($options);
468
        
469
        return $finder->getAll();
470
    }
471
472
    /**
473
     * Removes the extension from the specified path or file name,
474
     * if any, and returns the name without the extension.
475
     *
476
     * @param string|PathInfoInterface|SplFileInfo $filename
477
     * @param bool $keepPath Whether to keep the path component, if any. Default PHP pathinfo behavior is no.
478
     * @return string
479
     * @throws FileHelper_Exception
480
     */
481
    public static function removeExtension($filename, bool $keepPath=false) : string
482
    {
483
        $path = self::getPathInfo($filename);
484
485
        if($path instanceof FileInfo)
486
        {
487
            return $path->removeExtension($keepPath);
488
        }
489
490
        if($keepPath)
491
        {
492
            return $filename;
493
        }
494
495
        return basename($filename);
496
    }
497
498
    /**
499
     * @var UnicodeHandling|NULL
500
     */
501
    private static ?UnicodeHandling $unicodeHandling = null;
502
503
    public static function createUnicodeHandling() : UnicodeHandling
504
    {
505
        if(!isset(self::$unicodeHandling))
506
        {
507
            self::$unicodeHandling = new UnicodeHandling();
508
        }
509
510
        return self::$unicodeHandling;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::unicodeHandling could return the type null which is incompatible with the type-hinted return AppUtils\FileHelper\UnicodeHandling. Consider adding an additional type-check to rule them out.
Loading history...
511
    }
512
    
513
   /**
514
    * Normalizes the slash style in a file or folder path,
515
    * by replacing any anti-slashes with forward slashes.
516
    * 
517
    * @param string $path
518
    * @return string
519
    */
520
    public static function normalizePath(string $path) : string
521
    {
522
        return str_replace(array('\\', '//'), array('/', '/'), $path);
523
    }
524
525
    /**
526
     * Saves the specified data to a file, JSON encoded.
527
     *
528
     * @param mixed $data
529
     * @param string|PathInfoInterface|SplFileInfo $file
530
     * @param bool $pretty
531
     * @return JSONFile
532
     *
533
     * @throws FileHelper_Exception
534
     * @see FileHelper::ERROR_JSON_ENCODE_ERROR
535
     * @see FileHelper::ERROR_SAVE_FOLDER_NOT_WRITABLE
536
     * @see FileHelper::ERROR_SAVE_FILE_NOT_WRITABLE
537
     * @see FileHelper::ERROR_SAVE_FILE_WRITE_FAILED
538
     */
539
    public static function saveAsJSON($data, $file, bool $pretty=false) : JSONFile
540
    {
541
        return JSONFile::factory($file)->putData($data, $pretty);
542
    }
543
544
    /**
545
     * Saves the specified content to the target file, creating
546
     * the file and the folder as necessary.
547
     *
548
     * @param string|PathInfoInterface|SplFileInfo $filePath
549
     * @param string $content
550
     * @return FileInfo
551
     *
552
     * @throws FileHelper_Exception
553
     * @see FileHelper::ERROR_SAVE_FOLDER_NOT_WRITABLE
554
     * @see FileHelper::ERROR_SAVE_FILE_NOT_WRITABLE
555
     * @see FileHelper::ERROR_SAVE_FILE_WRITE_FAILED
556
     */
557
    public static function saveFile($filePath, string $content='') : FileInfo
558
    {
559
        return self::getFileInfo($filePath)->putContents($content);
560
    }
561
562
    /**
563
     * Checks whether it is possible to run PHP command
564
     * line commands.
565
     *
566
     * @return boolean
567
     * @throws FileHelper_Exception
568
     */
569
    public static function canMakePHPCalls() : bool
570
    {
571
        return self::cliCommandExists('php');
572
    }
573
    
574
    /**
575
     * Determines if a command exists on the current environment's command line interface.
576
     *
577
     * @param string $command The name of the command to check, e.g. "php"
578
     * @return bool True if the command has been found, false otherwise.
579
     * @throws FileHelper_Exception
580
     * @see FileHelper::ERROR_UNSUPPORTED_OS_CLI_COMMAND
581
     */
582
    public static function cliCommandExists(string $command) : bool
583
    {
584
        return CLICommandChecker::factory()->exists($command);
585
    }
586
587
    /**
588
     * Validates a PHP file's syntax.
589
     *
590
     * NOTE: This will fail silently if the PHP command line
591
     * is not available. Use {@link FileHelper::canMakePHPCalls()}
592
     * to check this beforehand as needed.
593
     *
594
     * @param string|PathInfoInterface|SplFileInfo $path
595
     * @return boolean|string[] A boolean true if the file is valid, an array with validation messages otherwise.
596
     * @throws FileHelper_Exception
597
     * @deprecated Use {@see PHPFile::checkSyntax()} instead.
598
     */
599
    public static function checkPHPFileSyntax($path)
600
    {
601
        return PHPFile::factory($path)->checkSyntax();
602
    }
603
604
    /**
605
     * Retrieves the last modified date for the specified file or folder.
606
     *
607
     * Note: If the target does not exist, returns null.
608
     *
609
     * @param string|PathInfoInterface|SplFileInfo $path
610
     * @return DateTime|NULL
611
     * @throws FileHelper_Exception
612
     */
613
    public static function getModifiedDate($path) : ?DateTime
614
    {
615
        return self::getFileInfo($path)->getModifiedDate();
616
    }
617
618
    /**
619
     * Retrieves the names of all sub-folders in the specified path.
620
     *
621
     * Available options:
622
     *
623
     * - recursive: true/false
624
     *   Whether to search for sub-folders recursively.
625
     *
626
     * - absolute-paths: true/false
627
     *   Whether to return a list of absolute paths.
628
     *
629
     * @param string|PathInfoInterface|SplFileInfo $targetFolder
630
     * @param array<string,mixed> $options
631
     * @return string[]
632
     *
633
     * @throws FileHelper_Exception
634
     * @see FileHelper::ERROR_FIND_SUBFOLDERS_FOLDER_DOES_NOT_EXIST
635
     */
636
    public static function getSubfolders($targetFolder, array $options = array()) : array
637
    {
638
        return FolderInfo::factory($targetFolder)
639
            ->createFolderFinder()
640
            ->setOptions($options)
641
            ->getPaths();
642
    }
643
644
   /**
645
    * Retrieves the maximum allowed upload file size, in bytes.
646
    * Takes into account the PHP ini settings <code>post_max_size</code>
647
    * and <code>upload_max_filesize</code>. Since these cannot
648
    * be modified at runtime, they are the hard limits for uploads.
649
    * 
650
    * NOTE: Based on binary values, where 1KB = 1024 Bytes.
651
    * 
652
    * @return int Will return <code>-1</code> if no limit.
653
    */
654
    public static function getMaxUploadFilesize() : int
655
    {
656
        return UploadFileSizeInfo::getFileSize();
657
    }
658
   
659
   /**
660
    * Makes a path relative using a folder depth: will reduce the
661
    * length of the path so that only the amount of folders defined
662
    * in the <code>$depth</code> attribute are shown below the actual
663
    * folder or file in the path.
664
    *  
665
    * @param string  $path The absolute or relative path
666
    * @param int $depth The folder depth to reduce the path to
667
    * @return string
668
    */
669
    public static function relativizePathByDepth(string $path, int $depth=2) : string
670
    {
671
        return PathRelativizer::relativizeByDepth($path, $depth);
672
    }
673
    
674
   /**
675
    * Makes the specified path relative to another path,
676
    * by removing one from the other if found. Also 
677
    * normalizes the path to use forward slashes. 
678
    * 
679
    * Example:
680
    * 
681
    * <pre>
682
    * relativizePath('c:\some\folder\to\file.txt', 'c:\some\folder');
683
    * </pre>
684
    * 
685
    * Result: <code>to/file.txt</code>
686
    * 
687
    * @param string $path
688
    * @param string $relativeTo
689
    * @return string
690
    */
691
    public static function relativizePath(string $path, string $relativeTo) : string
692
    {
693
        return PathRelativizer::relativize($path, $relativeTo);
694
    }
695
    
696
   /**
697
    * Checks that the target file exists, and throws an exception
698
    * if it does not. 
699
    * 
700
    * @param string|SplFileInfo $path
701
    * @param int|NULL $errorCode Optional custom error code
702
    * @throws FileHelper_Exception
703
    * @return string The real path to the file
704
    * 
705
    * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
706
    * @see FileHelper::ERROR_REAL_PATH_NOT_FOUND
707
    */
708
    public static function requireFileExists($path, ?int $errorCode=null) : string
709
    {
710
        return self::getPathInfo($path)
711
            ->requireIsFile()
712
            ->requireExists($errorCode)
713
            ->getRealPath();
714
    }
715
716
    /**
717
     * @param string|PathInfoInterface|SplFileInfo $path
718
     * @param int|NULL $errorCode
719
     * @return string
720
     * @throws FileHelper_Exception
721
     */
722
    public static function requireFileReadable($path, ?int $errorCode=null) : string
723
    {
724
        return self::getPathInfo($path)
725
            ->requireIsFile()
726
            ->requireReadable($errorCode)
727
            ->getPath();
728
    }
729
    
730
   /**
731
    * Reads a specific line number from the target file and returns its
732
    * contents, if the file has such a line. Does so with little memory
733
    * usage, as the file is not read entirely into memory.
734
    * 
735
    * @param string|PathInfoInterface|SplFileInfo $path
736
    * @param int $lineNumber Note: 1-based; the first line is number 1.
737
    * @return string|NULL Will return null if the requested line does not exist.
738
    * @throws FileHelper_Exception
739
    * 
740
    * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
741
    */
742
    public static function getLineFromFile($path, int $lineNumber) : ?string
743
    {
744
        return self::getFileInfo($path)->getLine($lineNumber);
745
    }
746
747
    /**
748
     * Retrieves the total amount of lines in the file, without
749
     * reading the whole file into memory.
750
     *
751
     * @param string|PathInfoInterface|SplFileInfo $path
752
     * @return int
753
     * @throws FileHelper_Exception
754
     */
755
    public static function countFileLines($path) : int
756
    {
757
        return self::getFileInfo($path)->countLines();
758
    }
759
760
    /**
761
     * Parses the target file to detect any PHP classes contained
762
     * within, and retrieve information on them. Does not use the
763
     * PHP reflection API.
764
     *
765
     * @param string|PathInfoInterface|SplFileInfo $filePath
766
     * @return FileHelper_PHPClassInfo
767
     * @throws FileHelper_Exception
768
     */
769
    public static function findPHPClasses($filePath) : FileHelper_PHPClassInfo
770
    {
771
        return PHPFile::factory($filePath)->findClasses();
772
    }
773
774
    /**
775
     * Detects the end of line style used in the target file, if any.
776
     * Can be used with large files, because it only reads part of it.
777
     *
778
     * @param string|PathInfoInterface|SplFileInfo $filePath The path to the file.
779
     * @return NULL|ConvertHelper_EOL The end of line character information, or NULL if none is found.
780
     * @throws FileHelper_Exception
781
     */
782
    public static function detectEOLCharacter($filePath) : ?ConvertHelper_EOL
783
    {
784
        return self::getFileInfo($filePath)->detectEOLCharacter();
785
    }
786
787
    /**
788
     * Reads the specified amount of lines from the target file.
789
     * Unicode BOM compatible: any byte order marker is stripped
790
     * from the resulting lines.
791
     *
792
     * @param string|PathInfoInterface|SplFileInfo $filePath
793
     * @param int $amount Set to 0 to read all lines.
794
     * @return string[]
795
     *
796
     * @throws FileHelper_Exception
797
     * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
798
     * @see FileHelper::ERROR_CANNOT_OPEN_FILE_TO_READ_LINES
799
     */
800
    public static function readLines($filePath, int $amount=0) : array
801
    {
802
        return self::getFileInfo($filePath)
803
            ->getLineReader()
804
            ->getLines($amount);
805
    }
806
    
807
   /**
808
    * Reads all content from a file.
809
    * 
810
    * @param string|PathInfoInterface|SplFileInfo $filePath
811
    * @throws FileHelper_Exception
812
    * @return string
813
    * 
814
    * @see FileHelper::ERROR_FILE_DOES_NOT_EXIST
815
    * @see FileHelper::ERROR_CANNOT_READ_FILE_CONTENTS
816
    */
817
    public static function readContents($filePath) : string
818
    {
819
        return self::getFileInfo($filePath)->getContents();
820
    }
821
822
   /**
823
    * Ensures that the target path exists on disk, and is a folder.
824
    * 
825
    * @param string|PathInfoInterface|SplFileInfo $path
826
    * @return string The real path, with normalized slashes.
827
    * @throws FileHelper_Exception
828
    * 
829
    * @see FileHelper::normalizePath()
830
    * 
831
    * @see FileHelper::ERROR_FOLDER_DOES_NOT_EXIST
832
    * @see FileHelper::ERROR_PATH_IS_NOT_A_FOLDER
833
    */
834
    public static function requireFolderExists($path) : string
835
    {
836
        return self::getFolderInfo($path)
837
            ->requireExists(self::ERROR_FOLDER_DOES_NOT_EXIST)
838
            ->getRealPath();
839
    }
840
841
    /**
842
     * Creates an instance of the path reducer tool, which can reduce
843
     * a list of paths to the closest common root folder.
844
     *
845
     * @param string[] $paths
846
     * @return PathsReducer
847
     *
848
     * @throws FileHelper_Exception
849
     */
850
    public static function createPathsReducer(array $paths=array()) : PathsReducer
851
    {
852
        return new PathsReducer($paths);
853
    }
854
}
855