Completed
Push — master ( e07c4c...11a961 )
by Lars
03:43
created

DB::getDebugger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace voku\db;
4
5
use voku\cache\Cache;
6
use voku\helper\UTF8;
7
8
/**
9
 * DB: this handles DB queries via MySQLi
10
 *
11
 * @package   voku\db
12
 */
13
final class DB
14
{
15
16
  /**
17
   * @var int
18
   */
19
  public $query_count = 0;
20
21
  /**
22
   * @var \mysqli
23
   */
24
  private $link = false;
25
26
  /**
27
   * @var bool
28
   */
29
  private $connected = false;
30
31
  /**
32
   * @var array
33
   */
34
  private $mysqlDefaultTimeFunctions;
35
36
  /**
37
   * @var string
38
   */
39
  private $hostname = '';
40
41
  /**
42
   * @var string
43
   */
44
  private $username = '';
45
46
  /**
47
   * @var string
48
   */
49
  private $password = '';
50
51
  /**
52
   * @var string
53
   */
54
  private $database = '';
55
56
  /**
57
   * @var int
58
   */
59
  private $port = 3306;
60
61
  /**
62
   * @var string
63
   */
64
  private $charset = 'utf8';
65
66
  /**
67
   * @var string
68
   */
69
  private $socket = '';
70
71
  /**
72
   * @var bool
73
   */
74
  private $session_to_db = false;
75
76
  /**
77
   * @var bool
78
   */
79
  private $_in_transaction = false;
80
81
  /**
82
   * @var bool
83
   */
84
  private $_convert_null_to_empty_string = false;
85
86
  /**
87
   * @var Debug
88
   */
89
  private $_debug;
90
91
  /**
92
   * __construct()
93
   *
94
   * @param string         $hostname
95
   * @param string         $username
96
   * @param string         $password
97
   * @param string         $database
98
   * @param int            $port
99
   * @param string         $charset
100
   * @param boolean|string $exit_on_error use a empty string "" or false to disable it
101
   * @param boolean|string $echo_on_error use a empty string "" or false to disable it
102
   * @param string         $logger_class_name
103
   * @param string         $logger_level  'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'
104
   * @param boolean|string $session_to_db use a empty string "" or false to disable it
105
   */
106 10
  protected function __construct($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db)
107
  {
108 10
    $this->connected = false;
109
110 10
    $this->_debug = new Debug($this);
111
112 10
    $this->_loadConfig(
113 10
        $hostname,
114 10
        $username,
115 10
        $password,
116 10
        $database,
117 10
        $port,
118 10
        $charset,
119 10
        $exit_on_error,
120 10
        $echo_on_error,
121 10
        $logger_class_name,
122 10
        $logger_level,
123
        $session_to_db
124 10
    );
125
126 7
    $this->connect();
127
128 4
    $this->mysqlDefaultTimeFunctions = array(
129
      // Returns the current date.
130 4
      'CURDATE()',
131
      // CURRENT_DATE	| Synonyms for CURDATE()
132 4
      'CURRENT_DATE()',
133
      // CURRENT_TIME	| Synonyms for CURTIME()
134 4
      'CURRENT_TIME()',
135
      // CURRENT_TIMESTAMP | Synonyms for NOW()
136 4
      'CURRENT_TIMESTAMP()',
137
      // Returns the current time.
138 4
      'CURTIME()',
139
      // Synonym for NOW()
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
140 4
      'LOCALTIME()',
141
      // Synonym for NOW()
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
142 4
      'LOCALTIMESTAMP()',
143
      // Returns the current date and time.
144 4
      'NOW()',
145
      // Returns the time at which the function executes.
146 4
      'SYSDATE()',
147
      // Returns a UNIX timestamp.
148 4
      'UNIX_TIMESTAMP()',
149
      // Returns the current UTC date.
150 4
      'UTC_DATE()',
151
      // Returns the current UTC time.
152 4
      'UTC_TIME()',
153
      // Returns the current UTC date and time.
154 4
      'UTC_TIMESTAMP()',
155
    );
156 4
  }
157
158
  /**
159
   * Load the config from the constructor.
160
   *
161
   * @param string         $hostname
162
   * @param string         $username
163
   * @param string         $password
164
   * @param string         $database
165
   * @param int            $port
166
   * @param string         $charset
167
   * @param boolean|string $exit_on_error use a empty string "" or false to disable it
168
   * @param boolean|string $echo_on_error use a empty string "" or false to disable it
169
   * @param string         $logger_class_name
170
   * @param string         $logger_level
171
   * @param boolean|string $session_to_db use a empty string "" or false to disable it
172
   *
173
   * @return bool
174
   */
175 10
  private function _loadConfig($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db)
176
  {
177 10
    $this->hostname = (string)$hostname;
178 10
    $this->username = (string)$username;
179 10
    $this->password = (string)$password;
180 10
    $this->database = (string)$database;
181
182 10
    if ($charset) {
183 4
      $this->charset = (string)$charset;
184 4
    }
185
186 10
    if ($port) {
187 4
      $this->port = (int)$port;
188 4
    } else {
189
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
190 7
      $this->port = @ini_get('mysqli.default_port');
191
    }
192
193 10
    if (!$this->socket) {
194
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
195 10
      $this->socket = @ini_get('mysqli.default_socket');
196 10
    }
197
198 10
    if ($exit_on_error === true || $exit_on_error === false) {
199 10
      $this->_debug->setExitOnError($exit_on_error);
200 10
    }
201
202 10
    if ($echo_on_error === true || $echo_on_error === false) {
203 10
      $this->_debug->setEchoOnError($echo_on_error);
204 10
    }
205
206 10
    $this->_debug->setLoggerClassName($logger_class_name);
207 10
    $this->_debug->setLoggerLevel($logger_level);
208
209 10
    $this->session_to_db = (boolean)$session_to_db;
210
211 10
    return $this->showConfigError();
212
  }
213
214
  /**
215
   * Show config errors by throw exceptions.
216
   *
217
   * @return bool
218
   *
219
   * @throws \Exception
220
   */
221 10
  public function showConfigError()
222
  {
223
224
    if (
225 10
        !$this->hostname
226 10
        ||
227 9
        !$this->username
228 9
        ||
229 8
        !$this->database
230 10
    ) {
231
232 3
      if (!$this->hostname) {
233 1
        throw new \Exception('no-sql-hostname');
234
      }
235
236 2
      if (!$this->username) {
237 1
        throw new \Exception('no-sql-username');
238
      }
239
240 1
      if (!$this->database) {
241 1
        throw new \Exception('no-sql-database');
242
      }
243
244
      return false;
245
    }
246
247 7
    return true;
248
  }
249
250
  /**
251
   * Open a new connection to the MySQL server.
252
   *
253
   * @return boolean
254
   */
255 9
  public function connect()
256
  {
257 9
    if ($this->isReady()) {
258 1
      return true;
259
    }
260
261 9
    mysqli_report(MYSQLI_REPORT_STRICT);
262
    try {
263 9
      $this->link = mysqli_init();
0 ignored issues
show
Documentation Bug introduced by
It seems like mysqli_init() of type object<mysql> is incompatible with the declared type object<mysqli> of property $link.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
264
265 9
      if (Helper::isMysqlndIsUsed() === true) {
266 9
        mysqli_options($this->link, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
267 9
      }
268
269
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
270 9
      $this->connected = @mysqli_real_connect(
271 9
          $this->link,
272 9
          $this->hostname,
273 9
          $this->username,
274 9
          $this->password,
275 9
          $this->database,
276 9
          $this->port,
277 9
          $this->socket
278 9
      );
279 9
    } catch (\Exception $e) {
280 3
      $this->_debug->displayError('Error connecting to mysql server: ' . $e->getMessage(), true);
281
    }
282 6
    mysqli_report(MYSQLI_REPORT_OFF);
283
284 6
    if (!$this->connected) {
285
      $this->_debug->displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true);
286
    } else {
287 6
      $this->set_charset($this->charset);
288
    }
289
290 6
    return $this->isReady();
291
  }
292
293
  /**
294
   * Check if db-connection is ready.
295
   *
296
   * @return boolean
297
   */
298 39
  public function isReady()
299
  {
300 39
    return $this->connected ? true : false;
301
  }
302
303
  /**
304
   * Get a new "Prepare"-Object for your sql-query.
305
   *
306
   * @param string $query
307
   *
308
   * @return Prepare
309
   */
310
  public function prepare($query)
311
  {
312
    return new Prepare($this, $query);
313
  }
314
315
  /**
316
   * Execute a sql-query and return the result-array for select-statements.
317
   *
318
   * @param $query
319
   *
320
   * @return mixed
321
   * @deprecated
322
   * @throws \Exception
323
   */
324
  public static function qry($query)
325
  {
326
    $db = self::getInstance();
327
328
    $args = func_get_args();
329
    $query = array_shift($args);
330
    $query = str_replace('?', '%s', $query);
331
    $args = array_map(
332
        array(
333
            $db,
334
            'escape',
335
        ),
336
        $args
337
    );
338
    array_unshift($args, $query);
339
    $query = call_user_func_array('sprintf', $args);
340
    $result = $db->query($query);
341
342
    if ($result instanceof Result) {
343
      return $result->fetchAllArray();
344
    } else {
345
      return $result;
346
    }
347
  }
348
349
  /**
350
   * getInstance()
351
   *
352
   * @param string      $hostname
353
   * @param string      $username
354
   * @param string      $password
355
   * @param string      $database
356
   * @param string      $port          default is (int)3306
357
   * @param string      $charset       default is 'utf8', but if you need 4-byte chars, then your tables need
358
   *                                   the 'utf8mb4'-charset
359
   * @param bool|string $exit_on_error use a empty string "" or false to disable it
360
   * @param bool|string $echo_on_error use a empty string "" or false to disable it
361
   * @param string      $logger_class_name
362
   * @param string      $logger_level
363
   * @param bool|string $session_to_db use a empty string "" or false to disable it
364
   *
365
   * @return \voku\db\DB
366
   */
367 50
  public static function getInstance($hostname = '', $username = '', $password = '', $database = '', $port = '', $charset = '', $exit_on_error = '', $echo_on_error = '', $logger_class_name = '', $logger_level = '', $session_to_db = '')
368
  {
369
    /**
370
     * @var $instance DB[]
371
     */
372 50
    static $instance = array();
373
374
    /**
375
     * @var $firstInstance DB
376
     */
377 50
    static $firstInstance = null;
378
379
    if (
380 50
        $hostname . $username . $password . $database . $port . $charset == ''
381 50
        &&
382 9
        null !== $firstInstance
383 50
    ) {
384 9
      return $firstInstance;
385
    }
386
387 50
    $connection = md5(
388 50
        $hostname . $username . $password . $database . $port . $charset . (int)$exit_on_error . (int)$echo_on_error . $logger_class_name . $logger_level . (int)$session_to_db
389 50
    );
390
391 50
    if (!isset($instance[$connection])) {
392 10
      $instance[$connection] = new self(
393 10
          $hostname,
394 10
          $username,
395 10
          $password,
396 10
          $database,
397 10
          $port,
398 10
          $charset,
399 10
          $exit_on_error,
400 10
          $echo_on_error,
401 10
          $logger_class_name,
402 10
          $logger_level,
403
          $session_to_db
404 10
      );
405
406 4
      if (null === $firstInstance) {
407 1
        $firstInstance = $instance[$connection];
408 1
      }
409 4
    }
410
411 50
    return $instance[$connection];
412
  }
413
414
  /**
415
   * Execute a sql-query.
416
   *
417
   * @param string        $sql            sql-query
418
   *
419
   * @param array|boolean $params         "array" of sql-query-parameters
420
   *                                      "false" if you don't need any parameter (default)
421
   *
422
   * @return bool|int|Result              "Result" by "<b>SELECT</b>"-queries<br />
423
   *                                      "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br />
424
   *                                      "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
425
   *                                      "true" by e.g. "DROP"-queries<br />
426
   *                                      "false" on error
427
   *
428
   * @throws \Exception
429
   */
430 29
  public function query($sql = '', $params = false)
431
  {
432 29
    if (!$this->isReady()) {
433
      return false;
434
    }
435
436 29 View Code Duplication
    if (!$sql || $sql === '') {
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...
437 4
      $this->_debug->displayError('Can\'t execute an empty Query', false);
438
439 4
      return false;
440
    }
441
442
    if (
443
        $params !== false
444 27
        &&
445 2
        is_array($params)
446 27
        &&
447 2
        count($params) > 0
448 27
    ) {
449 2
      $sql = $this->_parseQueryParams($sql, $params);
450 2
    }
451
452 27
    $query_start_time = microtime(true);
453 27
    $query_result = mysqli_real_query($this->link, $sql);
454 27
    $query_duration = microtime(true) - $query_start_time;
455
456 27
    $this->query_count++;
457
458 27
    $mysqli_field_count = mysqli_field_count($this->link);
459 27
    if ($mysqli_field_count) {
460 24
      $result = mysqli_store_result($this->link);
461 24
    } else {
462 18
      $result = $query_result;
463
    }
464
465 27
    if ($result instanceof \mysqli_result) {
466
467
      // log the select query
468 23
      $this->_debug->logQuery($sql, $query_duration, $mysqli_field_count);
469
470
      // return query result object
471 23
      return new Result($sql, $result);
472
473 19
    } elseif ($query_result === true) {
474
475
      // "INSERT" || "REPLACE"
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
476 17 View Code Duplication
      if (preg_match('/^\s*"?(INSERT|REPLACE)\s+/i', $sql)) {
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...
477 16
        $insert_id = (int)$this->insert_id();
478 16
        $this->_debug->logQuery($sql, $query_duration, $insert_id);
479
480 16
        return $insert_id;
481
      }
482
483
      // "UPDATE" || "DELETE"
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
484 7 View Code Duplication
      if (preg_match('/^\s*"?(UPDATE|DELETE)\s+/i', $sql)) {
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...
485 7
        $affected_rows = (int)$this->affected_rows();
486 7
        $this->_debug->logQuery($sql, $query_duration, $affected_rows);
487
488 7
        return $affected_rows;
489
      }
490
491
      // log the ? query
492
      $this->_debug->logQuery($sql, $query_duration, 0);
493
494
      return true;
495
    }
496
497
    // log the error query
498 8
    $this->_debug->logQuery($sql, $query_duration, 0, true);
499
500 8
    return $this->queryErrorHandling(mysqli_error($this->link), $sql, $params);
501
  }
502
503
  /**
504
   * _parseQueryParams
505
   *
506
   * @param string $sql
507
   * @param array  $params
508
   *
509
   * @return string
510
   */
511 2
  private function _parseQueryParams($sql, array $params)
512
  {
513
    // is there anything to parse?
514 2
    if (strpos($sql, '?') === false) {
515
      return $sql;
516
    }
517
518 2
    if (count($params) > 0) {
519 2
      $parseKey = md5(uniqid(mt_rand(), true));
520 2
      $sql = str_replace('?', $parseKey, $sql);
521
522 2
      $k = 0;
523 2
      while (strpos($sql, $parseKey) !== false) {
524 2
        $value = $this->secure($params[$k]);
525 2
        $sql = preg_replace("/$parseKey/", $value, $sql, 1);
526 2
        $k++;
527 2
      }
528 2
    }
529
530 2
    return $sql;
531
  }
532
533
  /**
534
   * Try to secure a variable, so can you use it in sql-queries.
535
   *
536
   * <p>
537
   * <strong>int:</strong> (also strings that contains only an int-value)<br />
538
   * 1. parse into (int)
539
   * </p><br />
540
   *
541
   * <p>
542
   * <strong>string:</strong><br />
543
   * 1. check if the string isn't a default mysql-time-function e.g. 'CURDATE()'<br />
544
   * 2. trim whitespace<br />
545
   * 3. trim '<br />
546
   * 4. escape the string (and remove non utf-8 chars)<br />
547
   * 5. trim ' again (because we maybe removed some chars)<br />
548
   * 6. add ' around the new string<br />
549
   * </p><br />
550
   *
551
   * <p>
552
   * <strong>array:</strong><br />
553
   * 1. return null
554
   * </p><br />
555
   *
556
   * <p>
557
   * <strong>object:</strong><br />
558
   * 1. return false
559
   * </p>
560
   *
561
   * @param mixed $var
562
   *
563
   * @return mixed
564
   */
565 20
  public function secure($var)
566
  {
567
    if (
568
        $var === ''
569 20
        ||
570 20
        ($this->_convert_null_to_empty_string === true && $var === null)
571 20
    ) {
572 1
      return "''";
573
    }
574
575 20
    if (in_array($var, $this->mysqlDefaultTimeFunctions, true)) {
576 1
      return $var;
577
    }
578
579 20
    if (is_string($var)) {
580 16
      $var = trim(trim($var), "'");
581 16
    }
582
583 20
    $var = $this->escape($var, false, false, null);
584
585 20
    if (is_string($var)) {
586 16
      $var = "'" . trim($var, "'") . "'";
587 16
    }
588
589 20
    return $var;
590
  }
591
592
  /**
593
   * Escape
594
   *
595
   * @param mixed     $var           boolean: convert into "integer"<br />
596
   *                                 int: convert into "integer"<br />
597
   *                                 float: convert into "float" and replace "," with "."<br />
598
   *                                 array: run escape() for every key => value<br />
599
   *                                 string: run UTF8::cleanup() and mysqli_real_escape_string()<br />
600
   * @param bool      $stripe_non_utf8
601
   * @param bool      $html_entity_decode
602
   * @param bool|null $convert_array <strong>false</strong> => Keep the array.<br />
603
   *                                 <strong>true</strong> => Convert to string var1,var2,var3...<br />
604
   *                                 <strong>null</strong> => Convert the array into null, every time.
605
   *
606
   * @return mixed
607
   */
608 26
  public function escape($var = '', $stripe_non_utf8 = true, $html_entity_decode = false, $convert_array = false)
609
  {
610 26
    if ($var === null) {
611 2
      return null;
612
    }
613
614
    // save the current value as int (for later usage)
615 26
    if (!is_object($var)) {
616 26
      $varInt = (int)$var;
617 26
    }
618
619
    /** @noinspection TypeUnsafeComparisonInspection */
620
    if (
621 26
        is_int($var)
622
        ||
623 26
        is_bool($var)
624 26
        ||
625 26
        (isset($varInt, $var[0]) && $var[0] != '0' && "$varInt" == $var)
0 ignored issues
show
Bug introduced by
The variable $varInt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
626 26
    ) {
627
628
      // "int" || int || bool
629
630 20
      return (int)$var;
631
632 26
    } elseif (is_float($var)) {
633
634
      // float
635
636 4
      return number_format((float)str_replace(',', '.', $var), 8, '.', '');
637
638 26
    } elseif (is_array($var)) {
639
640
      // array
641
642 3
      if ($convert_array === null) {
643 3
        return null;
644
      }
645
646 1
      $varCleaned = array();
647 1
      foreach ($var as $key => $value) {
648
649 1
        $key = $this->escape($key, $stripe_non_utf8, $html_entity_decode);
650 1
        $value = $this->escape($value, $stripe_non_utf8, $html_entity_decode);
651
652
        /** @noinspection OffsetOperationsInspection */
653 1
        $varCleaned[$key] = $value;
654 1
      }
655
656 1
      if ($convert_array === true) {
657 1
        $varCleaned = implode(',', $varCleaned);
658
659 1
        return $varCleaned;
660
      } else {
661 1
        return (array)$varCleaned;
662
      }
663
    }
664
665
    if (
666 26
        is_string($var)
667
        ||
668 3
        (is_object($var) && method_exists($var, '__toString'))
669 26
    ) {
670
671
      // "string"
672
673 26
      $var = (string)$var;
674
675 26
      if ($stripe_non_utf8 === true) {
676 9
        $var = UTF8::cleanup($var);
677 9
      }
678
679 26
      if ($html_entity_decode === true) {
680
        // use no-html-entity for db
681 1
        $var = UTF8::html_entity_decode($var);
682 1
      }
683
684 26
      $var = get_magic_quotes_gpc() ? stripslashes($var) : $var;
685
686 26
      $var = mysqli_real_escape_string($this->getLink(), $var);
687
688 26
      return (string)$var;
689
690 3
    } elseif ($var instanceof \DateTime) {
691
692
      // "DateTime"-object
693
694
      try {
695 3
        return $this->escape($var->format('Y-m-d H:i:s'), false);
696
      } catch (\Exception $e) {
697
        return null;
698
      }
699
700
    } else {
701 2
      return false;
702
    }
703
  }
704
705
  /**
706
   * Get the mysqli-link (link identifier returned by mysqli-connect).
707
   *
708
   * @return \mysqli
709
   */
710 28
  public function getLink()
711
  {
712 28
    return $this->link;
713
  }
714
715
  /**
716
   * Returns the auto generated id used in the last query.
717
   *
718
   * @return int|string
719
   */
720 16
  public function insert_id()
721
  {
722 16
    return mysqli_insert_id($this->link);
723
  }
724
725
  /**
726
   * Gets the number of affected rows in a previous MySQL operation.
727
   *
728
   * @return int
729
   */
730 7
  public function affected_rows()
731
  {
732 7
    return mysqli_affected_rows($this->link);
733
  }
734
735
  /**
736
   * Error-handling for the sql-query.
737
   *
738
   * @param string     $errorMsg
739
   * @param string     $sql
740
   * @param array|bool $sqlParams false if there wasn't any parameter
741
   *
742
   * @throws \Exception
743
   *
744
   * @return bool
745
   */
746 9 View Code Duplication
  protected function queryErrorHandling($errorMsg, $sql, $sqlParams = false)
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...
747
  {
748 9
    if ($errorMsg === 'DB server has gone away' || $errorMsg === 'MySQL server has gone away') {
749 1
      static $reconnectCounter;
750
751
      // exit if we have more then 3 "DB server has gone away"-errors
752 1
      if ($reconnectCounter > 3) {
753
        $this->_debug->mailToAdmin('SQL-Fatal-Error', $errorMsg . ":\n<br />" . $sql, 5);
754
        throw new \Exception($errorMsg);
755
      } else {
756 1
        $this->_debug->mailToAdmin('SQL-Error', $errorMsg . ":\n<br />" . $sql);
757
758
        // reconnect
759 1
        $reconnectCounter++;
760 1
        $this->reconnect(true);
761
762
        // re-run the current query
763 1
        return $this->query($sql, $sqlParams);
764
      }
765
    } else {
766 8
      $this->_debug->mailToAdmin('SQL-Warning', $errorMsg . ":\n<br />" . $sql);
767
768
      // this query returned an error, we must display it (only for dev) !!!
769 8
      $this->_debug->displayError($errorMsg . ' | ' . $sql);
770
    }
771
772 8
    return false;
773
  }
774
775
  /**
776
   * Reconnect to the MySQL-Server.
777
   *
778
   * @param bool $checkViaPing
779
   *
780
   * @return bool
781
   */
782 3
  public function reconnect($checkViaPing = false)
783
  {
784 3
    $ping = false;
785
786 3
    if ($checkViaPing === true) {
787 2
      $ping = $this->ping();
788 2
    }
789
790 3
    if ($ping !== true) {
791 3
      $this->connected = false;
792 3
      $this->connect();
793 3
    }
794
795 3
    return $this->isReady();
796
  }
797
798
  /**
799
   * Pings a server connection, or tries to reconnect
800
   * if the connection has gone down.
801
   *
802
   * @return boolean
803
   */
804 3
  public function ping()
805
  {
806
    if (
807 3
        $this->link
808 3
        &&
809 3
        $this->link instanceof \mysqli
810 3
    ) {
811
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
812 3
      return @mysqli_ping($this->link);
813
    } else {
814
      return false;
815
    }
816
  }
817
818
  /**
819
   * Execute select/insert/update/delete sql-queries.
820
   *
821
   * @param string $query    sql-query
822
   * @param bool   $useCache use cache?
823
   * @param int    $cacheTTL cache-ttl in seconds
824
   *
825
   * @return mixed "array" by "<b>SELECT</b>"-queries<br />
826
   *               "int" (insert_id) by "<b>INSERT</b>"-queries<br />
827
   *               "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
828
   *               "true" by e.g. "DROP"-queries<br />
829
   *               "false" on error
830
   */
831 3
  public static function execSQL($query, $useCache = false, $cacheTTL = 3600)
832
  {
833 3
    $db = self::getInstance();
834
835 3
    if ($useCache === true) {
836 1
      $cache = new Cache(null, null, false, $useCache);
837 1
      $cacheKey = 'sql-' . md5($query);
838
839
      if (
840 1
          $cache->getCacheIsReady() === true
841 1
          &&
842 1
          $cache->existsItem($cacheKey)
843 1
      ) {
844 1
        return $cache->getItem($cacheKey);
845
      }
846
847 1
    } else {
848 3
      $cache = false;
849
    }
850
851 3
    $result = $db->query($query);
852
853 3
    if ($result instanceof Result) {
854
855 1
      $return = $result->fetchAllArray();
856
857
      if (
858 1
          isset($cacheKey)
859 1
          &&
860
          $useCache === true
861 1
          &&
862
          $cache instanceof Cache
863 1
          &&
864 1
          $cache->getCacheIsReady() === true
865 1
      ) {
866 1
        $cache->setItem($cacheKey, $return, $cacheTTL);
867 1
      }
868
869 1
    } else {
870 2
      $return = $result;
871
    }
872
873 3
    return $return;
874
  }
875
876
  /**
877
   * Get the current charset.
878
   *
879
   * @return string
880
   */
881 1
  public function get_charset()
882
  {
883 1
    return $this->charset;
884
  }
885
886
  /**
887
   * Set the current charset.
888
   *
889
   * @param string $charset
890
   *
891
   * @return bool
892
   */
893 7
  public function set_charset($charset)
894
  {
895 7
    $this->charset = (string)$charset;
896
897 7
    $return = mysqli_set_charset($this->link, $charset);
898
    /** @noinspection PhpUsageOfSilenceOperatorInspection */
899 7
    @mysqli_query($this->link, 'SET CHARACTER SET ' . $charset);
900
    /** @noinspection PhpUsageOfSilenceOperatorInspection */
901 7
    @mysqli_query($this->link, "SET NAMES '" . ($charset === 'utf8' ? 'utf8mb4' : $charset) . "'");
902
903 7
    return $return;
904
  }
905
906
  /**
907
   * Set the option to convert null to "''" (empty string).
908
   *
909
   * Used in secure() => select(), insert(), update(), delete()
910
   *
911
   * @param $bool
912
   */
913 1
  public function set_convert_null_to_empty_string($bool)
914
  {
915 1
    $this->_convert_null_to_empty_string = (bool)$bool;
916 1
  }
917
918
  /**
919
   * Get all table-names via "SHOW TABLES".
920
   *
921
   * @return array
922
   */
923 1
  public function getAllTables()
924
  {
925 1
    $query = 'SHOW TABLES';
926 1
    $result = $this->query($query);
927
928 1
    return $result->fetchAllArray();
929
  }
930
931
  /**
932
   * Execute a sql-multi-query.
933
   *
934
   * @param string $sql
935
   *
936
   * @return false|Result[] "Result"-Array by "<b>SELECT</b>"-queries<br />
937
   *                        "boolean" by only "<b>INSERT</b>"-queries<br />
938
   *                        "boolean" by only (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
939
   *                        "boolean" by only by e.g. "DROP"-queries<br />
940
   *
941
   * @throws \Exception
942
   */
943 1
  public function multi_query($sql)
944
  {
945 1
    if (!$this->isReady()) {
946
      return false;
947
    }
948
949 1 View Code Duplication
    if (!$sql || $sql === '') {
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...
950 1
      $this->_debug->displayError('Can\'t execute an empty Query', false);
951
952 1
      return false;
953
    }
954
955 1
    $query_start_time = microtime(true);
956 1
    $resultTmp = mysqli_multi_query($this->link, $sql);
957 1
    $query_duration = microtime(true) - $query_start_time;
958
959 1
    $this->_debug->logQuery($sql, $query_duration, 0);
960
961 1
    $returnTheResult = false;
962 1
    $result = array();
963 1
    if ($resultTmp) {
964
      do {
965 1
        $resultTmpInner = mysqli_store_result($this->link);
966
967 1
        if ($resultTmpInner instanceof \mysqli_result) {
968 1
          $returnTheResult = true;
969 1
          $result[] = new Result($sql, $resultTmpInner);
970 1
        } else {
971 1
          $errorMsg = mysqli_error($this->link);
972
973
          // is the query successful
974 1
          if ($resultTmpInner === true || !$errorMsg) {
975 1
            $result[] = true;
976 1
          } else {
977
            $result[] = $this->queryErrorHandling($errorMsg, $sql);
978
          }
979
        }
980 1
      } while (mysqli_more_results($this->link) === true ? mysqli_next_result($this->link) : false);
981
982 1
    } else {
983
984
      $errorMsg = mysqli_error($this->link);
985
986
      if ($this->_debug->checkForDev() === true) {
987
        echo "Info: maybe you have to increase your 'max_allowed_packet = 30M' in the config: 'my.conf' \n<br />";
988
        echo 'Error:' . $errorMsg;
989
      }
990
991
      $this->_debug->mailToAdmin('SQL-Error in mysqli_multi_query', $errorMsg . ":\n<br />" . $sql);
992
    }
993
994
    // return the result only if there was a "SELECT"-query
995 1
    if ($returnTheResult === true) {
996 1
      return $result;
997
    }
998
999 1
    if (!in_array(false, $result, true)) {
1000 1
      return true;
1001
    } else {
1002
      return false;
1003
    }
1004
  }
1005
1006
  /**
1007
   * alias: "beginTransaction()"
1008
   */
1009 1
  public function startTransaction()
1010
  {
1011 1
    $this->beginTransaction();
1012 1
  }
1013
1014
  /**
1015
   * Begins a transaction, by turning off auto commit.
1016
   *
1017
   * @return boolean this will return true or false indicating success of transaction
1018
   */
1019 4
  public function beginTransaction()
1020
  {
1021 4
    $this->clearErrors();
1022
1023 4
    if ($this->inTransaction() === true) {
1024 1
      $this->_debug->displayError('Error mysql server already in transaction!', true);
1025
1026
      return false;
1027 4
    } elseif (mysqli_connect_errno()) {
1028
      $this->_debug->displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true);
1029
1030
      return false;
1031
    } else {
1032 4
      $this->_in_transaction = true;
1033 4
      mysqli_autocommit($this->link, false);
1034
1035 4
      return true;
1036
1037
    }
1038
  }
1039
1040
  /**
1041
   * Clear the errors in "_debug->_errors".
1042
   *
1043
   * @return bool
1044
   */
1045 4
  public function clearErrors()
1046
  {
1047 4
    return $this->_debug->clearErrors();
1048
  }
1049
1050
  /**
1051
   * Check if we are in a transaction.
1052
   *
1053
   * @return boolean
1054
   */
1055 4
  public function inTransaction()
1056
  {
1057 4
    return $this->_in_transaction;
1058
  }
1059
1060
  /**
1061
   * Ends a transaction and commits if no errors, then ends autocommit.
1062
   *
1063
   * @return boolean this will return true or false indicating success of transactions
1064
   */
1065 2
  public function endTransaction()
1066
  {
1067
1068 2
    if (!$this->errors()) {
1069 1
      mysqli_commit($this->link);
1070 1
      $return = true;
1071 1
    } else {
1072 1
      $this->rollback();
1073 1
      $return = false;
1074
    }
1075
1076 2
    mysqli_autocommit($this->link, true);
1077 2
    $this->_in_transaction = false;
1078
1079 2
    return $return;
1080
  }
1081
1082
  /**
1083
   * Get all errors from "$this->_errors".
1084
   *
1085
   * @return array|false false === on errors
1086
   */
1087 2
  public function errors()
1088
  {
1089 2
    $errors = $this->_debug->getErrors();
1090
1091 2
    return count($errors) > 0 ? $errors : false;
1092
  }
1093
1094
  /**
1095
   * Rollback in a transaction.
1096
   */
1097 2
  public function rollback()
1098
  {
1099
    // init
1100 2
    $return = false;
1101
1102 2
    if ($this->_in_transaction === true) {
1103 2
      $return = mysqli_rollback($this->link);
1104 2
      mysqli_autocommit($this->link, true);
1105 2
      $this->_in_transaction = false;
1106 2
    }
1107
1108 2
    return $return;
1109
  }
1110
1111
  /**
1112
   * Execute a "insert"-query.
1113
   *
1114
   * @param string $table
1115
   * @param array  $data
1116
   *
1117
   * @return false|int false on error
1118
   */
1119 15
  public function insert($table, $data = array())
1120
  {
1121 15
    $table = trim($table);
1122
1123 15
    if ($table === '') {
1124 2
      $this->_debug->displayError('invalid table name');
1125
1126 1
      return false;
1127
    }
1128
1129 14
    if (count($data) === 0) {
1130 3
      $this->_debug->displayError('empty data for INSERT');
1131
1132 2
      return false;
1133
    }
1134
1135 12
    $SET = $this->_parseArrayPair($data);
1136
1137 12
    $sql = 'INSERT INTO ' . $this->quote_string($table) . " SET $SET;";
1138
1139 12
    return $this->query($sql);
1140
  }
1141
1142
  /**
1143
   * Parses arrays with value pairs and generates SQL to use in queries.
1144
   *
1145
   * @param array  $arrayPair
1146
   * @param string $glue this is the separator
1147
   *
1148
   * @return string
1149
   */
1150 17
  private function _parseArrayPair($arrayPair, $glue = ',')
1151
  {
1152
    // init
1153 17
    $sql = '';
1154 17
    $pairs = array();
1155
1156
    /** @noinspection IsEmptyFunctionUsageInspection */
1157 17
    if (!empty($arrayPair)) {
1158
1159 17
      foreach ($arrayPair as $_key => $_value) {
1160 17
        $_connector = '=';
1161 17
        $_key_upper = strtoupper($_key);
1162
1163 17
        if (strpos($_key_upper, ' NOT') !== false) {
1164 2
          $_connector = 'NOT';
1165 2
        }
1166
1167 17
        if (strpos($_key_upper, ' IS') !== false) {
1168 1
          $_connector = 'IS';
1169 1
        }
1170
1171 17
        if (strpos($_key_upper, ' IS NOT') !== false) {
1172 1
          $_connector = 'IS NOT';
1173 1
        }
1174
1175 17
        if (strpos($_key_upper, ' IN') !== false) {
1176 1
          $_connector = 'IN';
1177 1
        }
1178
1179 17
        if (strpos($_key_upper, ' NOT IN') !== false) {
1180 1
          $_connector = 'NOT IN';
1181 1
        }
1182
1183 17
        if (strpos($_key_upper, ' BETWEEN') !== false) {
1184 1
          $_connector = 'BETWEEN';
1185 1
        }
1186
1187 17
        if (strpos($_key_upper, ' NOT BETWEEN') !== false) {
1188 1
          $_connector = 'NOT BETWEEN';
1189 1
        }
1190
1191 17
        if (strpos($_key_upper, ' LIKE') !== false) {
1192 2
          $_connector = 'LIKE';
1193 2
        }
1194
1195 17
        if (strpos($_key_upper, ' NOT LIKE') !== false) {
1196 2
          $_connector = 'NOT LIKE';
1197 2
        }
1198
1199 17 View Code Duplication
        if (strpos($_key_upper, ' >') !== false && strpos($_key_upper, ' =') === false) {
1200 2
          $_connector = '>';
1201 2
        }
1202
1203 17 View Code Duplication
        if (strpos($_key_upper, ' <') !== false && strpos($_key_upper, ' =') === false) {
1204 1
          $_connector = '<';
1205 1
        }
1206
1207 17
        if (strpos($_key_upper, ' >=') !== false) {
1208 2
          $_connector = '>=';
1209 2
        }
1210
1211 17
        if (strpos($_key_upper, ' <=') !== false) {
1212 1
          $_connector = '<=';
1213 1
        }
1214
1215 17
        if (strpos($_key_upper, ' <>') !== false) {
1216 1
          $_connector = '<>';
1217 1
        }
1218
1219 17
        if (is_array($_value) === true) {
1220 1
          foreach ($_value as $oldKey => $oldValue) {
1221 1
            $_value[$oldKey] = $this->secure($oldValue);
1222 1
          }
1223
1224 1
          if ($_connector === 'NOT IN' || $_connector === 'IN') {
1225 1
            $_value = '(' . implode(',', $_value) . ')';
1226 1
          } elseif ($_connector === 'NOT BETWEEN' || $_connector === 'BETWEEN') {
1227 1
            $_value = '(' . implode(' AND ', $_value) . ')';
1228 1
          }
1229
1230 1
        } else {
1231 17
          $_value = $this->secure($_value);
1232
        }
1233
1234 17
        $quoteString = $this->quote_string(trim(str_ireplace($_connector, '', $_key)));
1235 17
        $pairs[] = ' ' . $quoteString . ' ' . $_connector . ' ' . $_value . " \n";
1236 17
      }
1237
1238 17
      $sql = implode($glue, $pairs);
1239 17
    }
1240
1241 17
    return $sql;
1242
  }
1243
1244
  /**
1245
   * Quote && Escape e.g. a table name string.
1246
   *
1247
   * @param string $str
1248
   *
1249
   * @return string
1250
   */
1251 20
  public function quote_string($str)
1252
  {
1253 20
    return '`' . $this->escape($str, false) . '`';
1254
  }
1255
1256
  /**
1257
   * Get errors from "$this->_errors".
1258
   *
1259
   * @return array
1260
   */
1261 1
  public function getErrors()
1262
  {
1263 1
    return $this->_debug->getErrors();
1264
  }
1265
1266
  /**
1267
   * Execute a "replace"-query.
1268
   *
1269
   * @param string $table
1270
   * @param array  $data
1271
   *
1272
   * @return false|int false on error
1273
   */
1274 1
  public function replace($table, $data = array())
1275
  {
1276
1277 1
    $table = trim($table);
1278
1279 1
    if ($table === '') {
1280 1
      $this->_debug->displayError('invalid table name');
1281
1282 1
      return false;
1283
    }
1284
1285 1
    if (count($data) === 0) {
1286 1
      $this->_debug->displayError('empty data for REPLACE');
1287
1288 1
      return false;
1289
    }
1290
1291
    // extracting column names
1292 1
    $columns = array_keys($data);
1293 1
    foreach ($columns as $k => $_key) {
1294
      /** @noinspection AlterInForeachInspection */
1295 1
      $columns[$k] = $this->quote_string($_key);
1296 1
    }
1297
1298 1
    $columns = implode(',', $columns);
1299
1300
    // extracting values
1301 1
    foreach ($data as $k => $_value) {
1302
      /** @noinspection AlterInForeachInspection */
1303 1
      $data[$k] = $this->secure($_value);
1304 1
    }
1305 1
    $values = implode(',', $data);
1306
1307 1
    $sql = 'REPLACE INTO ' . $this->quote_string($table) . " ($columns) VALUES ($values);";
1308
1309 1
    return $this->query($sql);
1310
  }
1311
1312
  /**
1313
   * Execute a "update"-query.
1314
   *
1315
   * @param string       $table
1316
   * @param array        $data
1317
   * @param array|string $where
1318
   *
1319
   * @return false|int false on error
1320
   */
1321 6
  public function update($table, $data = array(), $where = '1=1')
1322
  {
1323 6
    $table = trim($table);
1324
1325 6
    if ($table === '') {
1326 1
      $this->_debug->displayError('invalid table name');
1327
1328 1
      return false;
1329
    }
1330
1331 6
    if (count($data) === 0) {
1332 2
      $this->_debug->displayError('empty data for UPDATE');
1333
1334 2
      return false;
1335
    }
1336
1337 6
    $SET = $this->_parseArrayPair($data);
1338
1339 6
    if (is_string($where)) {
1340 2
      $WHERE = $this->escape($where, false);
1341 6
    } elseif (is_array($where)) {
1342 4
      $WHERE = $this->_parseArrayPair($where, 'AND');
1343 4
    } else {
1344 1
      $WHERE = '';
1345
    }
1346
1347 6
    $sql = 'UPDATE ' . $this->quote_string($table) . " SET $SET WHERE ($WHERE);";
1348
1349 6
    return $this->query($sql);
1350
  }
1351
1352
  /**
1353
   * Execute a "delete"-query.
1354
   *
1355
   * @param string       $table
1356
   * @param string|array $where
1357
   *
1358
   * @return false|int false on error
1359
   */
1360 1 View Code Duplication
  public function delete($table, $where)
1361
  {
1362
1363 1
    $table = trim($table);
1364
1365 1
    if ($table === '') {
1366 1
      $this->_debug->displayError('invalid table name');
1367
1368 1
      return false;
1369
    }
1370
1371 1
    if (is_string($where)) {
1372 1
      $WHERE = $this->escape($where, false);
1373 1
    } elseif (is_array($where)) {
1374 1
      $WHERE = $this->_parseArrayPair($where, 'AND');
1375 1
    } else {
1376 1
      $WHERE = '';
1377
    }
1378
1379 1
    $sql = 'DELETE FROM ' . $this->quote_string($table) . " WHERE ($WHERE);";
1380
1381 1
    return $this->query($sql);
1382
  }
1383
1384
  /**
1385
   * Execute a "select"-query.
1386
   *
1387
   * @param string       $table
1388
   * @param string|array $where
1389
   *
1390
   * @return false|Result false on error
1391
   */
1392 18 View Code Duplication
  public function select($table, $where = '1=1')
1393
  {
1394
1395 18
    if ($table === '') {
1396 1
      $this->_debug->displayError('invalid table name');
1397
1398 1
      return false;
1399
    }
1400
1401 18
    if (is_string($where)) {
1402 3
      $WHERE = $this->escape($where, false);
1403 18
    } elseif (is_array($where)) {
1404 16
      $WHERE = $this->_parseArrayPair($where, 'AND');
1405 16
    } else {
1406 1
      $WHERE = '';
1407
    }
1408
1409 18
    $sql = 'SELECT * FROM ' . $this->quote_string($table) . " WHERE ($WHERE);";
1410
1411 18
    return $this->query($sql);
1412
  }
1413
1414
  /**
1415
   * Get the last sql-error.
1416
   *
1417
   * @return string false on error
1418
   */
1419 1
  public function lastError()
1420
  {
1421 1
    $errors = $this->_debug->getErrors();
1422
1423 1
    return count($errors) > 0 ? end($errors) : false;
1424
  }
1425
1426
  /**
1427
   * @return Debug
1428
   */
1429 7
  public function getDebugger()
1430
  {
1431 7
    return $this->_debug;
1432
  }
1433
1434
  /**
1435
   * __destruct
1436
   *
1437
   */
1438
  public function __destruct()
1439
  {
1440
    // close the connection only if we don't save PHP-SESSION's in DB
1441
    if ($this->session_to_db === false) {
1442
      $this->close();
1443
    }
1444
  }
1445
1446
  /**
1447
   * Closes a previously opened database connection.
1448
   */
1449 2
  public function close()
1450
  {
1451 2
    $this->connected = false;
1452
1453 2
    if ($this->link) {
1454 2
      mysqli_close($this->link);
1455 2
    }
1456 2
  }
1457
1458
  /**
1459
   * Prevent the instance from being cloned.
1460
   *
1461
   * @return void
1462
   */
1463
  private function __clone()
1464
  {
1465
  }
1466
1467
  /**
1468
   * __wakeup
1469
   *
1470
   * @return void
1471
   */
1472 2
  public function __wakeup()
1473
  {
1474 2
    $this->reconnect();
1475 2
  }
1476
1477
}
1478