Passed
Push — devel-3.0 ( ca2338...7158af )
by Rubén
03:39
created

FileHandler::close()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
8
 *
9
 * This file is part of sysPass.
10
 *
11
 * sysPass is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * sysPass is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 *  along with sysPass.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace SP\Storage\File;
26
27
/**
28
 * Class FileHandler
29
 *
30
 * @package SP\Storage\File;
31
 */
32
final class FileHandler
33
{
34
    const CHUNK_LENGTH = 8192;
35
    /**
36
     * @var string
37
     */
38
    protected $file;
39
    /**
40
     * @var resource
41
     */
42
    protected $handle;
43
44
    /**
45
     * FileHandler constructor.
46
     *
47
     * @param string $file
48
     */
49
    public function __construct(string $file)
50
    {
51
        $this->file = $file;
52
    }
53
54
    /**
55
     * Writes data into file
56
     *
57
     * @param $data
58
     *
59
     * @return FileHandler
60
     * @throws FileException
61
     */
62
    public function write($data)
63
    {
64
        if (!is_resource($this->handle)) {
65
            $this->open('wb');
66
        }
67
68
        if (@fwrite($this->handle, $data) === false) {
0 ignored issues
show
Bug introduced by
It seems like $this->handle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

68
        if (@fwrite(/** @scrutinizer ignore-type */ $this->handle, $data) === false) {
Loading history...
69
            throw new FileException(sprintf(__('No es posible escribir en el archivo (%s)'), $this->file));
70
        }
71
72
        return $this;
73
    }
74
75
    /**
76
     * Opens the file
77
     *
78
     * @param $mode
79
     *
80
     * @return resource
81
     * @throws FileException
82
     */
83
    public function open($mode = 'r')
84
    {
85
        if (($this->handle = @fopen($this->file, $mode)) === false) {
0 ignored issues
show
Documentation Bug introduced by
It seems like @fopen($this->file, $mode) can also be of type false. However, the property $handle is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
86
            throw new FileException(sprintf(__('No es posible abrir el archivo (%s)'), $this->file));
87
        }
88
89
        return $this->handle;
90
    }
91
92
    /**
93
     * Reads data from file into a string
94
     *
95
     * @return string Data read from file
96
     * @throws FileException
97
     */
98
    public function readToString(): string
99
    {
100
        if (($data = file_get_contents($this->file)) === false) {
101
            throw new FileException(sprintf(__('No es posible leer desde el archivo (%s)'), $this->file));
102
        }
103
104
        return $data;
105
    }
106
107
    /**
108
     * Reads data from file into an array
109
     *
110
     * @throws FileException
111
     */
112
    public function readToArray(): array
113
    {
114
        if (($data = @file($this->file, FILE_SKIP_EMPTY_LINES)) === false) {
115
            throw new FileException(sprintf(__('No es posible leer desde el archivo (%s)'), $this->file));
116
        }
117
118
        return $data;
119
    }
120
121
    /**
122
     * Reads data from file into a string
123
     *
124
     * @param string $data Data to write into file
125
     *
126
     * @return FileHandler
127
     * @throws FileException
128
     */
129
    public function save($data)
130
    {
131
        if (file_put_contents($this->file, $data, LOCK_EX) === false) {
132
            throw new FileException(sprintf(__('No es posible escribir en el archivo (%s)'), $this->file));
133
        }
134
135
        return $this;
136
    }
137
138
    /**
139
     * Reads data from file
140
     *
141
     * @return string Data read from file
142
     * @throws FileException
143
     */
144
    public function read()
145
    {
146
        if (!is_resource($this->handle)) {
147
            $this->open('rb');
148
        }
149
150
        $data = '';
151
152
        while (!feof($this->handle)) {
0 ignored issues
show
Bug introduced by
It seems like $this->handle can also be of type false; however, parameter $handle of feof() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

152
        while (!feof(/** @scrutinizer ignore-type */ $this->handle)) {
Loading history...
153
            $data .= fread($this->handle, self::CHUNK_LENGTH);
0 ignored issues
show
Bug introduced by
It seems like $this->handle can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

153
            $data .= fread(/** @scrutinizer ignore-type */ $this->handle, self::CHUNK_LENGTH);
Loading history...
154
        }
155
156
        $this->close();
157
158
        return $data;
159
    }
160
161
    /**
162
     * Closes the file
163
     *
164
     * @throws FileException
165
     * @return FileHandler
166
     */
167
    public function close()
168
    {
169
        if (!is_resource($this->handle) || @fclose($this->handle) === false) {
170
            throw new FileException(sprintf(__('No es posible cerrar el archivo (%s)'), $this->file));
171
        }
172
173
        return $this;
174
    }
175
176
    /**
177
     * Checks if the file is writable
178
     *
179
     * @throws FileException
180
     * @return FileHandler
181
     */
182
    public function checkIsWritable()
183
    {
184
        if (!is_writable($this->file) && @touch($this->file) === false) {
185
            throw new FileException(sprintf(__('No es posible escribir el archivo (%s)'), $this->file));
186
        }
187
188
        return $this;
189
    }
190
191
    /**
192
     * Checks if the file exists
193
     *
194
     * @throws FileException
195
     * @return FileHandler
196
     */
197
    public function checkFileExists()
198
    {
199
        if (!file_exists($this->file)) {
200
            throw new FileException(sprintf(__('Archivo no encontrado (%s)'), $this->file));
201
        }
202
203
        return $this;
204
    }
205
206
    /**
207
     * @return string
208
     */
209
    public function getFile(): string
210
    {
211
        return $this->file;
212
    }
213
214
    /**
215
     * @param bool $isExceptionOnZero
216
     *
217
     * @return int
218
     * @throws FileException
219
     */
220
    public function getFileSize($isExceptionOnZero = false): int
221
    {
222
        $size = filesize($this->file);
223
224
        if ($size === false || ($isExceptionOnZero === true && $size === 0)) {
225
            throw new FileException(sprintf(__('No es posible leer el archivo (%s)'), $this->file));
226
        }
227
228
        return $size;
229
    }
230
231
    /**
232
     * Clears the stat cache for the given file
233
     *
234
     * @return FileHandler
235
     */
236
    public function clearCache()
237
    {
238
        clearstatcache(true, $this->file);
239
240
        return $this;
241
    }
242
243
    /**
244
     * Deletes a file
245
     *
246
     * @return FileHandler
247
     * @throws FileException
248
     */
249
    public function delete()
250
    {
251
        if (@unlink($this->file) === false) {
252
            throw new FileException(sprintf(__('No es posible eliminar el archivo (%s)'), $this->file));
253
        }
254
255
        return $this;
256
    }
257
258
    /**
259
     * Returns the content type in MIME format
260
     *
261
     * @return string
262
     * @throws FileException
263
     */
264
    public function getFileType(): string
265
    {
266
        $this->checkIsReadable();
267
268
        return mime_content_type($this->file);
269
    }
270
271
    /**
272
     * Checks if the file is readable
273
     *
274
     * @throws FileException
275
     * @return FileHandler
276
     */
277
    public function checkIsReadable()
278
    {
279
        if (!is_readable($this->file)) {
280
            throw new FileException(sprintf(__('No es posible leer el archivo (%s)'), $this->file));
281
        }
282
283
        return $this;
284
    }
285
286
    /**
287
     * @return int
288
     * @throws FileException
289
     */
290
    public function getFileTime(): int
291
    {
292
        $this->checkIsReadable();
293
294
        return filemtime($this->file) ?: 0;
295
    }
296
}