Completed
Push — master ( a01c40...addfff )
by Lars
04:27
created

DB::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 49
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 1

Importance

Changes 5
Bugs 1 Features 1
Metric Value
c 5
b 1
f 1
dl 0
loc 49
ccs 30
cts 30
cp 1
rs 9.2258
cc 1
eloc 29
nc 1
nop 11
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
class DB
14
{
15
16
  /**
17
   * @var int
18
   */
19
  public $query_count = 0;
20
21
  /**
22
   * @var bool
23
   */
24
  protected $exit_on_error = true;
25
26
  /**
27
   * @var bool
28
   */
29
  protected $echo_on_error = true;
30
31
  /**
32
   * @var string
33
   */
34
  protected $css_mysql_box_border = '3px solid red';
35
36
  /**
37
   * @var string
38
   */
39
  protected $css_mysql_box_bg = '#FFCCCC';
40
41
  /**
42
   * @var \mysqli
43
   */
44
  protected $link = false;
45
46
  /**
47
   * @var bool
48
   */
49
  protected $connected = false;
50
51
  /**
52
   * @var array
53
   */
54
  protected $mysqlDefaultTimeFunctions;
55
56
  /**
57
   * @var string
58
   */
59
  private $logger_class_name;
60
61
  /**
62
   * @var string
63
   *
64
   * 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'
65
   */
66
  private $logger_level;
67
68
  /**
69
   * @var string
70
   */
71
  private $hostname = '';
72
73
  /**
74
   * @var string
75
   */
76
  private $username = '';
77
78
  /**
79
   * @var string
80
   */
81
  private $password = '';
82
83
  /**
84
   * @var string
85
   */
86
  private $database = '';
87
88
  /**
89
   * @var int
90
   */
91
  private $port = 3306;
92
93
  /**
94
   * @var string
95
   */
96
  private $charset = 'utf8';
97
98
  /**
99
   * @var string
100
   */
101
  private $socket = '';
102
103
  /**
104
   * @var array
105
   */
106
  private $_errors = array();
107
108
  /**
109
   * @var bool
110
   */
111
  private $session_to_db = false;
112
113
  /**
114
   * @var bool
115
   */
116
  private $_in_transaction = false;
117
118
  /**
119
   * __construct()
120
   *
121
   * @param string         $hostname
122
   * @param string         $username
123
   * @param string         $password
124
   * @param string         $database
125
   * @param int            $port
126
   * @param string         $charset
127
   * @param boolean|string $exit_on_error use a empty string "" or false to disable it
128
   * @param boolean|string $echo_on_error use a empty string "" or false to disable it
129
   * @param string         $logger_class_name
130
   * @param string         $logger_level  'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'
131
   * @param boolean|string $session_to_db use a empty string "" or false to disable it
132
   */
133 10
  protected function __construct($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db)
134
  {
135 10
    $this->connected = false;
136
137 10
    $this->_loadConfig(
138 10
        $hostname,
139 10
        $username,
140 10
        $password,
141 10
        $database,
142 10
        $port,
143 10
        $charset,
144 10
        $exit_on_error,
145 10
        $echo_on_error,
146 10
        $logger_class_name,
147 10
        $logger_level,
148
        $session_to_db
149 10
    );
150
151 7
    $this->connect();
152
153 4
    $this->mysqlDefaultTimeFunctions = array(
154
      // Returns the current date
155 4
      'CURDATE()',
156
      // CURRENT_DATE	| Synonyms for CURDATE()
157 4
      'CURRENT_DATE()',
158
      // CURRENT_TIME	| Synonyms for CURTIME()
159 4
      'CURRENT_TIME()',
160
      // CURRENT_TIMESTAMP | Synonyms for NOW()
161 4
      'CURRENT_TIMESTAMP()',
162
      // Returns the current time
163 4
      'CURTIME()',
164
      // Synonym for NOW()
165 4
      'LOCALTIME()',
166
      // Synonym for NOW()
167 4
      'LOCALTIMESTAMP()',
168
      // Returns the current date and time
169 4
      'NOW()',
170
      // Returns the time at which the function executes
171 4
      'SYSDATE()',
172
      // Returns a UNIX timestamp
173 4
      'UNIX_TIMESTAMP()',
174
      // Returns the current UTC date
175 4
      'UTC_DATE()',
176
      // Returns the current UTC time
177 4
      'UTC_TIME()',
178
      // Returns the current UTC date and time
179 4
      'UTC_TIMESTAMP()',
180
    );
181 4
  }
182
183
  /**
184
   * load the config
185
   *
186
   * @param string         $hostname
187
   * @param string         $username
188
   * @param string         $password
189
   * @param string         $database
190
   * @param int            $port
191
   * @param string         $charset
192
   * @param boolean|string $exit_on_error use a empty string "" or false to disable it
193
   * @param boolean|string $echo_on_error use a empty string "" or false to disable it
194
   * @param string         $logger_class_name
195
   * @param string         $logger_level
196
   * @param boolean|string $session_to_db use a empty string "" or false to disable it
197
   *
198
   * @return bool
199
   */
200 10
  private function _loadConfig($hostname, $username, $password, $database, $port, $charset, $exit_on_error, $echo_on_error, $logger_class_name, $logger_level, $session_to_db)
201
  {
202 10
    $this->hostname = (string)$hostname;
203 10
    $this->username = (string)$username;
204 10
    $this->password = (string)$password;
205 10
    $this->database = (string)$database;
206
207 10
    if ($charset) {
208 4
      $this->charset = (string)$charset;
209 4
    }
210
211 10
    if ($port) {
212 4
      $this->port = (int)$port;
213 4
    } else {
214
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
215 7
      $this->port = @ini_get('mysqli.default_port');
216
    }
217
218 10
    if (!$this->socket) {
219
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
220 10
      $this->socket = @ini_get('mysqli.default_socket');
221 10
    }
222
223 10
    if ($exit_on_error === true || $exit_on_error === false) {
224 10
      $this->exit_on_error = (boolean)$exit_on_error;
225 10
    }
226
227 10
    if ($echo_on_error === true || $echo_on_error === false) {
228 10
      $this->echo_on_error = (boolean)$echo_on_error;
229 10
    }
230
231 10
    $this->logger_class_name = (string)$logger_class_name;
232 10
    $this->logger_level = (string)$logger_level;
233
234 10
    $this->session_to_db = (boolean)$session_to_db;
235
236 10
    return $this->showConfigError();
237
  }
238
239
  /**
240
   * show config error and throw a exception
241
   */
242 10
  public function showConfigError()
243
  {
244
245
    if (
246 10
        !$this->hostname
247 10
        ||
248 9
        !$this->username
249 9
        ||
250 8
        !$this->database
251 10
    ) {
252
253 3
      if (!$this->hostname) {
254 1
        throw new \Exception('no-sql-hostname');
255
      }
256
257 2
      if (!$this->username) {
258 1
        throw new \Exception('no-sql-username');
259
      }
260
261 1
      if (!$this->database) {
262 1
        throw new \Exception('no-sql-database');
263
      }
264
    }
265
266 7
    return true;
267
  }
268
269
  /**
270
   * connect
271
   *
272
   * @return boolean
273
   */
274 8
  public function connect()
275
  {
276 8
    if ($this->isReady()) {
277 1
      return true;
278
    }
279
280 8
    mysqli_report(MYSQLI_REPORT_STRICT);
281
    try {
282
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
283 8
      $this->link = @mysqli_connect(
284 8
          $this->hostname,
285 8
          $this->username,
286 8
          $this->password,
287 8
          $this->database,
288 8
          $this->port,
289 8
          $this->socket
290 8
      );
291 8
    } catch (\Exception $e) {
292 3
      $this->_displayError('Error connecting to mysql server: ' . $e->getMessage(), true);
293
    }
294 5
    mysqli_report(MYSQLI_REPORT_OFF);
295
296 5
    if (!$this->link) {
297
      $this->_displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true);
298
    } else {
299 5
      $this->set_charset($this->charset);
300 5
      $this->connected = true;
301
    }
302
303 5
    return $this->isReady();
304
  }
305
306
  /**
307
   * check if db-connection is ready
308
   *
309
   * @return boolean
310
   */
311 29
  public function isReady()
312
  {
313 29
    return $this->connected ? true : false;
314
  }
315
316
  /**
317
   * _displayError
318
   *
319
   * @param string       $e
320
   * @param null|boolean $force_exception_after_error
321
   *
322
   * @throws \Exception
323
   */
324 18
  private function _displayError($e, $force_exception_after_error = null)
325
  {
326 18
    $fileInfo = $this->getFileAndLineFromSql();
327
328 18
    $this->logger(
329
        array(
330 18
            'error',
331 18
            '<strong>' . date(
332
                'd. m. Y G:i:s'
333 18
            ) . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . ') (sql-error):</strong> ' . $e . '<br>',
334
        )
335 18
    );
336
337 18
    $this->_errors[] = $e;
338
339 18
    if ($this->checkForDev() === true) {
340
341 18
      if ($this->echo_on_error) {
342 4
        $box_border = $this->css_mysql_box_border;
343 4
        $box_bg = $this->css_mysql_box_bg;
344
345
        echo '
346 4
        <div class="OBJ-mysql-box" style="border:' . $box_border . '; background:' . $box_bg . '; padding:10px; margin:10px;">
347
          <b style="font-size:14px;">MYSQL Error:</b>
348
          <code style="display:block;">
349 4
            file / line: ' . $fileInfo['file'] . ' / ' . $fileInfo['line'] . '
350 4
            ' . $e . '
351
          </code>
352
        </div>
353 4
        ';
354 4
      }
355
356 18
      if ($force_exception_after_error === true) {
357 4
        throw new \Exception($e);
358 14
      } elseif ($force_exception_after_error === false) {
359
        // nothing
360 14
      } elseif ($force_exception_after_error === null) {
361
        // default
362 11
        if ($this->exit_on_error === true) {
363 2
          throw new \Exception($e);
364
        }
365 9
      }
366 12
    }
367 12
  }
368
369
  /**
370
   * try to get the file & line from the current sql-query
371
   *
372
   * @return array will return array['file'] and array['line']
373
   */
374 19
  private function getFileAndLineFromSql()
375
  {
376
    // init
377 19
    $return = array();
378 19
    $file = '';
379 19
    $line = '';
380
381 19
    $referrer = debug_backtrace();
382
383 19
    foreach ($referrer as $key => $ref) {
384
385 View Code Duplication
      if (
386 19
          $ref['function'] == 'query'
387 19
          ||
388 19
          $ref['function'] == 'qry'
389 19
      ) {
390 11
        $file = $referrer[$key]['file'];
391 11
        $line = $referrer[$key]['line'];
392 11
      }
393
394 19 View Code Duplication
      if ($ref['function'] == '_logQuery') {
395 1
        $file = $referrer[$key + 1]['file'];
396 1
        $line = $referrer[$key + 1]['line'];
397 1
      }
398
399 19 View Code Duplication
      if ($ref['function'] == 'execSQL') {
400 1
        $file = $referrer[$key]['file'];
401 1
        $line = $referrer[$key]['line'];
402
403 1
        break;
404
      }
405 19
    }
406
407 19
    $return['file'] = $file;
408 19
    $return['line'] = $line;
409
410 19
    return $return;
411
  }
412
413
  /**
414
   * wrapper for a "Logger"-Class
415
   *
416
   * @param string[] $log [method, text, type] e.g.: array('error', 'this is a error', 'sql')
417
   */
418 20
  private function logger($log)
419
  {
420 20
    $logMethod = '';
421 20
    $logText = '';
422 20
    $logType = '';
423 20
    $logClass = $this->logger_class_name;
424
425 20
    if (isset($log[0])) {
426 20
      $logMethod = $log[0];
427 20
    }
428 20
    if (isset($log[1])) {
429 20
      $logText = $log[1];
430 20
    }
431 20
    if (isset($log[2])) {
432 1
      $logType = $log[2];
433 1
    }
434
435
    if (
436
        $logClass
437 20
        &&
438
        class_exists($logClass)
439 20
        &&
440
        method_exists($logClass, $logMethod)
441 20
    ) {
442
      $logClass::$logMethod($logText, $logType);
443
    }
444 20
  }
445
446
  /**
447
   * check for developer
448
   *
449
   * @return bool
450
   */
451 18
  private function checkForDev()
452
  {
453 18
    $return = false;
454
455 18
    if (function_exists('checkForDev')) {
456
      $return = checkForDev();
457
    } else {
458
459
      // for testing with dev-address
460 18
      $noDev = isset($_GET['noDev']) ? (int)$_GET['noDev'] : 0;
461 18
      $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
462
463
      if (
464
          $noDev != 1
465 18
          &&
466
          (
467
              $remoteAddr == '127.0.0.1'
468 18
              ||
469
              $remoteAddr == '::1'
470 18
              ||
471 18
              PHP_SAPI == 'cli'
472 18
          )
473 18
      ) {
474 18
        $return = true;
475 18
      }
476
    }
477
478 18
    return $return;
479
  }
480
481
  /**
482
   * execute a sql-query and
483
   * return the result-array for select-statements
484
   *
485
   * -----------------------
486
   *
487
   * e.g.:
488
   *  $retcode = DB::qry("UPDATE user_extension
489
   *    SET
490
   *      user_name='?'
491
   *    WHERE user_uid_fk='?'
492
   *  ",
493
   *    $userName,
494
   *    (int)$uid
495
   *  );
496
   *
497
   * -----------------------
498
   *
499
   * @param $query
500
   *
501
   * @return array|bool|int|\voku\db\Result
502
   * @deprecated
503
   * @throws \Exception
504
   */
505
  public static function qry($query)
506
  {
507
    $db = self::getInstance();
508
509
    $args = func_get_args();
510
    $query = array_shift($args);
511
    $query = str_replace('?', '%s', $query);
512
    $args = array_map(
513
        array(
514
            $db,
515
            'escape',
516
        ),
517
        $args
518
    );
519
    array_unshift($args, $query);
520
    $query = call_user_func_array('sprintf', $args);
521
    $result = $db->query($query);
522
523
    if ($result instanceof Result) {
524
      $return = $result->fetchAllArray();
525
    } else {
526
      $return = $result;
527
    }
528
529
    if ($return || is_array($return)) {
530
      return $return;
531
    } else {
532
      return false;
533
    }
534
  }
535
536
  /**
537
   * getInstance()
538
   *
539
   * @param string      $hostname
540
   * @param string      $username
541
   * @param string      $password
542
   * @param string      $database
543
   * @param string      $port          default is '3306'
544
   * @param string      $charset       default is 'utf8', but if you need 4-byte chars, then your tables need
545
   *                                   the 'utf8mb4'-charset
546
   * @param bool|string $exit_on_error use a empty string "" or false to disable it
547
   * @param bool|string $echo_on_error use a empty string "" or false to disable it
548
   * @param string      $logger_class_name
549
   * @param string      $logger_level
550
   * @param bool|string $session_to_db use a empty string "" or false to disable it
551
   *
552
   * @return \voku\db\DB
553
   */
554 39
  public static function getInstance($hostname = '', $username = '', $password = '', $database = '', $port = '', $charset = '', $exit_on_error = '', $echo_on_error = '', $logger_class_name = '', $logger_level = '', $session_to_db = '')
555
  {
556
    /**
557
     * @var $instance DB[]
558
     */
559 39
    static $instance = array();
560
561
    /**
562
     * @var $firstInstance DB
563
     */
564 39
    static $firstInstance = null;
565
566
    if (
567 39
        $hostname . $username . $password . $database . $port . $charset == ''
568 39
        &&
569 7
        null !== $firstInstance
570 39
    ) {
571 7
      return $firstInstance;
572
    }
573
574 39
    $connection = md5(
575 39
        $hostname . $username . $password . $database . $port . $charset . (int)$exit_on_error . (int)$echo_on_error . $logger_class_name . $logger_level . (int)$session_to_db
576 39
    );
577
578 39
    if (!isset($instance[$connection])) {
579 10
      $instance[$connection] = new self(
580 10
          $hostname,
581 10
          $username,
582 10
          $password,
583 10
          $database,
584 10
          $port,
585 10
          $charset,
586 10
          $exit_on_error,
587 10
          $echo_on_error,
588 10
          $logger_class_name,
589 10
          $logger_level,
590
          $session_to_db
591 10
      );
592
593 4
      if (null === $firstInstance) {
594 1
        $firstInstance = $instance[$connection];
595 1
      }
596 4
    }
597
598 39
    return $instance[$connection];
599
  }
600
601
  /**
602
   * run a sql-query
603
   *
604
   * @param string        $sql            sql-query string
605
   *
606
   * @param array|boolean $params         a "array" of sql-query-parameters
607
   *                                      "false" if you don't need any parameter
608
   *
609
   * @return bool|int|Result              "Result" by "<b>SELECT</b>"-queries<br />
610
   *                                      "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br />
611
   *                                      "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
612
   *                                      "true" by e.g. "DROP"-queries<br />
613
   *                                      "false" on error
614
   *
615
   * @throws \Exception
616
   */
617 22
  public function query($sql = '', $params = false)
618
  {
619 22
    if (!$this->isReady()) {
620
      return false;
621
    }
622
623 22
    if (!$sql || $sql === '') {
624 4
      $this->_displayError('Can\'t execute an empty Query', false);
625
626 4
      return false;
627
    }
628
629
    if (
630
        $params !== false
631 20
        &&
632 1
        is_array($params)
633 20
        &&
634 1
        count($params) > 0
635 20
    ) {
636 1
      $sql = $this->_parseQueryParams($sql, $params);
637 1
    }
638
639 20
    $query_start_time = microtime(true);
640 20
    $result = mysqli_query($this->link, $sql);
641 20
    $query_duration = microtime(true) - $query_start_time;
642 20
    $this->query_count++;
643
644 20
    $resultCount = 0;
645 20
    if ($result instanceof \mysqli_result) {
646 17
      $resultCount = (int)$result->num_rows;
647 17
    }
648 20
    $this->_logQuery($sql, $query_duration, $resultCount);
649
650
    if (
651
        $result !== null
652 20
        &&
653
        $result instanceof \mysqli_result
654 20
    ) {
655
656
      // return query result object
657 17
      return new Result($sql, $result);
658
659
    } else {
660
      // is the query successful
661 17
      if ($result === true) {
662
663 15
        if (preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE)\s+/i', $sql)) {
664
665
          // it is an "INSERT" || "REPLACE"
666 15
          if ($this->insert_id() > 0) {
667 14
            return (int)$this->insert_id();
668
          }
669
670
          // it is an "UPDATE" || "DELETE"
671 6
          if ($this->affected_rows() > 0) {
672 6
            return (int)$this->affected_rows();
673
          }
674
        }
675
676
        return true;
677
      } else {
678 8
        $this->queryErrorHandling(mysqli_error($this->link), $sql, $params);
679
      }
680
    }
681
682 8
    return false;
683
  }
684
685
  /**
686
   * _parseQueryParams
687
   *
688
   * @param string $sql
689
   * @param array  $params
690
   *
691
   * @return string
692
   */
693 1
  private function _parseQueryParams($sql, array $params)
694
  {
695
696
    // is there anything to parse?
697 1
    if (strpos($sql, '?') === false) {
698
      return $sql;
699
    }
700
701 1
    if (count($params) > 0) {
702 1
      $parseKey = md5(uniqid(mt_rand(), true));
703 1
      $sql = str_replace('?', $parseKey, $sql);
704
705 1
      $k = 0;
706 1
      while (strpos($sql, $parseKey) !== false) {
707 1
        $value = $this->secure($params[$k]);
708 1
        $sql = preg_replace("/$parseKey/", $value, $sql, 1);
709 1
        $k++;
710 1
      }
711 1
    }
712
713 1
    return $sql;
714
  }
715
716
  /**
717
   * secure
718
   *
719
   * @param mixed $var
720
   *
721
   * @return string | null
722
   */
723 14
  public function secure($var)
724
  {
725
    // init
726 14
    if (!is_object($var)) {
727 14
      $varInt = (int)$var;
728 14
    }
729
730 14
    if (is_string($var)) {
731
732 14
      if (!in_array($var, $this->mysqlDefaultTimeFunctions, true)) {
733 14
        $var = "'" . trim($this->escape(trim(trim((string)$var), "'")), "'") . "'";
734 14
      }
735
736 14
    } elseif ((isset($varInt) && "$varInt" == $var) || is_int($var) || is_bool($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...
737
738 12
      $var = (int)$var;
739
740 12 View Code Duplication
    } elseif (is_float($var)) {
741
742 2
      $var = number_format((float)str_replace(',', '.', $var), 8, '.', '');
743
744 2
    } elseif (is_array($var)) {
745
746 1
      $var = null;
747
748 1
    } elseif (($var instanceof \DateTime)) {
749
750
      try {
751 1
        $var = "'" . $this->escape($var->format('Y-m-d H:i:s'), false, false) . "'";
752 1
      } catch (\Exception $e) {
753
        $var = null;
754
      }
755
756 1
    } else {
757
758
      $var = "'" . trim($this->escape(trim(trim((string)$var), "'")), "'") . "'";
759
760
    }
761
762 14
    return $var;
763
  }
764
765
  /**
766
   * escape
767
   *
768
   * @param array|float|int|string|boolean $var boolean: convert into "integer"<br />
769
   *                                            int: convert into "integer"<br />
770
   *                                            float: convert into "float" and replace "," with "."<br />
771
   *                                            array: run escape() for every key => value<br />
772
   *                                            string: run UTF8::cleanup() and mysqli_real_escape_string()<br />
773
   * @param bool                           $stripe_non_utf8
774
   * @param bool                           $html_entity_decode
775
   * @param bool                           $array_to_string
776
   *
777
   * @return array|bool|float|int|string
778
   */
779 17
  public function escape($var = '', $stripe_non_utf8 = true, $html_entity_decode = true, $array_to_string = false)
780
  {
781
782 17
    if (is_int($var) || is_bool($var)) {
783
784
      // int
785
786 3
      return (int)$var;
787
788 17 View Code Duplication
    } elseif (is_float($var)) {
789
790
      // float
791
792 1
      return number_format((float)str_replace(',', '.', $var), 8, '.', '');
793
794 17
    } elseif (is_array($var)) {
795
796
      // array
797
798 1
      $varCleaned = array();
799 1
      foreach ($var as $key => $value) {
800
801 1
        $key = (string)$this->escape($key, $stripe_non_utf8, $html_entity_decode);
802 1
        $value = (string)$this->escape($value, $stripe_non_utf8, $html_entity_decode);
803
804 1
        $varCleaned[$key] = $value;
805 1
      }
806
807 1
      if ($array_to_string === true) {
808 1
        $varCleaned = implode(',', $varCleaned);
809
810 1
        return $varCleaned;
811
      } else {
812 1
        return (array)$varCleaned;
813
      }
814
    }
815
816 17
    if (is_string($var)) {
817
818
      // string
819
820 17
      if ($stripe_non_utf8 === true) {
821 17
        $var = UTF8::cleanup($var);
822 17
      }
823
824 17
      if ($html_entity_decode === true) {
825
        // use no-html-entity for db
826 17
        $var = UTF8::html_entity_decode($var);
827 17
      }
828
829 17
      $var = get_magic_quotes_gpc() ? stripslashes($var) : $var;
830
831 17
      $var = mysqli_real_escape_string($this->getLink(), $var);
832
833 17
      return (string)$var;
834
    } else {
835
      return false;
836
    }
837
  }
838
839
  /**
840
   * getLink
841
   *
842
   * @return \mysqli
843
   */
844 17
  public function getLink()
845
  {
846 17
    return $this->link;
847
  }
848
849
  /**
850
   * _logQuery
851
   *
852
   * @param String $sql     sql-query
853
   * @param int    $duration
854
   * @param int    $results result counter
855
   *
856
   * @return bool
857
   */
858 21
  private function _logQuery($sql, $duration, $results)
859
  {
860 21
    $logLevelUse = strtolower($this->logger_level);
861
862
    if (
863
        $logLevelUse != 'trace'
864 21
        &&
865
        $logLevelUse != 'debug'
866 21
    ) {
867 20
      return false;
868
    }
869
870 1
    $info = 'time => ' . round(
871 1
            $duration,
872
            5
873 1
        ) . ' - ' . 'results => ' . $results . ' - ' . 'SQL => ' . UTF8::htmlentities($sql);
874
875 1
    $fileInfo = $this->getFileAndLineFromSql();
876 1
    $this->logger(
877
        array(
878 1
            'debug',
879 1
            '<strong>' . date(
880
                'd. m. Y G:i:s'
881 1
            ) . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . '):</strong> ' . $info . '<br>',
882 1
            'sql',
883
        )
884 1
    );
885
886 1
    return true;
887
  }
888
889
  /**
890
   * insert_id
891
   *
892
   * @return int|string
893
   */
894 15
  public function insert_id()
895
  {
896 15
    return mysqli_insert_id($this->link);
897
  }
898
899
  /**
900
   * affected_rows
901
   *
902
   * @return int
903
   */
904 6
  public function affected_rows()
905
  {
906 6
    return mysqli_affected_rows($this->link);
907
  }
908
909
  /**
910
   * query error-handling
911
   *
912
   * @param string     $errorMsg
913
   * @param string     $sql
914
   * @param array|bool $sqlParams false if there wasn't any parameter
915
   *
916
   * @throws \Exception
917
   */
918 9
  protected function queryErrorHandling($errorMsg, $sql, $sqlParams = false)
919
  {
920 9
    if ($errorMsg == 'DB server has gone away' || $errorMsg == 'MySQL server has gone away') {
921 1
      static $reconnectCounter;
922
923
      // exit if we have more then 3 "DB server has gone away"-errors
924 1
      if ($reconnectCounter > 3) {
925
        $this->mailToAdmin('SQL-Fatal-Error', $errorMsg . ":\n<br />" . $sql, 5);
926
        throw new \Exception($errorMsg);
927
      } else {
928 1
        $this->mailToAdmin('SQL-Error', $errorMsg . ":\n<br />" . $sql);
929
930
        // reconnect
931 1
        $reconnectCounter++;
932 1
        $this->reconnect(true);
933
934
        // re-run the current query
935 1
        $this->query($sql, $sqlParams);
936
      }
937 1
    } else {
938 8
      $this->mailToAdmin('SQL-Warning', $errorMsg . ":\n<br />" . $sql);
939
940
      // this query returned an error, we must display it (only for dev) !!!
941 8
      $this->_displayError($errorMsg . ' | ' . $sql);
942
    }
943 9
  }
944
945
  /**
946
   * send a error mail to the admin / dev
947
   *
948
   * @param string $subject
949
   * @param string $htmlBody
950
   * @param int    $priority
951
   */
952 9
  private function mailToAdmin($subject, $htmlBody, $priority = 3)
953
  {
954 9
    if (function_exists('mailToAdmin')) {
955
      mailToAdmin($subject, $htmlBody, $priority);
956
    } else {
957
958 9
      if ($priority == 3) {
959 9
        $this->logger(
960
            array(
961 9
                'debug',
962 9
                $subject . ' | ' . $htmlBody,
963
            )
964 9
        );
965 9
      } elseif ($priority > 3) {
966
        $this->logger(
967
            array(
968
                'error',
969
                $subject . ' | ' . $htmlBody,
970
            )
971
        );
972
      } elseif ($priority < 3) {
973
        $this->logger(
974
            array(
975
                'info',
976
                $subject . ' | ' . $htmlBody,
977
            )
978
        );
979
      }
980
981
    }
982 9
  }
983
984
  /**
985
   * reconnect
986
   *
987
   * @param bool $checkViaPing
988
   *
989
   * @return bool
990
   */
991 2
  public function reconnect($checkViaPing = false)
992
  {
993 2
    $ping = false;
994
995 2
    if ($checkViaPing === true) {
996 2
      $ping = $this->ping();
997 2
    }
998
999 2
    if ($ping !== true) {
1000 2
      $this->connected = false;
1001 2
      $this->connect();
1002 2
    }
1003
1004 2
    return $this->isReady();
1005
  }
1006
1007
  /**
1008
   * ping
1009
   *
1010
   * @return boolean
1011
   */
1012 3
  public function ping()
1013
  {
1014
    if (
1015 3
        $this->link
1016 3
        &&
1017 3
        $this->link instanceof \mysqli
1018 3
    ) {
1019
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
1020 3
      return @mysqli_ping($this->link);
1021
    } else {
1022
      return false;
1023
    }
1024
  }
1025
1026
  /**
1027
   * can handel select/insert/update/delete queries
1028
   *
1029
   * @param string $query    sql-query
1030
   * @param bool   $useCache use cache?
1031
   * @param int    $cacheTTL cache-ttl in seconds
1032
   *
1033
   * @return bool|int|array       "array" by "<b>SELECT</b>"-queries<br />
1034
   *                              "int" (insert_id) by "<b>INSERT</b>"-queries<br />
1035
   *                              "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
1036
   *                              "true" by e.g. "DROP"-queries<br />
1037
   *                              "false" on error
1038
   *
1039
   */
1040 3
  public static function execSQL($query, $useCache = false, $cacheTTL = 3600)
1041
  {
1042 3
    $db = self::getInstance();
1043
1044 3
    if ($useCache === true) {
1045 1
      $cache = new Cache(null, null, false, $useCache);
1046 1
      $cacheKey = 'sql-' . md5($query);
1047
1048
      if (
1049 1
          $cache->getCacheIsReady() === true
1050 1
          &&
1051 1
          $cache->existsItem($cacheKey)
1052 1
      ) {
1053 1
        return $cache->getItem($cacheKey);
1054
      }
1055
1056 1
    } else {
1057 3
      $cache = false;
1058
    }
1059
1060 3
    $result = $db->query($query);
1061
1062 3
    if ($result instanceof Result) {
1063
1064 1
      $return = $result->fetchAllArray();
1065
1066
      if (
1067 1
          isset($cacheKey)
1068 1
          &&
1069
          $useCache === true
1070 1
          &&
1071
          $cache instanceof Cache
1072 1
          &&
1073 1
          $cache->getCacheIsReady() === true
1074 1
      ) {
1075 1
        $cache->setItem($cacheKey, $return, $cacheTTL);
1076 1
      }
1077
1078 1
    } else {
1079 2
      $return = $result;
1080
    }
1081
1082 3
    return $return;
1083
  }
1084
1085
  /**
1086
   * get charset
1087
   *
1088
   * @return string
1089
   */
1090 1
  public function get_charset()
1091
  {
1092 1
    return $this->charset;
1093
  }
1094
1095
  /**
1096
   * set charset
1097
   *
1098
   * @param string $charset
1099
   *
1100
   * @return bool
1101
   */
1102 6
  public function set_charset($charset)
1103
  {
1104 6
    $this->charset = (string)$charset;
1105
1106 6
    $return = mysqli_set_charset($this->link, $charset);
1107
    /** @noinspection PhpUsageOfSilenceOperatorInspection */
1108 6
    @mysqli_query($this->link, 'SET CHARACTER SET ' . $charset);
1109
    /** @noinspection PhpUsageOfSilenceOperatorInspection */
1110 6
    @mysqli_query($this->link, "SET NAMES '" . ($charset == 'utf8' ? 'utf8mb4' : $charset) . "'");
1111
1112 6
    return $return;
1113
  }
1114
1115
  /**
1116
   * __wakeup
1117
   *
1118
   * @return void
1119
   */
1120 1
  public function __wakeup()
1121
  {
1122 1
    $this->reconnect();
1123 1
  }
1124
1125
  /**
1126
   * get the names of all tables
1127
   *
1128
   * @return array
1129
   */
1130 1
  public function getAllTables()
1131
  {
1132 1
    $query = 'SHOW TABLES';
1133 1
    $result = $this->query($query);
1134
1135 1
    return $result->fetchAllArray();
1136
  }
1137
1138
  /**
1139
   * run a sql-multi-query
1140
   *
1141
   * @param string $sql
1142
   *
1143
   * @return bool|Result[]                "Result"-Array by "<b>SELECT</b>"-queries<br />
1144
   *                                      "boolean" by only "<b>INSERT</b>"-queries<br />
1145
   *                                      "boolean" by only (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
1146
   *                                      "boolean" by only by e.g. "DROP"-queries<br />
1147
   *
1148
   * @throws \Exception
1149
   */
1150 1
  public function multi_query($sql)
1151
  {
1152 1
    if (!$this->isReady()) {
1153
      return false;
1154
    }
1155
1156 1
    if (!$sql || $sql === '') {
1157 1
      $this->_displayError('Can\'t execute an empty Query', false);
1158
1159 1
      return false;
1160
    }
1161
1162 1
    $query_start_time = microtime(true);
1163 1
    $resultTmp = mysqli_multi_query($this->link, $sql);
1164 1
    $query_duration = microtime(true) - $query_start_time;
1165
1166 1
    $this->_logQuery($sql, $query_duration, 0);
1167
1168 1
    $returnTheResult = false;
1169 1
    $result = array();
1170 1
    if ($resultTmp) {
1171
      do {
1172 1
        $resultTmpInner = mysqli_store_result($this->link);
1173
1174
        if (
1175 1
            null !== $resultTmpInner
1176 1
            &&
1177
            $resultTmpInner instanceof \mysqli_result
1178 1
        ) {
1179 1
          $returnTheResult = true;
1180 1
          $result[] = new Result($sql, $resultTmpInner);
1181 1
        } else {
1182 1
          $errorMsg = mysqli_error($this->link);
1183
1184
          // is the query successful
1185 1
          if ($resultTmpInner === true || !$errorMsg) {
1186 1
            $result[] = true;
1187 1
          } else {
1188
            $result[] = false;
1189
1190
            $this->queryErrorHandling($errorMsg, $sql);
1191
          }
1192
        }
1193 1
      } while (mysqli_more_results($this->link) === true ? mysqli_next_result($this->link) : false);
1194
1195 1
    } else {
1196
1197
      $errorMsg = mysqli_error($this->link);
1198
1199
      if ($this->checkForDev() === true) {
1200
        echo "Info: maybe you have to increase your 'max_allowed_packet = 30M' in the config: 'my.conf' \n<br />";
1201
        echo 'Error:' . $errorMsg;
1202
      }
1203
1204
      $this->mailToAdmin('SQL-Error in mysqli_multi_query', $errorMsg . ":\n<br />" . $sql);
1205
    }
1206
1207
    // return the result only if there was a "SELECT"-query
1208 1
    if ($returnTheResult === true) {
1209 1
      return $result;
1210
    }
1211
1212 1
    if (!in_array(false, $result, true)) {
1213 1
      return true;
1214
    } else {
1215
      return false;
1216
    }
1217
  }
1218
1219
  /**
1220
   * alias for "beginTransaction()"
1221
   */
1222 1
  public function startTransaction()
1223
  {
1224 1
    $this->beginTransaction();
1225 1
  }
1226
1227
  /**
1228
   * Begins a transaction, by turning off auto commit
1229
   *
1230
   * @return boolean this will return true or false indicating success of transaction
1231
   */
1232 4
  public function beginTransaction()
1233
  {
1234 4
    $this->clearErrors();
1235
1236 4
    if ($this->inTransaction() === true) {
1237 1
      $this->_displayError('Error mysql server already in transaction!', true);
1238
1239
      return false;
1240 4
    } elseif (mysqli_connect_errno()) {
1241
      $this->_displayError('Error connecting to mysql server: ' . mysqli_connect_error(), true);
1242
1243
      return false;
1244
    } else {
1245 4
      $this->_in_transaction = true;
1246 4
      mysqli_autocommit($this->link, false);
1247
1248 4
      return true;
1249
1250
    }
1251
  }
1252
1253
  /**
1254
   * clear errors
1255
   *
1256
   * @return bool
1257
   */
1258 4
  public function clearErrors()
1259
  {
1260 4
    $this->_errors = array();
1261
1262 4
    return true;
1263
  }
1264
1265
  /**
1266
   * Check if in transaction
1267
   *
1268
   * @return boolean
1269
   */
1270 4
  public function inTransaction()
1271
  {
1272 4
    return $this->_in_transaction;
1273
  }
1274
1275
  /**
1276
   * Ends a transaction and commits if no errors, then ends autocommit
1277
   *
1278
   * @return boolean this will return true or false indicating success of transactions
1279
   */
1280 2
  public function endTransaction()
1281
  {
1282
1283 2
    if (!$this->errors()) {
1284 1
      mysqli_commit($this->link);
1285 1
      $return = true;
1286 1
    } else {
1287 1
      $this->rollback();
1288 1
      $return = false;
1289
    }
1290
1291 2
    mysqli_autocommit($this->link, true);
1292 2
    $this->_in_transaction = false;
1293
1294 2
    return $return;
1295
  }
1296
1297
  /**
1298
   * get all errors
1299
   *
1300
   * @return array false === on errors
1301
   */
1302 2
  public function errors()
1303
  {
1304 2
    return count($this->_errors) > 0 ? $this->_errors : false;
1305
  }
1306
1307
  /**
1308
   * rollback in a transaction
1309
   */
1310 2
  public function rollback()
1311
  {
1312
    // init
1313 2
    $return = false;
1314
1315 2
    if ($this->_in_transaction === true) {
1316 2
      $return = mysqli_rollback($this->link);
1317 2
      mysqli_autocommit($this->link, true);
1318 2
      $this->_in_transaction = false;
1319 2
    }
1320
1321 2
    return $return;
1322
  }
1323
1324
  /**
1325
   * insert
1326
   *
1327
   * @param string $table
1328
   * @param array  $data
1329
   *
1330
   * @return false|int false on error
1331
   */
1332 14
  public function insert($table, $data = array())
1333
  {
1334 14
    $table = trim($table);
1335
1336 14
    if ($table === '') {
1337 2
      $this->_displayError('invalid-table-name');
1338
1339 1
      return false;
1340
    }
1341
1342 13
    if (count($data) == 0) {
1343 3
      $this->_displayError('empty-data-for-INSERT');
1344
1345 2
      return false;
1346
    }
1347
1348 11
    $SET = $this->_parseArrayPair($data);
1349
1350 11
    $sql = 'INSERT INTO ' . $this->quote_string($table) . " SET $SET;";
1351
1352 11
    return $this->query($sql);
1353
  }
1354
1355
  /**
1356
   * Parses arrays with value pairs and generates SQL to use in queries
1357
   *
1358
   * @param array  $arrayPair
1359
   * @param string $glue this is the separator
1360
   *
1361
   * @return string
1362
   */
1363 12
  private function _parseArrayPair($arrayPair, $glue = ',')
1364
  {
1365
    // init
1366 12
    $sql = '';
1367 12
    $pairs = array();
1368
1369 12
    if (!empty($arrayPair)) {
1370
1371 12
      foreach ($arrayPair as $_key => $_value) {
1372 12
        $_connector = '=';
1373 12
        $_key_upper = strtoupper($_key);
1374
1375 12
        if (strpos($_key_upper, ' NOT') !== false) {
1376 2
          $_connector = 'NOT';
1377 2
        }
1378
1379 12
        if (strpos($_key_upper, ' IS') !== false) {
1380 1
          $_connector = 'IS';
1381 1
        }
1382
1383 12
        if (strpos($_key_upper, ' IS NOT') !== false) {
1384 1
          $_connector = 'IS NOT';
1385 1
        }
1386
1387 12
        if (strpos($_key_upper, ' IN') !== false) {
1388 1
          $_connector = 'IN';
1389 1
        }
1390
1391 12
        if (strpos($_key_upper, ' NOT IN') !== false) {
1392 1
          $_connector = 'NOT IN';
1393 1
        }
1394
1395 12
        if (strpos($_key_upper, ' BETWEEN') !== false) {
1396 1
          $_connector = 'BETWEEN';
1397 1
        }
1398
1399 12
        if (strpos($_key_upper, ' NOT BETWEEN') !== false) {
1400 1
          $_connector = 'NOT BETWEEN';
1401 1
        }
1402
1403 12
        if (strpos($_key_upper, ' LIKE') !== false) {
1404 2
          $_connector = 'LIKE';
1405 2
        }
1406
1407 12
        if (strpos($_key_upper, ' NOT LIKE') !== false) {
1408 2
          $_connector = 'NOT LIKE';
1409 2
        }
1410
1411 12 View Code Duplication
        if (strpos($_key_upper, ' >') !== false && strpos($_key_upper, ' =') === false) {
1412 2
          $_connector = '>';
1413 2
        }
1414
1415 12 View Code Duplication
        if (strpos($_key_upper, ' <') !== false && strpos($_key_upper, ' =') === false) {
1416 1
          $_connector = '<';
1417 1
        }
1418
1419 12
        if (strpos($_key_upper, ' >=') !== false) {
1420 2
          $_connector = '>=';
1421 2
        }
1422
1423 12
        if (strpos($_key_upper, ' <=') !== false) {
1424 1
          $_connector = '<=';
1425 1
        }
1426
1427 12
        if (strpos($_key_upper, ' <>') !== false) {
1428 1
          $_connector = '<>';
1429 1
        }
1430
1431
        if (
1432 12
            is_array($_value)
1433 12
            &&
1434
            (
1435
                $_connector == 'NOT IN'
1436 1
                ||
1437
                $_connector == 'IN'
1438 1
            )
1439 12
        ) {
1440 1
          foreach ($_value as $oldKey => $oldValue) {
1441
            /** @noinspection AlterInForeachInspection */
1442 1
            $_value[$oldKey] = $this->secure($oldValue);
1443 1
          }
1444 1
          $_value = '(' . implode(',', $_value) . ')';
1445 1
        } elseif (
1446 12
            is_array($_value)
1447 12
            &&
1448
            (
1449
                $_connector == 'NOT BETWEEN'
1450 1
                ||
1451
                $_connector == 'BETWEEN'
1452
            )
1453 12
        ) {
1454 1
          foreach ($_value as $oldKey => $oldValue) {
1455
            /** @noinspection AlterInForeachInspection */
1456 1
            $_value[$oldKey] = $this->secure($oldValue);
1457 1
          }
1458 1
          $_value = '(' . implode(' AND ', $_value) . ')';
1459 1
        } else {
1460 12
          $_value = $this->secure($_value);
1461
        }
1462
1463 12
        $quoteString = $this->quote_string(trim(str_ireplace($_connector, '', $_key)));
1464 12
        $pairs[] = ' ' . $quoteString . ' ' . $_connector . ' ' . $_value . " \n";
1465 12
      }
1466
1467 12
      $sql = implode($glue, $pairs);
1468 12
    }
1469
1470 12
    return $sql;
1471
  }
1472
1473
  /**
1474
   * Quote && Escape e.g. a table name string
1475
   *
1476
   * @param string $str
1477
   *
1478
   * @return string
1479
   */
1480 14
  public function quote_string($str)
1481
  {
1482 14
    return '`' . $this->escape($str, false, false) . '`';
1483
  }
1484
1485
  /**
1486
   * get errors
1487
   *
1488
   * @return array
1489
   */
1490 1
  public function getErrors()
1491
  {
1492 1
    return $this->_errors;
1493
  }
1494
1495
  /**
1496
   * replace
1497
   *
1498
   * @param string $table
1499
   * @param array  $data
1500
   *
1501
   * @return false|int false on error
1502
   */
1503 1
  public function replace($table, $data = array())
1504
  {
1505
1506 1
    $table = trim($table);
1507
1508 1
    if ($table === '') {
1509 1
      $this->_displayError('invalid table name');
1510
1511 1
      return false;
1512
    }
1513
1514 1
    if (count($data) == 0) {
1515 1
      $this->_displayError('empty data for REPLACE');
1516
1517 1
      return false;
1518
    }
1519
1520
    // extracting column names
1521 1
    $columns = array_keys($data);
1522 1
    foreach ($columns as $k => $_key) {
1523
      /** @noinspection AlterInForeachInspection */
1524 1
      $columns[$k] = $this->quote_string($_key);
1525 1
    }
1526
1527 1
    $columns = implode(',', $columns);
1528
1529
    // extracting values
1530 1
    foreach ($data as $k => $_value) {
1531
      /** @noinspection AlterInForeachInspection */
1532 1
      $data[$k] = $this->secure($_value);
1533 1
    }
1534 1
    $values = implode(',', $data);
1535
1536 1
    $sql = 'REPLACE INTO ' . $this->quote_string($table) . " ($columns) VALUES ($values);";
1537
1538 1
    return $this->query($sql);
1539
  }
1540
1541
  /**
1542
   * update
1543
   *
1544
   * @param string       $table
1545
   * @param array        $data
1546
   * @param array|string $where
1547
   *
1548
   * @return false|int false on error
1549
   */
1550 5
  public function update($table, $data = array(), $where = '1=1')
1551
  {
1552 5
    $table = trim($table);
1553
1554 5
    if ($table === '') {
1555 1
      $this->_displayError('invalid table name');
1556
1557 1
      return false;
1558
    }
1559
1560 5
    if (count($data) == 0) {
1561 1
      $this->_displayError('empty data for UPDATE');
1562
1563 1
      return false;
1564
    }
1565
1566 5
    $SET = $this->_parseArrayPair($data);
1567
1568 5
    if (is_string($where)) {
1569 1
      $WHERE = $this->escape($where, false, false);
1570 5
    } elseif (is_array($where)) {
1571 4
      $WHERE = $this->_parseArrayPair($where, 'AND');
1572 4
    } else {
1573 1
      $WHERE = '';
1574
    }
1575
1576 5
    $sql = 'UPDATE ' . $this->quote_string($table) . " SET $SET WHERE ($WHERE);";
1577
1578 5
    return $this->query($sql);
1579
  }
1580
1581
  /**
1582
   * delete
1583
   *
1584
   * @param string       $table
1585
   * @param string|array $where
1586
   *
1587
   * @return false|int false on error
1588
   */
1589 1 View Code Duplication
  public function delete($table, $where)
1590
  {
1591
1592 1
    $table = trim($table);
1593
1594 1
    if ($table === '') {
1595 1
      $this->_displayError('invalid table name');
1596
1597 1
      return false;
1598
    }
1599
1600 1
    if (is_string($where)) {
1601 1
      $WHERE = $this->escape($where, false, false);
1602 1
    } elseif (is_array($where)) {
1603 1
      $WHERE = $this->_parseArrayPair($where, 'AND');
1604 1
    } else {
1605 1
      $WHERE = '';
1606
    }
1607
1608 1
    $sql = 'DELETE FROM ' . $this->quote_string($table) . " WHERE ($WHERE);";
1609
1610 1
    return $this->query($sql);
1611
  }
1612
1613
  /**
1614
   * select
1615
   *
1616
   * @param string       $table
1617
   * @param string|array $where
1618
   *
1619
   * @return false|Result false on error
1620
   */
1621 13 View Code Duplication
  public function select($table, $where = '1=1')
1622
  {
1623
1624 13
    if ($table === '') {
1625 1
      $this->_displayError('invalid table name');
1626
1627 1
      return false;
1628
    }
1629
1630 13
    if (is_string($where)) {
1631 3
      $WHERE = $this->escape($where, false, false);
1632 13
    } elseif (is_array($where)) {
1633 11
      $WHERE = $this->_parseArrayPair($where, 'AND');
1634 11
    } else {
1635 1
      $WHERE = '';
1636
    }
1637
1638 13
    $sql = 'SELECT * FROM ' . $this->quote_string($table) . " WHERE ($WHERE);";
1639
1640 13
    return $this->query($sql);
1641
  }
1642
1643
  /**
1644
   * get the last error
1645
   *
1646
   * @return string false on error
1647
   */
1648 1
  public function lastError()
1649
  {
1650 1
    return count($this->_errors) > 0 ? end($this->_errors) : false;
1651
  }
1652
1653
  /**
1654
   * __destruct
1655
   *
1656
   */
1657 1
  public function __destruct()
1658
  {
1659
    // close the connection only if we don't save PHP-SESSION's in DB
1660 1
    if ($this->session_to_db === false) {
1661 1
      $this->close();
1662 1
    }
1663 1
  }
1664
1665
  /**
1666
   * close
1667
   */
1668 3
  public function close()
1669
  {
1670 3
    $this->connected = false;
1671
1672 3
    if ($this->link) {
1673 3
      mysqli_close($this->link);
1674 3
    }
1675 3
  }
1676
1677
  /**
1678
   * prevent the instance from being cloned
1679
   *
1680
   * @return void
1681
   */
1682
  private function __clone()
1683
  {
1684
  }
1685
1686
}
1687