File   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 312
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 113
c 1
b 0
f 0
dl 0
loc 312
rs 8.8
wmc 45

15 Methods

Rating   Name   Duplication   Size   Complexity  
A exist() 0 4 3
A size() 0 9 2
A saveFromUrl() 0 36 5
A remove() 0 8 2
A write() 0 12 2
A getMd5() 0 9 2
B listFiles() 0 27 9
A writable() 0 9 2
A inc() 0 12 5
A executable() 0 9 2
A copy() 0 14 2
A getFromUrl() 0 26 4
A mTime() 0 8 2
A read() 0 9 2
A readable() 0 3 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
namespace Ffcms\Core\Helper\FileSystem;
4
5
use Ffcms\Core\Helper\Type\Arr;
6
use Ffcms\Core\Helper\Type\Str;
7
8
/**
9
 * Class File. Provide methods to work with files in current filesystem.
10
 * @package Ffcms\Core\Helper
11
 */
12
class File
13
{
14
15
    /**
16
     * Read file content from local storage
17
     * @param $path
18
     * @return bool|string
19
     */
20
    public static function read($path)
21
    {
22
        $path = Normalize::diskFullPath($path);
23
24
        if (!self::exist($path)) {
25
            return false;
26
        }
27
28
        return @file_get_contents($path);
29
    }
30
31
    /**
32
     * Check if $path is exist and readable in filesystem
33
     * @param string $path
34
     * @return bool
35
     */
36
    public static function exist($path)
37
    {
38
        $path = Normalize::diskFullPath($path);
39
        return (file_exists($path) && is_readable($path) && is_file($path));
40
    }
41
42
    /**
43
     * Alias for exist method
44
     * @param string $path
45
     * @return bool
46
     */
47
    public static function readable($path)
48
    {
49
        return self::exist($path);
50
    }
51
52
    /**
53
     * Check is file writable
54
     * @param string $path
55
     * @return bool
56
     */
57
    public static function writable($path)
58
    {
59
        $path = Normalize::diskFullPath($path);
60
61
        if (!self::exist($path)) {
62
            return false;
63
        }
64
65
        return is_writable($path);
66
    }
67
68
    /**
69
     * Check is file executable
70
     * @param string $path
71
     * @return bool
72
     */
73
    public static function executable($path)
74
    {
75
        $path = Normalize::diskFullPath($path);
76
77
        if (!self::exist($path)) {
78
            return false;
79
        }
80
81
        return is_executable($path);
82
    }
83
84
    /**
85
     * Write $content to file in $path
86
     * @param string $path
87
     * @param null|string $content
88
     * @param null|int $flags
89
     * @return int
90
     */
91
    public static function write($path, $content = null, $flags = null)
92
    {
93
        $path = Normalize::diskFullPath($path);
94
95
        $pathArray = explode(DIRECTORY_SEPARATOR, $path);
96
        array_pop($pathArray);
97
        $pathName = implode(DIRECTORY_SEPARATOR, $pathArray);
98
99
        if (!Directory::exist($pathName)) {
100
            Directory::create($pathName);
101
        }
102
        return @file_put_contents($path, $content, $flags);
103
    }
104
105
    /**
106
     * Copy file from source to target destination
107
     * @param string $source
108
     * @param string $target
109
     * @return bool
110
     */
111
    public static function copy($source, $target)
112
    {
113
        $source = Normalize::diskFullPath($source);
114
        $target = Normalize::diskFullPath($target);
115
116
        // check if target directory exist & create new if not
117
        $targetArray = explode(DIRECTORY_SEPARATOR, $target);
118
        array_pop($targetArray);
119
        $targetDir = implode(DIRECTORY_SEPARATOR, $targetArray);
120
        if (!Directory::exist($targetDir)) {
121
            Directory::create($targetDir, 0777);
122
        }
123
124
        return copy($source, $target);
125
    }
126
127
    /**
128
     * Remove file
129
     * @param string $path
130
     * @return bool
131
     */
132
    public static function remove($path)
133
    {
134
        $path = Normalize::diskFullPath($path);
135
136
        if (!self::exist($path)) {
137
            return false;
138
        }
139
        return unlink($path);
140
    }
141
142
143
    /**
144
     * Alternative of functions include, require, include_once and etc in 1 function
145
     * @param string $path
146
     * @param bool|false $return
147
     * @param bool|false $once
148
     * @return bool|mixed
149
     */
150
    public static function inc($path, $return = false, $once = false)
151
    {
152
        $path = Normalize::diskFullPath($path);
153
154
        if (!self::exist($path)) {
155
            return false;
156
        }
157
158
        if ($return) {
159
            return $once === true ? require_once($path) : require $path;
160
        } else {
161
            ($once == true) ? require_once($path) : require $path;
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
162
        }
163
    }
164
165
    /**
166
     * Get file make time in unix timestamp
167
     * @param string $path
168
     * @return int
169
     */
170
    public static function mTime($path)
171
    {
172
        $path = Normalize::diskFullPath($path);
173
        if (!self::exist($path)) {
174
            return 0;
175
        }
176
177
        return filemtime($path);
178
    }
179
180
    /**
181
     * Recursive scan directory, based on $path and allowed extensions $ext or without it
182
     * @param string $path
183
     * @param array $ext
184
     * @param bool $returnRelative
185
     * @param $files
186
     * @return array
187
     */
188
    public static function listFiles($path, array $ext = null, $returnRelative = false, &$files = [])
189
    {
190
        $path = Normalize::diskFullPath($path);
191
192
        if (!Directory::exist($path)) {
193
            return [];
194
        }
195
196
        $dir = opendir($path . '/.');
197
        while ($item = readdir($dir)) {
0 ignored issues
show
Bug introduced by
It seems like $dir can also be of type false; however, parameter $dir_handle of readdir() 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

197
        while ($item = readdir(/** @scrutinizer ignore-type */ $dir)) {
Loading history...
198
            if (is_file($sub = $path . '/' . $item)) {
199
                $item_ext = Str::lastIn($item, '.');
200
                if ($ext === null || Arr::in($item_ext, $ext)) {
201
                    if ($returnRelative) {
202
                        $files[] = $item;
203
                    } else {
204
                        $files[] = $path . DIRECTORY_SEPARATOR . $item;
205
                    }
206
                }
207
            } else {
208
                if ($item !== '.' && $item !== '..') {
209
                    self::listFiles($sub, $ext, $returnRelative, $files);
210
                }
211
            }
212
        }
213
214
        return $files;
215
    }
216
217
    /**
218
     * Get file size in bytes
219
     * @param string $path
220
     * @return int
221
     */
222
    public static function size($path)
223
    {
224
        $path = Normalize::diskFullPath($path);
225
226
        if (!self::exist($path)) {
227
            return 0;
228
        }
229
230
        return filesize($path);
231
    }
232
233
    /**
234
     * Get file md5 hash
235
     * @param string $path
236
     * @return bool|string
237
     */
238
    public static function getMd5($path)
239
    {
240
        $path = Normalize::diskFullPath($path);
241
242
        if (!self::exist($path)) {
243
            return false;
244
        }
245
246
        return md5_file($path);
247
    }
248
249
    /**
250
     * Get data from remote $url by curl library
251
     * @param string $url
252
     * @return mixed|null|false
253
     */
254
    public static function getFromUrl($url)
255
    {
256
        // check is valid url
257
        if (!filter_var($url, FILTER_VALIDATE_URL) || !function_exists('curl_init')) {
258
            return null;
259
        }
260
261
        // initialize curl & set required options and target url
262
        $curl = \curl_init();
263
        \curl_setopt($curl, CURLOPT_URL, $url);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_setopt() 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

263
        \curl_setopt(/** @scrutinizer ignore-type */ $curl, CURLOPT_URL, $url);
Loading history...
264
        if (Str::startsWith('https', $url)) {
265
            \curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
266
            \curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
267
        }
268
        \curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
269
        \curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
270
        \curl_setopt($curl, CURLOPT_HEADER, 0);
271
        \curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)');
272
        \curl_setopt($curl, CURLOPT_FAILONERROR, true);
273
        \curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
274
        \curl_setopt($curl, CURLOPT_AUTOREFERER, true);
275
        \curl_setopt($curl, CURLOPT_TIMEOUT, 10);
276
        $content = \curl_exec($curl);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_exec() 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

276
        $content = \curl_exec(/** @scrutinizer ignore-type */ $curl);
Loading history...
277
        \curl_close($curl);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_close() 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

277
        \curl_close(/** @scrutinizer ignore-type */ $curl);
Loading history...
278
279
        return $content;
280
    }
281
282
    /**
283
     * Download file from $url and save it into $path
284
     * @param string $url
285
     * @param string $path
286
     * @return bool
287
     */
288
    public static function saveFromUrl($url, $path)
289
    {
290
        if (!filter_var($url, FILTER_VALIDATE_URL) || !function_exists('curl_init')) {
291
            return false;
292
        }
293
294
        $path = Normalize::diskFullPath($path);
295
        // check if upload directory is exists
296
        $dir = dirname($path);
297
        if (!Directory::exist($dir)) {
298
            Directory::create($dir);
299
        }
300
        // initialize stream resource
301
        $stream = @fopen($path, 'w');
302
        // initialize curl & set required options, target url, destination save stream
303
        $curl = \curl_init();
304
        \curl_setopt($curl, CURLOPT_URL, $url);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_setopt() 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

304
        \curl_setopt(/** @scrutinizer ignore-type */ $curl, CURLOPT_URL, $url);
Loading history...
305
        if (Str::startsWith('https', $url)) {
306
            \curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
307
            \curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
308
        }
309
        \curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
310
        \curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
311
        \curl_setopt($curl, CURLOPT_HEADER, 0);
312
        \curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322');
313
        \curl_setopt($curl, CURLOPT_FAILONERROR, true);
314
        \curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
315
        \curl_setopt($curl, CURLOPT_AUTOREFERER, true);
316
        \curl_setopt($curl, CURLOPT_TIMEOUT, 20);
317
        // set destination file path
318
        \curl_setopt($curl, CURLOPT_FILE, $stream);
319
        \curl_exec($curl);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_exec() 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

319
        \curl_exec(/** @scrutinizer ignore-type */ $curl);
Loading history...
320
        \curl_close($curl);
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_close() 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

320
        \curl_close(/** @scrutinizer ignore-type */ $curl);
Loading history...
321
        fclose($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fclose() 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

321
        fclose(/** @scrutinizer ignore-type */ $stream);
Loading history...
322
323
        return true;
324
    }
325
}
326