Passed
Push — master ( 9daf4a...489ae1 )
by Siad
06:23
created

PhingFile::constructPathname()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 10
c 1
b 0
f 0
ccs 4
cts 4
cp 1
crap 1
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
/**
21
 * An abstract representation of file and directory pathnames.
22
 *
23
 * @package phing.system.io
24
 */
25
class PhingFile
26
{
27
    /**
28
     * separator string, static, obtained from FileSystem
29
     */
30
    public static $separator;
31
32
    /**
33
     * path separator string, static, obtained from FileSystem (; or :)
34
     */
35
    public static $pathSeparator;
36
37
    /**
38
     * This abstract pathname's normalized pathname string.  A normalized
39
     * pathname string uses the default name-separator character and does not
40
     * contain any duplicate or redundant separators.
41
     */
42
    private $path = null;
43
44
    /**
45
     * The length of this abstract pathname's prefix, or zero if it has no prefix.
46
     *
47
     * @var int
48
     */
49
    private $prefixLength = 0;
50
51
    /**
52
     * constructor
53
     *
54
     * @param mixed $arg1
55
     * @param mixed $arg2
56
     *
57
     * @throws IOException
58
     * @throws NullPointerException
59
     */
60 766
    public function __construct($arg1 = null, $arg2 = null)
61
    {
62 766
        if (self::$separator === null || self::$pathSeparator === null) {
63
            $fs = FileSystem::getFileSystem();
64
            self::$separator = $fs->getSeparator();
65
            self::$pathSeparator = $fs->getPathSeparator();
66
        }
67
68
        /* simulate signature identified constructors */
69 766
        if ($arg1 instanceof PhingFile && is_string($arg2)) {
70 335
            $this->constructFileParentStringChild($arg1, $arg2);
71 766
        } elseif (is_string($arg1) && ($arg2 === null)) {
72 766
            $this->constructPathname($arg1);
73 98
        } elseif (is_string($arg1) && is_string($arg2)) {
74 6
            $this->constructStringParentStringChild($arg1, $arg2);
75
        } else {
76 95
            if ($arg1 === null) {
77
                throw new NullPointerException("Argument1 to function must not be null");
78
            }
79 95
            $this->path = (string) $arg1;
80 95
            $this->prefixLength = (int) $arg2;
81
        }
82 766
    }
83
84
    /**
85
     * Returns the length of this abstract pathname's prefix.
86
     *
87
     * @return int
88
     */
89 762
    public function getPrefixLength()
90
    {
91 762
        return (int) $this->prefixLength;
92
    }
93
94
    /* -- constructors not called by signature match, so we need some helpers --*/
95
96
    /**
97
     * @param string $pathname
98
     *
99
     * @throws IOException
100
     */
101 766
    protected function constructPathname(string $pathname): void
102
    {
103 766
        $fs = FileSystem::getFileSystem();
104
105 766
        $this->path = (string) $fs->normalize($pathname);
106 766
        $this->prefixLength = (int) $fs->prefixLength($this->path);
107 766
    }
108
109
    /**
110
     * @param string $parent
111
     * @param string $child
112
     * @throws IOException
113
     */
114 6
    protected function constructStringParentStringChild(string $parent, string $child): void
115
    {
116 6
        $fs = FileSystem::getFileSystem();
117
118 6
        if ($parent === "") {
119
            $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child));
120
        } else {
121 6
            $this->path = $fs->resolve($fs->normalize($parent), $fs->normalize($child));
122
        }
123
124 6
        $this->prefixLength = (int) $fs->prefixLength($this->path);
125 6
    }
126
127
    /**
128
     * @param PhingFile $parent
129
     * @param string $child
130
     * @throws IOException
131
     */
132 335
    protected function constructFileParentStringChild(PhingFile $parent, string $child): void
133
    {
134 335
        $fs = FileSystem::getFileSystem();
135
136 335
        if ($parent->path === "") {
137
            $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child));
138
        } else {
139 335
            $this->path = $fs->resolve($parent->path, $fs->normalize($child));
140
        }
141
142 335
        $this->prefixLength = $fs->prefixLength($this->path);
143 335
    }
144
145
    /* -- Path-component accessors -- */
146
147
    /**
148
     * Returns the name of the file or directory denoted by this abstract
149
     * pathname.  This is just the last name in the pathname's name
150
     * sequence.  If the pathname's name sequence is empty, then the empty
151
     * string is returned.
152
     *
153
     * @return string The name of the file or directory denoted by this abstract
154
     *                pathname, or the empty string if this pathname's name sequence
155
     *                is empty
156
     */
157 749
    public function getName()
158
    {
159
        // that's a lastIndexOf
160 749
        $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res);
161 749
        if ($index < $this->prefixLength) {
162 1
            return substr($this->path, $this->prefixLength);
163
        }
164
165 749
        return substr($this->path, $index + 1);
166
    }
167
168
    /**
169
     * Returns the pathname string of this abstract pathname's parent, or
170
     * null if this pathname does not name a parent directory.
171
     *
172
     * The parent of an abstract pathname consists of the pathname's prefix,
173
     * if any, and each name in the pathname's name sequence except for the last.
174
     * If the name sequence is empty then the pathname does not name a parent
175
     * directory.
176
     *
177
     * @return string $pathname string of the parent directory named by this
178
     *                          abstract pathname, or null if this pathname does not name a parent
179
     */
180 749
    public function getParent()
181
    {
182
        // that's a lastIndexOf
183 749
        $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res);
184 749
        if ($index < $this->prefixLength) {
185 14
            if (($this->prefixLength > 0) && (strlen($this->path) > $this->prefixLength)) {
186
                return substr($this->path, 0, $this->prefixLength);
187
            }
188
189 14
            return null;
190
        }
191
192 749
        return substr($this->path, 0, $index);
193
    }
194
195
    /**
196
     * Returns the abstract pathname of this abstract pathname's parent,
197
     * or null if this pathname does not name a parent directory.
198
     *
199
     * The parent of an abstract pathname consists of the pathname's prefix,
200
     * if any, and each name in the pathname's name sequence except for the
201
     * last.  If the name sequence is empty then the pathname does not name
202
     * a parent directory.
203
     *
204
     * @return PhingFile|null The abstract pathname of the parent directory named by this
205
     *             abstract pathname, or null if this pathname
206
     *             does not name a parent
207
     */
208 93
    public function getParentFile()
209
    {
210 93
        $p = $this->getParent();
211 93
        if ($p === null) {
0 ignored issues
show
introduced by
The condition $p === null is always false.
Loading history...
212
            return null;
213
        }
214
215 93
        return new PhingFile((string) $p, (int) $this->prefixLength);
216
    }
217
218
    /**
219
     * Converts this abstract pathname into a pathname string.  The resulting
220
     * string uses the default name-separator character to separate the names
221
     * in the name sequence.
222
     *
223
     * @return string The string form of this abstract pathname
224
     */
225 765
    public function getPath()
226
    {
227 765
        return (string) $this->path;
228
    }
229
230
    /**
231
     * Returns path without leading basedir.
232
     *
233
     * @param string $basedir Base directory to strip
234
     *
235
     * @return string Path without basedir
236
     *
237
     * @uses getPath()
238
     */
239 5
    public function getPathWithoutBase($basedir)
240
    {
241 5
        if (!StringHelper::endsWith(self::$separator, $basedir)) {
242 5
            $basedir .= self::$separator;
243
        }
244 5
        $path = $this->getPath();
245 5
        if (substr($path, 0, strlen($basedir)) != $basedir) {
246
            //path does not begin with basedir, we don't modify it
247 1
            return $path;
248
        }
249
250 4
        return substr($path, strlen($basedir));
251
    }
252
253
    /**
254
     * Tests whether this abstract pathname is absolute.  The definition of
255
     * absolute pathname is system dependent.  On UNIX systems, a pathname is
256
     * absolute if its prefix is "/".  On Win32 systems, a pathname is absolute
257
     * if its prefix is a drive specifier followed by "\\", or if its prefix
258
     * is "\\".
259
     *
260
     * @return boolean true if this abstract pathname is absolute, false otherwise
261
     */
262 170
    public function isAbsolute()
263
    {
264 170
        return ($this->prefixLength !== 0);
265
    }
266
267
    /**
268
     * Returns the file extension for a given file. For example test.php would be returned as php.
269
     *
270
     * @return string The name of the extension.
271
     */
272 13
    public function getFileExtension()
273
    {
274 13
        return pathinfo((string) $this->getAbsolutePath(), PATHINFO_EXTENSION);
275
    }
276
277
    /**
278
     * Returns the absolute pathname string of this abstract pathname.
279
     *
280
     * If this abstract pathname is already absolute, then the pathname
281
     * string is simply returned as if by the getPath method.
282
     * If this abstract pathname is the empty abstract pathname then
283
     * the pathname string of the current user directory, which is named by the
284
     * system property user.dir, is returned.  Otherwise this
285
     * pathname is resolved in a system-dependent way.  On UNIX systems, a
286
     * relative pathname is made absolute by resolving it against the current
287
     * user directory.  On Win32 systems, a relative pathname is made absolute
288
     * by resolving it against the current directory of the drive named by the
289
     * pathname, if any; if not, it is resolved against the current user
290
     * directory.
291
     *
292
     * @return string The absolute pathname string denoting the same file or
293
     *                directory as this abstract pathname
294
     * @see    #isAbsolute()
295
     */
296 762
    public function getAbsolutePath()
297
    {
298 762
        $fs = FileSystem::getFileSystem();
299
300 762
        return $fs->resolveFile($this);
301
    }
302
303
    /**
304
     * Returns the absolute form of this abstract pathname.  Equivalent to
305
     * getAbsolutePath.
306
     *
307
     * @return PhingFile The absolute abstract pathname denoting the same file or
308
     *                directory as this abstract pathname
309
     */
310 4
    public function getAbsoluteFile()
311
    {
312 4
        return new PhingFile((string) $this->getAbsolutePath());
313
    }
314
315
316
    /**
317
     * Returns the canonical pathname string of this abstract pathname.
318
     *
319
     * A canonical pathname is both absolute and unique. The precise
320
     * definition of canonical form is system-dependent. This method first
321
     * converts this pathname to absolute form if necessary, as if by invoking the
322
     * getAbsolutePath() method, and then maps it to its unique form in a
323
     * system-dependent way.  This typically involves removing redundant names
324
     * such as "." and .. from the pathname, resolving symbolic links
325
     * (on UNIX platforms), and converting drive letters to a standard case
326
     * (on Win32 platforms).
327
     *
328
     * Every pathname that denotes an existing file or directory has a
329
     * unique canonical form.  Every pathname that denotes a nonexistent file
330
     * or directory also has a unique canonical form.  The canonical form of
331
     * the pathname of a nonexistent file or directory may be different from
332
     * the canonical form of the same pathname after the file or directory is
333
     * created.  Similarly, the canonical form of the pathname of an existing
334
     * file or directory may be different from the canonical form of the same
335
     * pathname after the file or directory is deleted.
336
     *
337
     * @return string The canonical pathname string denoting the same file or
338
     *                directory as this abstract pathname
339
     */
340 31
    public function getCanonicalPath()
341
    {
342 31
        $fs = FileSystem::getFileSystem();
343
344 31
        return $fs->canonicalize($this->path);
345
    }
346
347
348
    /**
349
     * Returns the canonical form of this abstract pathname.  Equivalent to
350
     * getCanonicalPath(.
351
     *
352
     * @return PhingFile The canonical pathname string denoting the same file or
353
     *                   directory as this abstract pathname
354
     */
355 31
    public function getCanonicalFile()
356
    {
357 31
        return new PhingFile($this->getCanonicalPath());
358
    }
359
360
    /**
361
     * Converts this abstract pathname into a file: URL.  The
362
     * exact form of the URL is system-dependent.  If it can be determined that
363
     * the file denoted by this abstract pathname is a directory, then the
364
     * resulting URL will end with a slash.
365
     *
366
     * Usage note: This method does not automatically escape
367
     * characters that are illegal in URLs.  It is recommended that new code
368
     * convert an abstract pathname into a URL by first converting it into a
369
     * URI, via the toURI() method, and then converting the URI
370
     * into a URL via the URI::toURL()
371
     *
372
     * @return void A URL object representing the equivalent file URL
373
     * @todo   Not implemented yet
374
     */
375
    public function toURL()
376
    {
377
        /*
378
        // URL class not implemented yet
379
        return new URL("file", "", $this->_slashify($this->getAbsolutePath(), $this->isDirectory()));
380
        */
381
    }
382
383
    /**
384
     * Constructs a file: URI that represents this abstract pathname.
385
     *
386
     * @todo   Not implemented yet
387
     * @return void
388
     */
389
    public function toURI()
390
    {
391
        /*
392
        $f = $this->getAbsoluteFile();
393
           $sp = (string) $this->slashify($f->getPath(), $f->isDirectory());
394
           if (StringHelper::startsWith('//', $sp))
395
        $sp = '//' + sp;
396
397
           return new URI('file', null, $sp, null);
398
        */
399
    }
400
401
    /**
402
     * Enter description here ...
403
     *
404
     * @param  PhingFile|string $path
405
     * @param  boolean $isDirectory
406
     * @return string
407
     */
408
    public function _slashify($path, $isDirectory)
409
    {
410
        $p = (string) $path;
411
412
        if (self::$separator !== '/') {
413
            $p = str_replace(self::$separator, '/', $p);
414
        }
415
416
        if (!StringHelper::startsWith('/', $p)) {
417
            $p = '/' . $p;
418
        }
419
420
        if (!StringHelper::endsWith('/', $p) && $isDirectory) {
421
            $p .= '/';
422
        }
423
424
        return $p;
425
    }
426
427
    /* -- Attribute accessors -- */
428
429
    /**
430
     * Tests whether the application can read the file denoted by this
431
     * abstract pathname.
432
     *
433
     * @return boolean true if and only if the file specified by this
434
     *                 abstract pathname exists and can be read by the
435
     *                 application; false otherwise
436
     */
437 752
    public function canRead()
438
    {
439 752
        $fs = FileSystem::getFileSystem();
440
441 752
        if ($fs->checkAccess($this)) {
442 752
            return (bool) @is_link($this->getAbsolutePath()) || @is_readable($this->getAbsolutePath());
443
        }
444
445
        return false;
446
    }
447
448
    /**
449
     * Tests whether the application can modify to the file denoted by this
450
     * abstract pathname.
451
     *
452
     * @return boolean true if and only if the file system actually
453
     *                 contains a file denoted by this abstract pathname and
454
     *                 the application is allowed to write to the file;
455
     *                 false otherwise.
456
     */
457 72
    public function canWrite()
458
    {
459 72
        $fs = FileSystem::getFileSystem();
460
461 72
        return $fs->checkAccess($this, true);
462
    }
463
464
    /**
465
     * Tests whether the file denoted by this abstract pathname exists.
466
     *
467
     * @return boolean true if and only if the file denoted by this
468
     *                 abstract pathname exists; false otherwise
469
     */
470 759
    public function exists()
471
    {
472 759
        clearstatcache();
473
474 759
        if (is_link($this->path)) {
475 4
            return true;
476
        }
477
478 759
        if ($this->isDirectory()) {
479 758
            return true;
480
        }
481
482 750
        return @file_exists($this->path) || is_link($this->path);
483
    }
484
485
    /**
486
     * Tests whether the file denoted by this abstract pathname is a
487
     * directory.
488
     *
489
     * @throws IOException
490
     * @return boolean true if and only if the file denoted by this
491
     *                 abstract pathname exists and is a directory;
492
     *                 false otherwise
493
     */
494 759
    public function isDirectory()
495
    {
496 759
        clearstatcache();
497 759
        $fs = FileSystem::getFileSystem();
498 759
        if ($fs->checkAccess($this) !== true) {
499
            throw new IOException("No read access to " . $this->path);
500
        }
501
502 759
        return @is_dir($this->path) && !@is_link($this->path);
503
    }
504
505
    /**
506
     * Tests whether the file denoted by this abstract pathname is a normal
507
     * file.  A file is normal if it is not a directory and, in
508
     * addition, satisfies other system-dependent criteria.  Any non-directory
509
     * file created by a Java application is guaranteed to be a normal file.
510
     *
511
     * @return boolean true if and only if the file denoted by this
512
     *                 abstract pathname exists and is a normal file;
513
     *                 false otherwise
514
     */
515 125
    public function isFile()
516
    {
517 125
        clearstatcache();
518
        //$fs = FileSystem::getFileSystem();
519 125
        return @is_file($this->path);
520
    }
521
522
    /**
523
     * Tests whether the file named by this abstract pathname is a hidden
524
     * file.  The exact definition of hidden is system-dependent.  On
525
     * UNIX systems, a file is considered to be hidden if its name begins with
526
     * a period character ('.').  On Win32 systems, a file is considered to be
527
     * hidden if it has been marked as such in the filesystem. Currently there
528
     * seems to be no way to dermine isHidden on Win file systems via PHP
529
     *
530
     * @throws IOException
531
     * @return boolean true if and only if the file denoted by this
532
     *                 abstract pathname is hidden according to the conventions of the
533
     *                 underlying platform
534
     */
535
    public function isHidden()
536
    {
537
        $fs = FileSystem::getFileSystem();
538
        if ($fs->checkAccess($this) !== true) {
539
            throw new IOException("No read access to " . $this->path);
540
        }
541
542
        return (($fs->getBooleanAttributes($this) & FileSystem::BA_HIDDEN) !== 0);
543
    }
544
545
    /**
546
     * Tests whether the file denoted by this abstract pathname is a symbolic link.
547
     *
548
     * @throws IOException
549
     * @return boolean true if and only if the file denoted by this
550
     *                 abstract pathname exists and is a symbolic link;
551
     *                 false otherwise
552
     */
553 113
    public function isLink()
554
    {
555 113
        clearstatcache();
556 113
        $fs = FileSystem::getFileSystem();
557 113
        if ($fs->checkAccess($this) !== true) {
558
            throw new IOException("No read access to " . $this->path);
559
        }
560
561 113
        return @is_link($this->path);
562
    }
563
564
    /**
565
     * Tests whether the file denoted by this abstract pathname is executable.
566
     *
567
     * @throws IOException
568
     * @return boolean true if and only if the file denoted by this
569
     *                 abstract pathname exists and is a symbolic link;
570
     *                 false otherwise
571
     */
572 2
    public function isExecutable()
573
    {
574 2
        clearstatcache();
575 2
        $fs = FileSystem::getFileSystem();
576 2
        if ($fs->checkAccess($this) !== true) {
577
            throw new IOException("No read access to " . $this->path);
578
        }
579
580 2
        return @is_executable($this->path);
581
    }
582
583
    /**
584
     * Returns the target of the symbolic link denoted by this abstract pathname
585
     *
586
     * @return string the target of the symbolic link denoted by this abstract pathname
587
     */
588 8
    public function getLinkTarget()
589
    {
590 8
        return @readlink($this->path);
591
    }
592
593
    /**
594
     * Returns the time that the file denoted by this abstract pathname was
595
     * last modified.
596
     *
597
     * @throws IOException
598
     * @return int An integer value representing the time the file was
599
     *             last modified, measured in seconds since the epoch
600
     *             (00:00:00 GMT, January 1, 1970), or 0 if the
601
     *             file does not exist or if an I/O error occurs
602
     */
603 38
    public function lastModified()
604
    {
605 38
        $fs = FileSystem::getFileSystem();
606 38
        if ($fs->checkAccess($this) !== true) {
607
            throw new IOException("No read access to " . $this->path);
608
        }
609
610 38
        return $fs->getLastModifiedTime($this);
611
    }
612
613
    /**
614
     * Returns the length of the file denoted by this abstract pathname.
615
     * The return value is unspecified if this pathname denotes a directory.
616
     *
617
     * @throws IOException
618
     * @return int The length, in bytes, of the file denoted by this abstract
619
     *             pathname, or 0 if the file does not exist
620
     */
621 14
    public function length()
622
    {
623 14
        $fs = FileSystem::getFileSystem();
624 14
        if ($fs->checkAccess($this) !== true) {
625
            throw new IOException("No read access to " . $this->path . "\n");
626
        }
627
628 14
        return $fs->getLength($this);
629
    }
630
631
    /**
632
     * Convenience method for returning the contents of this file as a string.
633
     * This method uses file_get_contents() to read file in an optimized way.
634
     *
635
     * @return string
636
     * @throws Exception - if file cannot be read
637
     */
638 4
    public function contents()
639
    {
640 4
        if (!$this->canRead() || !$this->isFile()) {
641
            throw new IOException("Cannot read file contents!");
642
        }
643
644 4
        return file_get_contents($this->getAbsolutePath());
645
    }
646
647
    /* -- File operations -- */
648
649
    /**
650
     * Atomically creates a new, empty file named by this abstract pathname if
651
     * and only if a file with this name does not yet exist.  The check for the
652
     * existence of the file and the creation of the file if it does not exist
653
     * are a single operation that is atomic with respect to all other
654
     * filesystem activities that might affect the file.
655
     *
656
     * @param  bool $parents
657
     * @param  int $mode
658
     * @throws IOException
659
     * @return boolean     true if the named file does not exist and was
660
     *                     successfully created; <code>false</code> if the named file
661
     *                     already exists
662
     */
663 61
    public function createNewFile($parents = true, $mode = 0777)
0 ignored issues
show
Unused Code introduced by
The parameter $mode is not used and could be removed. ( Ignorable by Annotation )

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

663
    public function createNewFile($parents = true, /** @scrutinizer ignore-unused */ $mode = 0777)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
664
    {
665
        /**
666
         * @var PhingFile $parent
667
         */
668 61
        $parent = $this->getParentFile();
669 61
        if ($parents && $parent !== null && !$parent->exists()) {
670 2
            $parent->mkdirs();
671
        }
672
673 61
        $file = FileSystem::getFileSystem()->createNewFile($this->path);
674
675 60
        return $file;
676
    }
677
678
    /**
679
     * Deletes the file or directory denoted by this abstract pathname.  If
680
     * this pathname denotes a directory, then the directory must be empty in
681
     * order to be deleted.
682
     *
683
     * @param  bool $recursive
684
     * @throws IOException
685
     */
686 142
    public function delete($recursive = false)
687
    {
688 142
        $fs = FileSystem::getFileSystem();
689 142
        if ($fs->canDelete($this) !== true) {
690
            throw new IOException("Cannot delete " . $this->path . "\n");
691
        }
692
693 142
        $fs->delete($this, $recursive);
694 142
    }
695
696
    /**
697
     * Requests that the file or directory denoted by this abstract pathname
698
     * be deleted when php terminates.  Deletion will be attempted only for
699
     * normal termination of php and if and if only Phing::shutdown() is
700
     * called.
701
     *
702
     * Once deletion has been requested, it is not possible to cancel the
703
     * request.  This method should therefore be used with care.
704
     */
705
    public function deleteOnExit()
706
    {
707
        $fs = FileSystem::getFileSystem();
708
        $fs->deleteOnExit($this);
709
    }
710
711
    /**
712
     * Returns an array of strings naming the files and directories in the
713
     * directory denoted by this abstract pathname.
714
     *
715
     * If this abstract pathname does not denote a directory, then this
716
     * method returns null  Otherwise an array of strings is
717
     * returned, one for each file or directory in the directory.  Names
718
     * denoting the directory itself and the directory's parent directory are
719
     * not included in the result.  Each string is a file name rather than a
720
     * complete path.
721
     *
722
     * There is no guarantee that the name strings in the resulting array
723
     * will appear in any specific order; they are not, in particular,
724
     * guaranteed to appear in alphabetical order.
725
     *
726
     * @return array|null An array of strings naming the files and directories in the
727
     *                    directory denoted by this abstract pathname.  The array will be
728
     *                    empty if the directory is empty.  Returns null if
729
     *                    this abstract pathname does not denote a directory, or if an
730
     *                    I/O error occurs.
731
     */
732 173
    public function listDir(): ?array
733
    {
734
        try {
735 173
            $elements = FileSystem::getFileSystem()->listContents($this);
736
        } catch (IOException $e) {
737
            $elements = null;
738
        }
739
740 173
        return $elements;
741
    }
742
743
    /**
744
     * Creates the directory named by this abstract pathname, including any
745
     * necessary but nonexistent parent directories.  Note that if this
746
     * operation fails it may have succeeded in creating some of the necessary
747
     * parent directories.
748
     *
749
     * @param  int $mode
750
     * @throws IOException
751
     * @return boolean     true if and only if the directory was created,
752
     *                     along with all necessary parent directories; false
753
     *                     otherwise
754
     */
755 116
    public function mkdirs($mode = 0755)
756
    {
757 116
        if ($this->exists()) {
758
            return false;
759
        }
760
        try {
761 116
            if ($this->mkdir($mode)) {
762 116
                return true;
763
            }
764
        } catch (IOException $ioe) {
765
            // IOException from mkdir() means that directory propbably didn't exist.
766
        }
767 29
        $parentFile = $this->getParentFile();
768
769 29
        return (($parentFile !== null) && ($parentFile->mkdirs($mode) && $this->mkdir($mode)));
770
    }
771
772
    /**
773
     * Creates the directory named by this abstract pathname.
774
     *
775
     * @param  int $mode
776
     * @throws IOException
777
     * @return boolean     true if and only if the directory was created; false otherwise
778
     */
779 116
    public function mkdir($mode = 0755)
780
    {
781 116
        $fs = FileSystem::getFileSystem();
782
783 116
        if ($fs->checkAccess(new PhingFile($this->path), true) !== true) {
784
            throw new IOException("No write access to " . $this->getPath());
785
        }
786
787 116
        return $fs->createDirectory($this, $mode);
788
    }
789
790
    /**
791
     * Renames the file denoted by this abstract pathname.
792
     *
793
     * @param  PhingFile $destFile The new abstract pathname for the named file
794
     * @throws IOException
795
     */
796 1
    public function renameTo(PhingFile $destFile)
797
    {
798 1
        $fs = FileSystem::getFileSystem();
799 1
        if ($fs->checkAccess($this) !== true) {
800
            throw new IOException("No write access to " . $this->getPath());
801
        }
802
803 1
        $fs->rename($this, $destFile);
804 1
    }
805
806
    /**
807
     * Simple-copies file denoted by this abstract pathname into another
808
     * PhingFile
809
     *
810
     * @param  PhingFile $destFile The new abstract pathname for the named file
811
     * @throws IOException
812
     */
813 12
    public function copyTo(PhingFile $destFile)
814
    {
815 12
        $fs = FileSystem::getFileSystem();
816
817 12
        if ($fs->checkAccess($this) !== true) {
818
            throw new IOException("No read access to " . $this->getPath() . "\n");
819
        }
820
821 12
        if ($fs->checkAccess($destFile, true) !== true) {
822
            throw new IOException("File::copyTo() No write access to " . $destFile->getPath());
823
        }
824
825 12
        $fs->copy($this, $destFile);
826 12
    }
827
828
    /**
829
     * Sets the last-modified time of the file or directory named by this
830
     * abstract pathname.
831
     *
832
     * All platforms support file-modification times to the nearest second,
833
     * but some provide more precision.  The argument will be truncated to fit
834
     * the supported precision.  If the operation succeeds and no intervening
835
     * operations on the file take place, then the next invocation of the
836
     * lastModified method will return the (possibly truncated) time argument
837
     * that was passed to this method.
838
     *
839
     * @param  int $time The new last-modified time, measured in milliseconds since
840
     *                       the epoch (00:00:00 GMT, January 1, 1970)
841
     * @throws Exception
842
     */
843 65
    public function setLastModified($time)
844
    {
845 65
        $time = (int) $time;
846 65
        if ($time < 0) {
847
            throw new Exception("IllegalArgumentException, Negative $time\n");
848
        }
849
850 65
        $fs = FileSystem::getFileSystem();
851
852 65
        $fs->setLastModifiedTime($this, $time);
853 65
    }
854
855
    /**
856
     * Marks the file or directory named by this abstract pathname so that
857
     * only read operations are allowed.  After invoking this method the file
858
     * or directory is guaranteed not to change until it is either deleted or
859
     * marked to allow write access.  Whether or not a read-only file or
860
     * directory may be deleted depends upon the underlying system.
861
     *
862
     * @throws IOException
863
     */
864
    public function setReadOnly()
865
    {
866
        $fs = FileSystem::getFileSystem();
867
        if ($fs->checkAccess($this, true) !== true) {
868
            // Error, no write access
869
            throw new IOException("No write access to " . $this->getPath());
870
        }
871
872
        $fs->setReadOnly($this);
873
    }
874
875
    /**
876
     * Sets the owner of the file.
877
     *
878
     * @param mixed $user User name or number.
879
     *
880
     * @throws IOException
881
     */
882
    public function setUser($user)
883
    {
884
        $fs = FileSystem::getFileSystem();
885
886
        $fs->chown($this->getPath(), $user);
887
    }
888
889
    /**
890
     * Retrieve the owner of this file.
891
     *
892
     * @return int User ID of the owner of this file.
893
     */
894
    public function getUser()
895
    {
896
        return @fileowner($this->getPath());
897
    }
898
899
    /**
900
     * Sets the group of the file.
901
     *
902
     * @param string $group
903
     *
904
     * @throws IOException
905
     */
906
    public function setGroup($group)
907
    {
908
        $fs = FileSystem::getFileSystem();
909
910
        $fs->chgrp($this->getPath(), $group);
911
    }
912
913
    /**
914
     * Retrieve the group of this file.
915
     *
916
     * @return int User ID of the owner of this file.
917
     */
918
    public function getGroup()
919
    {
920
        return @filegroup($this->getPath());
921
    }
922
923
    /**
924
     * Sets the mode of the file
925
     *
926
     * @param  int $mode Octal mode.
927
     * @throws IOException
928
     */
929 39
    public function setMode($mode)
930
    {
931 39
        $fs = FileSystem::getFileSystem();
932
933 39
        $fs->chmod($this->getPath(), $mode);
934 39
    }
935
936
    /**
937
     * Retrieve the mode of this file.
938
     *
939
     * @return int
940
     */
941 34
    public function getMode()
942
    {
943 34
        return @fileperms($this->getPath());
944
    }
945
946
    /* -- Filesystem interface -- */
947
948
    /**
949
     * List the available filesystem roots.
950
     *
951
     * A particular platform may support zero or more hierarchically-organized
952
     * file systems.  Each file system has a root  directory from which all
953
     * other files in that file system can be reached.
954
     * Windows platforms, for example, have a root directory for each active
955
     * drive; UNIX platforms have a single root directory, namely "/".
956
     * The set of available filesystem roots is affected by various system-level
957
     * operations such the insertion or ejection of removable media and the
958
     * disconnecting or unmounting of physical or virtual disk drives.
959
     *
960
     * This method returns an array of PhingFile objects that
961
     * denote the root directories of the available filesystem roots.  It is
962
     * guaranteed that the canonical pathname of any file physically present on
963
     * the local machine will begin with one of the roots returned by this
964
     * method.
965
     *
966
     * The canonical pathname of a file that resides on some other machine
967
     * and is accessed via a remote-filesystem protocol such as SMB or NFS may
968
     * or may not begin with one of the roots returned by this method.  If the
969
     * pathname of a remote file is syntactically indistinguishable from the
970
     * pathname of a local file then it will begin with one of the roots
971
     * returned by this method.  Thus, for example, PhingFile objects
972
     * denoting the root directories of the mapped network drives of a Windows
973
     * platform will be returned by this method, while PhingFile
974
     * objects containing UNC pathnames will not be returned by this method.
975
     *
976
     * @return array An array of PhingFile objects denoting the available
977
     *               filesystem roots, or null if the set of roots
978
     *               could not be determined.  The array will be empty if there are
979
     *               no filesystem roots.
980
     */
981
    public function listRoots()
982
    {
983
        $fs = FileSystem::getFileSystem();
984
985
        return (array) $fs->listRoots();
986
    }
987
988
    /* -- Tempfile management -- */
989
990
    /**
991
     * Returns the path to the temp directory.
992
     *
993
     * @return string
994
     */
995
    public static function getTempDir()
996
    {
997
        return Phing::getProperty('php.tmpdir');
998
    }
999
1000
    /**
1001
     * Static method that creates a unique filename whose name begins with
1002
     * $prefix and ends with $suffix in the directory $directory. $directory
1003
     * is a reference to a PhingFile Object.
1004
     * Then, the file is locked for exclusive reading/writing.
1005
     *
1006
     * @author manuel holtgrewe, [email protected]
1007
     *
1008
     * @param $prefix
1009
     * @param $suffix
1010
     * @param PhingFile $directory
1011
     *
1012
     * @throws IOException
1013
     * @return PhingFile
1014
     */
1015
    public static function createTempFile($prefix, $suffix, PhingFile $directory)
1016
    {
1017
1018
        // quick but efficient hack to create a unique filename ;-)
1019
        $result = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
1020
        do {
1021
            $result = new PhingFile($directory, $prefix . substr(md5(time()), 0, 8) . $suffix);
1022
        } while (file_exists($result->getPath()));
1023
1024
        $fs = FileSystem::getFileSystem();
1025
        $fs->createNewFile($result->getPath());
1026
        $fs->lock($result);
1027
1028
        return $result;
1029
    }
1030
1031
    /**
1032
     * If necessary, $File the lock on $File is removed and then the file is
1033
     * deleted.
1034
     */
1035
    public function removeTempFile()
1036
    {
1037
        $fs = FileSystem::getFileSystem();
1038
        // catch IO Exception
1039
        $fs->unlock($this);
1040
        $this->delete();
1041
    }
1042
1043
    /* -- Basic infrastructure -- */
1044
1045
    /**
1046
     * Compares two abstract pathnames lexicographically.  The ordering
1047
     * defined by this method depends upon the underlying system.  On UNIX
1048
     * systems, alphabetic case is significant in comparing pathnames; on Win32
1049
     * systems it is not.
1050
     *
1051
     * @param PhingFile $file Th file whose pathname sould be compared to the pathname of this file.
1052
     *
1053
     * @return int Zero if the argument is equal to this abstract pathname, a
1054
     *             value less than zero if this abstract pathname is
1055
     *             lexicographically less than the argument, or a value greater
1056
     *             than zero if this abstract pathname is lexicographically
1057
     *             greater than the argument
1058
     */
1059 5
    public function compareTo(PhingFile $file)
1060
    {
1061 5
        $fs = FileSystem::getFileSystem();
1062
1063 5
        return $fs->compare($this, $file);
1064
    }
1065
1066
    /**
1067
     * Tests this abstract pathname for equality with the given object.
1068
     * Returns <code>true</code> if and only if the argument is not
1069
     * <code>null</code> and is an abstract pathname that denotes the same file
1070
     * or directory as this abstract pathname.  Whether or not two abstract
1071
     * pathnames are equal depends upon the underlying system.  On UNIX
1072
     * systems, alphabetic case is significant in comparing pathnames; on Win32
1073
     * systems it is not.
1074
     *
1075
     * @param PhingFile $obj
1076
     *
1077
     * @return boolean
1078
     */
1079 5
    public function equals($obj)
1080
    {
1081 5
        if (($obj !== null) && ($obj instanceof PhingFile)) {
1082 5
            return ($this->compareTo($obj) === 0);
1083
        }
1084
1085
        return false;
1086
    }
1087
1088
    /**
1089
     * Return string representation of the object
1090
     *
1091
     * @return string
1092
     */
1093 751
    public function __toString()
1094
    {
1095 751
        return $this->getPath();
1096
    }
1097
}
1098