Issues (6)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

streams/Stream.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace nyx\connect\streams;
2
3
// External dependencies
4
use nyx\core;
5
6
/**
7
 * Stream
8
 *
9
 * @package     Nyx\Connect
10
 * @version     0.1.0
11
 * @author      Michal Chojnacki <[email protected]>
12
 * @copyright   2012-2016 Nyx Dev Team
13
 * @link        http://docs.muyo.io/nyx/connect/index.html
14
 */
15
class Stream implements interfaces\Stream
16
{
17
    /**
18
     * @var array       Hash table of readable and writable stream modes for faster look-ups.
19
     */
20
    private static $rwh = [
21
        'read' => [
22
            'r'   => true, 'w+'  => true, 'r+'  => true, 'rw'  => true, 'x+'  => true,
23
            'c+'  => true, 'a+'  => true, 'a+b' => true, 'rb'  => true, 'w+b' => true,
24
            'r+b' => true, 'x+b' => true, 'c+b' => true, 'rt'  => true, 'w+t' => true,
25
            'r+t' => true, 'x+t' => true, 'c+t' => true
26
        ],
27
        'write' => [
28
            'w'   => true, 'w+'  => true, 'rw'  => true, 'r+'  => true, 'c'   => true,
29
            'c+'  => true, 'cb'  => true, 'x'   => true, 'xb'  => true, 'x+'  => true,
30
            'x+b' => true, 'a'   => true, 'a+'  => true, 'a+b' => true, 'ab'  => true,
31
            'wb'  => true, 'w+b' => true, 'r+b' => true, 'c+b' => true, 'w+t' => true,
32
            'r+t' => true, 'x+t' => true, 'c+t' => true
33
        ]
34
    ];
35
36
    /**
37
     * @var resource    The underlying stream resource.
38
     */
39
    private $resource;
40
41
    /**
42
     * @var resource    The stream context resource in use.
43
     */
44
    private $context;
45
46
    /**
47
     * @var array       Cached data about the stream.
48
     */
49
    private $metadata;
50
51
    /**
52
     * @var core\Mask   Status/mode mask of the Stream.
53
     */
54
    private $status;
55
56
    /**
57
     * @var int         The size of the stream's contents in bytes.
58
     */
59
    private $size;
60
61
    /**
62
     * Constructs a new Stream instance.
63
     *
64
     * @param   string|resource     $stream     The URI of the stream resource that should be opened or an already
65
     *                                          created stream resource.
66
     * @param   string              $mode       The mode in which the stream should be opened.
67
     * @param   array               $context    Stream context options. Will be ignored if an already created stream
68
     *                                          is passed to the constructor.
69
     * @param   int                 $size       The size of the stream in bytes. Should only be passed if it cannot be
70
     *                                          obtained by directly analyzing the stream.
71
     * @throws  \InvalidArgumentException       When a resource was given but was not a valid stream resource or when
72
     *                                          it was to be created but no mode was given.
73
     * @throws  \RuntimeException               When a stream was to be created but couldn't be opened.
74
     */
75
    public function __construct($stream, string $mode = null, array $context = null, int $size = null)
76
    {
77
        // Are we dealing with an already existing stream?
78
        if (is_resource($stream)) {
79
            // Ensure the resource is a stream.
80
            if (get_resource_type($stream) !== 'stream') {
81
                throw new \InvalidArgumentException('A resource was given but it was not a valid stream.');
82
            }
83
84
            $this->resource = $stream;
85
        }
86
        // Otherwise we should create our own.
87
        else {
88
            // We need a mode to work with.
89
            if (null === $mode) {
90
                throw new \InvalidArgumentException('A valid stream mode must be given to open a stream resource.');
91
            }
92
93
            // Let's prepare a stream context if asked to.
94
            if (null !== $context) {
95
                $this->context = stream_context_create($context);
96
            }
97
98
            // Open it either with a specific context or leave the default one.
99
            if (!$this->resource = $this->context ? fopen($stream, $mode, $this->context) : fopen($stream, $mode)) {
100
                throw new \RuntimeException("Failed to open a stream [$stream, mode: $mode].");
101
            }
102
        }
103
104
        $this->size = $size;
105
    }
106
107
    /**
108
     * {@inheritDoc}
109
     */
110 View Code Duplication
    public function getContents() : string
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
    {
112
        if (!$this->resource) {
113
            throw new \RuntimeException('No stream resource available - cannot get contents.');
114
        }
115
116
        if (!$this->is(interfaces\Stream::READABLE)) {
117
            throw new \RuntimeException('Cannot get stream contents - the stream is not readable.');
118
        }
119
120
        // As long as we've got a resource, we can try reading. If it fails, we can diagnose afterwards.
121
        if (!false === $data = stream_get_contents($this->resource)) {
122
            throw new \RuntimeException('Failed to read stream contents.');
123
        }
124
125
        return $data;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 View Code Duplication
    public function read($length) : string
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
    {
133
        if (!$this->resource) {
134
            throw new \RuntimeException('No stream resource available - cannot read.');
135
        }
136
137
        if (!$this->is(interfaces\Stream::READABLE)) {
138
            throw new \RuntimeException('Cannot read from non-readable stream.');
139
        }
140
141
        if (false === $data = fread($this->resource, $length)) {
142
            throw new \RuntimeException('Failed to read from the stream.');
143
        }
144
145
        return $data;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151 View Code Duplication
    public function line(int $length = null) : string
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
    {
153
        if (!$this->resource) {
154
            throw new \RuntimeException('No stream resource available - cannot read.');
155
        }
156
157
        if (!$this->is(interfaces\Stream::READABLE)) {
158
            throw new \RuntimeException('Cannot read from non-readable stream.');
159
        }
160
161
        if (false === $data = fgets($this->resource, $length)) {
162
            throw new \RuntimeException('Failed to read from the stream.');
163
        }
164
165
        return $data;
166
    }
167
168
169
    /**
170
     * {@inheritdoc}
171
     */
172 View Code Duplication
    public function write($string) : int
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
    {
174
        if (!$this->resource) {
175
            throw new \RuntimeException('No stream resource available - cannot write.');
176
        }
177
178
        if (!$this->is(interfaces\Stream::WRITABLE)) {
179
            throw new \RuntimeException('Cannot write to non-writable stream.');
180
        }
181
        if (false === $result = fwrite($this->resource, $string)) {
182
            throw new \RuntimeException('Failed to write to the stream.');
183
        }
184
185
        // The size has changed so make sure we get a fresh value for the next getSize() call.
186
        $this->size = null;
187
188
        return $result;
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194
    public function isReadable() : bool
195
    {
196
        if (!$this->resource) {
197
            return false;
198
        }
199
200
        return $this->is(interfaces\Stream::READABLE);
201
    }
202
203
    /**
204
     * {@inheritdoc}
205
     */
206
    public function isWritable() : bool
207
    {
208
        if (!$this->resource) {
209
            return false;
210
        }
211
212
        return $this->is(interfaces\Stream::WRITABLE);
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218
    public function isSeekable() : bool
219
    {
220
        if (!$this->resource) {
221
            return false;
222
        }
223
224
        return $this->is(interfaces\Stream::SEEKABLE);
225
    }
226
227
    /**
228
     * {@inheritDoc}
229
     */
230
    public function is($status) : bool
231
    {
232
        if (!$this->resource) {
233
            return false;
234
        }
235
236
        if (empty($this->metadata) || $this->status) {
237
            $this->refresh();
238
        }
239
240
        return $this->status->is($status);
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246
    public function tell()
247
    {
248
        if (!$this->resource) {
249
            throw new \RuntimeException('No stream resource available - cannot tell position.');
250
        }
251
252
        if (false === $result = ftell($this->resource)) {
253
            throw new \RuntimeException('Unable to determine stream position.');
254
        }
255
256
        return $result;
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262
    public function eof()
263
    {
264
        return !$this->resource || feof($this->resource);
265
    }
266
267
    /**
268
     * {@inheritdoc}
269
     */
270
    public function seek($offset, $whence = SEEK_SET)
271
    {
272
        if (!$this->resource) {
273
            throw new \RuntimeException('No stream resource available - cannot seek.');
274
        }
275
276
        if (!$this->is(interfaces\Stream::SEEKABLE)) {
277
            throw new \RuntimeException('The stream is not seekable.');
278
        }
279
280
        // As long as we've got a resource, we can try seeking. If it fails, we can diagnose afterwards.
281
        if (-1 === fseek($this->resource, $offset, $whence)) {
282
            throw new \RuntimeException("Failed to seek to stream position [$offset] with whence [".var_export($whence, true)."].");
283
        }
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289
    public function rewind()
290
    {
291
        $this->seek(0);
292
    }
293
294
    /**
295
     * {@inheritdoc}
296
     */
297
    public function getSize()
298
    {
299
        if (!$this->resource) {
300
            return null;
301
        }
302
303
        if ($this->size !== null) {
304
            return $this->size;
305
        }
306
307
        // We're gonna clear the cache for local streams with an URI to ensure we get
308
        // an updated size each time, in case we or something else is currently writing
309
        // to that resource.
310
        if ($this->is(interfaces\Stream::LOCAL) && $uri = $this->getMetadata('uri')) {
311
            clearstatcache(true, $uri);
312
        }
313
314
        $stats = fstat($this->resource);
315
316
        if (isset($stats['size'])) {
317
            return $this->size = $stats['size'];
318
        }
319
320
        return null;
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326
    public function getMetadata($key = null)
327
    {
328
        // If we've got no underlying stream (anymore?), we are going to return null for each requested
329
        // key and empty arrays if the whole metadata array was requested.
330
        if (!$this->resource) {
331
            return $key ? null : [];
332
        }
333
334
        // Certain data doesn't change in a given stream, so we might just as well return cached values
335
        // if we've got them.
336
        if (null !== $key && !empty($this->metadata)) {
337
            switch ($key) {
338
                case 'mode':
339
                case 'stream_type':
340
                case 'wrapper_type':
341
                case 'wrapper_data':
342
                case 'uri':
343
                    return $this->metadata[$key];
344
            }
345
        }
346
347
        // Grab the metadata and cache it.
348
        $this->metadata = stream_get_meta_data($this->resource);
349
350
        if (null === $key) {
351
            return $this->metadata;
352
        }
353
354
        if (!array_key_exists($key, $this->metadata)) {
355
            return null;
356
        }
357
358
        return $this->metadata[$key];
359
    }
360
361
    /**
362
     * {@inheritdoc}
363
     */
364
    public function close()
365
    {
366
        if (!$this->resource || !is_resource($this->resource)) {
367
            return;
368
        }
369
370
        // Close first, detach afterwards.
371
        fclose($this->resource);
372
373
        $this->detach();
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379
    public function detach()
380
    {
381
        $resource = $this->resource;
382
383
        $this->resource = null;
384
        $this->context  = null;
385
        $this->metadata = [];
386
        $this->status   = null;
387
        $this->size     = null;
388
389
        return $resource;
390
    }
391
392
    /**
393
     * {@inheritDoc}
394
     */
395
    public function toString() : string
396
    {
397
        // Trying to get the position first - we'll seek back to it after we're done.
398
        // This will also take care of all necessary checks.
399
        $position = $this->tell();
400
401
        // Grab the contents into memory. This might potentially use up a lot of memory
402
        // so be advised about the pitfalls.
403
        $body = stream_get_contents($this->resource, -1, 0);
404
405
        // Seek back to where we were.
406
        $this->seek($position);
407
408
        return (string) $body;
409
    }
410
411
    /**
412
     * {@inheritDoc}
413
     */
414
    public function __toString()
415
    {
416
        try {
417
            return $this->toString();
418
        } catch (\Exception $e) {
419
            return '';
420
        }
421
    }
422
423
    /**
424
     * Ensure the stream resource gets closed when the Stream instance gets destructed.
425
     */
426
    public function __destruct()
427
    {
428
        $this->close();
429
    }
430
431
    /**
432
     * Refreshes the status mask based on the current metadata of the stream.
433
     *
434
     * @return  bool    True if we successfully refreshed all relevant data, false otherwise.
435
     */
436
    protected function refresh() : bool
437
    {
438
        // Without a resource to grab the metadata for, let invokers know there's no data
439
        // to work with presently.
440
        if (!$this->resource) {
441
            return false;
442
        }
443
444
        // Prepare the status mask if necessary. Might as well give it a value to begin with.
445
        if (!$this->status) {
446
            $this->status = new core\Mask(stream_is_local($this->resource) ? interfaces\Stream::LOCAL : 0);
447
        }
448
449
        // The call results of metadata() are cached so we can just use the class property.
450
        $this->getMetadata();
451
452 View Code Duplication
        if (isset(self::$rwh['read'][$this->metadata['mode']])) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
453
            $this->status->set(interfaces\Stream::READABLE);
454
        }
455
456 View Code Duplication
        if (isset(self::$rwh['write'][$this->metadata['mode']])) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
457
            $this->status->set(interfaces\Stream::WRITABLE);
458
        }
459
460
        // Those may change, so... besides - fancy syntax, eh chaps?
461
        $this->status->{((isset($this->metadata['seekable']) && $this->metadata['seekable']) ? 'set' : 'remove')}(interfaces\Stream::SEEKABLE);
462
        $this->status->{((isset($this->metadata['blocked'])  && $this->metadata['blocked'])  ? 'set' : 'remove')}(interfaces\Stream::BLOCKED);
463
464
        return true;
465
    }
466
}
467