Completed
Push — master ( c74b38...1d4d8f )
by Vasily
09:45 queued 04:17
created

Connection::onReady()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 24
nop 0
dl 0
loc 26
rs 8.8817
c 0
b 0
f 0
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
        $l = $this->getInputLength();
427
        if ($l < 5) {
428
            return; // Not enough data buffered yet
429
        }
430
        $type = $this->look(1);
431
432
        list(, $length) = unpack('N', $this->look(4, 1));
433
434
        $length -= 4;
435
436
        if ($l < $length + 5) {
437
            // Not enough data buffered yet
438
            return;
439
        }
440
441
        $this->drain(5);
442
443
        $packet = $this->read($length);
444
445
        if ($type === 'R') {
446
            // Authentication request
447
            list(, $authType) = unpack('N', $packet);
448
449
            if ($authType === 0) {
450
                // Successful
451
                if ($this->pool->config->protologging->value) {
452
                    Daemon::log(self::class . ': auth. ok.');
453
                }
454
455
                $this->state = self::STATE_AUTH_OK;
456
457
                $this->connected = true;
458
                $this->onConnected->executeAll($this, true);
459
                if ($this->connected && !$this->busy) {
460
                    $this->pool->markConnFree($this, $this->url);
461
                }
462
            } // @todo move to constant values
463 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...
464
                // KerberosV5
465
                Daemon::log(self::class . ': Unsupported authentication method: KerberosV5.');
466
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
467
                $this->finish(); // Unsupported,  finish
468
            } elseif ($authType === 3) {
469
                // Cleartext
470
                $this->sendPacket('p', $this->password); // Password Message
471
                $this->state = self::STATE_AUTH_PACKET_SENT;
472
            } elseif ($authType === 4) {
473
                // Crypt
474
                $salt = mb_orig_substr($packet, 4, 2);
475
                $this->sendPacket('p', crypt($this->password, $salt)); // Password Message
476
                $this->state = self::STATE_AUTH_PACKET_SENT;
477
            } elseif ($authType === 5) {
478
                // MD5
479
                $salt = mb_orig_substr($packet, 4, 4);
480
                $this->sendPacket('p', 'md5' . md5(md5($this->password . $this->user) . $salt)); // Password Message
481
                $this->state = self::STATE_AUTH_PACKET_SENT;
482 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...
483
                // SCM
484
                Daemon::log(self::class . ': Unsupported authentication method: SCM.');
485
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
486
                $this->finish(); // Unsupported,  finish
487
            } elseif ($authType === 9) {
488
                // GSS
489
                Daemon::log(self::class . ': Unsupported authentication method: GSS.');
490
                $this->state = self::STATE_AUTH_ERROR; // Auth. error
491
                $this->finish(); // Unsupported,  finish
492
            }
493
        } elseif ($type === 'T') {
494
            // Row Description
495
            list(, $numfields) = unpack('n', mb_orig_substr($packet, 0, 2));
496
            $p = 2;
497
498
            for ($i = 0; $i < $numfields; ++$i) {
499
                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...
500
                $field = unpack('NtableOID/nattrNo/NdataType/ndataTypeSize/NtypeMod/nformat',
501
                    mb_orig_substr($packet, $p, 18));
502
                $p += 18;
503
                $field['name'] = $name;
504
                $this->resultFields[] = $field;
505
            }
506
        } elseif ($type === 'D') {
507
            // Data Row
508
            list(, $numfields) = unpack('n', mb_orig_substr($packet, 0, 2));
509
            $p = 2;
510
            $row = [];
511
512
            for ($i = 0; $i < $numfields; ++$i) {
513
                list(, $length) = unpack('N', mb_orig_substr($packet, $p, 4));
514
                $p += 4;
515
516
                if ($length === 0xffffffff) {
517
                    // hack
518
                    $length = -1;
519
                }
520
521
                if ($length === -1) {
522
                    $value = null;
523
                } else {
524
                    $value = mb_orig_substr($packet, $p, $length);
525
                    $p += $length;
526
                }
527
528
                $row[$this->resultFields[$i]['name']] = $value;
529
            }
530
531
            $this->resultRows[] = $row;
532
        } elseif ($type === 'G' || $type === 'H') {
533
            // Copy in response
534
            // The backend is ready to copy data from the frontend to a table; see Section 45.2.5.
535
            if ($this->pool->config->protologging->value) {
536
                Daemon::log(self::class . ': Caught CopyInResponse');
537
            }
538
        } elseif ($type === 'C') {
539
            // Close command
540
            $type = mb_orig_substr($packet, 0, 1);
541
542
            if ($type === 'S' || $type === 'P') {
543
                list($name) = $this->decodeNULstrings(mb_orig_substr($packet, 1));
544
            } else {
545
                $tag = $this->decodeNULstrings($packet);
0 ignored issues
show
Security Bug introduced by
It seems like $packet defined by $this->read($length) on line 443 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...
546
                $tag = explode(' ', $tag[0]);
547
548
                if ($tag[0] === 'INSERT') {
549
                    $this->insertId = $tag[1];
550
                    $this->insertNum = (int) $tag[2];
551
                    $this->affectedRows = (int) $tag[2];
552
                } elseif ($tag[0] === 'DELETE' || $tag[0] === 'UPDATE' || $tag[0] === 'MOVE'
553
                    || $tag[0] === 'FETCH' || $tag[0] === 'COPY'
554
                ) {
555
                    $this->affectedRows = (int) $tag[1];
556
                }
557
            }
558
559
            $this->onResultDone();
560
        } elseif ($type === 'n') {
561
            // No Data
562
            $this->onResultDone();
563
        } elseif ($type === 'E') {
564
            // Error Response
565
            $code = ord($packet);
566
            $message = '';
567
568
            foreach ($this->decodeNULstrings(mb_orig_substr($packet, 1), 0xFF) as $p) {
569
                if ($message !== '') {
570
                    $message .= ' ';
571
                    $p = mb_orig_substr($p, 1);
572
                }
573
574
                $message .= $p;
575
            }
576
577
            $this->errno = -1;
578
            $this->errmsg = $message;
579
580
            if ($this->state === self::STATE_AUTH_PACKET_SENT) {
581
                // Auth. error
582
                $this->onConnected->executeAll($this, false);
583
                $this->state = self::STATE_AUTH_ERROR;
584
                $this->finish();
585
            }
586
587
            $this->onError();
588
589
            if ($this->pool->config->protologging->value) {
590
                Daemon::log(self::class . ': Error response caught (0x' . dechex($code) . '): ' . $message);
591
            }
592
        } elseif ($type === 'I') {
593
            // Empty Query Response
594
            $this->errno = -1;
595
            $this->errmsg = 'Query was empty';
596
            $this->onError();
597
        } elseif ($type === 'S') {
598
            // Portal Suspended
599
            if ($this->pool->config->protologging->value) {
600
                Daemon::log(self::class . ': Caught PortalSuspended');
601
            }
602
        } elseif ($type === 'S') {
603
            // Parameter Status
604
            $u = $this->decodeNULstrings($packet, 2);
0 ignored issues
show
Security Bug introduced by
It seems like $packet defined by $this->read($length) on line 443 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...
605
606
            if (isset($u[0])) {
607
                $this->parameters[$u[0]] = isset($u[1]) ? $u[1] : null;
608
609
                if ($this->pool->config->protologging->value) {
610
                    Daemon::log(self::class . ': Parameter ' . $u[0] . ' = \'' . $this->parameters[$u[0]] . '\'');
611
                }
612
            }
613
        } elseif ($type === 'K') {
614
            // Backend Key Data
615
            list(, $this->backendKey) = unpack('N', $packet);
616
            $this->backendKey = isset($u[1]) ? $u[1] : null;
617
618
            if ($this->pool->config->protologging->value) {
619
                Daemon::log(self::class . ': BackendKey is ' . $this->backendKey);
620
            }
621
        } elseif ($type === 'Z') {
622
            // Ready For Query
623
            $this->status = $packet;
624
625
            if ($this->pool->config->protologging->value) {
626
                Daemon::log(self::class . ': Ready For Query. Status: ' . $this->status);
627
            }
628
        } else {
629
            Daemon::log(self::class . ': Caught message with unsupported type - ' . $type);
630
        }
631
632
        goto start;
633
634
    }
635
636
    /**
637
     * Decode strings from the NUL-terminated representation
638
     * @param  string $data Binary data
639
     * @param  integer $limit Optional. Limit of count. Default is 1.
640
     * @param  reference &$p Optional. Pointer.
641
     * @return array            Decoded strings
642
     */
643
    public function decodeNULstrings($data, $limit = 1, &$p = 0)
644
    {
645
        $r = [];
646
647
        for ($i = 0; $i < $limit; ++$i) {
648
            $pos = mb_orig_strpos($data, "\x00", $p);
649
650
            if ($pos === false) {
651
                break;
652
            }
653
654
            $r[] = mb_orig_substr($data, $p, $pos - $p);
655
656
            $p = $pos + 1;
657
        }
658
659
        return $r;
660
    }
661
662
    /**
663
     * Called when the whole result received
664
     * @return void
665
     */
666
    public function onResultDone()
667
    {
668
        $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...
669
        $this->onResponse->executeOne($this, true);
670
        $this->resultRows = [];
671
        $this->resultFields = [];
672
        $this->checkFree();
673
674
        if ($this->pool->config->protologging->value) {
675
            Daemon::log(__METHOD__);
676
        }
677
    }
678
679
    /**
680
     * Called when error occured
681
     * @return void
682
     */
683
    public function onError()
684
    {
685
        $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...
686
        $this->onResponse->executeOne($this, false);
687
        $this->resultRows = [];
688
        $this->resultFields = [];
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
        }
695
696
        $this->checkFree();
697
698
        Daemon::log(__METHOD__ . ' #' . $this->errno . ': ' . $this->errmsg);
699
    }
700
}
701