Test Failed
Push — trunk ( 769658...cc4c01 )
by SuperNova.WS
15:09
created

db_mysql::getServerInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
namespace DBAL;
4
5
use mysqli_result;
6
use SN;
7
8
/**
9
 * User: Gorlum
10
 * Date: 01.09.2015
11
 * Time: 15:58
12
 */
13
class db_mysql {
14
  const DB_MYSQL_TRANSACTION_SERIALIZABLE = 'SERIALIZABLE';
15
  const DB_MYSQL_TRANSACTION_REPEATABLE_READ = 'REPEATABLE READ';
16
  const DB_MYSQL_TRANSACTION_READ_COMMITTED = 'READ COMMITTED';
17
  const DB_MYSQL_TRANSACTION_READ_UNCOMMITTED = 'READ UNCOMMITTED';
18
19
  /**
20
   * DB schemes
21
   *
22
   * @var Schema|null $schema
23
   */
24
  protected static $schema = null;
25
26
  /**
27
   * Статус соеднения с MySQL
28
   *
29
   * @var bool
30
   */
31
  public $connected = false;
32
  /**
33
   * Префикс названий таблиц в БД
34
   *
35
   * @var string
36
   */
37
  public $db_prefix = '';
38
  public $dbName = '';
39
  /**
40
   * Настройки БД
41
   *
42
   * @var array
43
   */
44
  protected $dbsettings = [];
45
  /**
46
   * Драйвер для прямого обращения к MySQL
47
   *
48
   * @var db_mysql_v5 $driver
49
   */
50
  public $driver = null;
51
52
  /**
53
   * Общее время запросов
54
   *
55
   * @var float $time_mysql_total
56
   */
57
  public $time_mysql_total = 0.0;
58
59
  /**
60
   * @var bool $inTransaction
61
   */
62
  protected $inTransaction = false;
63
64
  /**
65
   * DBAL\db_mysql constructor.
66
   *
67
   * @param \Core\GlobalContainer $gc
68
   */
69
  public function __construct($gc) {
0 ignored issues
show
Unused Code introduced by
The parameter $gc is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

69
  public function __construct(/** @scrutinizer ignore-unused */ $gc) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
//    $this->transaction = new \DBAL\DbTransaction($gc, $this);
71
//    $this->snCache = new $gc->snCacheClass($gc, $this);
72
//    $this->operator = new DbRowDirectOperator($this);
73
  }
74
75
  /**
76
   * @return Schema
77
   */
78
  public function schema() {
79
    if (!isset(self::$schema)) {
80
      self::$schema = new Schema($this);
81
    }
82
83
    return self::$schema;
84
  }
85
86
  public function load_db_settings() {
87
    $dbsettings = array();
88
89
    require(SN_CONFIG_PATH);
90
91
    $this->setDbSettings($dbsettings);
92
  }
93
94
  public function sn_db_connect($external_db_settings = null) {
95
    $this->db_disconnect();
96
97
    if (!empty($external_db_settings) && is_array($external_db_settings)) {
98
      $this->setDbSettings($external_db_settings);
99
    }
100
101
    if (empty($this->dbsettings)) {
102
      $this->load_db_settings();
103
    }
104
105
    // TODO - фатальные (?) ошибки на каждом шагу. Хотя - скорее Эксепшны
106
    if (!empty($this->dbsettings)) {
107
      $driver_name = 'DBAL\\' . (empty($this->dbsettings['sn_driver']) ? 'db_mysql_v5' : $this->dbsettings['sn_driver']);
108
      $this->driver = new $driver_name();
109
      $this->db_prefix = $this->dbsettings['prefix'];
110
111
      $this->connected = $this->connected || $this->driver_connect();
112
113
      if ($this->connected && empty($this->schema()->getSnTables())) {
114
        die('DB error - cannot find any table. Halting...');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
115
      }
116
117
      $this->doQueryFast('SET SESSION TRANSACTION ISOLATION LEVEL ' . self::DB_MYSQL_TRANSACTION_REPEATABLE_READ);
118
    } else {
119
      $this->connected = false;
120
    }
121
122
    return $this->connected;
123
  }
124
125
  public function driver_connect() {
126
    global $debug;
127
128
    if (!is_object($this->driver)) {
129
      $debug->error_fatal('DB Error - No driver for MySQL found!');
130
    }
131
132
    if (!method_exists($this->driver, 'mysql_connect')) {
133
      $debug->error_fatal('DB Error - WRONG MySQL driver!');
134
    }
135
136
    return $this->driver->mysql_connect($this->dbsettings);
137
  }
138
139
  public function db_disconnect() {
140
    if ($this->connected) {
141
      $this->connected = !$this->driver_disconnect();
142
      $this->connected = false;
143
    }
144
145
    return !$this->connected;
146
  }
147
148
  /**
149
   * @param int    $errno
150
   * @param string $errstr
151
   * @param string $errfile
152
   * @param int    $errline
153
   * @param array  $errcontext
154
   */
155
  public function handlerQueryWarning($errno, $errstr, $errfile, $errline, $errcontext) {
0 ignored issues
show
Unused Code introduced by
The parameter $errfile is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

155
  public function handlerQueryWarning($errno, $errstr, /** @scrutinizer ignore-unused */ $errfile, $errline, $errcontext) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errline is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

155
  public function handlerQueryWarning($errno, $errstr, $errfile, /** @scrutinizer ignore-unused */ $errline, $errcontext) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errcontext is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

155
  public function handlerQueryWarning($errno, $errstr, $errfile, $errline, /** @scrutinizer ignore-unused */ $errcontext) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errno is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

155
  public function handlerQueryWarning(/** @scrutinizer ignore-unused */ $errno, $errstr, $errfile, $errline, $errcontext) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $errstr is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

155
  public function handlerQueryWarning($errno, /** @scrutinizer ignore-unused */ $errstr, $errfile, $errline, $errcontext) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
    static $alreadyHandled;
157
158
    // Error was suppressed with the @-operator
159
    if (0 === error_reporting()) {
160
      return false;
161
    }
162
163
    if (!$alreadyHandled) {
164
      print(SN_TIME_SQL . '<br />Server is busy. Please try again in several minutes...<br />Сервер занят. Попробуйте снова через несколько минут...<br />Server zanyat. Poprobujte snova cherez neskolko minut...');
165
      $alreadyHandled = true;
166
    }
167
168
    return true;
169
  }
170
171
  public function prefixReplace($sql) {
172
    if (strpos($sql, '{{') !== false) {
173
      foreach ($this->schema()->getSnTables() as $tableName) {
174
        $sql = str_replace("{{{$tableName}}}", $this->db_prefix . $tableName, $sql);
175
      }
176
    }
177
178
    return $sql;
179
  }
180
181
  public function doquery($query, $fetch = false, $skip_query_check = false) {
182
    global $numqueries, $debug, $config;
183
184
    if (!$this->connected) {
185
      $this->sn_db_connect();
186
    }
187
188
    $query = trim($query);
189
    $this->security_watch_user_queries($query);
190
    $skip_query_check or $this->security_query_check_bad_words($query);
191
192
    $sql = $this->prefixReplace($query);
193
//    $sql = $query;
194
//    if (strpos($sql, '{{') !== false) {
195
//      foreach ($this->schema()->getSnTables() as $tableName) {
196
//        $sql = str_replace("{{{$tableName}}}", $this->db_prefix . $tableName, $sql);
197
//      }
198
//    }
199
200
    if ($config->debug) {
201
      $numqueries++;
202
      $arr = debug_backtrace();
203
      $file = end(explode('/', $arr[0]['file']));
204
      $line = $arr[0]['line'];
205
      $debug->add("<tr><th>Query $numqueries: </th><th>$query</th><th>$file($line)</th><th>&nbsp;</th><th>$fetch</th></tr>");
206
    }
207
208
    if (defined('DEBUG_SQL_COMMENT')) {
209
      $backtrace = debug_backtrace();
210
      $sql_comment = $debug->compact_backtrace($backtrace, defined('DEBUG_SQL_COMMENT_LONG'));
211
212
      $sql_commented = '/* ' . implode("<br />", $sql_comment) . '<br /> */ ' . preg_replace("/\s+/", ' ', $sql);
213
      if (defined('DEBUG_SQL_ONLINE')) {
214
        $debug->warning($sql_commented, 'SQL Debug', LOG_DEBUG_SQL);
215
      }
216
217
      if (defined('DEBUG_SQL_ERROR')) {
218
        array_unshift($sql_comment, preg_replace("/\s+/", ' ', $sql));
219
        $debug->add_to_array($sql_comment);
220
        // $debug->add_to_array($sql_comment . preg_replace("/\s+/", ' ', $sql));
221
      }
222
      $sql = $sql_commented;
223
    }
224
225
    set_error_handler([$this, 'handlerQueryWarning']);
226
    $sqlquery = $this->db_sql_query($sql);
227
    if(!$sqlquery) {
228
      $debug->error(SN::$db->db_error() . "<br />$sql<br />", 'SQL Error');
229
    }
230
    restore_error_handler();
231
232
    return $fetch ? $this->db_fetch($sqlquery) : $sqlquery;
0 ignored issues
show
Bug introduced by
It seems like $sqlquery can also be of type true; however, parameter $query_result of DBAL\db_mysql::db_fetch() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

232
    return $fetch ? $this->db_fetch(/** @scrutinizer ignore-type */ $sqlquery) : $sqlquery;
Loading history...
233
  }
234
235
  public function doQueryAndFetch($query) {
236
    return $this->doquery($query, true);
237
  }
238
239
  public function doQueryFast($query, $fetch = false) {
240
    $sql = $this->prefixReplace($query);
241
242
    set_error_handler([$this, 'handlerQueryWarning']);
243
    $sqlquery = $this->db_sql_query($sql) or SN::$debug->error(SN::$db->db_error() . "<br />$sql<br />", 'SQL Error');
244
    restore_error_handler();
245
246
    return $fetch ? $this->db_fetch($sqlquery) : $sqlquery;
247
  }
248
249
  /**
250
   * @param string $query
251
   * @param bool   $skip_query_check
252
   *
253
   * @return DbMysqliResultIterator
254
   */
255
  public function selectIterator($query, $skip_query_check = false) {
256
    return new DbMysqliResultIterator($this->doquery($query, false, $skip_query_check));
257
  }
258
259
  /**
260
   * @param string $query
261
   * @param bool   $skip_query_check
262
   *
263
   * @return int|null
264
   */
265
  public function selectValue($query, $skip_query_check = false) {
266
    $row = $this->doquery($query, true, $skip_query_check);
267
268
    return !empty($row) ? intval(reset($row)) : null;
269
  }
270
271
  /**
272
   * @param \DBAL\DbQuery $dbQuery
273
   *
274
   * @return array|null
275
   */
276
  public function dbqSelectAndFetch(\DBAL\DbQuery $dbQuery) {
277
    return $this->doQueryAndFetch($dbQuery->select());
278
  }
279
280
281
  public function security_watch_user_queries($query) {
282
    // TODO Заменить это на новый логгер
283
    global $config, $is_watching, $user, $debug;
284
285
    if (!$is_watching && $config->game_watchlist_array && in_array($user['id'], $config->game_watchlist_array)) {
286
      if (!preg_match('/^(select|commit|rollback|start transaction)/i', $query)) {
287
        $is_watching = true;
288
        $msg = "\$query = \"{$query}\"\n\r";
289
        if (!empty($_POST)) {
290
          $msg .= "\n\r" . dump($_POST, '$_POST');
291
        }
292
        if (!empty($_GET)) {
293
          $msg .= "\n\r" . dump($_GET, '$_GET');
294
        }
295
        $debug->warning($msg, "Watching user {$user['id']}", 399, array('base_dump' => true));
296
        $is_watching = false;
297
      }
298
    }
299
  }
300
301
302
  public function security_query_check_bad_words($query) {
303
    global $user, $dm_change_legit, $mm_change_legit;
304
305
    switch (true) {
306
      case stripos($query, 'RUNCATE TABL') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'RUNCATE TABL') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
307
      case stripos($query, 'ROP TABL') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'ROP TABL') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
308
      case stripos($query, 'ENAME TABL') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'ENAME TABL') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
309
      case stripos($query, 'REATE DATABAS') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'REATE DATABAS') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
310
      case stripos($query, 'REATE TABL') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'REATE TABL') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
311
      case stripos($query, 'ET PASSWOR') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'ET PASSWOR') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
312
      case stripos($query, 'EOAD DAT') != false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'EOAD DAT') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
313
      case stripos($query, 'RPG_POINTS') != false && stripos(trim($query), 'UPDATE ') === 0 && !$dm_change_legit:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'RPG_POINTS') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
314
      case stripos($query, 'METAMATTER') != false && stripos(trim($query), 'UPDATE ') === 0 && !$mm_change_legit:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'METAMATTER') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
315
      case stripos($query, 'AUTHLEVEL') != false && $user['authlevel'] < 3 && stripos($query, 'SELECT') !== 0:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($query, 'AUTHLEVEL') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
316
        $report = "Hacking attempt (" . date("d.m.Y H:i:s") . " - [" . time() . "]):\n";
317
        $report .= ">Database Inforamation\n";
318
        $report .= "\tID - " . $user['id'] . "\n";
319
        $report .= "\tUser - " . $user['username'] . "\n";
320
        $report .= "\tAuth level - " . $user['authlevel'] . "\n";
321
        $report .= "\tAdmin Notes - " . $user['adminNotes'] . "\n";
322
        $report .= "\tCurrent Planet - " . $user['current_planet'] . "\n";
323
        $report .= "\tUser IP - " . $user['user_lastip'] . "\n";
324
        $report .= "\tUser IP at Reg - " . $user['ip_at_reg'] . "\n";
325
        $report .= "\tUser Agent- " . $_SERVER['HTTP_USER_AGENT'] . "\n";
326
        $report .= "\tCurrent Page - " . $user['current_page'] . "\n";
327
        $report .= "\tRegister Time - " . $user['register_time'] . "\n";
328
        $report .= "\n";
329
330
        $report .= ">Query Information\n";
331
        $report .= "\tQuery - " . $query . "\n";
332
        $report .= "\n";
333
334
        $report .= ">\$_SERVER Information\n";
335
        $report .= "\tIP - " . $_SERVER['REMOTE_ADDR'] . "\n";
336
        $report .= "\tHost Name - " . $_SERVER['HTTP_HOST'] . "\n";
337
        $report .= "\tUser Agent - " . $_SERVER['HTTP_USER_AGENT'] . "\n";
338
        $report .= "\tRequest Method - " . $_SERVER['REQUEST_METHOD'] . "\n";
339
        $report .= "\tCame From - " . $_SERVER['HTTP_REFERER'] . "\n";
340
        $report .= "\tPage is - " . $_SERVER['SCRIPT_NAME'] . "\n";
341
        $report .= "\tUses Port - " . $_SERVER['REMOTE_PORT'] . "\n";
342
        $report .= "\tServer Protocol - " . $_SERVER['SERVER_PROTOCOL'] . "\n";
343
344
        $report .= "\n--------------------------------------------------------------------------------------------------\n";
345
346
        $fp = fopen(SN_ROOT_PHYSICAL . 'badqrys.txt', 'a');
347
        fwrite($fp, $report);
348
        fclose($fp);
349
350
        $message = 'Привет, я не знаю то, что Вы пробовали сделать, но команда, которую Вы только послали базе данных, не выглядела очень дружественной и она была заблокированна.<br /><br />Ваш IP, и другие данные переданны администрации сервера. Удачи!.';
351
        die($message);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
352
      break;
353
    }
354
  }
355
356
  public function mysql_get_table_list() {
357
    return $this->db_sql_query('SHOW TABLES;');
358
  }
359
360
  public function mysql_get_innodb_status() {
361
    return $this->db_sql_query('SHOW ENGINE INNODB STATUS;');
362
  }
363
364
  /**
365
   * @param string $tableName_unsafe
366
   *
367
   * @return array[]
368
   */
369
  public function mysql_get_fields($tableName_unsafe) {
370
    $result = [];
371
372
    $prefixedTableName_safe = $this->db_escape($this->db_prefix . $tableName_unsafe);
373
    $q1 = $this->db_sql_query("SHOW FULL COLUMNS FROM `{$prefixedTableName_safe}`;");
374
    while ($r1 = db_fetch($q1)) {
375
      $dbf = new DbFieldDescription();
376
      $dbf->fromMySqlDescription($r1);
377
378
      $result[$r1['Field']] = $dbf;
379
    }
380
381
    return $result;
382
  }
383
384
  /**
385
   * @param string $tableName_unsafe
386
   *
387
   * @return DbIndexDescription[]
388
   */
389
  public function mysql_get_indexes($tableName_unsafe) {
390
    /**
391
     * @var DbIndexDescription[] $result
392
     */
393
    $result = [];
394
395
    $prefixedTableName_safe = $this->db_escape($this->db_prefix . $tableName_unsafe);
396
    $q1 = $this->db_sql_query("SHOW INDEX FROM {$prefixedTableName_safe};");
397
    while ($r1 = db_fetch($q1)) {
398
      $indexName = $r1['Key_name'];
399
      if(empty($result[$indexName])) {
400
        $result[$indexName] = new DbIndexDescription();
401
      }
402
      $result[$indexName]->addField($r1);
403
    }
404
405
    return $result;
406
  }
407
408
  /**
409
   * @param string $tableName_unsafe
410
   *
411
   * @return array[]
412
   */
413
  public function mysql_get_constraints($tableName_unsafe) {
414
    $result = [];
415
416
    $prefixedTableName_safe = $this->db_escape($this->db_prefix . $tableName_unsafe);
417
418
    $q1 = $this->db_sql_query("SELECT * FROM `information_schema`.`KEY_COLUMN_USAGE` WHERE `TABLE_SCHEMA` = '" . SN::$db->db_escape(SN::$db_name) . "' AND `TABLE_NAME` = '{$prefixedTableName_safe}' AND `REFERENCED_TABLE_NAME` IS NOT NULL;");
419
    while ($r1 = db_fetch($q1)) {
420
      $indexName = $r1['CONSTRAINT_NAME'];
421
422
      $table_referenced = str_replace($this->db_prefix, '', $r1['REFERENCED_TABLE_NAME']);
423
424
      $result[$indexName]['name'] = $indexName;
425
      $result[$indexName]['signature'][] = "{$r1['COLUMN_NAME']}=>{$table_referenced}.{$r1['REFERENCED_COLUMN_NAME']}";
426
      $r1['REFERENCED_TABLE_NAME'] = $table_referenced;
427
      $r1['TABLE_NAME'] = $tableName_unsafe;
428
      $result[$indexName]['fields'][$r1['COLUMN_NAME']] = $r1;
429
    }
430
431
    foreach ($result as &$constraint) {
432
      $constraint['signature'] = implode(',', $constraint['signature']);
433
    }
434
435
    return $result;
436
  }
437
438
439
  public function db_sql_query($query_string) {
440
    $microtime = microtime(true);
441
    $result = $this->driver->mysql_query($query_string);
442
    $this->time_mysql_total += microtime(true) - $microtime;
443
444
    return $result;
445
//    return $this->driver->mysql_query($query_string);
446
  }
447
448
  /**
449
   * @param mysqli_result $query_result
450
   *
451
   * @return array|null
452
   */
453
  public function db_fetch(&$query_result) {
454
    $microtime = microtime(true);
455
    $result = $this->driver->mysql_fetch_assoc($query_result);
456
    $this->time_mysql_total += microtime(true) - $microtime;
457
458
    return $result;
459
//    return $this->driver->mysql_fetch_assoc($query);
460
  }
461
462
  public function db_fetch_row(&$query) {
463
    return $this->driver->mysql_fetch_row($query);
464
  }
465
466
  public function db_escape($unescaped_string) {
467
    return $this->driver->mysql_real_escape_string($unescaped_string);
468
  }
469
470
  public function driver_disconnect() {
471
    return $this->driver->mysql_close_link();
472
  }
473
474
  public function db_error() {
475
    return $this->driver->mysql_error();
476
  }
477
478
  /**
479
   * @return int|string
480
   */
481
  public function db_insert_id() {
482
    return $this->driver->mysql_insert_id();
483
  }
484
485
  public function db_num_rows(&$result) {
486
    return $this->driver->mysql_num_rows($result);
487
  }
488
489
  public function db_affected_rows() {
490
    return $this->driver->mysql_affected_rows();
491
  }
492
493
  public function getClientInfo() {
494
    return $this->driver->mysql_get_client_info();
495
  }
496
497
  public function getServerInfo() {
498
    return $this->driver->mysql_get_server_info();
499
  }
500
501
  public function getHostInfo() {
502
    return $this->driver->mysql_get_host_info();
503
  }
504
505
  public function getServerStat() {
506
    return $this->driver->mysql_stat();
507
  }
508
509
  /**
510
   * @param array $dbSettings
511
   */
512
  public function setDbSettings($dbSettings) {
513
    $this->dbsettings = $dbSettings;
514
    $this->dbName = $this->dbsettings['name'];
515
516
    return $this;
517
  }
518
519
  public function getDbSettings() {
520
    return $this->dbsettings;
521
  }
522
523
  public function transactionStart($level = '') {
524
    $this->inTransaction = true;
525
526
    if ($level) {
527
      $this->db_sql_query("SET TRANSACTION ISOLATION LEVEL {$level};");
528
    }
529
530
    $this->db_sql_query('START TRANSACTION;');
531
  }
532
533
  public function transactionCommit() {
534
    $this->db_sql_query('COMMIT;');
535
    $this->inTransaction = false;
536
  }
537
538
  public function transactionRollback() {
539
    $this->db_sql_query('ROLLBACK;');
540
    $this->inTransaction = false;
541
  }
542
543
  /**
544
   * Check if transaction started
545
   *
546
   * @return bool
547
   */
548
  public function transactionCheck() {
549
    return $this->inTransaction;
550
  }
551
552
  /**
553
   * Wrap callback in transaction
554
   *
555
   * @param callable $callback
556
   * @param string   $level
557
   *
558
   * @return mixed
559
   */
560
  public function transactionWrap($callback, $level = '') {
561
    $this->transactionStart($level);
562
    $result = $callback();
563
    $this->transactionCommit();
564
565
    return $result;
566
  }
567
}
568