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 ( 8a4525...04b2e6 )
by t
05:00 queued 40s
created

LocalFile::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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

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

652
                /** @scrutinizer ignore-unhandled */ @chown($subFile, $user);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
653
            }
654
        } elseif ($this->isFile($file)) {
655
            return @chown($file, $user);
656
        } else {
657
            return false;
658
        }
659
    }
660
661
    /**
662
     * @ignore
663
     */
664
    public function chgrp($file, $group, $flags = FileConstants::RECURSIVE_DISABLED)
665
    {
666
        $file = $this->__file($file);
667
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
668
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
669
            foreach ($files as $subFile) {
670
                @chgrp($subFile, $group);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chgrp(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

670
                /** @scrutinizer ignore-unhandled */ @chgrp($subFile, $group);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
671
            }
672
        } elseif ($this->isFile($file)) {
673
            return @chgrp($file, $group);
674
        } else {
675
            return false;
676
        }
677
    }
678
679
    /**
680
     * @ignore
681
     */
682 28
    public function chmod($file, $mode = 0777, $flags = FileConstants::RECURSIVE_DISABLED)
683
    {
684 28
        $file = $this->__file($file);
685 28
        if ($this->isDir($file) && I::hasFlag($flags, FileConstants::RECURSIVE)) {
686 1
            $files = $this->getLists($file, FileConstants::COMPLETE_PATH | FileConstants::RECURSIVE);
687 1
            foreach ($files as $subFile) {
688 1
                @chmod($subFile, $mode);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

688
                /** @scrutinizer ignore-unhandled */ @chmod($subFile, $mode);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
689
            }
690 28
        } elseif ($this->isFile($file)) {
691 26
            return @chmod($file, $mode);
692
        } else {
693 9
            return false;
694
        }
695 1
    }
696
697
    /**
698
     * @ignore
699
     */
700
    public function symlink($from, $to)
701
    {
702
        $from = $this->__file($from);
703
        $to = $this->__file($to);
704
        return @symlink($from, $to);
705
    }
706
707
    /**
708
     * @ignore
709
     */
710 52
    public function close($fileName = null)
711
    {
712 52
        if (is_string($fileName)) {
713 9
            $fileName = [$this->__hash($fileName)];
714 52
        } elseif (is_array($fileName)) {
715 1
            foreach ($fileName as $k => $name) {
716 1
                $fileName[$k] = $this->__hash($name);
717
            }
718
        }
719 52
        foreach ($this->_attributes as $hashName => /** @scrutinizer ignore-unused */$attribute) {
720 28
            if (null === $fileName || is_array($fileName) && in_array($hashName, $fileName)) {
721 28
                unset($this->_attributes[$hashName]);
722
            }
723
        }
724 52
        return true;
725
    }
726
727
    /**
728
     * @ignore
729
     */
730 3
    protected function _copy($fromFile, $toFile)
731
    {
732 3
        $fromFile = $this->__file($fromFile);
733 3
        $toFile = $this->__file($toFile);
734 3
        return copy($fromFile, $toFile);
735
    }
736
737
    /**
738
     * @ignore
739
     */
740 1
    protected function _move($fromFile, $toFile)
741
    {
742 1
        $fromFile = $this->__file($fromFile);
743 1
        $toFile = $this->__file($toFile);
744 1
        return rename($fromFile, $toFile);
745
    }
746
747
    /**
748
     * @ignore
749
     */
750 1
    protected function _mkdir($dir, $mode = 0777)
751
    {
752 1
        $dir = $this->__file($dir);
753 1
        return mkdir($dir, $mode);
754
    }
755
756
    /**
757
     * @ignore
758
     */
759 1
    protected function _rmdir($dir)
760
    {
761 1
        $dir = $this->__file($dir);
762 1
        return rmdir($dir);
763
    }
764
765
}
766