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.
Passed
Push — master ( 6e41ae...f215c9 )
by t
06:13 queued 12s
created

LocalFile::getCommandResult()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
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 Exception;
12
use icy2003\php\C;
13
use icy2003\php\I;
14
use icy2003\php\icomponents\file\FileInterface;
15
use icy2003\php\ihelpers\Arrays;
16
use icy2003\php\ihelpers\Console;
17
use icy2003\php\ihelpers\Header;
18
use icy2003\php\ihelpers\Request;
19
use icy2003\php\ihelpers\Strings;
20
21
/**
22
 * 本地文件
23
 *
24
 * - 支持本地文件操作
25
 * - 支持网络文件部分属性:文件是否存在、文件大小
26
 */
27
class LocalFile extends Base implements FileInterface
28
{
29
30
    /**
31
     * 配置
32
     *
33
     * @var array
34
     */
35
    protected $_c = [
36
        'loader' => 'curl',
37
        'locale' => 'zh_CN.UTF-8',
38
        'buffer' => 4096,
39
        'mode' => 'rb',
40
        'rtrim' => true,
41
    ];
42
43
    /**
44
     * 文件属性
45
     *
46
     * - 文件名为键,属性为值
47
     *
48
     * @var array
49
     */
50
    protected $_attributes = [];
51
52
    /**
53
     * 初始化
54
     *
55
     * @param array $options 配置
56
     *      - locale:地区,默认 zh_CN.UTF-8
57
     *      - buffer:以字节方式读写时每段的字节长度,默认为 4096,即 4kb
58
     *      - mode:指定了所要求到该流的访问类型,默认 rb @link https://www.php.net/manual/zh/function.fopen.php
59
     *      - rtrim:在遍历行时是否去除行尾空白,默认 true,即去除
60
     *      - loader:读取远程资源时用的方法,默认为 curl(当其他方法无法读取时也会设置为 curl),支持值:curl、fopen、fsockopen
61
     *          - curl:使用 curl 获取远程文件信息
62
     *          - fopen:需要手动开启 allow_url_fopen 才能使用,不建议开启
63
     *          - fsockopen:使用 fsockopen 发送头获取信息
64
     * @return void
65
     */
66 35
    public function __construct($options = [])
67
    {
68 35
        $this->_c = Arrays::merge($this->_c, $options);
69 35
        setlocale(LC_ALL, (string)I::get($this->_c, 'locale', 'zh_CN.UTF-8'));
70 35
        clearstatcache();
71 35
    }
72
73
    /**
74
     * 获取 Hash 值
75
     *
76
     * @param string $fileName
77
     *
78
     * @return string
79
     */
80 17
    private function __hash($fileName)
81
    {
82 17
        return md5($fileName);
83
    }
84
85
    /**
86
     * 以别名返回路径
87
     *
88
     * @param string $file
89
     *
90
     * @return string
91
     */
92 34
    private function __file($file)
93
    {
94 34
        return (string)I::getAlias($file);
95
    }
96
97
    /**
98
     * 加载一个文件,本地(支持别名)或网络文件
99
     *
100
     * @param string $fileName
101
     *
102
     * @return static
103
     */
104 17
    protected function _load($fileName)
105
    {
106 17
        $fileName = $this->getRealpath($fileName);
107 17
        $hashName = $this->__hash($fileName);
108 17
        $this->_attributes[$hashName] = I::get($this->_attributes, $hashName, [
109 17
            'file' => $fileName,
110
            'isCached' => false,
111
            'isLocal' => true,
112
            // 以下属性需要重新设置
113
            'isExists' => false,
114 17
            'fileSize' => 0,
115
            'spl' => null,
116
            'splInfo' => null,
117
        ]);
118 17
        null === $this->_attributes[$hashName]['splInfo'] && $this->_attributes[$hashName]['splInfo'] = new \SplFileInfo($fileName);
119
        try {
120 17
            $splInfo = $this->_attributes[$hashName]['splInfo'];
121 17
            if (true !== $splInfo->isDir()) {
122 17
                null === $this->_attributes[$hashName]['spl'] && $this->_attributes[$hashName]['spl'] = new \SplFileObject($fileName, $this->_c['mode']);
123
            }
124 7
        } catch (Exception $e) {
125
            // 报错了也得继续跑,如果跑完一次 spl 和 splInfo 属性还是 null,在调用它们的时候自然会报错
126 7
            $this->_c['error'] = $e->getMessage();
127
            // 尝试用 curl 获取
128 7
            $this->_c['loader'] = 'curl';
129
        }
130
        // 如果已经被缓存了,直接返回
131 17
        if (true === $this->_attributes[$hashName]['isCached']) {
132 4
            return $this;
133
        }
134
        // 加上缓存标记
135 17
        $this->_attributes[$hashName]['isCached'] = true;
136 17
        if (preg_match('/^https?:\/\//', $fileName)) {
137 2
            $this->_attributes[$hashName]['isLocal'] = false;
138
            // 加载网络文件
139 2
            if ('curl' === $this->_c['loader'] && extension_loaded('curl')) {
140 2
                $curl = curl_init($fileName);
141 2
                if (is_resource($curl)) {
142 2
                    curl_setopt($curl, CURLOPT_NOBODY, true);
143 2
                    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
144 2
                    curl_setopt($curl, CURLOPT_HEADER, true);
145
                    // 公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)
146
                    // - 设置为 1 是检查服务器SSL证书中是否存在一个公用名(common name)
147
                    // - 设置成 2,会检查公用名是否存在,并且是否与提供的主机名匹配
148
                    // - 0 为不检查名称。 在生产环境中,这个值应该是 2(默认值)
149 2
                    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
150
                    // 禁止 cURL 验证对等证书(peer's certificate)。要验证的交换证书可以在 CURLOPT_CAINFO 选项中设置
151 2
                    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
152 2
                    $result = curl_exec($curl);
153 2
                    if ($result && $info = curl_getinfo($curl)) {
154 2
                        if (200 == $info['http_code']) {
155 2
                            $this->_attributes[$hashName]['isExists'] = true;
156 2
                            $this->_attributes[$hashName]['fileSize'] = (int)$info['download_content_length'];
157
                        }
158
                    }
159 2
                    curl_close($curl);
160
                }
161 2
                return $this;
162
            }
163 1
            if ('fsockopen' === $this->_c['loader']) {
164 1
                $url = parse_url($fileName);
165 1
                $host = $url['host'];
166 1
                $path = (string)I::get($url, 'path', '/');
167 1
                $port = (int)I::get($url, 'port', 80);
168 1
                $fp = fsockopen($host, $port);
169 1
                if (is_resource($fp)) {
170 1
                    fputs($fp, "GET {$path} HTTP/1.1\r\n");
171 1
                    fputs($fp, "Host: {$host}:{$port}\r\n");
172 1
                    fputs($fp, "Connection: Close\r\n\r\n");
173 1
                    while (!feof($fp)) {
174 1
                        $line = fgets($fp);
175 1
                        preg_match('/HTTP.*(\s\d{3}\s)/', $line, $arr) && $this->_attributes[$hashName]['isExists'] = true;
176 1
                        preg_match('/Content-Length:(.*)/si', $line, $arr) && $this->_attributes[$hashName]['fileSize'] = (int)trim($arr[1]);
177
                    }
178 1
                    fclose($fp);
179
                }
180 1
                return $this;
181
            }
182 1
            if ('fopen' === $this->_c['loader'] && (bool)ini_get('allow_url_fopen')) {
183 1
                $headArray = (array)get_headers($fileName, 1);
184 1
                if (preg_match('/200/', $headArray[0])) {
185 1
                    $this->_attributes[$hashName]['isExists'] = true;
186 1
                    $this->_attributes[$hashName]['fileSize'] = (int)$headArray['Content-Length'];
187
                }
188 1
                return $this;
189
            }
190
        } else {
191 17
            $this->_attributes[$hashName]['isLocal'] = true;
192 17
            $this->_attributes[$hashName]['isExists'] = file_exists($fileName);
193 17
            if ($this->_attributes[$hashName]['isExists']) {
194 15
                $this->_attributes[$hashName]['fileSize'] = filesize($fileName);
195
            }
196 17
            $this->chmod($fileName, 0777, FileConstants::RECURSIVE_DISABLED);
197
        }
198 17
        return $this;
199
    }
200
201
    /**
202
     * 获取文件的属性
203
     *
204
     * @param string $fileName
205
     * @param string $name
206
     *
207
     * @return mixed
208
     */
209 17
    public function attribute($fileName, $name)
210
    {
211 17
        $this->_load($fileName);
212 17
        return I::get($this->_attributes, $this->__hash($this->getRealpath($fileName)) . '.' . $name);
213
    }
214
215
    /**
216
     * 获取文件对象
217
     *
218
     * @param string $fileName
219
     * @param string $mode 读写的模式,默认 rb
220
     *
221
     * @return \SplFileObject|null
222
     * @throws Exception
223
     */
224 6
    public function spl($fileName, $mode = 'rb')
225
    {
226 6
        $this->_c['mode'] = $mode;
227 6
        $spl = $this->attribute($fileName, 'spl');
228 6
        C::assertTrue($spl instanceof \SplFileObject, '文件打开失败:' . $fileName);
229 4
        return $spl;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $spl also could return the type false|string which is incompatible with the documented return type SplFileObject|null.
Loading history...
230
    }
231
232
    /**
233
     * 获取文件信息对象
234
     *
235
     * @param string $fileName
236
     *
237
     * @return \SplFileInfo
238
     */
239 1
    public function splInfo($fileName)
240
    {
241 1
        $splInfo = $this->attribute($fileName, 'splInfo');
242 1
        return $splInfo;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $splInfo also could return the type false|string which is incompatible with the documented return type SplFileInfo.
Loading history...
243
    }
244
245
    /**
246
     * 遍历行的生成器
247
     *
248
     * - 自动关闭后再次调用需要重新读取文件,不建议自动关闭
249
     *
250
     * @param string $fileName
251
     * @param boolean $autoClose 是否自动关闭文件,默认 false
252
     *
253
     * @return \Generator
254
     */
255 2
    public function linesGenerator($fileName, $autoClose = false)
256
    {
257
        try {
258 2
            $spl = $this->spl($fileName, 'r');
259 2
            while (false === $spl->eof() && ($line = $spl->fgets())) {
260 2
                true === $this->_c['rtrim'] && $line = rtrim($line);
261 2
                yield $line;
262
            }
263 2
        } finally {
264 2
            true === $autoClose && $this->close($fileName);
265
        }
266 2
    }
267
268
    /**
269
     * 返回文本的某行
270
     *
271
     * - 每取一行,文件指针会回到初始位置,如果需要大量的行,请直接使用 linesGenerator
272
     * - 自动关闭后再次调用需要重新读取文件,不建议自动关闭
273
     *
274
     * @param string $fileName
275
     * @param integer $lineNumber 行号
276
     * @param boolean $autoClose 是否自动关闭文件,默认 false
277
     *
278
     * @return string|null
279
     */
280 1
    public function line($fileName, $lineNumber = 0, $autoClose = false)
281
    {
282 1
        $spl = $this->spl($fileName, 'r');
283 1
        $lineNumber = (int)$lineNumber;
284 1
        foreach ($this->linesGenerator($fileName, $autoClose) as $k => $line) {
285 1
            if ($k === $lineNumber) {
286 1
                $spl->rewind();
287 1
                return $line;
288
            }
289
        }
290 1
        return null;
291
    }
292
293
    /**
294
     * 遍历字节的生成器
295
     *
296
     * - 自动关闭后再次调用需要重新读取文件,不建议自动关闭
297
     *
298
     * @param string $fileName
299
     * @param boolean $autoClose 是否自动关闭文件,默认 false
300
     * @param integer|null $buffer 每次读取的字节数,默认 null,值等于初始化时的 buffer 选项
301
     *
302
     * @return \Generator
303
     */
304 1
    public function dataGenerator($fileName, $autoClose = false, $buffer = null)
305
    {
306 1
        $bufferSize = 0;
307 1
        null === $buffer && $buffer = $this->_c['buffer'];
308
        try {
309 1
            $spl = $this->spl($fileName, 'rb');
310 1
            $size = $this->getFilesize($fileName);
311 1
            while (!$spl->eof() && $size > $bufferSize) {
312 1
                $bufferSize += $buffer;
313 1
                yield $spl->fread($bufferSize);
314
            }
315 1
        } finally {
316 1
            true === $autoClose && $this->close($fileName);
317
        }
318 1
    }
319
320
    /**
321
     * @ignore
322
     */
323 1
    public function getATime($fileName)
324
    {
325 1
        return fileatime($this->__file($fileName));
326
    }
327
328
    /**
329
     * @ignore
330
     */
331 2
    public function getBasename($file, $suffix = null)
332
    {
333 2
        return parent::getBasename($this->__file($file), $suffix);
334
    }
335
336
    /**
337
     * @ignore
338
     */
339 1
    public function getCTime($fileName)
340
    {
341 1
        return filectime($this->__file($fileName));
342
    }
343
344
    /**
345
     * @ignore
346
     */
347 1
    public function getExtension($fileName)
348
    {
349 1
        return pathinfo($this->__file($fileName), PATHINFO_EXTENSION);
350
    }
351
352
    /**
353
     * @ignore
354
     */
355 1
    public function getFilename($fileName)
356
    {
357 1
        return pathinfo($this->__file($fileName), PATHINFO_FILENAME);
358
    }
359
360
    /**
361
     * @ignore
362
     */
363 1
    public function getMtime($fileName)
364
    {
365 1
        return filemtime($this->__file($fileName));
366
    }
367
368
    /**
369
     * @ignore
370
     */
371 5
    public function getDirname($path)
372
    {
373 5
        return parent::getDirname($this->__file($path));
374
    }
375
376
    /**
377
     * @ignore
378
     */
379 1
    public function getPerms($path)
380
    {
381 1
        return fileperms($this->__file($path));
382
    }
383
384
    /**
385
     * @ignore
386
     */
387 3
    public function getFilesize($fileName)
388
    {
389 3
        return (int)$this->attribute($fileName, 'fileSize');
390
    }
391
392
    /**
393
     * @ignore
394
     */
395 1
    public function getType($path)
396
    {
397 1
        return filetype($this->__file($path));
398
    }
399
400
    /**
401
     * @ignore
402
     */
403 19
    public function isDir($dir)
404
    {
405 19
        return is_dir($this->__file($dir));
406
    }
407
408
    /**
409
     * @ignore
410
     */
411 1
    public function isDot($dir)
412
    {
413 1
        return in_array($this->getBasename($dir), ['.', '..']);
414
    }
415
416
    /**
417
     * @ignore
418
     */
419 10
    public function isFile($file)
420
    {
421 10
        $isLocal = $this->attribute($file, 'isLocal');
422 10
        if (true === $isLocal) {
423 10
            return is_file($this->__file($file));
424
        } else {
425 1
            return (bool)$this->attribute($file, 'isExists');
426
        }
427
    }
428
429
    /**
430
     * @ignore
431
     */
432 1
    public function isLink($link)
433
    {
434 1
        return is_link($this->__file($link));
435
    }
436
437
    /**
438
     * @ignore
439
     */
440 1
    public function isReadable($path)
441
    {
442 1
        return is_readable($this->__file($path));
443
    }
444
445
    /**
446
     * @ignore
447
     */
448 1
    public function isWritable($path)
449
    {
450 1
        return is_writable($this->__file($path));
451
    }
452
453
    /**
454
     * @ignore
455
     */
456
    public function getCommandResult($command)
457
    {
458
        return Console::exec($command);
459
    }
460
461
    /**
462
     * @ignore
463
     */
464 18
    public function getRealpath($path)
465
    {
466 18
        $path = $this->__file($path);
467 18
        $realPath = realpath($path);
468 18
        false === $realPath && $realPath = parent::getRealpath($path);
469 18
        return Strings::replace($realPath, ["\\" => '/']);
470
    }
471
472
    /**
473
     * @ignore
474
     */
475 3
    public function getLists($dir = null, $flags = FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE_DISABLED)
476
    {
477 3
        null === $dir && $dir = $this->getRealpath('./');
478 3
        $dir = rtrim($this->__file($dir), '/') . '/';
479 3
        $iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
480 3
        if (I::hasFlag($flags, FileConstants::RECURSIVE)) {
481 3
            $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
482
        }
483 3
        $files = [];
484
        /**
485
         * @var \RecursiveDirectoryIterator $file
486
         */
487 3
        foreach ($iterator as $file) {
488 3
            if (I::hasFlag($flags, FileConstants::COMPLETE_PATH)) {
489 3
                $files[] = $file->getPathname();
490
            } else {
491 2
                $files[] = $file->getFilename();
492
            }
493
        }
494 3
        return $files;
495
    }
496
497
    /**
498
     * @ignore
499
     */
500 2
    public function getFileContent($file)
501
    {
502 2
        if ($this->isFile($file)) {
503 2
            return file_get_contents($this->__file($file));
504
        }
505
        return false;
506
    }
507
508
    /**
509
     * @ignore
510
     */
511 1
    public function putFileContent($file, $string, $mode = 0777)
512
    {
513 1
        $this->createDir($this->getDirname($file), $mode);
514 1
        $isCreated = false !== file_put_contents($this->__file($file), $string);
515 1
        $this->chmod($file, $mode, FileConstants::RECURSIVE_DISABLED);
516 1
        return $isCreated;
517
    }
518
519
    /**
520
     * @ignore
521
     */
522 5
    public function deleteFile($file)
523
    {
524 5
        if ($this->isFile($file)) {
525 5
            $this->close($file);
526 5
            return unlink($this->__file($file));
527
        }
528 1
        return true;
529
    }
530
531
    /**
532
     * @ignore
533
     */
534 1
    public function uploadFile($fileMap, $overwrite = true)
535
    {
536 1
        return false;
537
    }
538
539
    /**
540
     * - 从远程下载文件到本地
541
     * @param callback|null $callback 执行中的回调([当前下载的字节], [总字节])
542
     * @param callback|null $finishCallback 执行完成后的回调([本地文件 \SplFileObject])
543
     *
544
     * @ignore
545
     */
546 1
    public function downloadFile($fileMap, $overwrite = true, $callback = null, $finishCallback = null)
547
    {
548 1
        set_time_limit(0);
549 1
        list($fromFile, $toFile) = $this->fileMap($fileMap);
550 1
        $toSpl = $this->spl($toFile, 'wb');
551
        if ($this->isFile($toFile) && false === $overwrite) {
552
            $this->close($toFile);
553
            I::call($finishCallback, [$toSpl]);
554
            return true;
555
        }
556
        $fromSpl = $this->spl($fromFile, 'rb');
557
        $size = 0;
558
        $total = $this->getFilesize($fromFile);
559
        while (false === $fromSpl->eof()) {
560
            $out = $fromSpl->fread($this->_c['buffer']);
561
            $toSpl->fwrite($out);
562
            $size += Strings::byteLength($out);
563
            I::call($callback, [$size, $total]);
564
        }
565
        $this->close([$fromFile, $toFile]);
566
        I::call($finishCallback, [$toSpl]);
567
    }
568
569
    /**
570
     * download() 配置名:ip
571
     */
572
    const C_DOWNLOAD_IP = 'ip';
573
    /**
574
     * download() 配置名:speed
575
     */
576
    const C_DOWNLOAD_SPEED = 'speed';
577
    /**
578
     * download() 配置名:xSendFile
579
     */
580
    const C_DOWNLOAD_X_SEND_FILE = 'xSendFile';
581
    /**
582
     * download() 配置名:xSendFileRoot
583
     */
584
    const C_DOWNLOAD_X_SEND_FILE_ROOT = 'xSendFileRoot';
585
586
    /**
587
     * 服务端给客户端提供下载请求
588
     *
589
     * @param string|array $fileName self::fileMap()
590
     * @param null|array $config 配置项
591
     *      - ip:限特定 IP 访问,数组或逗号字符串,默认为 *,即对所有 IP 不限制
592
     *      - speed:限速,默认不限速(读取速度为1024 * [buffer]),单位 kb/s
593
     *      - xSendFile:是否使用 X-Sendfile 进行下载,默认 false,即不使用。X-Sendfile 缓解了 PHP 的压力,但同时 PHP 将失去对资源的控制权,因为 PHP 并不知道资源发完了没
594
     *      - xSendFileRoot:文件根路径,默认为 /protected/。此时 Nginx 可作如下配置,更多 @link https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
595
     *      ```nginx.conf
596
     *      location /protected/ {
597
     *          internal; # 表示这个路径只能在 Nginx 内部访问,不能用浏览器直接访问防止未授权的下载
598
     *          alias   /usr/share/nginx/html/protected/; # 别名
599
     *          # root    /usr/share/nginx/html; # 根目录
600
     *      }
601
     *      ```
602
     * @param callback $callback 下载完成后的回调,参数列表:文件属性数组
603
     *
604
     * @return void
605
     * @info 此函数之后不得有任何输出
606
     * @throws Exception
607
     */
608
    public function download($fileName, $config = null, $callback = null)
609
    {
610
        Header::xPoweredBy();
611
        set_time_limit(0);
612
        list($originName, $downloadName) = $this->fileMap($fileName);
613
        $originName = $this->__file($originName);
614
        try {
615
            $ip = (string)I::get($config, self::C_DOWNLOAD_IP, '*');
616
            if ('*' !== $ip) {
617
                C::assertTrue(Arrays::in((new Request())->getUserIP(), Strings::toArray($ip)), 'http/1.1 403.6 此 IP 禁止访问');
618
            }
619
            if ($this->isFile($originName)) {
620
                $fileSize = $this->getFilesize($originName);
621
                header('Content-type:application/octet-stream');
622
                header('Accept-Ranges:bytes');
623
                header('Content-Length:' . $fileSize);
624
                header('Content-Disposition: attachment; filename=' . $downloadName);
625
                $speed = (int)I::get($config, self::C_DOWNLOAD_SPEED, 0);
626
                $xSendFile = I::get($config, self::C_DOWNLOAD_X_SEND_FILE, false);
627
                $xSendFileRoot = (string)I::get($config, self::C_DOWNLOAD_X_SEND_FILE_ROOT, '/protected/');
628
                if (true === $xSendFile) {
629
                    $path = rtrim($xSendFileRoot, '/') . '/' . $this->getBasename($originName);
630
                    header('X-Accel-Redirect: ' . $path); // Nginx、Cherokee 实现了该头
631
                    header('X-Sendfile: ' . $path); // Apache、Lighttpd v1.5、Cherokee 实现了该头
632
                    header('X-LIGHTTPD-send-file: ' . $path); // Lighttpd v1.4 实现了该头
633
                    if ($speed) {
634
                        header('X-Accel-Limit-Rate: ' . $speed); // 单位 kb/s
635
                    }
636
                } else {
637
                    flush();
638
                    foreach ($this->dataGenerator($originName, true, ($speed ? $speed : $this->_c['buffer'] * 1024)) as $data) {
639
                        echo $data;
640
                        flush();
641
                        $speed > 0 && sleep(1);
642
                    }
643
                }
644
            }
645
        } catch (Exception $e) {
646
            header($e->getMessage());
647
        } finally {
648
            I::call($callback, [$this->_attributes]);
649
            // 必须要终止掉,防止发送其他数据导致错误
650
            die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
651
        }
652
    }
653
654
    /**
655
     * @ignore
656
     */
657
    public function chown($file, $user, $flags = FileConstants::RECURSIVE_DISABLED)
658
    {
659
        $file = $this->__file($file);
660
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
661
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
662
            foreach ($files as $subFile) {
663
                /** @scrutinizer ignore-unhandled */@chown($subFile, $user);
664
            }
665
        } elseif ($this->isFile($file)) {
666
            return /** @scrutinizer ignore-unhandled */@chown($file, $user);
667
        } else {
668
            return false;
669
        }
670
    }
671
672
    /**
673
     * @ignore
674
     */
675
    public function chgrp($file, $group, $flags = FileConstants::RECURSIVE_DISABLED)
676
    {
677
        $file = $this->__file($file);
678
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
679
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
680
            foreach ($files as $subFile) {
681
                /** @scrutinizer ignore-unhandled */@chgrp($subFile, $group);
682
            }
683
        } elseif ($this->isFile($file)) {
684
            return /** @scrutinizer ignore-unhandled */@chgrp($file, $group);
685
        } else {
686
            return false;
687
        }
688
    }
689
690
    /**
691
     * @ignore
692
     */
693 18
    public function chmod($file, $mode = 0777, $flags = FileConstants::RECURSIVE_DISABLED)
694
    {
695 18
        $file = $this->__file($file);
696 18
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
697 1
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
698 1
            foreach ($files as $subFile) {
699 1
                /** @scrutinizer ignore-unhandled */@chmod($subFile, $mode);
700
            }
701
        } else {
702 18
            return /** @scrutinizer ignore-unhandled */@chmod($file, $mode);
703
        }
704 1
    }
705
706
    /**
707
     * @ignore
708
     */
709
    public function symlink($from, $to)
710
    {
711
        $from = $this->__file($from);
712
        $to = $this->__file($to);
713
        return @symlink($from, $to);
714
    }
715
716
    /**
717
     * @ignore
718
     */
719 35
    public function close($fileName = null)
720
    {
721 35
        if (is_string($fileName)) {
722 8
            $fileName = [$this->__hash($this->getRealpath($fileName))];
723 35
        } elseif (is_array($fileName)) {
724
            foreach ($fileName as $k => $name) {
725
                $fileName[$k] = $this->__hash($this->getRealpath($name));
726
            }
727
        }
728 35
        foreach ($this->_attributes as $hashName => /** @scrutinizer ignore-unused */$attribute) {
729 17
            if (null === $fileName || is_array($fileName) && in_array($hashName, $fileName)) {
730 17
                unset($this->_attributes[$hashName]);
731
            }
732
        }
733 35
        return true;
734
    }
735
736
    /**
737
     * @ignore
738
     */
739 3
    protected function _copy($fromFile, $toFile)
740
    {
741 3
        $fromFile = $this->__file($fromFile);
742 3
        $toFile = $this->__file($toFile);
743 3
        return copy($fromFile, $toFile);
744
    }
745
746
    /**
747
     * @ignore
748
     */
749 1
    protected function _move($fromFile, $toFile)
750
    {
751 1
        $fromFile = $this->__file($fromFile);
752 1
        $toFile = $this->__file($toFile);
753 1
        return rename($fromFile, $toFile);
754
    }
755
756
    /**
757
     * @ignore
758
     */
759 1
    protected function _mkdir($dir, $mode = 0777)
760
    {
761 1
        $dir = $this->__file($dir);
762 1
        return mkdir($dir, $mode);
763
    }
764
765
    /**
766
     * @ignore
767
     */
768 1
    protected function _rmdir($dir)
769
    {
770 1
        $dir = $this->__file($dir);
771 1
        return rmdir($dir);
772
    }
773
774
}
775