Issues (1507)

Security Analysis    not enabled

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.

PHPDaemon/Servers/WebSocket/Connection.php (23 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
2
namespace PHPDaemon\Servers\WebSocket;
3
4
use PHPDaemon\Core\Daemon;
5
use PHPDaemon\HTTPRequest\Generic;
6
use PHPDaemon\Request\RequestHeadersAlreadySent;
7
8
class Connection extends \PHPDaemon\Network\Connection
9
{
10
    use \PHPDaemon\Traits\DeferredEventHandlers;
11
    use \PHPDaemon\Traits\Sessions;
12
13
    /**
14
     * @var integer Timeout
15
     */
16
    protected $timeout = 120;
17
18
    protected $handshaked = false;
19
20
	/**
21
	 * @var $route \PHPDaemon\WebSocket\Route
22
	 */
23
	protected $route;
24
25
    protected $writeReady = true;
26
    protected $extensions = [];
27
    protected $extensionsCleanRegex = '/(?:^|\W)x-webkit-/iS';
28
29
    protected $headers = [];
30
    protected $headers_sent = false;
31
32
    /**
33
     * @var array _SERVER
34
     */
35
    public $server = [];
36
37
    /**
38
     * @var array _COOKIE
39
     */
40
    public $cookie = [];
41
42
    /**
43
     * @var array _GET
44
     */
45
    public $get = [];
46
47
48
    protected $policyReqNotFound = false;
49
    protected $currentHeader;
50
    protected $EOL = "\r\n";
51
52
    /**
53
     * @var boolean Is this connection running right now?
54
     */
55
    protected $running = false;
56
57
    /**
58
     * State: first line
59
     */
60
    const STATE_FIRSTLINE = 1;
61
62
    /**
63
     * State: headers
64
     */
65
    const STATE_HEADERS = 2;
66
67
    /**
68
     * State: content
69
     */
70
    const STATE_CONTENT = 3;
71
72
    /**
73
     * State: prehandshake
74
     */
75
    const STATE_PREHANDSHAKE = 5;
76
77
    /**
78
     * State: handshaked
79
     */
80
    const STATE_HANDSHAKED = 6;
81
82
    const STRING = null;
83
84
    const BINARY = null;
85
86
    /**
87
     * @var integer Content length from header() method
88
     */
89
    protected $contentLength;
90
91
    /**
92
     * @var integer Number of outgoing cookie-headers
93
     */
94
    protected $cookieNum = 0;
95
96
    /**
97
     * @var array Replacement pairs for processing some header values in parse_str()
98
     */
99
    public static $hvaltr = ['; ' => '&', ';' => '&', ' ' => '%20'];
100
101
    /**
102
     * Called when the stream is handshaked (at low-level), and peer is ready to recv. data
103
     * @return void
104
     */
105
    public function onReady()
106
    {
107
        $this->setWatermark(null, $this->pool->maxAllowedPacket + 100);
108
    }
109
110
    /**
111
     * Get real frame type identificator
112
     * @param $type
113
     * @return integer
114
     */
115
    public function getFrameType($type)
116
    {
117
        if (is_int($type)) {
118
            return $type;
119
        }
120
        if ($type === null) {
121
            $type = 'STRING';
122
        }
123
        $frametype = @constant(get_class($this) . '::' . $type);
124
        if ($frametype === null) {
125
            Daemon::log(__METHOD__ . ' : Undefined frametype "' . $type . '"');
126
        }
127
        return $frametype;
128
    }
129
130
131
    /**
132
     * Called when connection is inherited from HTTP request
133
     * @param  object $req
134
     * @return void
135
     */
136 View Code Duplication
    public function onInheritanceFromRequest($req)
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...
137
    {
138
        $this->state = self::STATE_HEADERS;
139
        $this->addr = $req->attrs->server['REMOTE_ADDR'];
140
        $this->server = $req->attrs->server;
141
        $this->get = $req->attrs->get;
142
        $this->prependInput("\r\n");
143
        $this->onRead();
144
    }
145
146
    /**
147
     * Sends a frame.
148
     * @param  string $data Frame's data.
149
     * @param  string $type Frame's type. ("STRING" OR "BINARY")
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
150
     * @param  callable $cb Optional. Callback called when the frame is received by client.
0 ignored issues
show
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
151
     * @callback $cb ( )
152
     * @return boolean         Success.
153
     */
154
    public function sendFrame($data, $type = null, $cb = null)
155
    {
156
        return false;
157
    }
158
159
    /**
160
     * Event of Connection.
161
     * @return void
162
     */
163
    public function onFinish()
164
    {
165
        $this->sendFrame('', 'CONNCLOSE');
166
167
        if ($this->route) {
168
            $this->route->onFinish();
169
        }
170
        $this->route = null;
171
    }
172
173
    /**
174
     * Uncaught exception handler
175
     * @param  \Exception $e
176
     * @return boolean      Handled?
177
     */
178
    public function handleException($e)
179
    {
180
        if (!isset($this->route)) {
181
            return false;
182
        }
183
        return $this->route->handleException($e);
184
    }
185
186
    /**
187
     * Called when new frame received.
188
     * @param  string $data Frame's data.
189
     * @param  string $type Frame's type ("STRING" OR "BINARY").
190
     * @return boolean      Success.
191
     */
192
    public function onFrame($data, $type)
193
    {
194
        if (!isset($this->route)) {
195
            return false;
196
        }
197
        try {
198
            $this->route->onWakeup();
199
            $this->route->onFrame($data, $type);
200
        } catch (\Throwable $e) {
0 ignored issues
show
The class Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
201
            Daemon::uncaughtExceptionHandler($e);
202
        }
203
        if ($this->route) {
204
            $this->route->onSleep();
205
        }
206
        return true;
207
    }
208
209
    /**
210
     * Called when the worker is going to shutdown.
211
     * @return boolean Ready to shutdown ?
212
     */
213
    public function gracefulShutdown()
214
    {
215
        if ((!$this->route) || $this->route->gracefulShutdown()) {
216
            $this->finish();
217
            return true;
218
        }
219
        return false;
220
    }
221
222
223
    /**
224
     * Called when we're going to handshake.
225
     * @return boolean               Handshake status
226
     */
227
    public function handshake()
228
    {
229
        $this->route = $this->pool->getRoute($this->server['DOCUMENT_URI'], $this);
230 View Code Duplication
        if (!$this->route) {
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...
231
            Daemon::$process->log(get_class($this) . '::' . __METHOD__ . ' : Cannot handshake session for client "' . $this->addr . '"');
232
            $this->finish();
233
            return false;
234
        }
235
236
        if (method_exists($this->route, 'onBeforeHandshake')) {
237
            $this->route->onWakeup();
238
            $ret = $this->route->onBeforeHandshake(function () {
239
                $this->handshakeAfter();
240
            });
241
            if ($this->route) {
242
                $this->route->onSleep();
243
            }
244
            if ($ret !== false) {
245
                return true;
246
            }
247
        }
248
249
	    return $this->handshakeAfter();
250
    }
251
252
    protected function handshakeAfter()
253
    {
254
        $extraHeaders = '';
255
        foreach ($this->headers as $k => $line) {
256
            if ($k !== 'STATUS') {
257
                $extraHeaders .= $line . "\r\n";
258
            }
259
        }
260
261 View Code Duplication
        if (!$this->sendHandshakeReply($extraHeaders)) {
0 ignored issues
show
The method sendHandshakeReply() does not exist on PHPDaemon\Servers\WebSocket\Connection. Did you maybe mean handshake()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
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...
262
            Daemon::$process->log(get_class($this) . '::' . __METHOD__ . ' : Handshake protocol failure for client "' . $this->addr . '"');
263
            $this->finish();
264
            return false;
265
        }
266
267
        $this->handshaked = true;
268
        $this->headers_sent = true;
269
        $this->state = static::STATE_HANDSHAKED;
270
        if (is_callable([$this->route, 'onHandshake'])) {
271
            $this->route->onWakeup();
0 ignored issues
show
The method onWakeup cannot be called on $this->route (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...
272
            $this->route->onHandshake();
0 ignored issues
show
The method onHandshake cannot be called on $this->route (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...
273
            if ($this->route) {
274
                $this->route->onSleep();
275
            }
276
        }
277
        return true;
278
    }
279
280
    /**
281
     * Send Bad request
282
     * @return void
283
     */
284
    public function badRequest()
285
    {
286
        $this->state = self::STATE_STANDBY;
287
        $this->write("400 Bad Request\r\n\r\n<html><head><title>400 Bad Request</title></head><body bgcolor=\"white\"><center><h1>400 Bad Request</h1></center></body></html>");
288
        $this->finish();
289
    }
290
291
    /**
292
     * Read first line of HTTP request
293
     * @return boolean|null Success
294
     */
295
    protected function httpReadFirstline()
296
    {
297
        if (($l = $this->readline()) === null) {
298
            return null;
299
        }
300
        $e = explode(' ', $l);
301
        $u = isset($e[1]) ? parse_url($e[1]) : false;
302
        if ($u === false) {
303
            $this->badRequest();
304
            return false;
305
        }
306
        if (!isset($u['path'])) {
307
            $u['path'] = null;
308
        }
309
        if (isset($u['host'])) {
310
            $this->server['HTTP_HOST'] = $u['host'];
311
        }
312
        $srv = &$this->server;
313
        $srv['REQUEST_METHOD'] = $e[0];
314
        $srv['REQUEST_TIME'] = time();
315
        $srv['REQUEST_TIME_FLOAT'] = microtime(true);
316
        $srv['REQUEST_URI'] = $u['path'] . (isset($u['query']) ? '?' . $u['query'] : '');
317
        $srv['DOCUMENT_URI'] = $u['path'];
318
        $srv['PHP_SELF'] = $u['path'];
319
        $srv['QUERY_STRING'] = isset($u['query']) ? $u['query'] : null;
320
        $srv['SCRIPT_NAME'] = $srv['DOCUMENT_URI'] = isset($u['path']) ? $u['path'] : '/';
321
        $srv['SERVER_PROTOCOL'] = isset($e[2]) ? $e[2] : 'HTTP/1.1';
322
        $srv['REMOTE_ADDR'] = $this->addr;
323
        $srv['REMOTE_PORT'] = $this->port;
324
        return true;
325
    }
326
327
    /**
328
     * Read headers line-by-line
329
     * @return boolean|null Success
330
     */
331
    protected function httpReadHeaders()
332
    {
333
        while (($l = $this->readLine()) !== null) {
334
            if ($l === '') {
335
                return true;
336
            }
337
            $e = explode(': ', $l);
338
            if (isset($e[1])) {
339
                $this->currentHeader = 'HTTP_' . strtoupper(strtr($e[0], Generic::$htr));
340
                $this->server[$this->currentHeader] = $e[1];
341 View Code Duplication
            } elseif (($e[0][0] === "\t" || $e[0][0] === "\x20") && $this->currentHeader) {
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...
342
                // multiline header continued
343
                $this->server[$this->currentHeader] .= $e[0];
344
            } else {
345
                // whatever client speaks is not HTTP anymore
346
                $this->badRequest();
347
                return false;
348
            }
349
        }
350
        return null;
351
    }
352
353
    /**
354
     * Called when new data received.
355
     * @return void
356
     */
357
    protected function onRead()
358
    {
359 View Code Duplication
        if (!$this->policyReqNotFound) {
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...
360
            $d = $this->drainIfMatch("<policy-file-request/>\x00");
361
            if ($d === null) { // partially match
362
                return;
363
            }
364
            if ($d) {
365
                if (($FP = \PHPDaemon\Servers\FlashPolicy\Pool::getInstance($this->pool->config->fpsname->value,
366
                        false)) && $FP->policyData
367
                ) {
368
                    $this->write($FP->policyData . "\x00");
369
                }
370
                $this->finish();
371
                return;
372
            } else {
373
                $this->policyReqNotFound = true;
374
            }
375
        }
376
        start:
377
        if ($this->finished) {
378
            return;
379
        }
380
        if ($this->state === self::STATE_STANDBY) {
381
            $this->state = self::STATE_FIRSTLINE;
382
        }
383
        if ($this->state === self::STATE_FIRSTLINE) {
384
            if (!$this->httpReadFirstline()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->httpReadFirstline() of type null|boolean is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
385
                return;
386
            }
387
            $this->state = self::STATE_HEADERS;
388
        }
389
390 View Code Duplication
        if ($this->state === self::STATE_HEADERS) {
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...
391
            if (!$this->httpReadHeaders()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->httpReadHeaders() of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
392
                return;
393
            }
394
            if (!$this->httpProcessHeaders()) {
395
                $this->finish();
396
                return;
397
            }
398
            $this->state = self::STATE_CONTENT;
399
        }
400
        if ($this->state === self::STATE_CONTENT) {
401
            $this->state = self::STATE_PREHANDSHAKE;
402
        }
403
    }
404
405
    /**
406
     * Process headers
407
     * @return bool
408
     */
409
    protected function httpProcessHeaders()
410
    {
411
        $this->state = self::STATE_PREHANDSHAKE;
412
        if (isset($this->server['HTTP_SEC_WEBSOCKET_EXTENSIONS'])) {
413
            $str = strtolower($this->server['HTTP_SEC_WEBSOCKET_EXTENSIONS']);
414
            $str = preg_replace($this->extensionsCleanRegex, '', $str);
415
            $this->extensions = explode(', ', $str);
416
        }
417
        if (!isset($this->server['HTTP_CONNECTION'])
418
            || (!preg_match('~(?:^|\W)Upgrade(?:\W|$)~i',
419
                $this->server['HTTP_CONNECTION'])) // "Upgrade" is not always alone (ie. "Connection: Keep-alive, Upgrade")
420
            || !isset($this->server['HTTP_UPGRADE'])
421
            || (strtolower($this->server['HTTP_UPGRADE']) !== 'websocket') // Lowercase comparison iss important
422
        ) {
423
            $this->finish();
424
            return false;
425
        }
426 View Code Duplication
        if (isset($this->server['HTTP_COOKIE'])) {
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...
427
            Generic::parseStr(strtr($this->server['HTTP_COOKIE'], Generic::$hvaltr), $this->cookie);
428
        }
429
        if (isset($this->server['QUERY_STRING'])) {
430
            Generic::parseStr($this->server['QUERY_STRING'], $this->get);
431
        }
432
        // ----------------------------------------------------------
433
        // Protocol discovery, based on HTTP headers...
434
        // ----------------------------------------------------------
435
        if (isset($this->server['HTTP_SEC_WEBSOCKET_VERSION'])) { // HYBI
436
            if ($this->server['HTTP_SEC_WEBSOCKET_VERSION'] === '8') { // Version 8 (FF7, Chrome14)
437
                $this->switchToProtocol('V13');
438
            } elseif ($this->server['HTTP_SEC_WEBSOCKET_VERSION'] === '13') { // newest protocol
439
                $this->switchToProtocol('V13');
440
            } else {
441
                Daemon::$process->log(get_class($this) . '::' . __METHOD__ . " : Websocket protocol version " . $this->server['HTTP_SEC_WEBSOCKET_VERSION'] . ' is not yet supported for client "' . $this->addr . '"');
442
                $this->finish();
443
                return false;
444
            }
445 View Code Duplication
        } elseif (!isset($this->server['HTTP_SEC_WEBSOCKET_KEY1']) || !isset($this->server['HTTP_SEC_WEBSOCKET_KEY2'])) {
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...
446
            $this->switchToProtocol('VE');
447
        } else { // Defaulting to HIXIE (Safari5 and many non-browser clients...)
448
            $this->switchToProtocol('V0');
449
        }
450
        // ----------------------------------------------------------
451
        // End of protocol discovery
452
        // ----------------------------------------------------------
453
        return true;
454
    }
455
456
    protected function switchToProtocol($proto)
457
    {
458
        $class = '\\PHPDaemon\\Servers\\WebSocket\\Protocols\\' . $proto;
459
        $conn = new $class(null, $this->pool);
460
        $this->pool->attach($conn);
461
        $conn->setFd($this->getFd(), $this->getBev());
462
        $this->unsetFd();
463
        $this->pool->detach($this);
464
        $conn->onInheritance($this);
465
    }
466
467 View Code Duplication
    public function onInheritance($conn)
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...
468
    {
469
        $this->server = $conn->server;
470
        $this->cookie = $conn->cookie;
471
        $this->get = $conn->get;
472
        $this->state = self::STATE_PREHANDSHAKE;
473
        $this->addr = $conn->addr;
474
        $this->onRead();
475
    }
476
477
478
    /**
479
     * Send HTTP-status
480
     * @throws RequestHeadersAlreadySent
481
     * @param  integer $code Code
482
     * @return boolean       Success
483
     */
484
    public function status($code = 200)
0 ignored issues
show
The parameter $code is not used and could be removed.

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

Loading history...
485
    {
486
        return false;
487
    }
488
489
    /**
490
     * Send the header
491
     * @param  string $s Header. Example: 'Location: http://php.net/'
492
     * @param  boolean $replace Optional. Replace?
493
     * @param  boolean $code Optional. HTTP response code
494
     * @throws \PHPDaemon\Request\RequestHeadersAlreadySent
495
     * @return boolean          Success
496
     */
497 View Code Duplication
    public function header($s, $replace = true, $code = false)
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...
498
    {
499
        if ($code) {
500
            $this->status($code);
0 ignored issues
show
$code is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
The call to the method PHPDaemon\Servers\WebSocket\Connection::status() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
501
        }
502
503
        if ($this->headers_sent) {
504
            throw new RequestHeadersAlreadySent;
505
        }
506
        $s = strtr($s, "\r\n", '  ');
507
508
        $e = explode(':', $s, 2);
509
510
        if (!isset($e[1])) {
511
            $e[0] = 'STATUS';
512
513
            if (strncmp($s, 'HTTP/', 5) === 0) {
514
                $s = substr($s, 9);
515
            }
516
        }
517
518
        $k = strtr(strtoupper($e[0]), Generic::$htr);
519
520
        if ($k === 'CONTENT_TYPE') {
521
            Generic::parseStr(strtolower($e[1]), $ctype, true);
522
            if (!isset($ctype['charset'])) {
523
                $ctype['charset'] = $this->upstream->pool->config->defaultcharset->value;
0 ignored issues
show
The property upstream does not exist on object<PHPDaemon\Servers\WebSocket\Connection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
524
525
                $s = $e[0] . ': ';
526
                $i = 0;
527
                foreach ($ctype as $k => $v) {
528
                    $s .= ($i > 0 ? '; ' : '') . $k . ($v !== '' ? '=' . $v : '');
529
                    ++$i;
530
                }
531
            }
532
        }
533
        if ($k === 'SET_COOKIE') {
534
            $k .= '_' . ++$this->cookieNum;
535
        } elseif (!$replace && isset($this->headers[$k])) {
536
            return false;
537
        }
538
539
        $this->headers[$k] = $s;
540
541
        if ($k === 'CONTENT_LENGTH') {
542
            $this->contentLength = (int)$e[1];
543
        } elseif ($k === 'LOCATION') {
544
            $this->status(301);
0 ignored issues
show
The call to the method PHPDaemon\Servers\WebSocket\Connection::status() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
545
        }
546
547
        if (Daemon::$compatMode) {
548
            is_callable('header_native') ? header_native($s) : header($s);
549
        }
550
551
        return true;
552
    }
553
}
554