Pool::findAndModify()   F
last analyzed

Complexity

Conditions 17
Paths 1728

Size

Total Lines 67

Duplication

Lines 17
Ratio 25.37 %

Importance

Changes 0
Metric Value
cc 17
dl 17
loc 67
rs 1.0499
c 0
b 0
f 0
nc 1728
nop 2

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
namespace PHPDaemon\Clients\Mongo;
3
4
use PHPDaemon\Core\CallbackWrapper;
5
use PHPDaemon\Core\Daemon;
6
use PHPDaemon\Network\Client;
7
8
/**
9
 * @package    Applications
10
 * @subpackage MongoClientAsync
11
 * @author     Vasily Zorin <[email protected]>
12
 */
13
class Pool extends Client
14
{
15
    use \PHPDaemon\Traits\StaticObjectWatchdog;
16
17
    /* Codes of operations */
18
19
    /**
20
     * @TODO DESCR
21
     */
22
    const OP_REPLY = 1;
23
24
    /**
25
     * @TODO DESCR
26
     */
27
    const OP_MSG = 1000;
28
29
    /**
30
     * @TODO DESCR
31
     */
32
    const OP_UPDATE = 2001;
33
34
    /**
35
     * @TODO DESCR
36
     */
37
    const OP_INSERT = 2002;
38
39
    /**
40
     * @TODO DESCR
41
     */
42
    const OP_QUERY = 2004;
43
44
    /**
45
     * @TODO DESCR
46
     */
47
    const OP_GETMORE = 2005;
48
49
    /**
50
     * @TODO DESCR
51
     */
52
    const OP_DELETE = 2006;
53
54
    /**
55
     * @TODO DESCR
56
     */
57
    const OP_KILL_CURSORS = 2007;
58
59
    /**
60
     * @var array Objects of MongoClientAsyncCollection
61
     */
62
    public $collections = [];
63
64
    /**
65
     * @var string Current database
66
     */
67
    public $dbname = '';
68
69
    /**
70
     * @var Connection Holds last used MongoClientAsyncConnection object
71
     */
72
    public $lastRequestConnection;
73
74
    /**
75
     * @var object Object of MemcacheClient
76
     */
77
    public $cache;
78
79
    protected $safeMode = true;
80
81
    /**
82
     * Setting default config options
83
     * Overriden from AppInstance::getConfigDefaults
84
     * @return array|bool
85
     */
86
    protected function getConfigDefaults()
87
    {
88
        return [
89
            /* [string|array] default server list */
90
            'servers' => 'tcp://127.0.0.1',
91
92
            /* [integer] default port */
93
            'port' => 27017,
94
95
            /* [integer] maxconnperserv */
96
            'maxconnperserv' => 32,
97
        ];
98
    }
99
100
    /**
101
     * @TODO
102
     * @param  array $o
103
     * @return void
104
     */
105
    public static function safeModeEnc(&$o)
106
    {
107
        foreach ($o as &$v) {
108
            if (is_array($v)) {
109
                static::safeModeEnc($v);
110
            } elseif ($v instanceof MongoId) {
111
                $v = $v->getPlainObject();
112
            }
113
        }
114
    }
115
116
    /**
117
     * Sets default database name
118
     * @param  string $name Database name
119
     * @return boolean       Success
120
     */
121
    public function selectDB($name)
122
    {
123
        $this->dbname = $name;
124
125
        return true;
126
    }
127
128
    /**
129
     * Generates auth. key
130
     * @param  string $username Username
131
     * @param  string $password Password
132
     * @param  string $nonce Nonce
133
     * @return string           MD5 hash
134
     */
135
    public static function getAuthKey($username, $password, $nonce)
136
    {
137
        return md5($nonce . $username . md5($username . ':mongo:' . $password));
138
    }
139
140
    /**
141
     * Adds mongo server
142
     * @param string $url URL
143
     * @param integer $weight Weight
0 ignored issues
show
Documentation introduced by
Should the type for parameter $weight not be integer|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...
144
     * @param mixed $mock @deprecated
145
     * @return void
146
     */
147
    public function addServer($url, $weight = null, $mock = null)
0 ignored issues
show
Unused Code introduced by
The parameter $mock 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...
148
    {
149
        $this->servers[$url] = $weight;
150
    }
151
152
    /**
153
     * Gets the key
154
     * @param  integer $opcode Opcode (see constants above)
155
     * @param  string $data Data
156
     * @param  boolean $reply Is an answer expected?
157
     * @param  Connection $conn Connection. Optional
0 ignored issues
show
Documentation introduced by
Should the type for parameter $conn not be Connection|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...
158
     * @param  callable $sentcb Sent callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $sentcb 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...
159
     * @callback $sentcb ( )
160
     * @throws ConnectionFinished
161
     * @return void
162
     */
163
    public function request($opcode, $data, $reply = false, $conn = null, $sentcb = null)
164
    {
165
        $cb = $this->requestCbProducer($opcode, $data, $reply, $sentcb);
166
        if (is_object($conn) && ($conn instanceof Connection)) {
167
            if ($conn->isFinished()) {
168
                throw new ConnectionFinished;
169
            }
170
            $cb($conn);
171
        } elseif ($this->finished) {
172
            $cb(false);
173
        } else {
174
            $this->getConnectionRR($cb);
175
        }
176
    }
177
178
    /**
179
     * @TODO DESCR
180
     * @param  integer $opcode Opcode (see constants above)
181
     * @param  string $data Data
182
     * @param  boolean $reply Is an answer expected?
183
     * @param  callable $sentcb Sent callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $sentcb 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...
184
     * @callback $sentcb ( )
185
     * @return callable
186
     */
187
    protected function requestCbProducer($opcode, $data, $reply = false, $sentcb = null)
188
    {
189
        return function ($conn) use ($opcode, $data, $reply, $sentcb) {
190
            if (!$conn || $conn->isFinished()) {
191
                if ($this->finished) {
192
                    if ($sentcb !== null) {
193
                        $sentcb(false);
194
                    }
195
                } else {
196
                    $this->getConnectionRR($this->requestCbProducer($opcode, $data, $reply, $sentcb));
197
                }
198
                return;
199
            }
200
            $reqId = ++$conn->lastReqId;
201
            $this->lastRequestConnection = $conn;
202
            $conn->write(pack('VVVV', mb_orig_strlen($data) + 16, $reqId, 0, $opcode));
203
            $conn->write($data);
204
            if ($reply) {
205
                $conn->setFree(false);
206
            }
207
            if ($sentcb !== null) {
208
                $sentcb($conn, $reqId);
209
            }
210
        };
211
    }
212
213
    /**
214
     * Finds objects in collection and fires callback when got all objects
215
     * @param  array $p Hash of properties (offset, limit, opts, tailable, await, where, col, fields, sort, hint, explain, snapshot, orderby, parse_oplog)
216
     * @param  callable $cb Callback called when response received
217
     * @callback $cb ( )
218
     * @return void
219
     */
220
    public function findAll($p, $cb)
221
    {
222
        $this->find($p, function ($cursor) use ($cb) {
223
            if (!$cursor->isFinished()) {
224
                $cursor->getMore();
225
            } else {
226
                $cb($cursor);
227
            }
228
        });
229
    }
230
231
    /**
232
     * Finds objects in collection
233
     * @param  array $p Hash of properties (offset, limit, opts, tailable, await, where, col, fields, sort, hint, explain, snapshot, orderby, parse_oplog)
234
     * @param  callable $cb Callback called when response received
235
     * @callback $cb ( )
236
     * @return void
237
     */
238
    public function find($p, $cb)
239
    {
240
        if (!isset($p['offset'])) {
241
            $p['offset'] = 0;
242
        }
243
244
        if (!isset($p['limit'])) {
245
            $p['limit'] = 0;
246
        }
247
248
        if (!isset($p['opts'])) {
249
            $p['opts'] = '0';
250
        }
251
252
        if (isset($p['tailable']) && $p['tailable']) {
253
            $p['opts'] = '01000' . (isset($p['await']) && $p['await'] ? '1' : '0') . '00';
254
        }
255
256
        if (!isset($p['where'])) {
257
            $p['where'] = [];
258
        }
259
260
        $this->_params($p);
261
262
        $o = [];
263
        $s = false;
264
265 View Code Duplication
        foreach ($p as $k => $v) {
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...
266
            if (($k === 'sort') || ($k === 'hint') || ($k === 'explain') || ($k === 'snapshot')) {
267
                if (!$s) {
268
                    $s = true;
269
                }
270
271
                if ($k === 'sort') {
272
                    $o['orderby'] = $v;
273
                } elseif ($k === 'parse_oplog') {
274
                } elseif ($k === 'rp') {
275
                    $o['$readPreference'] = $v;
276
                } else {
277
                    $o[$k] = $v;
278
                }
279
            }
280
        }
281
282
        if ($s) {
283
            $o['query'] = $p['where'];
284
        } else {
285
            $o = $p['where'];
286
        }
287
288
        if (empty($o['orderby'])) {
289
            unset($o['orderby']);
290
        }
291
292
        if ($this->safeMode) {
293
            static::safeModeEnc($o);
294
        }
295
        try {
296
            $bson = bson_encode($o);
297
298
            if (isset($p['parse_oplog'])) {
299
                $bson = str_replace("\x11\$gt", "\x09\$gt", $bson);
300
            }
301
            $cb = CallbackWrapper::wrap($cb);
302
            $this->request(
303
                self::OP_QUERY,
304
                chr(bindec(strrev($p['opts']))) . "\x00\x00\x00" . $p['col'] . "\x00"
305
                . pack('VV', $p['offset'], $p['limit']) . $bson
306
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
307
                true,
308
                null,
309
                function ($conn, $reqId = null) use ($p, $cb) {
310
                    if (!$conn) {
311
                        !$cb || $cb(['$err' => 'Connection error.']);
312
                        return;
313
                    }
314
                    $conn->requests[$reqId] = [$p['col'], $cb, false, isset($p['parse_oplog']), isset($p['tailable'])];
315
                }
316
            );
317
        } catch (\MongoException $e) {
318
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
319 View Code Duplication
            if ($cb !== null) {
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...
320
                $cb([
321
                    '$err' => $e->getMessage(),
322
                    '$query' => $o,
323
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
324
                ]);
325
            }
326
        }
327
    }
328
329
    /**
330
     * Finds one object in collection
331
     * @param  array $p Hash of properties (offset,  opts, where, col, fields, sort, hint, explain, snapshot, orderby, parse_oplog)
332
     * @param  callable $cb Callback called when response received
333
     * @callback $cb ( )
334
     * @return void
335
     */
336
    public function findOne($p, $cb)
337
    {
338
        if (isset($p['cachekey'])) {
339
            $db = $this;
340
            $this->cache->get($p['cachekey'], function ($r) use ($db, $p, $cb) {
341
                if ($r->result !== null) {
342
                    $cb(bson_decode($r->result));
343
                } else {
344
                    unset($p['cachekey']);
345
                    $db->findOne($p, $cb);
346
                }
347
            });
348
349
            return;
350
        }
351
        if (!isset($p['where'])) {
352
            $p['where'] = [];
353
        }
354
355
        $this->_params($p);
356
357
        $o = [];
358
        $s = false;
359
360 View Code Duplication
        foreach ($p as $k => $v) {
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...
361
            if (($k === 'sort') || ($k === 'hint') || ($k === 'explain') || ($k === 'snapshot')) {
362
                if (!$s) {
363
                    $s = true;
364
                }
365
366
                if ($k === 'sort') {
367
                    $o['orderby'] = $v;
368
                } elseif ($k === 'parse_oplog') {
369
                } elseif ($k === 'rp') {
370
                    $o['$readPreference'] = $v;
371
                } else {
372
                    $o[$k] = $v;
373
                }
374
            }
375
        }
376
        if (empty($o['orderby'])) {
377
            unset($o['orderby']);
378
        }
379
380
        if ($s) {
381
            $o['query'] = $p['where'];
382
        } else {
383
            $o = $p['where'];
384
        }
385
        $cb = CallbackWrapper::wrap($cb);
386
        if ($this->safeMode) {
387
            static::safeModeEnc($o);
388
        }
389
        try {
390
            $this->request(
391
                self::OP_QUERY,
392
                pack('V', $p['opts']) . $p['col'] . "\x00" . pack('VV', $p['offset'], -1)
393
                . bson_encode($o) . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
394
                true,
395
                null,
396 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
397
                    if (!$conn) {
398
                        !$cb || $cb(['$err' => 'Connection error.']);
399
                        return;
400
                    }
401
                    $conn->requests[$reqId] = [$p['col'], $cb, true];
402
                }
403
            );
404
        } catch (\MongoException $e) {
405
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
406 View Code Duplication
            if ($cb !== null) {
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...
407
                $cb([
408
                    '$err' => $e->getMessage(),
409
                    '$query' => $o,
410
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
411
                ]);
412
            }
413
        }
414
    }
415
416
    /**
417
     * Counts objects in collection
418
     * @param  array $p Hash of properties (offset, limit, opts, where, col)
419
     * @param  callable $cb Callback called when response received
420
     * @callback $cb ( )
421
     * @return void
422
     */
423
    public function findCount($p, $cb)
424
    {
425
        if (!isset($p['offset'])) {
426
            $p['offset'] = 0;
427
        }
428
429
        if (!isset($p['limit'])) {
430
            $p['limit'] = -1;
431
        }
432
433
        if (!isset($p['opts'])) {
434
            $p['opts'] = 0;
435
        }
436
437
        if (!isset($p['where'])) {
438
            $p['where'] = [];
439
        }
440
441 View Code Duplication
        if (mb_orig_strpos($p['col'], '.') === false) {
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...
442
            $p['col'] = $this->dbname . '.' . $p['col'];
443
        }
444
445
        $e = explode('.', $p['col'], 2);
446
447
        $query = [
448
            'count' => $e[1],
449
            'query' => $p['where'],
450
            'fields' => ['_id' => 1],
451
        ];
452
453 View Code Duplication
        if (isset($p[$k = 'rp'])) {
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...
454
            $v = $p[$k];
455
            if (is_string($v)) {
456
                $v = ['mode' => $v];
457
            }
458
            $query['$readPreference'] = $v;
459
        }
460
461 View Code Duplication
        if (is_string($p['where'])) {
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...
462
            $query['where'] = new \MongoCode($p['where']);
463
        } elseif (is_object($p['where']) || sizeof($p['where'])) {
464
            $query['query'] = $p['where'];
465
        }
466
        $cb = CallbackWrapper::wrap($cb);
467
        if ($this->safeMode) {
468
            static::safeModeEnc($query);
469
        }
470
        try {
471
            $this->request(
472
                self::OP_QUERY,
473
                pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00" . pack('VV', $p['offset'], $p['limit'])
474
                . bson_encode($query) . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
475
                true,
476
                null,
477 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
478
                    if (!$conn) {
479
                        !$cb || $cb(['$err' => 'Connection error.']);
480
                        return;
481
                    }
482
                    $conn->requests[$reqId] = [$p['col'], $cb, true];
483
                }
484
            );
485
        } catch (\MongoException $e) {
486
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
487 View Code Duplication
            if ($cb !== null) {
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
                $cb([
489
                    '$err' => $e->getMessage(),
490
                    '$query' => $query,
491
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
492
                ]);
493
            }
494
        }
495
    }
496
497
    /**
498
     * Sends authenciation packet
499
     * @param  array $p Hash of properties (dbname, user, password, nonce)
500
     * @param  callable $cb Callback called when response received
501
     * @callback $cb ( )
502
     * @return void
503
     */
504
    public function auth($p, $cb)
505
    {
506
        if (!isset($p['opts'])) {
507
            $p['opts'] = 0;
508
        }
509
510
        $query = [
511
            'authenticate' => 1,
512
            'user' => $p['user'],
513
            'nonce' => $p['nonce'],
514
            'key' => self::getAuthKey($p['user'], $p['password'], $p['nonce']),
515
        ];
516
        if ($this->safeMode) {
517
            static::safeModeEnc($query);
518
        }
519
        try {
520
            $this->request(
521
                self::OP_QUERY,
522
                pack('V', $p['opts']) . $p['dbname'] . '.$cmd' . "\x00" . pack('VV', 0, -1)
523
                . bson_encode($query) . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
524
                true,
525
                null,
526 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
527
                    if (!$conn) {
528
                        !$cb || $cb(['$err' => 'Connection error.']);
529
                        return;
530
                    }
531
                    $conn->requests[$reqId] = [$p['dbname'], $cb, true];
532
                }
533
            );
534
        } catch (\MongoException $e) {
535
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
536 View Code Duplication
            if ($cb !== null) {
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...
537
                $cb([
538
                    '$err' => $e->getMessage(),
539
                    '$query' => $query,
540
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
541
                ]);
542
            }
543
        }
544
    }
545
546
    /**
547
     * Sends request of nonce
548
     * @param  array $p Hash of properties
549
     * @param  callable $cb Callback called when response received
550
     * @callback $cb ( )
551
     * @return void
552
     */
553
    public function getNonce($p, $cb)
554
    {
555
        if (!isset($p['opts'])) {
556
            $p['opts'] = 0;
557
        }
558
559
        $query = [
560
            'getnonce' => 1,
561
        ];
562
        $cb = CallbackWrapper::wrap($cb);
563
        try {
564
            $this->request(
565
                self::OP_QUERY,
566
                pack('V', $p['opts']) . $p['dbname'] . '.$cmd' . "\x00"
567
                . pack('VV', 0, -1) . bson_encode($query)
568
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
569
                true,
570
                null,
571 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
572
                    if (!$conn) {
573
                        !$cb || $cb(['$err' => 'Connection error.']);
574
                        return;
575
                    }
576
                    $conn->requests[$reqId] = [$p['dbname'], $cb, true];
577
                }
578
            );
579
        } catch (\MongoException $e) {
580
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
581 View Code Duplication
            if ($cb !== null) {
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...
582
                $cb([
583
                    '$err' => $e->getMessage(),
584
                    '$query' => $query,
585
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
586
                ]);
587
            }
588
        }
589
    }
590
591
    /**
592
     * @TODO DESCR
593
     * @param  array $keys
594
     * @return string
595
     */
596
    public function getIndexName($keys)
597
    {
598
        $name = '';
599
        $first = true;
600
        foreach ($keys as $k => $v) {
601
            $name .= ($first ? '_' : '') . $k . '_' . $v;
602
            $first = false;
603
        }
604
        return $name;
605
    }
606
607
    /**
608
     * Ensure index
609
     * @param  string $ns Collection
610
     * @param  array $keys Keys
611
     * @param  array $options Optional. Options
612
     * @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...
613
     * @callback $cb ( )
614
     * @return void
615
     */
616
    public function ensureIndex($ns, $keys, $options = [], $cb = null)
617
    {
618
        $e = explode('.', $ns, 2);
619
        $doc = [
620
            'ns' => $ns,
621
            'key' => $keys,
622
            'name' => isset($options['name']) ? $options['name'] : $this->getIndexName($keys),
623
        ];
624
        if (isset($options['unique'])) {
625
            $doc['unique'] = $options['unique'];
626
        }
627
        if (isset($options['sparse'])) {
628
            $doc['sparse'] = $options['sparse'];
629
        }
630
        if (isset($options['version'])) {
631
            $doc['v'] = $options['version'];
632
        }
633
        if (isset($options['background'])) {
634
            $doc['background'] = $options['background'];
635
        }
636
        if (isset($options['ttl'])) {
637
            $doc['expireAfterSeconds'] = $options['ttl'];
638
        }
639
        $this->getCollection($e[0] . '.system.indexes')->insert($doc, $cb);
640
    }
641
642
    /**
643
     * Gets last error
644
     * @param  string $db Dbname
645
     * @param  callable $cb Callback called when response received
646
     * @param  array $params Parameters.
647
     * @param  Connection $conn Connection. Optional
0 ignored issues
show
Documentation introduced by
Should the type for parameter $conn not be Connection|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...
648
     * @callback $cb ( )
649
     * @return void
650
     */
651
    public function lastError($db, $cb, $params = [], $conn = null)
652
    {
653
        $e = explode('.', $db, 2);
654
        $params['getlasterror'] = 1;
655
        $cb = CallbackWrapper::wrap($cb);
656
        try {
657
            $this->request(
658
                self::OP_QUERY,
659
                pack('V', 0) . $e[0] . '.$cmd' . "\x00"
660
                . pack('VV', 0, -1) . bson_encode($params),
661
                true,
662
                $conn,
663 View Code Duplication
                function ($conn, $reqId = null) use ($db, $cb) {
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...
664
                    if (!$conn) {
665
                        !$cb || $cb(['$err' => 'Connection error.']);
666
                        return;
667
                    }
668
                    $conn->requests[$reqId] = [$db, $cb, true];
669
                }
670
            );
671
        } catch (\MongoException $e) {
672
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
673
            if ($cb !== null) {
674
                $cb(['$err' => $e->getMessage()]);
675
            }
676
        }
677
    }
678
679
    /**
680
     * Find objects in collection using min/max specifiers
681
     * @param  array $p Hash of properties (offset, limit, opts, where, col, min, max)
682
     * @param  callable $cb Callback called when response received
683
     * @callback $cb ( )
684
     * @return void
685
     */
686
    public function range($p, $cb)
687
    {
688
        if (!isset($p['offset'])) {
689
            $p['offset'] = 0;
690
        }
691
692
        if (!isset($p['limit'])) {
693
            $p['limit'] = -1;
694
        }
695
696
        if (!isset($p['opts'])) {
697
            $p['opts'] = 0;
698
        }
699
700
        if (!isset($p['where'])) {
701
            $p['where'] = [];
702
        }
703
704
        if (!isset($p['min'])) {
705
            $p['min'] = [];
706
        }
707
708
        if (!isset($p['max'])) {
709
            $p['max'] = [];
710
        }
711
712 View Code Duplication
        if (mb_orig_strpos($p['col'], '.') === false) {
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...
713
            $p['col'] = $this->dbname . '.' . $p['col'];
714
        }
715
716
        $e = explode('.', $p['col'], 2);
717
718
        $query = [
719
            '$query' => $p['where'],
720
        ];
721
722
        if (sizeof($p['min'])) {
723
            $query['$min'] = $p['min'];
724
        }
725
726
        if (sizeof($p['max'])) {
727
            $query['$max'] = $p['max'];
728
        }
729
730 View Code Duplication
        if (is_string($p['where'])) {
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...
731
            $query['where'] = new \MongoCode($p['where']);
732
        } elseif (is_object($p['where']) || sizeof($p['where'])) {
733
            $query['query'] = $p['where'];
734
        }
735
736
        $cb = CallbackWrapper::wrap($cb);
737
        if ($this->safeMode) {
738
            static::safeModeEnc($query);
739
        }
740
        try {
741
            $this->request(
742
                self::OP_QUERY,
743
                pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00"
744
                . pack('VV', $p['offset'], $p['limit']) . bson_encode($query)
745
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
746
                true,
747
                null,
748 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
749
                    if (!$conn) {
750
                        !$cb || $cb(['$err' => 'Connection error.']);
751
                        return;
752
                    }
753
                    $conn->requests[$reqId] = [$p['col'], $cb, true];
754
                }
755
            );
756
        } catch (\MongoException $e) {
757
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
758 View Code Duplication
            if ($cb !== null) {
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...
759
                $cb([
760
                    '$err' => $e->getMessage(),
761
                    '$query' => $query,
762
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
763
                ]);
764
            }
765
        }
766
    }
767
768
    /**
769
     * Evaluates a code on the server side
770
     * @param  string $code Code
771
     * @param  callable $cb Callback called when response received
772
     * @callback $cb ( )
773
     * @return void
774
     */
775
    public function evaluate($code, $cb)
776
    {
777
        $p = [];
778
779
        if (!isset($p['offset'])) {
780
            $p['offset'] = 0;
781
        }
782
783
        if (!isset($p['limit'])) {
784
            $p['limit'] = -1;
785
        }
786
787
        if (!isset($p['opts'])) {
788
            $p['opts'] = 0;
789
        }
790
791
        if (!isset($p['db'])) {
792
            $p['db'] = $this->dbname;
793
        }
794
795
        $cb = CallbackWrapper::wrap($cb);
796
        try {
797
            $this->request(
798
                self::OP_QUERY,
799
                pack('V', $p['opts']) . $p['db'] . '.$cmd' . "\x00"
800
                . pack('VV', $p['offset'], $p['limit']) . bson_encode(['$eval' => new \MongoCode($code)])
801
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
802
                true,
803
                null,
804 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
805
                    if (!$conn) {
806
                        !$cb || $cb(['$err' => 'Connection error.']);
807
                        return;
808
                    }
809
                    $conn->requests[$reqId] = [$p['db'], $cb, true];
810
                }
811
            );
812
        } catch (\MongoException $e) {
813
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
814 View Code Duplication
            if ($cb !== null) {
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...
815
                $cb([
816
                    '$err' => $e->getMessage(),
817
                    '$query' => $query,
0 ignored issues
show
Bug introduced by
The variable $query does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
818
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
819
                ]);
820
            }
821
        }
822
    }
823
824
    /**
825
     * Returns distinct values of the property
826
     * @param  array $p Hash of properties (offset, limit, opts, key, col, where)
827
     * @param  callable $cb Callback called when response received
828
     * @callback $cb ( )
829
     * @return void
830
     */
831
    public function distinct($p, $cb)
832
    {
833
        $this->_params($p);
834
        $e = explode('.', $p['col'], 2);
835
836
        $query = [
837
            'distinct' => $e[1],
838
            'key' => $p['key'],
839
        ];
840
841 View Code Duplication
        if (isset($p[$k = 'rp'])) {
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...
842
            $v = $p[$k];
843
            if (is_string($v)) {
844
                $v = ['mode' => $v];
845
            }
846
            $query['$readPreference'] = $v;
847
        }
848
849
        if (isset($p['where'])) {
850
            $query['query'] = $p['where'];
851
        }
852
        $cb = CallbackWrapper::wrap($cb);
853
        $this->request(
854
            self::OP_QUERY,
855
            pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00"
856
            . pack('VV', $p['offset'], $p['limit']) . bson_encode($query)
857
            . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
858
            true,
859
            null,
860 View Code Duplication
            function ($conn, $reqId = null) use ($p, $cb) {
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...
861
                if (!$conn) {
862
                    !$cb || $cb(['$err' => 'Connection error.']);
863
                    return;
864
                }
865
                $conn->requests[$reqId] = [$p['col'], $cb, true];
866
            }
867
        );
868
    }
869
870
    /**
871
     * [_paramFields description]
872
     * @param  mixed $f
873
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be null|array?

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...
874
     */
875
    protected function _paramFields($f)
876
    {
877
        if (is_string($f)) {
878
            $f = array_map('trim', explode(',', $f));
879
        }
880
        if (!is_array($f) || sizeof($f) === 0) {
881
            return null;
882
        }
883
        if (!isset($f[0])) {
884
            return $f;
885
        }
886
        $p = [];
887
        foreach ($f as $k) {
888
            $p[$k] = 1;
889
        }
890
        return $p;
891
    }
892
893
    /**
894
     * [_params description]
895
     * @param  array &$p
896
     * @return void
897
     */
898
    protected function _params(&$p)
899
    {
900
        foreach ($p as $k => &$v) {
901
            if ($k === 'fields' || $k === 'sort') {
902
                $v = $this->_paramFields($v);
903
            } elseif ($k === 'where') {
904
                if (is_string($v)) {
905
                    $v = new \MongoCode($v);
906
                }
907
            } elseif ($k === 'reduce') {
908
                if (is_string($v)) {
909
                    $v = new \MongoCode($v);
910
                }
911
            } elseif ($k === 'rp') {
912
                if (is_string($v)) {
913
                    $v = ['mode' => $v];
914
                }
915
            }
916
        }
917
918
        if (!isset($p['offset'])) {
919
            $p['offset'] = 0;
920
        }
921
922
        if (!isset($p['limit'])) {
923
            $p['limit'] = -1;
924
        }
925
926
        if (!isset($p['opts'])) {
927
            $p['opts'] = 0;
928
        }
929
930
        if (!isset($p['key'])) {
931
            $p['key'] = '';
932
        }
933
934 View Code Duplication
        if (mb_orig_strpos($p['col'], '.') === false) {
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...
935
            $p['col'] = $this->dbname . '.' . $p['col'];
936
        }
937
    }
938
939
    /**
940
     * Find and modify
941
     * @param  array $p Hash of properties
942
     * @param  callable $cb Callback called when response received
943
     * @callback $cb ( )
944
     * @return void
945
     */
946
    public function findAndModify($p, $cb)
947
    {
948
        $this->_params($p);
949
        $e = explode('.', $p['col'], 2);
950
        $query = [
951
            'findAndModify' => $e[1],
952
        ];
953
954 View Code Duplication
        if (isset($p[$k = 'rp'])) {
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...
955
            $v = $p[$k];
956
            if (is_string($v)) {
957
                $v = ['mode' => $v];
958
            }
959
            $query['$readPreference'] = $v;
960
        }
961
962
        if (isset($p['sort'])) {
963
            $query['sort'] = $p['sort'];
964
        }
965
        if (isset($p['update'])) {
966
            $query['update'] = $p['update'];
967
        }
968
        if (isset($p['new'])) {
969
            $query['new'] = (boolean)$p['new'];
970
        }
971
        if (isset($p['remove'])) {
972
            $query['remove'] = (boolean)$p['remove'];
973
        }
974
        if (isset($p['upsert'])) {
975
            $query['upsert'] = (boolean)$p['upsert'];
976
        }
977
        if (isset($p['where'])) {
978
            $query['query'] = $p['where'];
979
        } elseif (isset($p['query'])) {
980
            $query['query'] = $p['query'];
981
        }
982
        if ($this->safeMode) {
983
            static::safeModeEnc($query);
984
        }
985
        $cb = CallbackWrapper::wrap($cb);
986
        try {
987
            $this->request(
988
                self::OP_QUERY,
989
                pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00"
990
                . pack('VV', $p['offset'], $p['limit']) . bson_encode($query)
991
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
992
                true,
993
                null,
994 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
995
                    if (!$conn) {
996
                        !$cb || $cb(['$err' => 'Connection error.']);
997
                        return;
998
                    }
999
                    $conn->requests[$reqId] = [$p['col'], $cb, true];
1000
                }
1001
            );
1002
        } catch (\MongoException $e) {
1003
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1004 View Code Duplication
            if ($cb !== null) {
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...
1005
                $cb([
1006
                    '$err' => $e->getMessage(),
1007
                    '$query' => $query,
1008
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
1009
                ]);
1010
            }
1011
        }
1012
    }
1013
1014
    /**
1015
     * Groupping function
1016
     * @param  array $p Hash of properties (offset, limit, opts, key, col, reduce, initial)
1017
     * @param  callable $cb Callback called when response received
1018
     * @callback $cb ( )
1019
     * @return void
1020
     */
1021
    public function group($p, $cb)
1022
    {
1023
        if (!isset($p['reduce'])) {
1024
            $p['reduce'] = '';
1025
        }
1026
        $this->_params($p);
1027
1028
        $e = explode('.', $p['col'], 2);
1029
1030
        $query = [
1031
            'group' => [
1032
                'ns' => $e[1],
1033
                'key' => $p['key'],
1034
                '$reduce' => $p['reduce'],
1035
                'initial' => $p['initial'],
1036
            ]
1037
        ];
1038
1039
        if (isset($p[$k = 'cond'])) {
1040
            $query['group'][$k] = $p[$k];
1041
        }
1042
1043
        if (isset($p['rp'])) {
1044
            $query['$readPreference'] = $p['rp'];
1045
        }
1046
1047
        if (isset($p[$k = 'finalize'])) {
1048
            if (is_string($p[$k])) {
1049
                $p[$k] = new \MongoCode($p[$k]);
1050
            }
1051
1052
            $query['group'][$k] = $p[$k];
1053
        }
1054
1055
        if (isset($p[$k = 'keyf'])) {
1056
            $query[$k] = $p[$k];
1057
        }
1058
        if ($this->safeMode) {
1059
            static::safeModeEnc($query);
1060
        }
1061
        $cb = CallbackWrapper::wrap($cb);
1062
        try {
1063
            $this->request(
1064
                self::OP_QUERY,
1065
                pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00"
1066
                . pack('VV', $p['offset'], $p['limit']) . bson_encode($query)
1067
                . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
1068
                true,
1069
                null,
1070 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
1071
                    if (!$conn) {
1072
                        !$cb || $cb(['$err' => 'Connection error.']);
1073
                        return;
1074
                    }
1075
                    $conn->requests[$reqId] = [$p['col'], $cb, false];
1076
                }
1077
            );
1078
        } catch (\MongoException $e) {
1079
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1080 View Code Duplication
            if ($cb !== null) {
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...
1081
                $cb([
1082
                    '$err' => $e->getMessage(),
1083
                    '$query' => $query,
1084
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
1085
                ]);
1086
            }
1087
        }
1088
    }
1089
1090
    /**
1091
     * Aggregate function
1092
     * @param  array $p Hash of properties (offset, limit, opts, key, col)
1093
     * @param  callable $cb Callback called when response received
1094
     * @callback $cb ( )
1095
     * @return void
1096
     */
1097
    public function aggregate($p, $cb)
1098
    {
1099
        $this->_params($p);
1100
1101
        $e = explode('.', $p['col'], 2);
1102
        $query = [
1103
            'aggregate' => $e[1]
1104
        ];
1105
1106
        if (isset($p['rp'])) {
1107
            $query['$readPreference'] = $p['rp'];
1108
            unset($p['rp']);
1109
        }
1110
        foreach ($p as $k => $v) {
1111
            if (substr($k, 0, 1) === '$' || $k === 'pipeline') {
1112
                $query[$k] = $v;
1113
            }
1114
        }
1115
        $cb = CallbackWrapper::wrap($cb);
1116
        try {
1117
            $this->request(
1118
                self::OP_QUERY,
1119
                pack('V', $p['opts']) . $e[0] . '.$cmd' . "\x00" . pack('VV', $p['offset'], $p['limit'])
1120
                . bson_encode($query) . (isset($p['fields']) ? bson_encode($p['fields']) : ''),
1121
                true,
1122
                null,
1123 View Code Duplication
                function ($conn, $reqId = null) use ($p, $cb) {
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...
1124
                    if (!$conn) {
1125
                        !$cb || $cb(['$err' => 'Connection error.']);
1126
                        return;
1127
                    }
1128
                    $conn->requests[$reqId] = [$p['col'], $cb, false];
1129
                }
1130
            );
1131
        } catch (\MongoException $e) {
1132
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1133 View Code Duplication
            if ($cb !== null) {
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...
1134
                $cb([
1135
                    '$err' => $e->getMessage(),
1136
                    '$query' => $query,
1137
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
1138
                ]);
1139
            }
1140
        }
1141
    }
1142
1143
    /**
1144
     * Updates one object in collection
1145
     * @param  string $col Collection's name
1146
     * @param  array $cond Conditions
1147
     * @param  array $data Data
1148
     * @param  integer $flags Optional. Flags
1149
     * @param  callable $cb Optional. Callback
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...
1150
     * @param  array $params Optional. Parameters
1151
     * @callback $cb ( )
1152
     * @return void
1153
     */
1154
    public function update($col, $cond, $data, $flags = 0, $cb = null, $params = [])
1155
    {
1156 View Code Duplication
        if (mb_orig_strpos($col, '.') === false) {
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...
1157
            $col = $this->dbname . '.' . $col;
1158
        }
1159
1160
        if (is_string($cond)) {
1161
            $cond = new \MongoCode($cond);
1162
        }
1163
1164
        if ($flags) {
1165
            //if (!isset($data['_id'])) {$data['_id'] = new MongoId();}
1166
        }
1167
        if ($this->safeMode) {
1168
            static::safeModeEnc($cond);
0 ignored issues
show
Bug introduced by
It seems like $cond defined by new \MongoCode($cond) on line 1161 can also be of type object<MongoCode>; however, PHPDaemon\Clients\Mongo\Pool::safeModeEnc() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1169
            static::safeModeEnc($data);
1170
        }
1171
1172
        $this->request(
1173
            self::OP_UPDATE,
1174
            "\x00\x00\x00\x00" . $col . "\x00" . pack('V', $flags) . bson_encode($cond) . bson_encode($data),
1175
            false,
1176
            null,
1177 View Code Duplication
            function ($conn, $reqId = null) use ($cb, $col, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $reqId 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...
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...
1178
                if (!$conn) {
1179
                    !$cb || $cb(['$err' => 'Connection error.']);
1180
                    return;
1181
                }
1182
                if ($cb !== null) {
1183
                    $this->lastError($col, $cb, $params, $conn);
1184
                }
1185
            }
1186
        );
1187
    }
1188
1189
    /**
1190
     * Updates one object in collection
1191
     * @param  string $col Collection's name
1192
     * @param  array $cond Conditions
1193
     * @param  array $data Data
1194
     * @param  callable $cb Optional. Callback
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...
1195
     * @param  array $params Optional. Parameters
1196
     * @callback $cb ( )
1197
     * @return void
1198
     */
1199
    public function updateOne($col, $cond, $data, $cb = null, $params = [])
1200
    {
1201
        $this->update($col, $cond, $data, 0, $cb, $params);
1202
    }
1203
1204
    /**
1205
     * Updates several objects in collection
1206
     * @param  string $col Collection's name
1207
     * @param  array $cond Conditions
1208
     * @param  array $data Data
1209
     * @param  callable $cb Optional. Callback
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...
1210
     * @param  array $params Optional. Parameters
1211
     * @callback $cb ( )
1212
     * @return void
1213
     */
1214
    public function updateMulti($col, $cond, $data, $cb = null, $params = [])
1215
    {
1216
        $this->update($col, $cond, $data, 2, $cb, $params);
1217
    }
1218
1219
    /**
1220
     * Upserts an object (updates if exists, insert if not exists)
1221
     * @param  string $col Collection's name
1222
     * @param  array $cond Conditions
1223
     * @param  array $data Data
1224
     * @param  boolean $multi Optional. Multi
1225
     * @param  callable $cb Optional. Callback
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...
1226
     * @param  array $params Optional. Parameters
1227
     * @callback $cb ( )
1228
     * @return void
1229
     */
1230
    public function upsert($col, $cond, $data, $multi = false, $cb = null, $params = [])
1231
    {
1232
        $this->update($col, $cond, $data, $multi ? 3 : 1, $cb, $params);
1233
    }
1234
1235
    /**
1236
     * Upserts an object (updates if exists, insert if not exists)
1237
     * @param  string $col Collection's name
1238
     * @param  array $cond Conditions
1239
     * @param  array $data Data
1240
     * @param  callable $cb Optional. Callback
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...
1241
     * @param  array $params Optional. Parameters
1242
     * @callback $cb ( )
1243
     * @return void
1244
     */
1245
    public function upsertOne($col, $cond, $data, $cb = null, $params = [])
1246
    {
1247
        $this->update($col, $cond, $data, 1, $cb, $params);
1248
    }
1249
1250
    /**
1251
     * Upserts an object (updates if exists, insert if not exists)
1252
     * @param  string $col Collection's name
1253
     * @param  array $cond Conditions
1254
     * @param  array $data Data
1255
     * @param  callable $cb Optional. Callback
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...
1256
     * @param  array $params Optional. Parameters
1257
     * @callback $cb ( )
1258
     * @return void
1259
     */
1260
    public function upsertMulti($col, $cond, $data, $cb = null, $params = [])
1261
    {
1262
        $this->update($col, $cond, $data, 3, $cb, $params);
1263
    }
1264
1265
    /**
1266
     * Inserts an object
1267
     * @param  string $col Collection's name
1268
     * @param  array $doc Document
1269
     * @param  callable $cb Optional. Callback
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...
1270
     * @param  array $params Optional. Parameters
1271
     * @callback $cb ( )
1272
     * @return MongoId
1273
     */
1274
    public function insert($col, $doc = [], $cb = null, $params = [])
1275
    {
1276 View Code Duplication
        if (mb_orig_strpos($col, '.') === false) {
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...
1277
            $col = $this->dbname . '.' . $col;
1278
        }
1279
1280
        if (!isset($doc['_id'])) {
1281
            $doc['_id'] = new \MongoId;
1282
        }
1283
        if ($this->safeMode) {
1284
            static::safeModeEnc($doc);
1285
        }
1286
        try {
1287
            $this->request(
1288
                self::OP_INSERT,
1289
                "\x00\x00\x00\x00" . $col . "\x00" . bson_encode($doc),
1290
                false,
1291
                null,
1292 View Code Duplication
                function ($conn, $reqId = null) use ($cb, $col, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $reqId 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...
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...
1293
                    if ($cb !== null) {
1294
                        $this->lastError($col, $cb, $params, $conn);
1295
                    }
1296
                }
1297
            );
1298
1299
            return $doc['_id'];
1300
        } catch (\MongoException $e) {
1301
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1302
            if ($cb !== null) {
1303
                if ($cb !== null) {
1304
                    $cb(['$err' => $e->getMessage(), '$doc' => $doc]);
1305
                }
1306
            }
1307
        }
1308
    }
1309
1310
    /**
1311
     * Sends a request to kill certain cursors on the server side
1312
     * @param  array $cursors Array of cursors
1313
     * @param  Connection $conn Connection
1314
     * @return void
1315
     */
1316
    public function killCursors($cursors, $conn)
1317
    {
1318
        if (!$cursors) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cursors of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1319
            $cursors = [];
1320
        }
1321
1322
        $this->request(
1323
            self::OP_KILL_CURSORS,
1324
            "\x00\x00\x00\x00" . pack('V', sizeof($cursors)) . implode('', $cursors),
1325
            false,
1326
            $conn
1327
        );
1328
    }
1329
1330
    /**
1331
     * Inserts several documents
1332
     * @param  string $col Collection's name
1333
     * @param  array $docs Array of docs
1334
     * @param  callable $cb Optional. Callback
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...
1335
     * @param  array $params Optional. Parameters
1336
     * @callback $cb ( )
1337
     * @return array IDs
1338
     */
1339
    public function insertMulti($col, $docs = [], $cb = null, $params = [])
1340
    {
1341 View Code Duplication
        if (mb_orig_strpos($col, '.') === false) {
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...
1342
            $col = $this->dbname . '.' . $col;
1343
        }
1344
1345
        $ids = [];
1346
        $bson = '';
1347
1348
        foreach ($docs as &$doc) {
1349
            if (!isset($doc['_id'])) {
1350
                $doc['_id'] = new MongoId();
1351
            }
1352
            try {
1353
                $bson .= bson_encode($doc);
1354
            } catch (\MongoException $e) {
1355
                Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1356
                if ($cb !== null) {
1357
                    $cb(['$err' => $e->getMessage(), '$doc' => $doc]);
1358
                }
1359
            }
1360
1361
            $ids[] = $doc['_id'];
1362
        }
1363
1364
        $this->request(
1365
            self::OP_INSERT,
1366
            "\x00\x00\x00\x00" . $col . "\x00" . $bson,
1367
            false,
1368
            null,
1369 View Code Duplication
            function ($conn, $reqId = null) use ($cb, $col, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $reqId 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...
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...
1370
                if ($cb !== null) {
1371
                    $this->lastError($col, $cb, $params, $conn);
1372
                }
1373
            }
1374
        );
1375
1376
        return $ids;
1377
    }
1378
1379
    /**
1380
     * Remove objects from collection
1381
     * @param  string $col Collection's name
1382
     * @param  array $cond Conditions
1383
     * @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...
1384
     * @param  array $params Optional. Parameters
1385
     * @callback $cb ( )
1386
     * @return void
1387
     */
1388
    public function remove($col, $cond = [], $cb = null, $params = [])
1389
    {
1390 View Code Duplication
        if (mb_orig_strpos($col, '.') === false) {
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...
1391
            $col = $this->dbname . '.' . $col;
1392
        }
1393
1394
        if (is_string($cond)) {
1395
            $cond = new \MongoCode($cond);
1396
        }
1397
1398
        if ($this->safeMode && is_array($cond)) {
1399
            static::safeModeEnc($cond);
1400
        }
1401
        try {
1402
            $this->request(
1403
                self::OP_DELETE,
1404
                "\x00\x00\x00\x00" . $col . "\x00" . "\x00\x00\x00\x00" . bson_encode($cond),
1405
                false,
1406
                null,
1407 View Code Duplication
                function ($conn, $reqId = null) use ($col, $cb, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $reqId 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...
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...
1408
                    if (!$conn) {
1409
                        !$cb || $cb(['$err' => 'Connection error.']);
1410
                        return;
1411
                    }
1412
                    if ($cb !== null) {
1413
                        $this->lastError($col, $cb, $params, $conn);
1414
                    }
1415
                }
1416
            );
1417
        } catch (\MongoException $e) {
1418
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1419
            if ($cb !== null) {
1420
                $cb(['$err' => $e->getMessage(), '$query' => $cond]);
1421
            }
1422
        }
1423
    }
1424
1425
    /**
1426
     * Asks for more objects
1427
     * @param  string $col Collection's name
1428
     * @param  string $id Cursor's ID
1429
     * @param  integer $number Number of objects
1430
     * @param  Connection $conn Connection
1431
     * @return void
1432
     */
1433
    public function getMore($col, $id, $number, $conn)
1434
    {
1435 View Code Duplication
        if (mb_orig_strpos($col, '.') === false) {
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...
1436
            $col = $this->dbname . '.' . $col;
1437
        }
1438
1439
        $this->request(
1440
            self::OP_GETMORE,
1441
            "\x00\x00\x00\x00" . $col . "\x00" . pack('V', $number) . $id,
1442
            false,
1443
            $conn,
1444
            function ($conn, $reqId = null) use ($id) {
1445
                if (!$conn) {
1446
                    !$cb || $cb(['$err' => 'Connection error.']);
0 ignored issues
show
Bug introduced by
The variable $cb does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1447
                    return;
1448
                }
1449
                $conn->requests[$reqId] = [$id];
1450
            }
1451
        );
1452
    }
1453
1454
    /**
1455
     * Returns an object of collection
1456
     * @param  string $col Collection's name
1457
     * @return Collection
1458
     */
1459
    public function getCollection($col)
1460
    {
1461
        if (mb_orig_strpos($col, '.') === false) {
1462
            $col = $this->dbname . '.' . $col;
1463
        } else {
1464
            $collName = explode('.', $col, 2);
0 ignored issues
show
Unused Code introduced by
$collName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1465
        }
1466
1467
        if (isset($this->collections[$col])) {
1468
            return $this->collections[$col];
1469
        }
1470
1471
        return $this->collections[$col] = new Collection($col, $this);
1472
    }
1473
1474
    /**
1475
     * Magic getter-method. Proxy for getCollection
1476
     * @param  string $name Collection's name
1477
     * @return Collection
1478
     */
1479
    public function __get($name)
1480
    {
1481
        return $this->getCollection($name);
1482
    }
1483
1484
    public function saslScrumSHA1Auth($p, $cb)
1485
    {
1486
        $session = [
1487
            'cb' => $cb,
1488
            'step' => 0,
1489
            'dbname' => $p['dbname'],
1490
            'user' => $p['user'],
1491
            'password' => $p['password'],
1492
            'auth_message' => '',
1493
            'conn' => array_key_exists('conn', $p) ? $p['conn'] : null,
1494
        ];
1495
        $this->saslScrumSHA1Step($session);
1496
    }
1497
1498
    public function saslScrumSHA1Step($session, $input = null)
1499
    {
1500
        $session['step']++;
1501
        $query = [];
1502
1503
        if (!is_null($input) && (!empty($input['$err']) || !empty($input['errmsg']))) {
1504
            $session['cb']($input);
1505
            return;
1506
        }
1507
1508
        if ($session['step'] == 1) {
1509
            $session['nonce'] = base64_encode(openssl_random_pseudo_bytes(24));
1510
            $payload = 'n,,n=' . $session['user'] . ',r=' . $session['nonce'];
1511
            $query = ['saslStart' => 1, 'mechanism' => 'SCRAM-SHA-1', 'payload' => base64_encode($payload)];
1512
            $session['auth_message'] .= 'n=' . $session['user'] . ',r=' . $session['nonce'] . ',';
1513
        } elseif ($session['step'] == 2) {
1514
            $in_payload = $this->saslScrumSHA1ExtractPayload($input['payload']);
1515
1516
            $error = null;
1517
            if (count($in_payload) != 3) {
1518
                $error = 'Incorrect number of arguments for first SCRAM-SHA-1 server message, got ' . count($in_payload) . 'expected 3';
1519
            } elseif (mb_orig_strlen($in_payload['r']) < 2) {
1520
                $error = 'Incorrect SCRAM-SHA-1 client|server nonce: ' . $in_payload['r'];
1521
            } elseif (mb_orig_strlen($in_payload['s']) < 6) {
1522
                $error = 'Incorrect SCRAM-SHA-1 salt: ' . $in_payload['s'];
1523
            } elseif (mb_orig_strlen($in_payload['i']) < 3) {
1524
                $error = 'Incorrect SCRAM-SHA-1 iteration count: ' . $in_payload['i'];
1525
            } elseif (mb_orig_strpos($in_payload['r'], $session['nonce']) !== 0) {
1526
                $error = 'Server SCRAM-SHA-1 nonce does not match client nonce';
1527
            }
1528
            if (!empty($error)) {
1529
                $session['cb'](['ok' => 0, 'errmsg' => $error]);
1530
                return;
1531
            } else {
1532
                $session['conversation_id'] = $input['conversationId'];
1533
                $session['nonce'] = $in_payload['r'];
1534
            }
1535
1536
            $payload = 'c=biws,r=' . $session['nonce'];
1537
            $session['auth_message'] .= base64_decode($input['payload']) . ',' . $payload;
1538
1539
            $decoded_salt = base64_decode($in_payload['s']);
1540
            $password = md5($session['user'] . ':mongo:' . $session['password']);
1541
            $salted_password = hash_pbkdf2('sha1', $password, $decoded_salt, (int)$in_payload['i'], 0, true);
1542
1543
            $client_key = hash_hmac('sha1', 'Client Key', $salted_password, true);
1544
            $stored_key = sha1($client_key, true);
1545
            $client_sign = hash_hmac('sha1', $session['auth_message'], $stored_key, true);
1546
            $client_proof = $client_key ^ $client_sign;
1547
1548
            $payload .= ',p=' . base64_encode($client_proof);
1549
1550
            $query = [
1551
                'saslContinue' => 1,
1552
                'conversationId' => $session['conversation_id'],
1553
                'payload' => base64_encode($payload)
1554
            ];
1555
        } elseif ($session['step'] == 3) {
1556
            $in_payload = $this->saslScrumSHA1ExtractPayload($input['payload']);
1557
            if (!empty($in_payload['v'])) {
1558
                $session['server_signature'] = $in_payload['v'];
1559
                $query = [
1560
                    'saslContinue' => 1,
1561
                    'conversationId' => $session['conversation_id'],
1562
                    'payload' => base64_encode('')
1563
                ];
1564
            }
1565
        } elseif ($session['step'] == 4) {
1566
            $in_payload = $this->saslScrumSHA1ExtractPayload($input['payload']);
0 ignored issues
show
Unused Code introduced by
$in_payload is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1567
            $res = $input['done'] ? [
1568
                'ok' => 1,
1569
                'server_signature' => $session['server_signature'],
1570
            ] : [
1571
                'ok' => 0,
1572
                'errmsg' => 'Authentication failed.',
1573
            ];
1574
            $session['cb']($res);
1575
            return;
1576
        }
1577
1578
        $this->saslScrumSHA1Conversation($session['dbname'], $query, function ($res) use ($session) {
1579
            $this->saslScrumSHA1Step($session, $res);
1580
        }, $session['conn']);
1581
    }
1582
1583
    public function saslScrumSHA1Conversation($dbname, $query, $cb, $conn = null)
1584
    {
1585
        if ($this->safeMode) {
1586
            static::safeModeEnc($query);
1587
        }
1588
1589
        try {
1590
            $this->request(
1591
                self::OP_QUERY,
1592
                pack('V', 0) . $dbname . '.$cmd' . "\x00" . pack('VV', 0, -1) . bson_encode($query),
1593
                true,
1594
                $conn,
1595 View Code Duplication
                function ($conn, $reqId = null) use ($dbname, $cb) {
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...
1596
                    if (!$conn) {
1597
                        !$cb || $cb(['$err' => 'Connection error.']);
1598
                        return;
1599
                    }
1600
                    $conn->requests[$reqId] = [$dbname, $cb, true];
1601
                }
1602
            );
1603
        } catch (\MongoException $e) {
1604
            Daemon::log('MongoClient exception: ' . $e->getMessage() . ': ' . $e->getTraceAsString());
1605 View Code Duplication
            if ($cb !== null) {
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...
1606
                $cb([
1607
                    '$err' => $e->getMessage(),
1608
                    '$query' => $query,
1609
                    '$fields' => isset($p['fields']) ? $p['fields'] : null
0 ignored issues
show
Bug introduced by
The variable $p seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1610
                ]);
1611
            }
1612
        }
1613
    }
1614
1615
    public function saslScrumSHA1ExtractPayload($payload)
1616
    {
1617
        $result = [];
1618
        $payload = base64_decode($payload);
1619
        foreach (explode(',', $payload) as $line) {
1620
            if (preg_match('/^([a-z]+)=(.*)/', $line, $ms)) {
1621
                $result[$ms[1]] = $ms[2];
1622
            }
1623
        }
1624
        return $result;
1625
    }
1626
}
1627