GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( f5b4f0...d88521 )
by t
01:58
created

LocalFile::getPerms()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class LocalFile
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2019, icy2003
8
 */
9
namespace icy2003\php\icomponents\file;
10
11
use icy2003\php\I;
12
use icy2003\php\icomponents\file\FileInterface;
13
14
/**
15
 * 本地文件
16
 *
17
 * - 支持本地文件操作
18
 * - 支持网络文件:文件是否存在、文件大小
19
 */
20
class LocalFile extends Base implements FileInterface
21
{
22
23
    /**
24
     * 加载文件用的函数
25
     *
26
     * @var callback
27
     */
28
    protected $_functions = [
29
        'loader' => null,
30
    ];
31
32
    /**
33
     * 文件属性
34
     *
35
     * - 文件名为键,属性为值
36
     *
37
     * @var array
38
     */
39
    protected $_attributes = [];
40
41
    /**
42
     * 初始化
43
     *
44
     * @param mixed $locale 地区信息
45
     */
46
    public function __construct($locale = 'zh_CN.UTF-8')
47
    {
48
        setlocale(LC_ALL, $locale);
49
        clearstatcache();
50
        $this->_functions['loader'] = function ($fileName) {
51
            $hashName = $this->_getHashName($fileName);
52
            $this->_attributes[$hashName] = I::get($this->_attributes, $hashName, [
53
                'isCached' => false,
54
                'isLocal' => true,
55
                'isExists' => false,
56
                'fileSize' => 0,
57
            ]);
58
            // 如果已经被缓存了,直接返回
59
            if (true === $this->_attributes[$hashName]['isCached']) {
60
                return;
61
            }
62
            $this->_attributes[$hashName]['isCached'] = true;
63
            if (preg_match('/^https?:\/\//', $fileName)) {
64
                $this->_attributes[$hashName]['isLocal'] = false;
65
                // 加载网络文件
66
                if (extension_loaded('curl')) {
67
                    $curl = curl_init($fileName);
68
                    curl_setopt($curl, CURLOPT_NOBODY, true);
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

68
                    curl_setopt(/** @scrutinizer ignore-type */ $curl, CURLOPT_NOBODY, true);
Loading history...
69
                    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
70
                    curl_setopt($curl, CURLOPT_HEADER, true);
71
                    $result = 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

71
                    $result = curl_exec(/** @scrutinizer ignore-type */ $curl);
Loading history...
72
                    if ($result && $info = curl_getinfo($curl)) {
0 ignored issues
show
Bug introduced by
It seems like $curl can also be of type false; however, parameter $ch of curl_getinfo() 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

72
                    if ($result && $info = curl_getinfo(/** @scrutinizer ignore-type */ $curl)) {
Loading history...
73
                        if (200 == $info['http_code']) {
74
                            $this->_attributes[$hashName]['isExists'] = true;
75
                            $this->_attributes[$hashName]['fileSize'] = $info['download_content_length'];
76
                        }
77
                    }
78
                    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

78
                    curl_close(/** @scrutinizer ignore-type */ $curl);
Loading history...
79
                } elseif (ini_get('allow_url_fopen')) {
80
                    $headArray = get_headers($fileName, true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type integer expected by parameter $format of get_headers(). ( Ignorable by Annotation )

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

80
                    $headArray = get_headers($fileName, /** @scrutinizer ignore-type */ true);
Loading history...
81
                    if (preg_match('/200/', $headArray[0])) {
82
                        $this->_attributes[$hashName]['isExists'] = true;
83
                        $this->_attributes[$hashName]['fileSize'] = $headArray['Content-Length'];
84
                    }
85
                } else {
86
                    $url = parse_url($fileName);
87
                    $host = $url['host'];
88
                    $path = I::get($url, 'path', '/');
89
                    $port = I::get($url, 'port', 80);
90
                    $fp = fsockopen($host, $port);
91
                    if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
92
                        $header = [
93
                            'GET ' . $path . ' HTTP/1.0',
94
                            'HOST: ' . $host . ':' . $port,
95
                            'Connection: Close',
96
                        ];
97
                        fwrite($fp, implode('\r\n', $header) . '\r\n\r\n');
98
                        while (!feof($fp)) {
99
                            $line = fgets($fp);
100
                            if ('' == trim($line)) {
101
                                break;
102
                            } else {
103
                                preg_match('/HTTP.*(\s\d{3}\s)/', $line, $arr) && $this->_attributes[$hashName]['isExists'] = true;
104
                                preg_match('/Content-Length:(.*)/si', $line, $arr) && $this->_attributes[$hashName]['fileSize'] = trim($arr[1]);
105
                            }
106
                        }
107
                    }
108
                    fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp 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

108
                    fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
109
                }
110
            } else {
111
                $this->_attributes[$hashName]['isLocal'] = true;
112
                $this->_attributes[$hashName]['spl'] = new \SplFileObject($fileName);
113
                $this->_attributes[$hashName]['splInfo'] = new \SplFileInfo($fileName);
114
            }
115
        };
116
    }
117
118
    /**
119
     * 获取 Hash 值
120
     *
121
     * @param string $fileName
122
     *
123
     * @return string
124
     */
125
    protected function _getHashName($fileName)
126
    {
127
        return md5($fileName);
128
    }
129
130
    /**
131
     * 获取网络文件的属性
132
     *
133
     * @param string $fileName
134
     * @param string $name
135
     *
136
     * @return array
137
     */
138
    protected function _getFileAttribute($fileName, $name)
139
    {
140
        I::trigger($this->_functions['loader'], [$fileName]);
141
        return $this->_attributes[$this->_getHashName($fileName)][$name];
142
    }
143
144
    /**
145
     * 获取文件对象
146
     *
147
     * @param string $fileName
148
     *
149
     * @return \SplFileObject
150
     */
151
    public function spl($fileName)
152
    {
153
        I::trigger($this->_functions['loader'], [$fileName]);
154
        return $this->_getFileAttribute($fileName, 'spl');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_getFileAttribute($fileName, 'spl') returns the type array which is incompatible with the documented return type SplFileObject.
Loading history...
155
    }
156
157
    /**
158
     * 获取文件信息对象
159
     *
160
     * @param string $fileName
161
     *
162
     * @return \SplFileInfo
163
     */
164
    public function splInfo($fileName)
165
    {
166
        I::trigger($this->_functions['loader'], [$fileName]);
167
        return $this->_getFileAttribute($fileName, 'splInfo');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_getFileAt...e($fileName, 'splInfo') returns the type array which is incompatible with the documented return type SplFileInfo.
Loading history...
168
    }
169
170
    /**
171
     * 遍历行的生成器
172
     *
173
     * - 自动关闭后再次调用需要重新读取文件,不建议自动关闭
174
     *
175
     * @param string $fileName
176
     * @param boolean $autoClose 是否自动关闭文件,默认 false
177
     *
178
     * @return \Generator
179
     */
180
    public function linesGenerator($fileName, $autoClose = false)
181
    {
182
        try {
183
            $spl = $this->spl($fileName);
184
            while ($line = $spl->fgets()) {
185
                yield $line;
186
            }
187
        } finally {
188
            true === $autoClose && $this->close($fileName);
189
        }
190
    }
191
192
    /**
193
     * 返回文本的某行
194
     *
195
     * - 每取一行,文件指针会回到初始位置,如果需要大量的行,请直接使用 linesGenerator
196
     * - 自动关闭后再次调用需要重新读取文件,不建议自动关闭
197
     *
198
     * @param string $fileName
199
     * @param integer $num 行号
200
     * @param boolean $autoClose 是否自动关闭文件,默认 false
201
     *
202
     * @return string
203
     */
204
    public function line($fileName, $num = 0, $autoClose = false)
205
    {
206
        foreach ($this->linesGenerator($fileName, $autoClose) as $k => $line) {
207
            if ($k == $num) {
208
                $this->spl($fileName)->rewind();
209
                return $line;
210
            }
211
        }
212
    }
213
214
    /**
215
     * 遍历字节的生成器
216
     *
217
     * @param string $fileName
218
     * @param boolean $autoClose 是否自动关闭文件,默认 false
219
     * @param integer $buffer 缓冲区长度,默认 1024
220
     *
221
     * @return \Generator
222
     */
223
    public function dataGenerator($fileName, $autoClose = false, $buffer = 1024)
224
    {
225
        $bufferSize = 0;
226
        try {
227
            while (!$this->spl($fileName)->eof() && $this->splInfo($fileName)->getSize() > $bufferSize) {
228
                $bufferSize += $buffer;
229
                yield $this->spl($fileName)->fread($bufferSize);
230
            }
231
        } finally {
232
            true === $autoClose && $this->close($fileName);
233
        }
234
    }
235
236
    /**
237
     * @ignore
238
     */
239
    public function getATime($filename)
240
    {
241
        return fileatime($filename);
242
    }
243
244
    /**
245
     * @ignore
246
     */
247
    public function getBasename($path, $suffix = null)
248
    {
249
        return parent::getBasename($path, $suffix);
250
    }
251
252
    /**
253
     * @ignore
254
     */
255
    public function getCTime($filename)
256
    {
257
        return filectime($filename);
258
    }
259
260
    /**
261
     * @ignore
262
     */
263
    public function getExtension($filename)
264
    {
265
        return pathinfo($filename, PATHINFO_EXTENSION);
266
    }
267
268
    /**
269
     * @ignore
270
     */
271
    public function getFilename($filename)
272
    {
273
        return pathinfo($filename, PATHINFO_FILENAME);
274
    }
275
276
    /**
277
     * @ignore
278
     */
279
    public function getMtime($filename)
280
    {
281
        return filemtime($filename);
282
    }
283
284
    /**
285
     * @ignore
286
     */
287
    public function getDirname($path)
288
    {
289
        return parent::getDirname($path);
290
    }
291
292
    /**
293
     * @ignore
294
     */
295
    public function getPerms($path)
296
    {
297
        return fileperms($path);
298
    }
299
300
    /**
301
     * @ignore
302
     */
303
    public function getFilesize($file)
304
    {
305
        I::trigger($this->_functions['loader'], [$file]);
306
        if (false === $this->_getFileAttribute($file, 'isLocal')) {
0 ignored issues
show
introduced by
The condition false === $this->_getFil...ibute($file, 'isLocal') is always false.
Loading history...
307
            return $this->_getFileAttribute($file, 'fileSize');
308
        }
309
        return filesize($file);
310
    }
311
312
    /**
313
     * @ignore
314
     */
315
    public function getType($path)
316
    {
317
        return filetype($path);
318
    }
319
320
    /**
321
     * @ignore
322
     */
323
    public function isDir($dir)
324
    {
325
        return is_dir($dir);
326
    }
327
328
    /**
329
     * @ignore
330
     */
331
    public function isDot($dir)
332
    {
333
        return in_array($this->getBasename($dir), ['.', '..']);
334
    }
335
336
    /**
337
     * @ignore
338
     */
339
    public function isFile($file)
340
    {
341
        I::trigger($this->_functions['loader'], [$file]);
342
        if (false === $this->_getNetFileAttribute($file, 'isLocal')) {
0 ignored issues
show
Bug introduced by
The method _getNetFileAttribute() does not exist on icy2003\php\icomponents\file\LocalFile. ( Ignorable by Annotation )

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

342
        if (false === $this->/** @scrutinizer ignore-call */ _getNetFileAttribute($file, 'isLocal')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
343
            return $this->_getNetFileAttribute($file, 'isExists');
344
        }
345
        return file_exists($file);
346
    }
347
348
    /**
349
     * @ignore
350
     */
351
    public function isLink($filename)
352
    {
353
        return is_link($filename);
354
    }
355
356
    /**
357
     * @ignore
358
     */
359
    public function isReadable($path)
360
    {
361
        return is_readable($path);
362
    }
363
364
    /**
365
     * @ignore
366
     */
367
    public function isWritable($path)
368
    {
369
        return is_writable($path);
370
    }
371
372
    /**
373
     * @ignore
374
     */
375
    public function getCommandResult($command)
376
    {
377
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by icy2003\php\icomponents\...ase::getCommandResult() of string.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
378
    }
379
380
    /**
381
     * @ignore
382
     */
383
    public function getRealpath($path)
384
    {
385
        return realpath($path);
386
    }
387
388
    /**
389
     * @ignore
390
     */
391
    public function getLists($dir = null, $flags = FileConstants::COMPLETE_PATH)
392
    {
393
        null === $dir && $dir = $this->getRealpath('./');
394
        $dir = rtrim($dir, '/') . '/';
395
        $iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
396
        if (I::hasFlag($flags, FileConstants::RECURSIVE)) {
397
            $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
398
        }
399
        $files = [];
400
        /**
401
         * @var \RecursiveDirectoryIterator $file
402
         */
403
        foreach ($iterator as $file) {
404
            if (I::hasFlag($flags, FileConstants::COMPLETE_PATH)) {
405
                $files[] = $file->getPathname();
406
            } else {
407
                $files[] = $file->getFilename();
408
            }
409
        }
410
        return $files;
411
    }
412
413
    /**
414
     * @ignore
415
     */
416
    public function getFileContent($file)
417
    {
418
        return file_get_contents($file);
419
    }
420
421
    /**
422
     * @ignore
423
     */
424
    public function putFileContent($file, $string, $mode = 0777)
425
    {
426
        $this->createDir($this->getDirname($file), $mode);
427
        $isCreated = false !== file_put_contents($file, $string);
428
        $this->chmod($file, $mode, FileConstants::RECURSIVE_DISABLED);
429
        return $isCreated;
430
    }
431
432
    /**
433
     * @ignore
434
     */
435
    public function deleteFile($file)
436
    {
437
        if ($this->isFile($file)) {
438
            return unlink($file);
439
        }
440
        return true;
441
    }
442
443
    /**
444
     * @ignore
445
     */
446
    public function uploadFile($toFile, $fromFile = null, $overwrite = true)
447
    {
448
        return false;
449
    }
450
451
    /**
452
     * @ignore
453
     */
454
    public function downloadFile($fromFile, $toFile = null, $overwrite = true)
455
    {
456
        return false;
457
    }
458
459
    /**
460
     * @ignore
461
     */
462
    public function chown($file, $user, $flags = FileConstants::RECURSIVE_DISABLED)
463
    {
464
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
465
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
466
            foreach ($files as $subFile) {
467
                chown($subFile, $user);
468
            }
469
        }
470
        return chown($file, $user);
471
    }
472
473
    /**
474
     * @ignore
475
     */
476
    public function chgrp($file, $group, $flags = FileConstants::RECURSIVE_DISABLED)
477
    {
478
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
479
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
480
            foreach ($files as $subFile) {
481
                chgrp($subFile, $group);
482
            }
483
        }
484
        return chgrp($file, $group);
485
    }
486
487
    /**
488
     * @ignore
489
     */
490
    public function chmod($file, $mode = 0777, $flags = FileConstants::RECURSIVE_DISABLED)
491
    {
492
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
493
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
494
            foreach ($files as $subFile) {
495
                chmod($subFile, $mode);
496
            }
497
        }
498
        return (bool) chmod($file, $mode);
499
    }
500
501
    /**
502
     * @ignore
503
     */
504
    public function symlink($from, $to)
505
    {
506
        return symlink($from, $to);
507
    }
508
509
    /**
510
     * @ignore
511
     */
512
    public function close($fileName = null)
513
    {
514
        if (is_string($fileName)) {
515
            $fileName = [$this->_getHashName($fileName)];
516
        } elseif (is_array($fileName)) {
517
            foreach ($fileName as $k => $name) {
518
                $fileName[$k] = $this->_getHashName($name);
519
            }
520
        }
521
        foreach ($this->_attributes as $hashName => /** @scrutinizer ignore-unused */$attribute) {
522
            if (null === $fileName || is_array($fileName) && in_array($hashName, $fileName)) {
523
                unset($this->_attributes[$hashName]);
524
            }
525
        }
526
        return true;
527
    }
528
529
    /**
530
     * @ignore
531
     */
532
    protected function _copy($fromFile, $toFile)
533
    {
534
        return copy($fromFile, $toFile);
535
    }
536
537
    /**
538
     * @ignore
539
     */
540
    protected function _move($fromFile, $toFile)
541
    {
542
        return rename($fromFile, $toFile);
543
    }
544
545
    /**
546
     * @ignore
547
     */
548
    protected function _mkdir($dir, $mode = 0777)
549
    {
550
        return mkdir($dir, $mode);
551
    }
552
553
    /**
554
     * @ignore
555
     */
556
    protected function _rmdir($dir)
557
    {
558
        return rmdir($dir);
559
    }
560
561
}
562