Connection::onRead()   F
last analyzed

Complexity

Conditions 51
Paths 0

Size

Total Lines 210

Duplication

Lines 12
Ratio 5.71 %

Importance

Changes 0
Metric Value
cc 51
nc 0
nop 0
dl 12
loc 210
rs 3.3333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PHPDaemon\Clients\PostgreSQL;
4
5
use PHPDaemon\Core\Daemon;
6
use PHPDaemon\Core\Debug;
7
use PHPDaemon\Network\ClientConnection;
8
use PHPDaemon\Structures\StackCallbacks;
9
10
class Connection extends ClientConnection
11
{
12
13
    /**
14
     * @var string Protocol version
15
     */
16
    public $protover = '3.0';
17
18
    /**
19
     * @var integer Maximum packet size
20
     */
21
    public $maxPacketSize = 0x1000000;
22
23
    /**
24
     * @var integer Charset number
25
     */
26
    public $charsetNumber = 0x08;
27
28
    /**
29
     * @var string Database name
30
     */
31
    public $dbname = '';
32
33
    /**
34
     * @var string Username
35
     */
36
    protected $user = 'root';
37
38
    /**
39
     * @var string Password
40
     */
41
    protected $password = '';
42
43
    /**
44
     * @var string Default options
45
     */
46
    public $options = '';
47
48
    /**
49
     * @var integer Connection's state. 0 - start,  1 - got initial packet,  2 - auth. packet sent,  3 - auth. error,  4 - handshaked OK
50
     */
51
    public $state = 0;
52
53
    /**
54
     * @var string State of pointer of incoming data. 0 - Result Set Header Packet,  1 - Field Packet,  2 - Row Packet
55
     */
56
    public $instate = 0;
57
58
    /**
59
     * @var array Resulting rows
60
     */
61
    public $resultRows = [];
62
63
    /**
64
     * @var array Resulting fields
65
     */
66
    public $resultFields = [];
67
68
    /**
69
     * @var string Equals to INSERT_ID().
70
     */
71
    public $insertId;
72
73
    /**
74
     * @var integer Inserted rows number
75
     */
76
    public $insertNum;
77
78
    /**
79
     * @var integer Number of affected rows
80
     */
81
    public $affectedRows;
82
83
    /**
84
     * @var array Runtime parameters from server
85
     */
86
    public $parameters = [];
87
88
    /**
89
     * @var string Backend key
90
     */
91
    public $backendKey;
92
93
    /**
94
     * @var int
95
     */
96
    public $errno = 0;
97
98
    /**
99
     * @var string
100
     */
101
    public $errmsg;
102
103
    /**
104
     * @var
105
     */
106
    public $status;
107
108
    /**
109
     * State: authentication packet sent
110
     */
111
    const STATE_AUTH_PACKET_SENT = 2;
112
113
    /**
114
     * State: authencation error
115
     */
116
    const STATE_AUTH_ERROR = 3;
117
118
    /**
119
     * State: authentication passed
120
     */
121
    const STATE_AUTH_OK = 4;
122
123
    /**
124
     * Called when the stream is handshaked (at low-level), and peer is ready to recv. data
125
     * @return void
126
     */
127
    public function onReady()
128
    {
129
        if ($this->pool->config->protologging->value) {
130
            Daemon::log("New connection\n\n");
131
        }
132
        $e = explode('.', $this->protover);
133
        $packet = pack('nn', $e[0], $e[1]);
134
135
        if (strlen($this->user)) {
136
            $packet .= "user\x00" . $this->user . "\x00";
137
        }
138
139
        if (strlen($this->dbname)) {
140
            $packet .= "database\x00" . $this->dbname . "\x00";
141
        }
142
        elseif (strlen($this->path)) {
143
            $packet .= "database\x00" . $this->path . "\x00";
144
        }
145
146
        if (strlen($this->options)) {
147
            $packet .= "options\x00" . $this->options . "\x00";
148
        }
149
150
        $packet .= "\x00";
151
        $this->sendPacket('', $packet);
152
    }
153
154
    /**
155
     * Executes the given callback when/if the connection is handshaked.
156
     * @param  callable $cb Callback
157
     * @callback $cb ( )
158
     * @return void
159
     */
160 View Code Duplication
    public function onConnected($cb)
0 ignored issues
show
Duplication introduced by
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...
161
    {
162
        if ($this->state === self::STATE_AUTH_ERROR) {
163
            $cb($this, false);
164
        } elseif ($this->state === self::STATE_AUTH_OK) {
165
            $cb($this, true);
166
        } else {
167
            if (!$this->onConnected) {
168
                $this->onConnected = new StackCallbacks();
169
            }
170
            $this->onConnected->push($cb);
171
        }
172
    }
173
174
    /**
175
     * Converts binary string to integer
176
     * @param  string $str Binary string
177
     * @param  boolean $l Optional. Little endian. Default value - true.
178
     * @return integer      Resulting integer
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
179
     */
180 View Code Duplication
    public function bytes2int($str, $l = true)
0 ignored issues
show
Duplication introduced by
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...
181
    {
182
        if ($l) {
183
            $str = strrev($str);
184
        }
185
186
        $dec = 0;
187
        $len = mb_orig_strlen($str);
188
189
        for ($i = 0; $i < $len; ++$i) {
190
            $dec += ord(mb_orig_substr($str, $i, 1)) * pow(0x100, $len - $i - 1);
191
        }
192
193
        return $dec;
194
    }
195
196
    /**
197
     * Converts integer to binary string
198
     * @param  integer $len Length
199
     * @param  integer $int Integer
200
     * @param  boolean $l Optional. Little endian. Default value - true.
201
     * @return string       Resulting binary string
202
     */
203 View Code Duplication
    public function int2bytes($len, $int = 0, $l = true)
0 ignored issues
show
Duplication introduced by
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...
204
    {
205
        $hexstr = dechex($int);
206
207
        if ($len === null) {
208
            if (mb_orig_strlen($hexstr) % 2) {
209
                $hexstr = "0" . $hexstr;
210
            }
211
        } else {
212
            $hexstr = str_repeat('0', $len * 2 - mb_orig_strlen($hexstr)) . $hexstr;
213
        }
214
215
        $bytes = mb_orig_strlen($hexstr) / 2;
216
        $bin = '';
217
218
        for ($i = 0; $i < $bytes; ++$i) {
219
            $bin .= chr(hexdec(substr($hexstr, $i * 2, 2)));
220
        }
221
222
        return $l ? strrev($bin) : $bin;
223
    }
224
225
    /**
226
     * Send a packet
227
     * @param  string $type Data
228
     * @param  string $packet Packet
229
     * @return boolean         Success
230
     */
231
    public function sendPacket($type, $packet)
232
    {
233
        $header = $type . pack('N', mb_orig_strlen($packet) + 4);
234
235
        $this->write($header);
236
        $this->write($packet);
237
238
        if ($this->pool->config->protologging->value) {
239
            Daemon::log('Client --> Server: ' . Debug::exportBytes($header . $packet) . "\n\n");
240
        }
241
242
        return true;
243
    }
244
245
    /**
246
     * Builds length-encoded binary string
247
     * @param  string $s String
248
     * @return string    Resulting binary string
249
     */
250
    public function buildLenEncodedBinary($s)
251
    {
252
        if ($s === null) {
253
            return "\251";
254
        }
255
256
        $l = mb_orig_strlen($s);
257
258
        if ($l <= 250) {
259
            return chr($l) . $s;
260
        }
261
262
        if ($l <= 0xFFFF) {
263
            return "\252" . $this->int2bytes(2, $l) . $s;
264
        }
265
266
        if ($l <= 0xFFFFFF) {
267
            return "\254" . $this->int2bytes(3, $l) . $s;
268
        }
269
270
        return $this->int2bytes(8, $l) . $s;
271
    }
272
273
    /**
274
     * Parses length-encoded binary
275
     * @param  string &$s Reference to source string
276
     * @param  integer &$p
277
     * @return integer     Result
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|null|false|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
278
     */
279
    public function parseEncodedBinary(&$s, &$p)
280
    {
281
        $f = ord(mb_orig_substr($s, $p, 1));
282
        ++$p;
283
284
        if ($f <= 250) {
285
            return $f;
286
        }
287
288
        if ($s === 251) {
289
            return null;
290
        }
291
292
        if ($s === 255) {
293
            return false;
294
        }
295
296 View Code Duplication
        if ($f === 252) {
0 ignored issues
show
Duplication introduced by
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...
297
            $o = $p;
298
            $p += 2;
299
300
            return $this->bytes2int(mb_orig_substr($s, $o, 2));
301
        }
302
303 View Code Duplication
        if ($f === 253) {
0 ignored issues
show
Duplication introduced by
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...
304
            $o = $p;
305
            $p += 3;
306
307
            return $this->bytes2int(mb_orig_substr($s, $o, 3));
308
        }
309
310
        $o = $p;
311
        $p = +8;
312
313
        return $this->bytes2int(mb_orig_substr($s, $o, 8));
314
    }
315
316
    /**
317
     * Parse length-encoded string
318
     * @param  string &$s Reference to source string
319
     * @param  integer &$p Reference to pointer
320
     * @return integer     Result
0 ignored issues
show
Documentation introduced by
Should the return type not be null|false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
321
     */
322
    public function parseEncodedString(&$s, &$p)
323
    {
324
        $l = $this->parseEncodedBinary($s, $p);
325
326
        if ($l === null || $l === false) {
327
            return $l;
328
        }
329
330
        $o = $p;
331
        $p += $l;
332
333
        return mb_orig_substr($s, $o, $l);
334
    }
335
336
    /**
337
     * Send SQL-query
338
     * @param  string $q Query
339
     * @param  callable $callback Optional. Callback called when response received.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $callback 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...
340
     * @callback $callback ( )
341
     * @return boolean            Success
342
     */
343
    public function query($q, $callback = null)
344
    {
345
        return $this->command('Q', $q . "\x00", $callback);
346
    }
347
348
    /**
349
     * Send echo-request
350
     * @param  callable $callback Optional. Callback called when response received
0 ignored issues
show
Documentation introduced by
Should the type for parameter $callback 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...
351
     * @callback $callback ( )
352
     * @return boolean Success
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
353
     */
354
    public function ping($callback = null)
0 ignored issues
show
Unused Code introduced by
The parameter $callback 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...
355
    {
356
        // @todo There is no command for echo-request.
357
        //return $this->command(, '', $callback);
358
    }
359
360
    /**
361
     * Sends sync-request
362
     * @param  callable $cb Optional. Callback called when response received.
0 ignored issues
show
Documentation introduced by
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...
363
     * @callback $cb ( )
364
     * @return boolean Success
365
     */
366
    public function sync($cb = null)
367
    {
368
        return $this->command('S', '', $cb);
369
    }
370
371
    /**
372
     * Send terminate-request to shutdown the connection
373
     * @param  callable $cb Optional. Callback called when response received.
0 ignored issues
show
Documentation introduced by
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...
374
     * @callback $cb ( )
375
     * @return boolean Success
376
     */
377
    public function terminate($cb = null)
378
    {
379
        return $this->command('X', '', $cb);
380
    }
381
382
    /**
383
     * Sends arbitrary command
384
     * @param  integer $cmd Command's code. See constants above.
385
     * @param  string $q Data
386
     * @param  callable $cb Optional. Callback called when response received.
0 ignored issues
show
Documentation introduced by
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...
387
     * @callback $cb ( )
388
     * @return boolean Success
389
     */
390 View Code Duplication
    public function command($cmd, $q = '', $cb = null)
0 ignored issues
show
Duplication introduced by
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...
391
    {
392
        if ($this->state !== self::STATE_AUTH_OK) {
393
            return false;
394
        }
395
396
        $this->sendPacket($cmd, $q);
397
398
        $this->onResponse->push($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by parameter $cb on line 390 can also be of type null; however, PHPDaemon\Structures\StackCallbacks::push() does only seem to accept callable, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
399
        $this->checkFree();
400
401
        return true;
402
    }
403
404
    /**
405
     * Set default database name
406
     * @param  string $name Database name
407
     * @return boolean       Success
408
     */
409
    public function selectDB($name)
410
    {
411
        $this->dbname = $name;
412
413
        if ($this->state !== 1) {
414
            return $this->query('USE `' . $name . '`');
415
        }
416
417
        return true;
418
    }
419
420
    /**
421
     *
422
     */
423
    public function onRead()
424
    {
425
        start:
426
        if ($this->finished) {
427
            return;
428
        }
429
        $l = $this->getInputLength();
430
        if ($l < 5) {
431
            return; // Not enough data buffered yet
432
        }
433
        $type = $this->look(1);
434
435
        list(, $length) = unpack('N', $this->look(4, 1));
436
437
        $length -= 4;
438
439
        if ($l < $length + 5) {
440
            // Not enough data buffered yet
441
            return;
442
        }
443
444
        $this->drain(5);
445
446
        $packet = $this->read($length);
447
448
        if ($type === 'R') {
449
            // Authentication request
450
            list(, $authType) = unpack('N', $packet);
451
            if ($this->pool->config->protologging->value) {
452
                Daemon::log('auth type = ' . $authType);
453
            }
454
            if ($authType === 0) {
455
                // Successful
456
                if ($this->pool->config->protologging->value) {
457
                    Daemon::log(self::class . ': auth. ok.');
458
                }
459
460
                $this->state = self::STATE_AUTH_OK;
461
462
                $this->connected = true;
463
                $this->onConnected->executeAll($this, true);
464
                if ($this->connected && !$this->busy) {
465
                    $this->pool->markConnFree($this, $this->url);
466
                }
467
            } // @todo move to constant values
468 View Code Duplication
            elseif ($authType === 2) {
0 ignored issues
show
Duplication introduced by
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...
469
                // KerberosV5
470
                Daemon::log(self::class . ': Unsupported authentication method: KerberosV5.');
471
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
472
                $this->finish(); // Unsupported,  finish
473
            } elseif ($authType === 3) {
474
                // Cleartext
475
                $this->sendPacket('p', $this->password); // Password Message
476
                $this->state = self::STATE_AUTH_PACKET_SENT;
477
            } elseif ($authType === 4) {
478
                // Crypt
479
                $salt = mb_orig_substr($packet, 4, 2);
480
                $this->sendPacket('p', crypt($this->password, $salt)  . "\x00"); // Password Message
481
                $this->state = self::STATE_AUTH_PACKET_SENT;
482
            } elseif ($authType === 5) {
483
                // MD5
484
                $salt = mb_orig_substr($packet, 4, 4);
485
                $this->sendPacket('p', 'md5' . md5(md5($this->password . $this->user) . $salt) . "\x00"); // Password Message
486
                $this->state = self::STATE_AUTH_PACKET_SENT;
487 View Code Duplication
            } elseif ($authType === 6) {
0 ignored issues
show
Duplication introduced by
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...
488
                // SCM
489
                Daemon::log(self::class . ': Unsupported authentication method: SCM.');
490
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
491
                $this->finish(); // Unsupported,  finish
492
            } elseif ($authType === 9) {
493
                // GSS
494
                Daemon::log(self::class . ': Unsupported authentication method: GSS.');
495
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
496
                $this->finish(); // Unsupported,  finish
497
            }
498
        } elseif ($type === 'T') {
499
            // Row Description
500
            list(, $numfields) = unpack('n', mb_orig_substr($packet, 0, 2));
501
            $p = 2;
502
503
            for ($i = 0; $i < $numfields; ++$i) {
504
                list($name) = $this->decodeNULstrings($packet, 1, $p);
0 ignored issues
show
Security Bug introduced by
It seems like $packet can also be of type false; however, PHPDaemon\Clients\Postgr...ion::decodeNULstrings() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
505
                $field = unpack('NtableOID/nattrNo/NdataType/ndataTypeSize/NtypeMod/nformat',
506
                    mb_orig_substr($packet, $p, 18));
507
                $p += 18;
508
                $field['name'] = $name;
509
                $this->resultFields[] = $field;
510
            }
511
        } elseif ($type === 'D') {
512
            // Data Row
513
            list(, $numfields) = unpack('n', mb_orig_substr($packet, 0, 2));
514
            $p = 2;
515
            $row = [];
516
517
            for ($i = 0; $i < $numfields; ++$i) {
518
                list(, $length) = unpack('N', mb_orig_substr($packet, $p, 4));
519
                $p += 4;
520
521
                if ($length === 0xffffffff) {
522
                    // hack
523
                    $length = -1;
524
                }
525
526
                if ($length === -1) {
527
                    $value = null;
528
                } else {
529
                    $value = mb_orig_substr($packet, $p, $length);
530
                    $p += $length;
531
                }
532
533
                $row[$this->resultFields[$i]['name']] = $value;
534
            }
535
536
            $this->resultRows[] = $row;
537
        } elseif ($type === 'G' || $type === 'H') {
538
            // Copy in response
539
            // The backend is ready to copy data from the frontend to a table; see Section 45.2.5.
540
            if ($this->pool->config->protologging->value) {
541
                Daemon::log(self::class . ': Caught CopyInResponse');
542
            }
543
        } elseif ($type === 'C') {
544
            // Close command
545
            $type = mb_orig_substr($packet, 0, 1);
546
547
            if ($type === 'S' || $type === 'P') {
548
                list($name) = $this->decodeNULstrings(mb_orig_substr($packet, 1));
549
            } else {
550
                $tag = $this->decodeNULstrings($packet);
0 ignored issues
show
Security Bug introduced by
It seems like $packet defined by $this->read($length) on line 446 can also be of type false; however, PHPDaemon\Clients\Postgr...ion::decodeNULstrings() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
551
                $tag = explode(' ', $tag[0]);
552
553
                if ($tag[0] === 'INSERT') {
554
                    $this->insertId = $tag[1];
555
                    $this->insertNum = (int) $tag[2];
556
                    $this->affectedRows = (int) $tag[2];
557
                } elseif ($tag[0] === 'DELETE' || $tag[0] === 'UPDATE' || $tag[0] === 'MOVE'
558
                    || $tag[0] === 'FETCH' || $tag[0] === 'COPY'
559
                ) {
560
                    $this->affectedRows = (int) $tag[1];
561
                }
562
            }
563
564
            $this->onResultDone();
565
        } elseif ($type === 'n') {
566
            // No Data
567
            $this->onResultDone();
568
        } elseif ($type === 'E') {
569
            // Error Response
570
            $code = ord($packet);
571
            $message = '';
572
573
            foreach ($this->decodeNULstrings(mb_orig_substr($packet, 1), 0xFF) as $p) {
574
                if ($message !== '') {
575
                    $message .= ' ';
576
                    $p = mb_orig_substr($p, 1);
577
                }
578
579
                $message .= $p;
580
            }
581
582
            $this->errno = -1;
583
            $this->errmsg = $message;
584
585
            $this->onError();
586
587
            if ($this->pool->config->protologging->value) {
588
                Daemon::log(self::class . ': Error response caught (0x' . dechex($code) . '): ' . $message);
589
            }
590
        } elseif ($type === 'I') {
591
            // Empty Query Response
592
            $this->errno = -1;
593
            $this->errmsg = 'Query was empty';
594
            $this->onError();
595
        } elseif ($type === 'S') {
596
            // Portal Suspended
597
            if ($this->pool->config->protologging->value) {
598
                Daemon::log(self::class . ': Caught PortalSuspended');
599
            }
600
        } elseif ($type === 'S') {
601
            // Parameter Status
602
            $u = $this->decodeNULstrings($packet, 2);
0 ignored issues
show
Security Bug introduced by
It seems like $packet defined by $this->read($length) on line 446 can also be of type false; however, PHPDaemon\Clients\Postgr...ion::decodeNULstrings() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
603
604
            if (isset($u[0])) {
605
                $this->parameters[$u[0]] = isset($u[1]) ? $u[1] : null;
606
607
                if ($this->pool->config->protologging->value) {
608
                    Daemon::log(self::class . ': Parameter ' . $u[0] . ' = \'' . $this->parameters[$u[0]] . '\'');
609
                }
610
            }
611
        } elseif ($type === 'K') {
612
            // Backend Key Data
613
            list(, $this->backendKey) = unpack('N', $packet);
614
            $this->backendKey = isset($u[1]) ? $u[1] : null;
615
616
            if ($this->pool->config->protologging->value) {
617
                Daemon::log(self::class . ': BackendKey is ' . $this->backendKey);
618
            }
619
        } elseif ($type === 'Z') {
620
            // Ready For Query
621
            $this->status = $packet;
622
623
            if ($this->pool->config->protologging->value) {
624
                Daemon::log(self::class . ': Ready For Query. Status: ' . $this->status);
625
            }
626
        } else {
627
            Daemon::log(self::class . ': Caught message with unsupported type - ' . $type);
628
        }
629
630
        goto start;
631
632
    }
633
634
    /**
635
     * Decode strings from the NUL-terminated representation
636
     * @param  string $data Binary data
637
     * @param  integer $limit Optional. Limit of count. Default is 1.
638
     * @param  reference &$p Optional. Pointer.
639
     * @return array            Decoded strings
640
     */
641
    public function decodeNULstrings($data, $limit = 1, &$p = 0)
642
    {
643
        $r = [];
644
645
        for ($i = 0; $i < $limit; ++$i) {
646
            $pos = mb_orig_strpos($data, "\x00", $p);
647
648
            if ($pos === false) {
649
                break;
650
            }
651
652
            $r[] = mb_orig_substr($data, $p, $pos - $p);
653
654
            $p = $pos + 1;
655
        }
656
657
        return $r;
658
    }
659
660
    /**
661
     * Called when the whole result received
662
     * @return void
663
     */
664
    public function onResultDone()
665
    {
666
        $this->instate = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $instate was declared of type string, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
667
        $this->onResponse->executeOne($this, true);
668
        $this->resultRows = [];
669
        $this->resultFields = [];
670
        $this->checkFree();
671
672
        if ($this->pool->config->protologging->value) {
673
            Daemon::log(__METHOD__);
674
        }
675
    }
676
677
    /**
678
     * Called when error occured
679
     * @return void
680
     */
681
    public function onError()
682
    {
683
        $this->instate = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $instate was declared of type string, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
684
        $this->onResponse->executeOne($this, false);
685
        $this->resultRows = [];
686
        $this->resultFields = [];
687
688
        Daemon::log(__METHOD__ . ' #' . $this->errno . ': ' . $this->errmsg);
689
690
        if ($this->state === self::STATE_AUTH_PACKET_SENT) {
691
            // in case of auth error
692
            $this->state = self::STATE_AUTH_ERROR;
693
            $this->finish();
694
        } else {
695
            $this->checkFree();
696
        }
697
    }
698
}
699