Completed
Push — master ( e466ef...7ee5e1 )
by Vladimir
03:18
created

File::isSafeToRead()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 15
ccs 8
cts 8
cp 1
rs 9.4285
c 1
b 0
f 0
cc 3
eloc 7
nc 3
nop 0
crap 3
1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Filesystem;
9
10
use allejo\stakx\Exception\FileAccessDeniedException;
11
use allejo\stakx\Service;
12
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
13
14
/**
15
 * A representation of a file on a given filesystem, virtual or physical.
16
 *
17
 * This class extends \SplFileInfo and adds new methods along with overriding some methods solely because I feel that
18
 * some of the naming can be misleading.
19
 *
20
 * @since 0.2.0
21
 */
22
final class File extends \SplFileInfo
23
{
24
    /** @var string */
25
    private $relativePath;
26
27
    /**
28
     * File Constructor.
29
     *
30
     * @param string $filePath An absolute file path or a path relative to the current working directory.
31
     *
32
     * @since 0.2.0
33
     */
34 156
    public function __construct($filePath)
35
    {
36 156
        parent::__construct(self::realpath($filePath));
37
38 156
        $this->relativePath = str_replace(Service::getWorkingDirectory() . DIRECTORY_SEPARATOR, '', $this->getAbsolutePath());
39 156
    }
40
41
    /**
42
     * Get a new File object for another file relative to this file.
43
     *
44
     * @param string $path
45
     *
46
     * @return File
47
     */
48 11
    public function createFileForRelativePath($path)
49
    {
50 11
        return new File(Service::getWorkingDirectory() . DIRECTORY_SEPARATOR . $path);
51
    }
52
53
    /**
54
     * Whether or not this file exists on the filesystem.
55
     *
56
     * @return bool
57
     */
58 147
    public function exists()
59
    {
60 147
        return file_exists($this->getAbsolutePath());
61
    }
62
63
    /**
64
     * Get the name of the file without an extension.
65
     *
66
     * @param  null $suffix This value will be discarded and is only needed to be able to override the \SplFileInfo
67
     *                      definition.
68
     *
69
     * @since 0.2.0
70
     *
71
     * @return string
72
     */
73 5
    public function getBasename($suffix = null)
74
    {
75 5
        return parent::getBasename('.' . $this->getExtension());
76
    }
77
78
    /**
79
     * Get the name of the with the extension.
80
     *
81
     * @since 0.2.0
82
     *
83
     * @return string
84
     */
85 1
    public function getFilename()
86
    {
87 1
        return parent::getBasename();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getBasename() instead of getFilename()). Are you sure this is correct? If so, you might want to change this to $this->getBasename().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
88
    }
89
90
    /**
91
     * Get the absolute path to this file.
92
     *
93
     * @since 0.2.0
94
     *
95
     * @return string
96
     */
97 156
    public function getAbsolutePath()
98
    {
99 156
        return $this->getPathname();
100
    }
101
102
    /**
103
     * Get the path to the parent folder of this file.
104
     *
105
     * @since 0.2.0
106
     *
107
     * @return string
108
     */
109 1
    public function getParentFolder()
110
    {
111 1
        return $this->getPath();
112
    }
113
114
    /**
115
     * Get the file path to this file, relative to where it was created; likely the current working directory.
116
     *
117
     * @since 0.2.0
118
     *
119
     * @return string
120
     */
121 127
    public function getRelativeFilePath()
122
    {
123 127
        return $this->relativePath;
124
    }
125
126
    /**
127
     * Get the path to the parent folder this file, relative to where it was created; likely the current working directory.
128
     *
129
     * @since 0.2.0
130
     *
131
     * @return string
132
     */
133 2
    public function getRelativeParentFolder()
134
    {
135 2
        return dirname($this->getRelativeFilePath());
136
    }
137
138
    /**
139
     * Get the contents of this file.
140
     *
141
     * @since 0.2.0
142
     *
143
     * @throws \RuntimeException When the file could not be read.
144
     *
145
     * @return string
146
     */
147 146
    public function getContents()
148
    {
149 146
        $this->isSafeToRead();
150
151 145
        if (!$this->exists())
152
        {
153 1
            throw new FileNotFoundException(null, 0, null, $this->getAbsolutePath());
154
        }
155
156 145
        $content = file_get_contents($this->getAbsolutePath());
157
158 145
        if ($content === false)
159
        {
160
            $error = error_get_last();
161
            throw new \RuntimeException($error['message']);
162
        }
163
164 145
        return $content;
165
    }
166
167
    /**
168
     * Check if a file is safe to read.
169
     */
170 146
    private function isSafeToRead()
171
    {
172 146
        if (self::isVFS($this->getAbsolutePath()))
173
        {
174 107
            return;
175
        }
176
177 44
        if (strpos($this->getAbsolutePath(), Service::getWorkingDirectory()) !== 0)
178
        {
179 1
            throw new FileAccessDeniedException(sprintf(
180 1
                'The given path "%s" is outside the website working directory',
181 1
                $this->getRelativeFilePath()
182
            ));
183
        }
184 43
    }
185
186
    /**
187
     * A vfsStream friendly way of getting the realpath() of something.
188
     *
189
     * @param string $path
190
     *
191
     * @return string
192
     */
193 156
    public static function realpath($path)
194
    {
195 156
        return self::isVFS($path) ? $path : realpath($path);
196
    }
197
198
    /**
199
     * Check whether a given path is on the virtual filesystem.
200
     *
201
     * @param string $path
202
     *
203
     * @return bool
204
     */
205 156
    private static function isVFS($path)
206
    {
207 156
        return substr($path, 0, 6) == 'vfs://';
208
    }
209
}
210