Issues (105)

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.

src/Redis/Redis.php (10 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
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 25 and the first side effect is on line 384.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace Dazzle\Redis;
4
5
use Clue\Redis\Protocol\Model\ErrorReply;
6
use Clue\Redis\Protocol\Model\ModelInterface;
7
use Clue\Redis\Protocol\Parser\ParserException;
8
use Dazzle\Event\BaseEventEmitter;
9
use Dazzle\Loop\LoopAwareTrait;
10
use Dazzle\Loop\LoopInterface;
11
use Dazzle\Promise\Deferred;
12
use Dazzle\Promise\Promise;
13
use Dazzle\Promise\PromiseInterface;
14
use Dazzle\Redis\Driver\Request;
15
use Dazzle\Redis\Driver\Driver;
16
use Dazzle\Redis\Driver\DriverInterface;
17
use Dazzle\Socket\Socket;
18
use Dazzle\Socket\SocketInterface;
19
use Dazzle\Throwable\Exception\Runtime\ExecutionException;
20
use Dazzle\Throwable\Exception\Runtime\UnderflowException;
21
use Dazzle\Throwable\Exception\Runtime\WriteException;
22
use Error;
23
use Exception;
24
25
class Redis extends BaseEventEmitter implements RedisInterface
26
{
27
    use LoopAwareTrait;
28
    use Command\Compose\ApiChannelTrait;
29
    use Command\Compose\ApiClusterTrait;
30
    use Command\Compose\ApiConnTrait;
31
    use Command\Compose\ApiCoreTrait;
32
    use Command\Compose\ApiGeospatialTrait;
33
    use Command\Compose\ApiHyperLogTrait;
34
    use Command\Compose\ApiKeyValTrait;
35
    use Command\Compose\ApiListTrait;
36
    use Command\Compose\ApiSetTrait;
37
    use Command\Compose\ApiSetHashTrait;
38
    use Command\Compose\ApiSetSortedTrait;
39
    use Command\Compose\ApiTransactionTrait;
40
41
    /**
42
     * @var string
43
     */
44
    protected $endpoint;
45
46
    /**
47
     * @var SocketInterface
48
     */
49
    protected $stream;
50
51
    /**
52
     * @var DriverInterface
53
     */
54
    protected $driver;
55
56
    /**
57
     * @var bool
58
     */
59
    protected $isConnected;
60
61
    /**
62
     * @var bool
63
     */
64
    protected $isBeingDisconnected;
65
66
    /**
67
     * @var PromiseInterface|null;
68
     */
69
    protected $endPromise;
70
71
    /**
72
     * @var array
73
     */
74
    private $reqs;
75
76
    /**
77
     * @param string $endpoint
78
     * @param LoopInterface $loop
79
     */
80
    public function __construct($endpoint, LoopInterface $loop)
81
    {
82
        $this->endpoint = $endpoint;
83
        $this->loop = $loop;
84
        $this->stream = null;
85
        $this->driver = new Driver();
86
87
        $this->isConnected = false;
88
        $this->isBeingDisconnected = false;
89
        $this->endPromise = null;
90
91
        $this->reqs = [];
92
    }
93
94
    /**
95
     *
96
     */
97
    public function __destruct()
98
    {
99
        $this->stop();
100
        parent::__destruct();
101
    }
102
103
    /**
104
     * @override
105
     * @inheritDoc
106
     */
107
    public function isPaused()
108
    {
109
        return $this->stream === null ? false : $this->stream->isPaused();
110
    }
111
112
    /**
113
     * @override
114
     * @inheritDoc
115
     */
116
    public function pause()
117
    {
118
        if ($this->stream !== null)
119
        {
120
            $this->stream->pause();
121
        }
122
    }
123
124
    /**
125
     * @override
126
     * @inheritDoc
127
     */
128
    public function resume()
129
    {
130
        if ($this->stream !== null)
131
        {
132
            $this->stream->resume();
133
        }
134
    }
135
136
    /**
137
     * @override
138
     * @inheritDoc
139
     */
140 138
    public function isStarted()
141
    {
142 138
        return $this->isConnected;
143
    }
144
145
    /**
146
     * @override
147
     * @inheritDoc
148
     */
149 138
    public function isBusy()
150
    {
151 138
        return !empty($this->reqs);
152
    }
153
154
    /**
155
     * @override
156
     * @inheritDoc
157
     */
158 138
    public function start()
159
    {
160 138
        if ($this->isStarted())
161
        {
162
            return Promise::doResolve($this);
163
        }
164
165 138
        $ex = null;
166 138
        $stream = null;
167
168
        try
169
        {
170 138
            $stream = $this->createClient($this->endpoint);
171
        }
172
        catch (Error $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
173
        {}
174
        catch (Exception $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
175
        {}
176
177 138
        if ($ex !== null)
178
        {
179
            return Promise::doReject($ex);
180
        }
181
182 138
        $this->isConnected = true;
183 138
        $this->isBeingDisconnected = false;
184 138
        $this->stream = $stream;
185 138
        $this->handleStart();
186 138
        $this->emit('start', [ $this ]);
187
188 138
        return Promise::doResolve($this);
189
    }
190
191
    /**
192
     * @override
193
     * @inheritDoc
194
     */
195 138
    public function stop()
196
    {
197 138
        if (!$this->isStarted())
198
        {
199 138
            return Promise::doResolve($this);
200
        }
201
202 138
        $this->isBeingDisconnected = true;
203 138
        $this->isConnected = false;
204
205 138
        $this->stream->close();
206 138
        $this->stream = null;
207
208 138
        foreach ($this->reqs as $req)
209
        {
210 2
            $req->reject(new ExecutionException('Connection has been closed!'));
211
        }
212
213 138
        $this->reqs = [];
214 138
        $this->handleStop();
215 138
        $this->emit('stop', [ $this ]);
216
217 138
        if ($this->endPromise !== null)
218
        {
219
            $promise = $this->endPromise;
220
            $this->endPromise = null;
221
            $promise->resolve($this);
0 ignored issues
show
The method resolve cannot be called on $promise (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
222
        }
223
224 138
        return Promise::doResolve($this);
225
    }
226
227
    /**
228
     * @override
229
     * @inheritDoc
230
     */
231
    public function end()
232
    {
233
        if (!$this->isStarted())
234
        {
235
            return Promise::doResolve($this);
236
        }
237
        if ($this->isBeingDisconnected)
238
        {
239
            return Promise::doReject(new WriteException('Tried to double end same connection.'));
240
        }
241
        if (!$this->isBusy())
242
        {
243
            return $this->stop();
244
        }
245
246
        $promise = new Promise();
247
        $this->isBeingDisconnected = true;
248
        $this->endPromise = $promise;
249
250
        return $promise;
251
    }
252
253
    /**
254
     * Dispatch Redis request.
255
     *
256
     * @param Request $command
257
     * @return PromiseInterface
258
     */
259 138
    protected function dispatch(Request $command)
260
    {
261 138
        $request = new Deferred();
262 138
        $promise = $request->getPromise();
263
264 138
        if ($this->isBeingDisconnected)
265
        {
266
            $request->reject(new ExecutionException('Redis client connection is being stopped now.'));
267
        }
268
        else
269
        {
270 138
            $this->stream->write($this->driver->commands($command));
271 138
            $this->reqs[] = $request;
272
        }
273
274 138
        return $promise;
275
    }
276
277
    /**
278
     * @internal
279
     */
280 138 View Code Duplication
    protected function handleStart()
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...
281
    {
282 138
        if ($this->stream !== null)
283
        {
284 138
            $this->stream->on('data', [ $this, 'handleData' ]);
285 138
            $this->stream->on('close', [ $this, 'stop' ]);
286
        }
287 138
    }
288
289
    /**
290
     * @internal
291
     */
292 138 View Code Duplication
    protected function handleStop()
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...
293
    {
294 138
        if ($this->stream !== null)
295
        {
296
            $this->stream->removeListener('data', [ $this, 'handleData' ]);
297
            $this->stream->removeListener('close', [ $this, 'stop' ]);
298
        }
299 138
    }
300
301
    /**
302
     * @internal
303
     * @param SocketInterface $stream
304
     * @param string $chunk
305
     */
306 138
    public function handleData($stream, $chunk)
307
    {
308
        try
309
        {
310 138
            $models = $this->driver->parseResponse($chunk);
311
        }
312
        catch (ParserException $error)
313
        {
314
            $this->emit('error', [ $this, $error ]);
315
            $this->stop();
316
            return;
317
        }
318
319 138
        foreach ($models as $data)
320
        {
321
            try
322
            {
323 138
                $this->handleMessage($data);
324
            }
325
            catch (UnderflowException $error)
326
            {
327
                $this->emit('error', [ $this, $error ]);
328
                $this->stop();
329 138
                return;
330
            }
331
        }
332 138
    }
333
334
    /**
335
     * @internal
336
     * @param ModelInterface $message
337
     */
338 138
    protected function handleMessage(ModelInterface $message)
339
    {
340 138
        if (!$this->reqs)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->reqs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
341
        {
342
            throw new UnderflowException('Unexpected reply received, no matching request found');
343
        }
344
345 138
        $request = array_shift($this->reqs);
346
347 138
        if ($message instanceof ErrorReply)
348
        {
349
            $request->reject($message);
350
        }
351
        else
352
        {
353 138
            $request->resolve($message->getValueNative());
354
        }
355
356 138
        if ($this->isBeingDisconnected && !$this->isBusy())
357
        {
358 138
            $this->stop();
359
        }
360 138
    }
361
362
    /**
363
     * Create socket client with connection to Redis database.
364
     *
365
     * @param string $endpoint
366
     * @return SocketInterface
367
     * @throws ExecutionException
368
     */
369 138
    protected function createClient($endpoint)
370
    {
371 138
        $ex = null;
372
373
        try
374
        {
375 138
            return new Socket($endpoint, $this->loop);
0 ignored issues
show
It seems like $this->loop can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
376
        }
377
        catch (Error $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
378
        {}
379
        catch (Exception $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
380
        {}
381
382
        throw new ExecutionException('Redis connection socket could not be created!', 0, $ex);
383
    }
384
};
385