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.
Test Failed
Pull Request — master (#17)
by Oliver
03:19
created

PharStreamWrapper::learnInvocation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
namespace TYPO3\PharStreamWrapper;
4
5
/*
6
 * This file is part of the TYPO3 project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under the terms
9
 * of the MIT License (MIT). For the full copyright and license information,
10
 * please read the LICENSE file that was distributed with this source code.
11
 *
12
 * The TYPO3 project - inspiring people to share!
13
 */
14
15
class PharStreamWrapper
16
{
17
    /**
18
     * Internal stream constants that are not exposed to PHP, but used...
19
     * @see https://github.com/php/php-src/blob/e17fc0d73c611ad0207cac8a4a01ded38251a7dc/main/php_streams.h
20
     */
21
    const STREAM_OPEN_FOR_INCLUDE = 128;
22
23
    /**
24
     * @var resource
25
     */
26
    public $context;
27
28
    /**
29
     * @var resource
30
     */
31
    protected $internalResource;
32
33
    /**
34
     * @var PharInvocation
0 ignored issues
show
Bug introduced by
The type TYPO3\PharStreamWrapper\PharInvocation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
     */
36
    protected $invocation;
37
38
    /**
39
     * @return bool
40
     */
41
    public function dir_closedir(): bool
42
    {
43
        if (!is_resource($this->internalResource)) {
44
            return false;
45
        }
46
47
        $this->invokeInternalStreamWrapper(
48
            'closedir',
49
            $this->internalResource
50
        );
51
        return !is_resource($this->internalResource);
52
    }
53
54
    /**
55
     * @param string $path
56
     * @param int $options
57
     * @return bool
58
     */
59
    public function dir_opendir(string $path, int $options): bool
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

59
    public function dir_opendir(string $path, /** @scrutinizer ignore-unused */ int $options): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
60
    {
61
        $this->assert($path, Behavior::COMMAND_DIR_OPENDIR);
62
        $this->internalResource = $this->invokeInternalStreamWrapper(
63
            'opendir',
64
            $path,
65
            $this->context
66
        );
67
        return is_resource($this->internalResource);
68
    }
69
70
    /**
71
     * @return string|false
72
     */
73
    public function dir_readdir()
74
    {
75
        return $this->invokeInternalStreamWrapper(
76
            'readdir',
77
            $this->internalResource
78
        );
79
    }
80
81
    /**
82
     * @return bool
83
     */
84
    public function dir_rewinddir(): bool
85
    {
86
        if (!is_resource($this->internalResource)) {
87
            return false;
88
        }
89
90
        $this->invokeInternalStreamWrapper(
91
            'rewinddir',
92
            $this->internalResource
93
        );
94
        return is_resource($this->internalResource);
95
    }
96
97
    /**
98
     * @param string $path
99
     * @param int $mode
100
     * @param int $options
101
     * @return bool
102
     */
103
    public function mkdir(string $path, int $mode, int $options): bool
104
    {
105
        $this->assert($path, Behavior::COMMAND_MKDIR);
106
        return $this->invokeInternalStreamWrapper(
107
            'mkdir',
108
            $path,
109
            $mode,
110
            (bool) ($options & STREAM_MKDIR_RECURSIVE),
111
            $this->context
112
        );
113
    }
114
115
    /**
116
     * @param string $path_from
117
     * @param string $path_to
118
     * @return bool
119
     */
120
    public function rename(string $path_from, string $path_to): bool
121
    {
122
        $this->assert($path_from, Behavior::COMMAND_RENAME);
123
        $this->assert($path_to, Behavior::COMMAND_RENAME);
124
        return $this->invokeInternalStreamWrapper(
125
            'rename',
126
            $path_from,
127
            $path_to,
128
            $this->context
129
        );
130
    }
131
132
    /**
133
     * @param string $path
134
     * @param int $options
135
     * @return bool
136
     */
137
    public function rmdir(string $path, int $options): bool
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

137
    public function rmdir(string $path, /** @scrutinizer ignore-unused */ int $options): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
138
    {
139
        $this->assert($path, Behavior::COMMAND_RMDIR);
140
        return $this->invokeInternalStreamWrapper(
141
            'rmdir',
142
            $path,
143
            $this->context
144
        );
145
    }
146
147
    /**
148
     * @param int $cast_as
149
     */
150
    public function stream_cast(int $cast_as)
0 ignored issues
show
Unused Code introduced by
The parameter $cast_as is not used and could be removed. ( Ignorable by Annotation )

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

150
    public function stream_cast(/** @scrutinizer ignore-unused */ int $cast_as)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
151
    {
152
        throw new Exception(
153
            'Method stream_select() cannot be used',
154
            1530103999
155
        );
156
    }
157
158
    public function stream_close()
159
    {
160
        $this->invokeInternalStreamWrapper(
161
            'fclose',
162
            $this->internalResource
163
        );
164
    }
165
166
    /**
167
     * @return bool
168
     */
169
    public function stream_eof(): bool
170
    {
171
        return $this->invokeInternalStreamWrapper(
172
            'feof',
173
            $this->internalResource
174
        );
175
    }
176
177
    /**
178
     * @return bool
179
     */
180
    public function stream_flush(): bool
181
    {
182
        return $this->invokeInternalStreamWrapper(
183
            'fflush',
184
            $this->internalResource
185
        );
186
    }
187
188
    /**
189
     * @param int $operation
190
     * @return bool
191
     */
192
    public function stream_lock(int $operation): bool
193
    {
194
        return $this->invokeInternalStreamWrapper(
195
            'flock',
196
            $this->internalResource,
197
            $operation
198
        );
199
    }
200
201
    /**
202
     * @param string $path
203
     * @param int $option
204
     * @param string|int $value
205
     * @return bool
206
     */
207
    public function stream_metadata(string $path, int $option, $value): bool
208
    {
209
        $this->assert($path, Behavior::COMMAND_STEAM_METADATA);
210
        if ($option === STREAM_META_TOUCH) {
211
            return $this->invokeInternalStreamWrapper(
212
                'touch',
213
                $path,
214
                ...$value
215
            );
216
        }
217
        if ($option === STREAM_META_OWNER_NAME || $option === STREAM_META_OWNER) {
218
            return $this->invokeInternalStreamWrapper(
219
                'chown',
220
                $path,
221
                $value
222
            );
223
        }
224
        if ($option === STREAM_META_GROUP_NAME || $option === STREAM_META_GROUP) {
225
            return $this->invokeInternalStreamWrapper(
226
                'chgrp',
227
                $path,
228
                $value
229
            );
230
        }
231
        if ($option === STREAM_META_ACCESS) {
232
            return $this->invokeInternalStreamWrapper(
233
                'chmod',
234
                $path,
235
                $value
236
            );
237
        }
238
        return false;
239
    }
240
241
    /**
242
     * @param string $path
243
     * @param string $mode
244
     * @param int $options
245
     * @param string|null $opened_path
246
     * @return bool
247
     */
248
    public function stream_open(
249
        string $path,
250
        string $mode,
251
        int $options,
252
        string &$opened_path = null
253
    ): bool {
254
        $this->assert($path, Behavior::COMMAND_STREAM_OPEN);
255
        $arguments = [$path, $mode, (bool) ($options & STREAM_USE_PATH)];
256
        // only add stream context for non include/require calls
257
        if (!($options & static::STREAM_OPEN_FOR_INCLUDE)) {
258
            $arguments[] = $this->context;
259
        // work around https://bugs.php.net/bug.php?id=66569
260
        // for including files from Phar stream with OPcache enabled
261
        } else {
262
            Helper::resetOpCache();
263
        }
264
        $this->internalResource = $this->invokeInternalStreamWrapper(
265
            'fopen',
266
            ...$arguments
267
        );
268
        if (!is_resource($this->internalResource)) {
269
            return false;
270
        }
271
        if ($opened_path !== null) {
272
            $metaData = stream_get_meta_data($this->internalResource);
273
            $opened_path = $metaData['uri'];
274
        }
275
        return true;
276
    }
277
278
    /**
279
     * @param int $count
280
     * @return string
281
     */
282
    public function stream_read(int $count): string
283
    {
284
        return $this->invokeInternalStreamWrapper(
285
            'fread',
286
            $this->internalResource,
287
            $count
288
        );
289
    }
290
291
    /**
292
     * @param int $offset
293
     * @param int $whence
294
     * @return bool
295
     */
296
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool
297
    {
298
        return $this->invokeInternalStreamWrapper(
299
            'fseek',
300
            $this->internalResource,
301
            $offset,
302
            $whence
303
        ) !== -1;
304
    }
305
306
    /**
307
     * @param int $option
308
     * @param int $arg1
309
     * @param int $arg2
310
     * @return bool
311
     */
312
    public function stream_set_option(int $option, int $arg1, int $arg2): bool
313
    {
314
        if ($option === STREAM_OPTION_BLOCKING) {
315
            return $this->invokeInternalStreamWrapper(
316
                'stream_set_blocking',
317
                $this->internalResource,
318
                $arg1
319
            );
320
        }
321
        if ($option === STREAM_OPTION_READ_TIMEOUT) {
322
            return $this->invokeInternalStreamWrapper(
323
                'stream_set_timeout',
324
                $this->internalResource,
325
                $arg1,
326
                $arg2
327
            );
328
        }
329
        if ($option === STREAM_OPTION_WRITE_BUFFER) {
330
            return $this->invokeInternalStreamWrapper(
331
                'stream_set_write_buffer',
332
                $this->internalResource,
333
                $arg2
334
            ) === 0;
335
        }
336
        return false;
337
    }
338
339
    /**
340
     * @return array
341
     */
342
    public function stream_stat(): array
343
    {
344
        return $this->invokeInternalStreamWrapper(
345
            'fstat',
346
            $this->internalResource
347
        );
348
    }
349
350
    /**
351
     * @return int
352
     */
353
    public function stream_tell(): int
354
    {
355
        return $this->invokeInternalStreamWrapper(
356
            'ftell',
357
            $this->internalResource
358
        );
359
    }
360
361
    /**
362
     * @param int $new_size
363
     * @return bool
364
     */
365
    public function stream_truncate(int $new_size): bool
366
    {
367
        return $this->invokeInternalStreamWrapper(
368
            'ftruncate',
369
            $this->internalResource,
370
            $new_size
371
        );
372
    }
373
374
    /**
375
     * @param string $data
376
     * @return int
377
     */
378
    public function stream_write(string $data): int
379
    {
380
        return $this->invokeInternalStreamWrapper(
381
            'fwrite',
382
            $this->internalResource,
383
            $data
384
        );
385
    }
386
387
    /**
388
     * @param string $path
389
     * @return bool
390
     */
391
    public function unlink(string $path): bool
392
    {
393
        $this->assert($path, Behavior::COMMAND_UNLINK);
394
        return $this->invokeInternalStreamWrapper(
395
            'unlink',
396
            $path,
397
            $this->context
398
        );
399
    }
400
401
    /**
402
     * @param string $path
403
     * @param int $flags
404
     * @return array|false
405
     */
406
    public function url_stat(string $path, int $flags)
407
    {
408
        $this->assert($path, Behavior::COMMAND_URL_STAT);
409
        $functionName = $flags & STREAM_URL_STAT_QUIET ? '@stat' : 'stat';
410
        return $this->invokeInternalStreamWrapper($functionName, $path);
411
    }
412
413
    /**
414
     * @param string $path
415
     * @param string $command
416
     */
417
    protected function assert(string $path, string $command)
418
    {
419
        if (Manager::instance()->assert($path, $command) === true) {
420
            $this->learnInvocation($path);
421
            return;
422
        }
423
424
        throw new Exception(
425
            sprintf(
426
                'Denied invocation of "%s" for command "%s"',
427
                $path,
428
                $command
429
            ),
430
            1535189880
431
        );
432
    }
433
434
    /**
435
     * @param string $path
436
     */
437
    protected function learnInvocation(string $path)
438
    {
439
        if (isset($this->invocation)) {
440
            return;
441
        }
442
443
        $this->invocation = Manager::instance()->resolve($path);
0 ignored issues
show
Documentation Bug introduced by
It seems like TYPO3\PharStreamWrapper\...tance()->resolve($path) can also be of type TYPO3\PharStreamWrapper\Resolver\PharInvocation. However, the property $invocation is declared as type TYPO3\PharStreamWrapper\PharInvocation. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
444
        Manager::instance()->learnInvocation($this->invocation);
0 ignored issues
show
Bug introduced by
It seems like $this->invocation can also be of type null; however, parameter $invocation of TYPO3\PharStreamWrapper\Manager::learnInvocation() does only seem to accept TYPO3\PharStreamWrapper\Resolver\PharInvocation, 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

444
        Manager::instance()->learnInvocation(/** @scrutinizer ignore-type */ $this->invocation);
Loading history...
445
    }
446
447
    /**
448
     * @return Manager|Assertable
449
     * @deprecated Use Manager::instance() directly
450
     */
451
    protected function resolveAssertable(): Assertable
452
    {
453
        return Manager::instance();
454
    }
455
456
    /**
457
     * Invokes commands on the native PHP Phar stream wrapper.
458
     *
459
     * @param string $functionName
460
     * @param mixed ...$arguments
461
     * @return mixed
462
     */
463
    private function invokeInternalStreamWrapper(string $functionName, ...$arguments)
464
    {
465
        $silentExecution = $functionName{0} === '@';
466
        $functionName = ltrim($functionName, '@');
467
        $this->restoreInternalSteamWrapper();
468
469
        try {
470
            if ($silentExecution) {
471
                $result = @call_user_func_array($functionName, $arguments);
472
            } else {
473
                $result = call_user_func_array($functionName, $arguments);
474
            }
475
        } finally {
476
            $this->registerStreamWrapper();
477
        }
478
479
        return $result;
480
    }
481
482
    private function restoreInternalSteamWrapper()
483
    {
484
        stream_wrapper_restore('phar');
485
    }
486
487
    private function registerStreamWrapper()
488
    {
489
        stream_wrapper_unregister('phar');
490
        stream_wrapper_register('phar', static::class);
491
    }
492
}
493