Passed
Pull Request — master (#186)
by Dmitriy
02:25
created

HttpStreamProxy::dir_readdir()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 10
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Debug\Collector;
6
7
use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapper;
8
use Yiisoft\Yii\Debug\Helper\StreamWrapper\StreamWrapperInterface;
9
10
use const SEEK_SET;
11
12
class HttpStreamProxy implements StreamWrapperInterface
13
{
14
    public static bool $registered = false;
15
    /**
16
     * @var resource|null
17
     */
18
    public $context;
19
    public StreamWrapperInterface $decorated;
20
    public bool $ignored = false;
21
22
    public static ?HttpStreamCollector $collector = null;
23
24
    public function __construct()
25
    {
26
        $this->decorated = new StreamWrapper();
27
        $this->decorated->context = $this->context;
0 ignored issues
show
Bug introduced by
Accessing context on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
28
    }
29
30
    public function __call(string $name, array $arguments)
31
    {
32
        try {
33
            self::unregister();
34
            return $this->decorated->{$name}(...$arguments);
35
        } finally {
36
            self::register();
37
        }
38
    }
39
40
    public function __get(string $name)
41
    {
42
        return $this->decorated->{$name};
43
    }
44
45
    public static function register(): void
46
    {
47
        if (self::$registered) {
48
            return;
49
        }
50
        /**
51
         * It's important to trigger autoloader before unregistering the file stream handler
52
         */
53
        class_exists(StreamWrapper::class);
54
        stream_wrapper_unregister('http');
55
        stream_wrapper_register('http', self::class, STREAM_IS_URL);
56
        stream_wrapper_unregister('https');
57
        stream_wrapper_register('https', self::class, STREAM_IS_URL);
58
        self::$registered = true;
59
    }
60
61
    public static function unregister(): void
62
    {
63
        if (!self::$registered) {
64
            return;
65
        }
66
        @stream_wrapper_restore('http');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for stream_wrapper_restore(). 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

66
        /** @scrutinizer ignore-unhandled */ @stream_wrapper_restore('http');

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...
67
        @stream_wrapper_restore('https');
68
        self::$registered = false;
69
    }
70
71
    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_open" is not in camel caps format
Loading history...
72
    {
73
        return $this->__call(__FUNCTION__, func_get_args());
74
    }
75
76
    public function stream_read(int $count): string|false
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_read" is not in camel caps format
Loading history...
77
    {
78
        if (!$this->ignored) {
79
            $metadata = stream_get_meta_data($this->decorated->stream);
0 ignored issues
show
Bug introduced by
Accessing stream on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
80
            $context = $this->decorated->context === null
0 ignored issues
show
Bug introduced by
Accessing context on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
81
                ? null
82
                : stream_context_get_options($this->decorated->context);
83
            /**
84
             * @link https://www.php.net/manual/en/context.http.php
85
             */
86
            $method = $context['http']['method'] ?? $context['https']['method'] ?? 'GET';
87
            $headers = (array) ($context['http']['header'] ?? $context['https']['header'] ?? []);
88
89
            self::$collector->collect(
0 ignored issues
show
Bug introduced by
The method collect() does not exist on null. ( Ignorable by Annotation )

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

89
            self::$collector->/** @scrutinizer ignore-call */ 
90
                              collect(

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...
90
                operation: 'read',
91
                path: $this->decorated->filename,
0 ignored issues
show
Bug introduced by
Accessing filename on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
92
                args: [
93
                    'method' => $method,
94
                    'response_headers' => $metadata['wrapper_data'],
95
                    'request_headers' => $headers,
96
                    // TODO: get rid of?
97
                    'metadata' => $metadata,
98
                    'context' => $context,
99
                ],
100
            );
101
        }
102
        return $this->__call(__FUNCTION__, func_get_args());
103
    }
104
105
    public function stream_set_option(int $option, int $arg1, ?int $arg2): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_set_option" is not in camel caps format
Loading history...
106
    {
107
        return $this->__call(__FUNCTION__, func_get_args());
108
    }
109
110
    public function stream_tell(): int
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_tell" is not in camel caps format
Loading history...
111
    {
112
        return $this->__call(__FUNCTION__, func_get_args());
113
    }
114
115
    public function stream_eof(): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_eof" is not in camel caps format
Loading history...
116
    {
117
        return $this->__call(__FUNCTION__, func_get_args());
118
    }
119
120
    public function stream_seek(int $offset, int $whence = SEEK_SET): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_seek" is not in camel caps format
Loading history...
121
    {
122
        return $this->__call(__FUNCTION__, func_get_args());
123
    }
124
125
    public function stream_cast(int $castAs)
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_cast" is not in camel caps format
Loading history...
126
    {
127
        return $this->__call(__FUNCTION__, func_get_args());
128
    }
129
130
    public function stream_stat(): array|false
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_stat" is not in camel caps format
Loading history...
131
    {
132
        return $this->__call(__FUNCTION__, func_get_args());
133
    }
134
135
    public function dir_closedir(): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::dir_closedir" is not in camel caps format
Loading history...
136
    {
137
        return $this->__call(__FUNCTION__, func_get_args());
138
    }
139
140
    public function dir_opendir(string $path, int $options): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::dir_opendir" is not in camel caps format
Loading history...
141
    {
142
        return $this->__call(__FUNCTION__, func_get_args());
143
    }
144
145
    public function dir_readdir(): string
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::dir_readdir" is not in camel caps format
Loading history...
146
    {
147
        if (!$this->ignored) {
148
            self::$collector->collect(
149
                operation: __FUNCTION__,
150
                path: $this->decorated->filename,
0 ignored issues
show
Bug introduced by
Accessing filename on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
151
                args: [],
152
            );
153
        }
154
        return $this->__call(__FUNCTION__, func_get_args());
155
    }
156
157
    public function dir_rewinddir(): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::dir_rewinddir" is not in camel caps format
Loading history...
158
    {
159
        return $this->__call(__FUNCTION__, func_get_args());
160
    }
161
162
    public function mkdir(string $path, int $mode, int $options): bool
163
    {
164
        if (!$this->ignored) {
165
            self::$collector->collect(
166
                operation: __FUNCTION__,
167
                path: $path,
168
                args: [
169
                    'mode' => $mode,
170
                    'options' => $options,
171
                ]
172
            );
173
        }
174
        return $this->__call(__FUNCTION__, func_get_args());
175
    }
176
177
    public function rename(string $path_from, string $path_to): bool
178
    {
179
        if (!$this->ignored) {
180
            self::$collector->collect(
181
                operation: __FUNCTION__,
182
                path: $path_from,
183
                args: [
184
                    'path_to' => $path_to,
185
                ],
186
            );
187
        }
188
        return $this->__call(__FUNCTION__, func_get_args());
189
    }
190
191
    public function rmdir(string $path, int $options): bool
192
    {
193
        if (!$this->ignored) {
194
            self::$collector->collect(
195
                operation: __FUNCTION__,
196
                path: $path,
197
                args: [
198
                    'options' => $options,
199
                ],
200
            );
201
        }
202
        return $this->__call(__FUNCTION__, func_get_args());
203
    }
204
205
    public function stream_close(): void
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_close" is not in camel caps format
Loading history...
206
    {
207
        $this->__call(__FUNCTION__, func_get_args());
208
    }
209
210
    public function stream_flush(): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_flush" is not in camel caps format
Loading history...
211
    {
212
        return $this->__call(__FUNCTION__, func_get_args());
213
    }
214
215
    public function stream_lock(int $operation): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_lock" is not in camel caps format
Loading history...
216
    {
217
        return $this->__call(__FUNCTION__, func_get_args());
218
    }
219
220
    public function stream_metadata(string $path, int $option, mixed $value): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_metadata" is not in camel caps format
Loading history...
221
    {
222
        return $this->__call(__FUNCTION__, func_get_args());
223
    }
224
225
    public function stream_truncate(int $new_size): bool
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_truncate" is not in camel caps format
Loading history...
226
    {
227
        return $this->__call(__FUNCTION__, func_get_args());
228
    }
229
230
    public function stream_write(string $data): int
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::stream_write" is not in camel caps format
Loading history...
231
    {
232
        if (!$this->ignored) {
233
            self::$collector->collect(
234
                operation: 'write',
235
                path: $this->decorated->filename,
0 ignored issues
show
Bug introduced by
Accessing filename on the interface Yiisoft\Yii\Debug\Helper...\StreamWrapperInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
236
                args: [],
237
            );
238
        }
239
240
        return $this->__call(__FUNCTION__, func_get_args());
241
    }
242
243
    public function unlink(string $path): bool
244
    {
245
        if (!$this->ignored) {
246
            self::$collector->collect(
247
                operation: __FUNCTION__,
248
                path: $path,
249
                args: [],
250
            );
251
        }
252
        return $this->__call(__FUNCTION__, func_get_args());
253
    }
254
255
    public function url_stat(string $path, int $flags): array|false
0 ignored issues
show
Coding Style introduced by
Method name "HttpStreamProxy::url_stat" is not in camel caps format
Loading history...
256
    {
257
        return $this->__call(__FUNCTION__, func_get_args());
258
    }
259
}
260