File   F
last analyzed

Complexity

Total Complexity 91

Size/Duplication

Total Lines 836
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 91
eloc 155
dl 0
loc 836
rs 2
c 0
b 0
f 0

43 Methods

Rating   Name   Duplication   Size   Complexity  
A setMode() 0 5 1
A listDir() 0 9 2
A setLastModified() 0 10 2
A isExecutable() 0 9 2
A constructFileParentStringChild() 0 11 2
A setGroup() 0 5 1
A isAbsolute() 0 3 1
A getParentFile() 0 8 2
A renameTo() 0 8 2
A isDirectory() 0 9 3
A equals() 0 7 3
A getPathWithoutBase() 0 12 3
A getFileExtension() 0 3 1
A getMode() 0 3 1
A getName() 0 9 3
A mkdir() 0 9 2
A isLink() 0 9 2
A canRead() 0 9 3
A getLinkTarget() 0 3 1
A __toString() 0 3 1
A constructStringParentStringChild() 0 11 2
A copyTo() 0 13 3
A constructPathname() 0 6 1
A getCanonicalPath() 0 5 1
A lastModified() 0 8 2
A exists() 0 13 4
B __construct() 0 15 8
A mkdirs() 0 16 6
A getParent() 0 13 5
A getCanonicalFile() 0 3 1
A setUser() 0 5 1
A getPath() 0 3 1
A getAbsoluteFile() 0 3 1
A compareTo() 0 5 1
A contents() 0 7 3
A getPrefixLength() 0 3 1
A canWrite() 0 5 1
A isFile() 0 5 1
A delete() 0 8 2
A createNewFile() 0 11 4
A length() 0 8 2
A getAbsolutePath() 0 5 1
A deleteOnExit() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like File often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use File, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Io;
22
23
use Exception;
24
use Phing\Util\StringHelper;
25
26
/**
27
 * An abstract representation of file and directory pathnames.
28
 */
29
class File
30
{
31
    /**
32
     * This abstract pathname's normalized pathname string.  A normalized
33
     * pathname string uses the default name-separator character and does not
34
     * contain any duplicate or redundant separators.
35
     */
36
    private $path = '';
37
38
    /**
39
     * The length of this abstract pathname's prefix, or zero if it has no prefix.
40
     *
41
     * @var int
42
     */
43
    private $prefixLength = 0;
44
45
    /**
46
     * constructor.
47
     *
48
     * @param null|mixed $arg1
49
     * @param null|mixed $arg2
50
     *
51
     * @throws IOException
52
     * @throws \InvalidArgumentException
53
     */
54
    public function __construct($arg1 = null, $arg2 = null)
55
    {
56
        // simulate signature identified constructors
57
        if ($arg1 instanceof File && is_string($arg2)) {
58
            $this->constructFileParentStringChild($arg1, $arg2);
59
        } elseif (is_string($arg1) && (null === $arg2)) {
60
            $this->constructPathname($arg1);
61
        } elseif (is_string($arg1) && is_string($arg2)) {
62
            $this->constructStringParentStringChild($arg1, $arg2);
63
        } else {
64
            if (null === $arg1) {
65
                throw new \InvalidArgumentException('Argument1 to function must not be null');
66
            }
67
            $this->path = (string) $arg1;
68
            $this->prefixLength = (int) $arg2;
69
        }
70
    }
71
72
    /**
73
     * Return string representation of the object.
74
     *
75
     * @return string
76
     */
77
    public function __toString()
78
    {
79
        return $this->getPath();
80
    }
81
82
    /**
83
     * Returns the length of this abstract pathname's prefix.
84
     *
85
     * @return int
86
     */
87
    public function getPrefixLength()
88
    {
89
        return (int) $this->prefixLength;
90
    }
91
92
    // -- Path-component accessors --
93
94
    /**
95
     * Returns the name of the file or directory denoted by this abstract
96
     * pathname.  This is just the last name in the pathname's name
97
     * sequence.  If the pathname's name sequence is empty, then the empty
98
     * string is returned.
99
     *
100
     * @return string The name of the file or directory denoted by this abstract
101
     *                pathname, or the empty string if this pathname's name sequence
102
     *                is empty
103
     */
104
    public function getName()
105
    {
106
        // that's a lastIndexOf
107
        $index = ((($res = strrpos($this->path, FileUtils::getSeparator())) === false) ? -1 : $res);
108
        if ($index < $this->prefixLength) {
109
            return substr($this->path, $this->prefixLength);
110
        }
111
112
        return substr($this->path, $index + 1);
113
    }
114
115
    /**
116
     * Returns the pathname string of this abstract pathname's parent, or
117
     * null if this pathname does not name a parent directory.
118
     *
119
     * The parent of an abstract pathname consists of the pathname's prefix,
120
     * if any, and each name in the pathname's name sequence except for the last.
121
     * If the name sequence is empty then the pathname does not name a parent
122
     * directory.
123
     *
124
     * @return string $pathname string of the parent directory named by this
125
     *                abstract pathname, or null if this pathname does not name a parent
126
     */
127
    public function getParent()
128
    {
129
        // that's a lastIndexOf
130
        $index = ((($res = strrpos($this->path, FileUtils::getSeparator())) === false) ? -1 : $res);
131
        if ($index < $this->prefixLength) {
132
            if (($this->prefixLength > 0) && (strlen($this->path) > $this->prefixLength)) {
133
                return substr($this->path, 0, $this->prefixLength);
134
            }
135
136
            return null;
137
        }
138
139
        return substr($this->path, 0, $index);
140
    }
141
142
    /**
143
     * Returns the abstract pathname of this abstract pathname's parent,
144
     * or null if this pathname does not name a parent directory.
145
     *
146
     * The parent of an abstract pathname consists of the pathname's prefix,
147
     * if any, and each name in the pathname's name sequence except for the
148
     * last.  If the name sequence is empty then the pathname does not name
149
     * a parent directory.
150
     *
151
     * @return null|File The abstract pathname of the parent directory named by this
152
     *                   abstract pathname, or null if this pathname
153
     *                   does not name a parent
154
     */
155
    public function getParentFile()
156
    {
157
        $p = $this->getParent();
158
        if (null === $p) {
0 ignored issues
show
introduced by
The condition null === $p is always false.
Loading history...
159
            return null;
160
        }
161
162
        return new File((string) $p, (int) $this->prefixLength);
163
    }
164
165
    /**
166
     * Converts this abstract pathname into a pathname string.  The resulting
167
     * string uses the default name-separator character to separate the names
168
     * in the name sequence.
169
     *
170
     * @return string The string form of this abstract pathname
171
     */
172
    public function getPath()
173
    {
174
        return (string) $this->path;
175
    }
176
177
    /**
178
     * Returns path without leading basedir.
179
     *
180
     * @param string $basedir Base directory to strip
181
     *
182
     * @return string Path without basedir
183
     *
184
     * @uses getPath()
185
     */
186
    public function getPathWithoutBase($basedir)
187
    {
188
        if (!StringHelper::endsWith(FileUtils::getSeparator(), $basedir)) {
189
            $basedir .= FileUtils::getSeparator();
190
        }
191
        $path = $this->getPath();
192
        if (substr($path, 0, strlen($basedir)) != $basedir) {
193
            //path does not begin with basedir, we don't modify it
194
            return $path;
195
        }
196
197
        return substr($path, strlen($basedir));
198
    }
199
200
    /**
201
     * Tests whether this abstract pathname is absolute.  The definition of
202
     * absolute pathname is system dependent.  On UNIX systems, a pathname is
203
     * absolute if its prefix is "/".  On Win32 systems, a pathname is absolute
204
     * if its prefix is a drive specifier followed by "\\", or if its prefix
205
     * is "\\".
206
     *
207
     * @return bool true if this abstract pathname is absolute, false otherwise
208
     */
209
    public function isAbsolute()
210
    {
211
        return 0 !== $this->prefixLength;
212
    }
213
214
    /**
215
     * Returns the file extension for a given file. For example test.php would be returned as php.
216
     *
217
     * @return string the name of the extension
218
     */
219
    public function getFileExtension()
220
    {
221
        return pathinfo((string) $this->getAbsolutePath(), PATHINFO_EXTENSION);
0 ignored issues
show
Bug Best Practice introduced by
The expression return pathinfo((string)...\Io\PATHINFO_EXTENSION) also could return the type array which is incompatible with the documented return type string.
Loading history...
222
    }
223
224
    /**
225
     * Returns the absolute pathname string of this abstract pathname.
226
     *
227
     * If this abstract pathname is already absolute, then the pathname
228
     * string is simply returned as if by the getPath method.
229
     * If this abstract pathname is the empty abstract pathname then
230
     * the pathname string of the current user directory, which is named by the
231
     * system property user.dir, is returned.  Otherwise this
232
     * pathname is resolved in a system-dependent way.  On UNIX systems, a
233
     * relative pathname is made absolute by resolving it against the current
234
     * user directory.  On Win32 systems, a relative pathname is made absolute
235
     * by resolving it against the current directory of the drive named by the
236
     * pathname, if any; if not, it is resolved against the current user
237
     * directory.
238
     *
239
     * @return string The absolute pathname string denoting the same file or
240
     *                directory as this abstract pathname
241
     *
242
     * @see    #isAbsolute()
243
     */
244
    public function getAbsolutePath()
245
    {
246
        $fs = FileSystem::getFileSystem();
247
248
        return $fs->resolveFile($this);
249
    }
250
251
    /**
252
     * Returns the absolute form of this abstract pathname.  Equivalent to
253
     * getAbsolutePath.
254
     *
255
     * @return File The absolute abstract pathname denoting the same file or
256
     *              directory as this abstract pathname
257
     */
258
    public function getAbsoluteFile()
259
    {
260
        return new File((string) $this->getAbsolutePath());
261
    }
262
263
    /**
264
     * Returns the canonical pathname string of this abstract pathname.
265
     *
266
     * A canonical pathname is both absolute and unique. The precise
267
     * definition of canonical form is system-dependent. This method first
268
     * converts this pathname to absolute form if necessary, as if by invoking the
269
     * getAbsolutePath() method, and then maps it to its unique form in a
270
     * system-dependent way.  This typically involves removing redundant names
271
     * such as "." and .. from the pathname, resolving symbolic links
272
     * (on UNIX platforms), and converting drive letters to a standard case
273
     * (on Win32 platforms).
274
     *
275
     * Every pathname that denotes an existing file or directory has a
276
     * unique canonical form.  Every pathname that denotes a nonexistent file
277
     * or directory also has a unique canonical form.  The canonical form of
278
     * the pathname of a nonexistent file or directory may be different from
279
     * the canonical form of the same pathname after the file or directory is
280
     * created.  Similarly, the canonical form of the pathname of an existing
281
     * file or directory may be different from the canonical form of the same
282
     * pathname after the file or directory is deleted.
283
     *
284
     * @return string The canonical pathname string denoting the same file or
285
     *                directory as this abstract pathname
286
     */
287
    public function getCanonicalPath()
288
    {
289
        $fs = FileSystem::getFileSystem();
290
291
        return $fs->canonicalize($this->path);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $fs->canonicalize($this->path) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
292
    }
293
294
    /**
295
     * Returns the canonical form of this abstract pathname.  Equivalent to
296
     * getCanonicalPath(.
297
     *
298
     * @return File The canonical pathname string denoting the same file or
299
     *              directory as this abstract pathname
300
     */
301
    public function getCanonicalFile()
302
    {
303
        return new File($this->getCanonicalPath());
304
    }
305
306
    // -- Attribute accessors --
307
308
    /**
309
     * Tests whether the application can read the file denoted by this
310
     * abstract pathname.
311
     *
312
     * @return bool true if and only if the file specified by this
313
     *              abstract pathname exists and can be read by the
314
     *              application; false otherwise
315
     */
316
    public function canRead()
317
    {
318
        $fs = FileSystem::getFileSystem();
319
320
        if ($fs->checkAccess($this)) {
321
            return (bool) @is_link($this->getAbsolutePath()) || @is_readable($this->getAbsolutePath());
322
        }
323
324
        return false;
325
    }
326
327
    /**
328
     * Tests whether the application can modify to the file denoted by this
329
     * abstract pathname.
330
     *
331
     * @return bool true if and only if the file system actually
332
     *              contains a file denoted by this abstract pathname and
333
     *              the application is allowed to write to the file;
334
     *              false otherwise
335
     */
336
    public function canWrite()
337
    {
338
        $fs = FileSystem::getFileSystem();
339
340
        return $fs->checkAccess($this, true);
341
    }
342
343
    /**
344
     * Tests whether the file denoted by this abstract pathname exists.
345
     *
346
     * @return bool true if and only if the file denoted by this
347
     *              abstract pathname exists; false otherwise
348
     */
349
    public function exists()
350
    {
351
        clearstatcache();
352
353
        if (is_link($this->path)) {
354
            return true;
355
        }
356
357
        if ($this->isDirectory()) {
358
            return true;
359
        }
360
361
        return @file_exists($this->path) || is_link($this->path);
362
    }
363
364
    /**
365
     * Tests whether the file denoted by this abstract pathname is a
366
     * directory.
367
     *
368
     * @throws IOException
369
     *
370
     * @return bool true if and only if the file denoted by this
371
     *              abstract pathname exists and is a directory;
372
     *              false otherwise
373
     */
374
    public function isDirectory()
375
    {
376
        clearstatcache();
377
        $fs = FileSystem::getFileSystem();
378
        if (true !== $fs->checkAccess($this)) {
379
            throw new IOException('No read access to ' . $this->path);
380
        }
381
382
        return @is_dir($this->path) && !@is_link($this->path);
383
    }
384
385
    /**
386
     * Tests whether the file denoted by this abstract pathname is a normal
387
     * file.  A file is normal if it is not a directory and, in
388
     * addition, satisfies other system-dependent criteria.  Any non-directory
389
     * file created by a Java application is guaranteed to be a normal file.
390
     *
391
     * @return bool true if and only if the file denoted by this
392
     *              abstract pathname exists and is a normal file;
393
     *              false otherwise
394
     */
395
    public function isFile()
396
    {
397
        clearstatcache();
398
        //$fs = FileSystem::getFileSystem();
399
        return @is_file($this->path);
400
    }
401
402
    /**
403
     * Tests whether the file denoted by this abstract pathname is a symbolic link.
404
     *
405
     * @throws IOException
406
     *
407
     * @return bool true if and only if the file denoted by this
408
     *              abstract pathname exists and is a symbolic link;
409
     *              false otherwise
410
     */
411
    public function isLink()
412
    {
413
        clearstatcache();
414
        $fs = FileSystem::getFileSystem();
415
        if (true !== $fs->checkAccess($this)) {
416
            throw new IOException('No read access to ' . $this->path);
417
        }
418
419
        return @is_link($this->path);
420
    }
421
422
    /**
423
     * Tests whether the file denoted by this abstract pathname is executable.
424
     *
425
     * @throws IOException
426
     *
427
     * @return bool true if and only if the file denoted by this
428
     *              abstract pathname exists and is a symbolic link;
429
     *              false otherwise
430
     */
431
    public function isExecutable()
432
    {
433
        clearstatcache();
434
        $fs = FileSystem::getFileSystem();
435
        if (true !== $fs->checkAccess($this)) {
436
            throw new IOException('No read access to ' . $this->path);
437
        }
438
439
        return @is_executable($this->path);
440
    }
441
442
    /**
443
     * Returns the target of the symbolic link denoted by this abstract pathname.
444
     *
445
     * @return string the target of the symbolic link denoted by this abstract pathname
446
     */
447
    public function getLinkTarget()
448
    {
449
        return @readlink($this->path);
0 ignored issues
show
Bug Best Practice introduced by
The expression return @readlink($this->path) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
450
    }
451
452
    /**
453
     * Returns the time that the file denoted by this abstract pathname was
454
     * last modified.
455
     *
456
     * @throws IOException
457
     *
458
     * @return int An int value representing the time the file was
459
     *             last modified, measured in seconds since the epoch
460
     *             (00:00:00 GMT, January 1, 1970), or 0 if the
461
     *             file does not exist or if an I/O error occurs
462
     */
463
    public function lastModified()
464
    {
465
        $fs = FileSystem::getFileSystem();
466
        if (true !== $fs->checkAccess($this)) {
467
            throw new IOException('No read access to ' . $this->path);
468
        }
469
470
        return $fs->getLastModifiedTime($this);
471
    }
472
473
    /**
474
     * Returns the length of the file denoted by this abstract pathname.
475
     * The return value is unspecified if this pathname denotes a directory.
476
     *
477
     * @throws IOException
478
     *
479
     * @return int The length, in bytes, of the file denoted by this abstract
480
     *             pathname, or 0 if the file does not exist
481
     */
482
    public function length()
483
    {
484
        $fs = FileSystem::getFileSystem();
485
        if (true !== $fs->checkAccess($this)) {
486
            throw new IOException('No read access to ' . $this->path . "\n");
487
        }
488
489
        return $fs->getLength($this);
490
    }
491
492
    /**
493
     * Convenience method for returning the contents of this file as a string.
494
     * This method uses file_get_contents() to read file in an optimized way.
495
     *
496
     * @throws Exception - if file cannot be read
497
     *
498
     * @return string
499
     */
500
    public function contents()
501
    {
502
        if (!$this->canRead() || !$this->isFile()) {
503
            throw new IOException('Cannot read file contents!');
504
        }
505
506
        return file_get_contents($this->getAbsolutePath());
507
    }
508
509
    // -- File operations --
510
511
    /**
512
     * Atomically creates a new, empty file named by this abstract pathname if
513
     * and only if a file with this name does not yet exist.  The check for the
514
     * existence of the file and the creation of the file if it does not exist
515
     * are a single operation that is atomic with respect to all other
516
     * filesystem activities that might affect the file.
517
     *
518
     * @param bool $parents
519
     *
520
     * @throws IOException
521
     *
522
     * @return bool true if the named file does not exist and was
523
     *              successfully created; <code>false</code> if the named file
524
     *              already exists
525
     */
526
    public function createNewFile($parents = true)
527
    {
528
        /**
529
         * @var File $parent
530
         */
531
        $parent = $this->getParentFile();
532
        if ($parents && null !== $parent && !$parent->exists()) {
533
            $parent->mkdirs();
534
        }
535
536
        return FileSystem::getFileSystem()->createNewFile($this->path);
537
    }
538
539
    /**
540
     * Deletes the file or directory denoted by this abstract pathname.  If
541
     * this pathname denotes a directory, then the directory must be empty in
542
     * order to be deleted.
543
     *
544
     * @param bool $recursive
545
     *
546
     * @throws IOException
547
     */
548
    public function delete($recursive = false)
549
    {
550
        $fs = FileSystem::getFileSystem();
551
        if (true !== $fs->canDelete($this)) {
552
            throw new IOException('Cannot delete ' . $this->path . "\n");
553
        }
554
555
        $fs->delete($this, $recursive);
556
    }
557
558
    /**
559
     * Requests that the file or directory denoted by this abstract pathname
560
     * be deleted when php terminates.  Deletion will be attempted only for
561
     * normal termination of php and if and if only Phing::shutdown() is
562
     * called.
563
     *
564
     * Once deletion has been requested, it is not possible to cancel the
565
     * request.  This method should therefore be used with care.
566
     */
567
    public function deleteOnExit()
568
    {
569
        $fs = FileSystem::getFileSystem();
570
        $fs->deleteOnExit($this);
571
    }
572
573
    /**
574
     * Returns an array of strings naming the files and directories in the
575
     * directory denoted by this abstract pathname.
576
     *
577
     * If this abstract pathname does not denote a directory, then this
578
     * method returns null  Otherwise an array of strings is
579
     * returned, one for each file or directory in the directory.  Names
580
     * denoting the directory itself and the directory's parent directory are
581
     * not included in the result.  Each string is a file name rather than a
582
     * complete path.
583
     *
584
     * There is no guarantee that the name strings in the resulting array
585
     * will appear in any specific order; they are not, in particular,
586
     * guaranteed to appear in alphabetical order.
587
     *
588
     * @return null|array An array of strings naming the files and directories in the
589
     *                    directory denoted by this abstract pathname.  The array will be
590
     *                    empty if the directory is empty.  Returns null if
591
     *                    this abstract pathname does not denote a directory, or if an
592
     *                    I/O error occurs.
593
     */
594
    public function listDir(): ?array
595
    {
596
        try {
597
            $elements = FileSystem::getFileSystem()->listContents($this);
598
        } catch (IOException $e) {
599
            $elements = null;
600
        }
601
602
        return $elements;
603
    }
604
605
    /**
606
     * Creates the directory named by this abstract pathname, including any
607
     * necessary but nonexistent parent directories.  Note that if this
608
     * operation fails it may have succeeded in creating some of the necessary
609
     * parent directories.
610
     *
611
     * @param null|int $mode
612
     *
613
     * @throws IOException
614
     *
615
     * @return bool true if and only if the directory was created,
616
     *              along with all necessary parent directories; false
617
     *              otherwise
618
     */
619
    public function mkdirs($mode = null)
620
    {
621
        if ($this->exists()) {
622
            return false;
623
        }
624
625
        try {
626
            if ($this->mkdir($mode)) {
627
                return true;
628
            }
629
        } catch (IOException $ioe) {
630
            // IOException from mkdir() means that directory propbably didn't exist.
631
        }
632
        $parentFile = $this->getParentFile();
633
634
        return (null !== $parentFile) && ($parentFile->mkdirs() && $this->mkdir($mode));
635
    }
636
637
    /**
638
     * Creates the directory named by this abstract pathname.
639
     *
640
     * @param null|int $mode
641
     *
642
     * @throws IOException
643
     *
644
     * @return bool true if and only if the directory was created; false otherwise
645
     */
646
    public function mkdir($mode = null)
647
    {
648
        $fs = FileSystem::getFileSystem();
649
650
        if (true !== $fs->checkAccess(new File($this->path), true)) {
651
            throw new IOException('No write access to ' . $this->getPath());
652
        }
653
654
        return $fs->createDirectory($this, $mode);
655
    }
656
657
    /**
658
     * Renames the file denoted by this abstract pathname.
659
     *
660
     * @param File $destFile The new abstract pathname for the named file
661
     *
662
     * @throws IOException
663
     */
664
    public function renameTo(File $destFile)
665
    {
666
        $fs = FileSystem::getFileSystem();
667
        if (true !== $fs->checkAccess($this)) {
668
            throw new IOException('No write access to ' . $this->getPath());
669
        }
670
671
        $fs->rename($this, $destFile);
672
    }
673
674
    /**
675
     * Simple-copies file denoted by this abstract pathname into another
676
     * PhingFile.
677
     *
678
     * @param File $destFile The new abstract pathname for the named file
679
     *
680
     * @throws IOException
681
     */
682
    public function copyTo(File $destFile)
683
    {
684
        $fs = FileSystem::getFileSystem();
685
686
        if (true !== $fs->checkAccess($this)) {
687
            throw new IOException('No read access to ' . $this->getPath() . "\n");
688
        }
689
690
        if (true !== $fs->checkAccess($destFile, true)) {
691
            throw new IOException('File::copyTo() No write access to ' . $destFile->getPath());
692
        }
693
694
        $fs->copy($this, $destFile);
695
    }
696
697
    /**
698
     * Sets the last-modified time of the file or directory named by this
699
     * abstract pathname.
700
     *
701
     * All platforms support file-modification times to the nearest second,
702
     * but some provide more precision.  The argument will be truncated to fit
703
     * the supported precision.  If the operation succeeds and no intervening
704
     * operations on the file take place, then the next invocation of the
705
     * lastModified method will return the (possibly truncated) time argument
706
     * that was passed to this method.
707
     *
708
     * @param int $time The new last-modified time, measured in milliseconds since
709
     *                  the epoch (00:00:00 GMT, January 1, 1970)
710
     *
711
     * @throws Exception
712
     */
713
    public function setLastModified($time)
714
    {
715
        $time = (int) $time;
716
        if ($time < 0) {
717
            throw new Exception("IllegalArgumentException, Negative {$time}\n");
718
        }
719
720
        $fs = FileSystem::getFileSystem();
721
722
        $fs->setLastModifiedTime($this, $time);
723
    }
724
725
    /**
726
     * Sets the owner of the file.
727
     *
728
     * @param mixed $user user name or number
729
     *
730
     * @throws IOException
731
     */
732
    public function setUser($user)
733
    {
734
        $fs = FileSystem::getFileSystem();
735
736
        $fs->chown($this->getPath(), $user);
737
    }
738
739
    /**
740
     * Sets the group of the file.
741
     *
742
     * @param string $group
743
     *
744
     * @throws IOException
745
     */
746
    public function setGroup($group)
747
    {
748
        $fs = FileSystem::getFileSystem();
749
750
        $fs->chgrp($this->getPath(), $group);
751
    }
752
753
    /**
754
     * Sets the mode of the file.
755
     *
756
     * @param int $mode octal mode
757
     *
758
     * @throws IOException
759
     */
760
    public function setMode($mode)
761
    {
762
        $fs = FileSystem::getFileSystem();
763
764
        $fs->chmod($this->getPath(), $mode);
765
    }
766
767
    /**
768
     * Retrieve the mode of this file.
769
     *
770
     * @return int
771
     */
772
    public function getMode()
773
    {
774
        return @fileperms($this->getPath());
0 ignored issues
show
Bug Best Practice introduced by
The expression return @fileperms($this->getPath()) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
775
    }
776
777
    // -- Basic infrastructure --
778
779
    /**
780
     * Compares two abstract pathnames lexicographically.  The ordering
781
     * defined by this method depends upon the underlying system.  On UNIX
782
     * systems, alphabetic case is significant in comparing pathnames; on Win32
783
     * systems it is not.
784
     *
785
     * @param File $file th file whose pathname sould be compared to the pathname of this file
786
     *
787
     * @return int Zero if the argument is equal to this abstract pathname, a
788
     *             value less than zero if this abstract pathname is
789
     *             lexicographically less than the argument, or a value greater
790
     *             than zero if this abstract pathname is lexicographically
791
     *             greater than the argument
792
     */
793
    public function compareTo(File $file)
794
    {
795
        $fs = FileSystem::getFileSystem();
796
797
        return $fs->compare($this, $file);
798
    }
799
800
    /**
801
     * Tests this abstract pathname for equality with the given object.
802
     * Returns <code>true</code> if and only if the argument is not
803
     * <code>null</code> and is an abstract pathname that denotes the same file
804
     * or directory as this abstract pathname.  Whether or not two abstract
805
     * pathnames are equal depends upon the underlying system.  On UNIX
806
     * systems, alphabetic case is significant in comparing pathnames; on Win32
807
     * systems it is not.
808
     *
809
     * @param File $obj
810
     *
811
     * @return bool
812
     */
813
    public function equals($obj)
814
    {
815
        if ((null !== $obj) && ($obj instanceof File)) {
816
            return 0 === $this->compareTo($obj);
817
        }
818
819
        return false;
820
    }
821
822
    // -- constructors not called by signature match, so we need some helpers --
823
824
    /**
825
     * @throws IOException
826
     */
827
    protected function constructPathname(string $pathname): void
828
    {
829
        $fs = FileSystem::getFileSystem();
830
831
        $this->path = (string) $fs->normalize($pathname);
832
        $this->prefixLength = (int) $fs->prefixLength($this->path);
833
    }
834
835
    /**
836
     * @throws IOException
837
     */
838
    protected function constructStringParentStringChild(string $parent, string $child): void
839
    {
840
        $fs = FileSystem::getFileSystem();
841
842
        if ('' === $parent) {
843
            $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child));
844
        } else {
845
            $this->path = $fs->resolve($fs->normalize($parent), $fs->normalize($child));
846
        }
847
848
        $this->prefixLength = (int) $fs->prefixLength($this->path);
849
    }
850
851
    /**
852
     * @throws IOException
853
     */
854
    protected function constructFileParentStringChild(File $parent, string $child): void
855
    {
856
        $fs = FileSystem::getFileSystem();
857
858
        if ('' === $parent->path) {
859
            $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child));
860
        } else {
861
            $this->path = $fs->resolve($parent->path, $fs->normalize($child));
862
        }
863
864
        $this->prefixLength = $fs->prefixLength($this->path);
865
    }
866
}
867