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

DB::execSQL()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 44
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 9

Importance

Changes 10
Bugs 2 Features 1
Metric Value
c 10
b 2
f 1
dl 0
loc 44
ccs 26
cts 26
cp 1
rs 4.909
cc 9
eloc 27
nc 7
nop 3
crap 9
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