Completed
Push — work-fleets ( 006942...3604bd )
by SuperNova.WS
06:54
created

db_mysql::doUpdateAdjust()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
use \DBAL\DbQuery;
4
use \DBAL\DbTransaction;
5
6
/**
7
 * Created by Gorlum 01.09.2015 15:58
8
 */
9
class db_mysql {
10
  const TRANSACTION_SERIALIZABLE = 'SERIALIZABLE';
11
  const TRANSACTION_REPEATABLE_READ = 'REPEATABLE READ';
12
  const TRANSACTION_READ_COMMITTED = 'READ COMMITTED';
13
  const TRANSACTION_READ_UNCOMMITTED = 'READ UNCOMMITTED';
14
15
  /**
16
   * Статус соеднения с MySQL
17
   *
18
   * @var bool
19
   */
20
  public $connected = false;
21
  /**
22
   * Префикс названий таблиц в БД
23
   *
24
   * @var string
25
   */
26
  public $db_prefix = '';
27
  /**
28
   * Список таблиц в БД
29
   *
30
   * @var array
31
   */
32
  public $table_list = array();
33
34
  /**
35
   * Настройки БД
36
   *
37
   * @var array
38
   */
39
  protected $dbsettings = array();
40
  /**
41
   * Драйвер для прямого обращения к MySQL
42
   *
43
   * @var db_mysql_v5 $driver
44
   */
45
  public $driver = null;
46
47
  /**
48
   * Общее время запросов
49
   *
50
   * @var float $time_mysql_total
51
   */
52
  public $time_mysql_total = 0.0;
53
54
  /**
55
   * Amount of queries on this DB
56
   *
57
   * @var int
58
   */
59
  public $queryCount = 0;
60
61
  public $isWatching = false;
62
63
  /**
64
   * @var \DBAL\DbTransaction $transaction
65
   */
66
  protected $transaction;
67
68
  /**
69
   * Should query check be skipped?
70
   *
71
   * Used for altering scheme of DB
72
   *
73
   * @var bool $skipQueryCheck
74
   */
75
  protected $skipQueryCheck = false;
76
77
  /**
78
   * @var SnCache $snCache
79
   */
80
  public $snCache;
81
82
  /**
83
   * @var DbRowDirectOperator $operator
84
   */
85
  protected $operator;
86
87
  /**
88
   * db_mysql constructor.
89
   *
90
   * @param \Common\GlobalContainer $gc
91
   */
92
  public function __construct($gc) {
93
    $this->transaction = new \DBAL\DbTransaction($gc, $this);
94
    $this->snCache = new $gc->snCacheClass($gc, $this);
95
    $this->operator = new DbRowDirectOperator($this);
96
  }
97
98
  public function load_db_settings($configFile = '') {
99
    $dbsettings = array();
100
101
    empty($configFile) ? $configFile = SN_ROOT_PHYSICAL . "config" . DOT_PHP_EX : false;
102
103
    require $configFile;
104
105
    $this->dbsettings = $dbsettings;
106
  }
107
108
  /**
109
   * @param null|array $external_db_settings
110
   *
111
   * @return bool
112
   */
113
  public function sn_db_connect($external_db_settings = null) {
114
    $this->db_disconnect();
115
116
    if (is_array($external_db_settings) && !empty($external_db_settings)) {
117
      $this->dbsettings = $external_db_settings;
118
    }
119
120
    if (empty($this->dbsettings)) {
121
      $this->load_db_settings(SN_ROOT_PHYSICAL . "config.php");
122
    }
123
124
    // TODO - фатальные (?) ошибки на каждом шагу. Хотя - скорее Эксепшны
125
    if (!empty($this->dbsettings)) {
126
      $driver_name = empty($this->dbsettings['sn_driver']) ? 'db_mysql_v5' : $this->dbsettings['sn_driver'];
127
      $this->driver = new $driver_name();
128
      $this->db_prefix = $this->dbsettings['prefix'];
129
130
      $this->connected = $this->connected || $this->driver_connect();
131
132
      if ($this->connected) {
133
        $this->table_list = $this->db_get_table_list();
134
        // TODO Проверка на пустоту
135
      }
136
    } else {
137
      $this->connected = false;
138
    }
139
140
    return $this->connected;
141
  }
142
143
  protected function driver_connect() {
144
    if (!is_object($this->driver)) {
145
      classSupernova::$debug->error_fatal('DB Error - No driver for MySQL found!');
146
    }
147
148
    if (!method_exists($this->driver, 'mysql_connect')) {
149
      classSupernova::$debug->error_fatal('DB Error - WRONG MySQL driver!');
150
    }
151
152
    return $this->driver->mysql_connect($this->dbsettings);
153
  }
154
155
  public function db_disconnect() {
156
    if ($this->connected) {
157
      $this->connected = !$this->driver_disconnect();
158
      $this->connected = false;
159
    }
160
161
    return !$this->connected;
162
  }
163
164
  /**
165
   * @param string $query
166
   *
167
   * @return mixed|string
168
   */
169
  public function replaceTablePlaceholders($query) {
170
    $sql = $query;
171
    if (strpos($sql, '{{') !== false) {
172
      foreach ($this->table_list as $tableName) {
173
        $sql = str_replace("{{{$tableName}}}", $this->db_prefix . $tableName, $sql);
174
      }
175
    }
176
177
    return $sql;
178
  }
179
180
  /**
181
   * @param $query
182
   */
183
  protected function logQuery($query) {
184
    if (!classSupernova::$config->debug) {
185
      return;
186
    }
187
188
    $this->queryCount++;
189
    $arr = debug_backtrace();
190
    $file = end(explode('/', $arr[0]['file']));
0 ignored issues
show
Bug introduced by
explode('/', $arr[0]['file']) cannot be passed to end() as the parameter $array expects a reference.
Loading history...
191
    $line = $arr[0]['line'];
192
    classSupernova::$debug->add("<tr><th>Query {$this->queryCount}: </th><th>$query</th><th>{$file} @ {$line}</th><th>&nbsp;</th></tr>");
193
  }
194
195
196
  /**
197
   * @return string
198
   */
199
  public function traceQuery() {
200
    if (!defined('DEBUG_SQL_COMMENT') || constant('DEBUG_SQL_ERROR') !== true) {
201
      return '';
202
    }
203
204
    $backtrace = debug_backtrace();
205
    $sql_comment = classSupernova::$debug->compact_backtrace($backtrace, defined('DEBUG_SQL_COMMENT_LONG'));
206
207
    if (defined('DEBUG_SQL_ERROR') && constant('DEBUG_SQL_ERROR') === true) {
208
      classSupernova::$debug->add_to_array($sql_comment);
209
    }
210
211
    $sql_commented = implode("\r\n", $sql_comment);
212
    if (defined('DEBUG_SQL_ONLINE') && constant('DEBUG_SQL_ONLINE') === true) {
213
      classSupernova::$debug->warning($sql_commented, 'SQL Debug', LOG_DEBUG_SQL);
214
    }
215
216
    return $sql_commented;
217
  }
218
219
  /**
220
   * @param string $query
221
   *
222
   * @return array|bool|mysqli_result|null
223
   */
224
  protected function queryDriver($query) {
225
    if (!$this->connected) {
226
      $this->sn_db_connect();
227
    }
228
229
    $stringQuery = $query;
230
    $stringQuery = trim($stringQuery);
231
    // You can't do it - 'cause you can break commented statement with line-end comments
232
    // $stringQuery = preg_replace("/\s+/", ' ', $stringQuery);
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
233
234
    $this->security_watch_user_queries($stringQuery);
235
    $this->security_query_check_bad_words($stringQuery);
236
    $this->logQuery($stringQuery);
237
238
    $stringQuery = $this->replaceTablePlaceholders($stringQuery);
239
240
    $queryTrace = $this->traceQuery();
241
242
    $queryResult = null;
243
    try {
244
      $queryResult = $this->db_sql_query($stringQuery . DbSqlHelper::quoteComment($queryTrace));
245
      if (!$queryResult) {
246
        throw new Exception();
247
      }
248
    } catch (Exception $e) {
249
      classSupernova::$debug->error($this->db_error() . "<br />{$query}<br />", 'SQL Error');
250
    }
251
252
    return $queryResult;
253
  }
254
255
256
  // Just wrappers to distinguish query types
257
  /**
258
   * Executes non-data manipulation statements
259
   *
260
   * Can execute queries with check skip
261
   * Honor current state of query checking
262
   *
263
   * @param string $query
264
   * @param bool   $skip_query_check
265
   *
266
   * @return array|bool|mysqli_result|null
267
   */
268
  public function doSql($query, $skip_query_check = false) {
269
    $prevState = $this->skipQueryCheck;
270
    $this->skipQueryCheck = $skip_query_check;
271
    // TODO - disable watch ??
272
    $result = $this->queryDriver($query);
273
    $this->skipQueryCheck = $prevState;
274
275
    return $result;
276
  }
277
278
279
  // TODO - should be in DbRowDirectOperator eventually
280
  // SQL operations ====================================================================================================
281
  // SELECTS -----------------------------------------------------------------------------------------------------------
282
  public function doSelect($query) {
283
    return $this->doSql($query);
284
  }
285
286
  /**
287
   * DANGER! Fields and Where can be danger
288
   *
289
   * @param string $table
290
   * @param array  $fields
291
   * @param array  $where
292
   * @param bool   $isOneRecord
293
   *
294
   * @return array|bool|mysqli_result|null
295
   *
296
   * TODO - replace with appropriate DbQuery when it's be ready
297
   */
298
  public function doSelectDanger($table, $fields, $where = array(), $isOneRecord = DB_RECORDS_ALL, $forUpdate = DB_SELECT_PLAIN) {
299
    // TODO - TEMPORARY UNTIL DbQuery
300
    if (!empty($where)) {
301
      foreach ($where as $key => &$value) {
302
        if (!is_int($key)) {
303
          $value = "`$key` = '" . $this->db_escape($value) . "'";
304
        }
305
      }
306
    }
307
308
    $query =
309
      "SELECT " . implode(',', $fields) .
310
      " FROM `{{{$table}}}`" .
311
      (!empty($where) ? ' WHERE ' . implode(' AND ', $where) : '') .
312
      ($isOneRecord == DB_RECORD_ONE ? ' LIMIT 1' : '') .
313
      ($forUpdate == DB_SELECT_FOR_UPDATE ? ' FOR UPDATE' : '');
314
315
    return $this->doSql($query);
316
  }
317
318
  /**
319
   * @param string $strSql
320
   *
321
   * @return array|null
322
   *
323
   * @deprecated
324
   * TODO - УДАЛИТЬ
325
   * Метод временно находится здесь - слишком много переписывать, что бы его отсюда вынести
326
   */
327
  public function doSelectFetchArray($strSql) {
328
    return $this->operator->doSelectFetchArray($strSql);
329
  }
330
331
332
333
  //
334
  // INSERT/REPLACE ----------------------------------------------------------------------------------------------------
335
  public function doInsertComplex($query) {
336
    return $this->doSql($query);
337
  }
338
339
  // TODO - batch insert and replace here
340
  // перед тем, как переделывать данные из депрекейтов - убедится, что
341
  // null - это null, а не строка'NULL'
342
343
  /**
344
   * @param string        $table
345
   * @param array|array[] $valuesOptionallyKeyByFields
346
   * @param array         $fields
347
   *
348
   * @param int           $replace - DB_INSERT_PLAIN || DB_INSERT_IGNORE
349
   *
350
   * @return array|bool|mysqli_result|null TODO - избаватьися от $fields. Это поле нужно только при пакетной вставке - а поля вполне можно брать из общего массива
351
   * TODO - избаватьися от $fields. Это поле нужно только при пакетной вставке - а поля вполне можно брать из общего массива
352
   */
353
  public function doInsertSet($table, $valuesOptionallyKeyByFields, $fields = array(), $replace = DB_INSERT_PLAIN) {
354
    $query = DbQuery::build($this)
355
      ->setTable($table)
356
      ->setFields($fields)
357
      ->setValues($valuesOptionallyKeyByFields)
358
      ->insert($replace);
359
360
    return $this->doSql($query);
361
  }
362
363
  /**+
364
   * Values should be passed as array of arrays
365
   *
366
   * @param string  $table
367
   * @param array[] $valuesBatch
368
   * @param array   $fields
369
   *
370
   * @param int     $replace
371
   *
372
   * @return array|bool|mysqli_result|null
373
   */
374
  public function doInsertBatch($table, &$valuesBatch, $fields, $replace) {
375
    return $this->doInsertSet($table, $valuesBatch, $fields, $replace);
376
  }
377
378
  // Just to separate INSERTS from REPLACES
379
  /**
380
   * Replaces record in DB
381
   *
382
   * There are no DANGER replace operations
383
   *
384
   * @param string $table
385
   * @param array  $fieldsAndValues
386
   *
387
   * @return array|bool|mysqli_result|null
388
   */
389
  public function doReplaceSet($table, $fieldsAndValues) {
390
    return $this->doInsertSet($table, $fieldsAndValues, array(), DB_INSERT_REPLACE);
391
  }
392
393
394
  //
395
  // UPDATERS
396
  // Deprecated
397
  public function doUpdateAdjust($strSql) {
398
    return $this->doSql($strSql);
399
  }
400
401
  public function doUpdateReallyComplex($query) {
402
    return $this->doSql($query);
403
  }
404
405
  /**
406
   * Executes self-contained SQL UPDATE query
407
   *
408
   * Self-contained - means no params used
409
   * Such queries usually used to make large amount of in-base calculations
410
   *
411
   * @param $query
412
   *
413
   * @return array|bool|mysqli_result|null
414
   */
415
  public function doUpdateSqlNoParam($query) {
416
    return $this->doSql($query);
417
  }
418
419
420
  /**
421
   * @param $DbQuery DbQuery
422
   */
423
  protected function doUpdateDbQuery($DbQuery) {
424
    return $this->doSql($DbQuery->update());
425
  }
426
427
  /**
428
   * @param $DbQuery DbQuery
429
   */
430
  public function doUpdateDbQueryAdjust($DbQuery) {
431
    return $this->doUpdateDbQuery($DbQuery);
432
  }
433
434
435
  protected function doUpdateWhere($table, $fieldsSet, $fieldsAdjust = array(), $where = array(), $isOneRecord = DB_RECORDS_ALL, $whereDanger = array()) {
436
    $query = DbQuery::build($this)
437
      ->setTable($table)
438
      ->setValues($fieldsSet)
439
      ->setAdjust($fieldsAdjust)
440
      // TODO - separate danger WHEREs
441
      ->setWhereArray($where)
442
      ->setWhereArrayDanger($whereDanger)
443
      ->setOneRow($isOneRecord)
444
      ->update();
445
446
    return $this->doSql($query);
447
  }
448
449
  public function doUpdateRowSet($table, $fieldsAndValues, $where) {
450
    return $this->doUpdateWhere($table, $fieldsAndValues, array(), $where, DB_RECORD_ONE);
451
  }
452
453
  public function doUpdateTableSet($table, $fieldsAndValues, $where = array()) {
454
    return $this->doUpdateWhere($table, $fieldsAndValues, array(), $where, DB_RECORDS_ALL);
455
  }
456
457
  public function doUpdateRowAdjust($table, $fieldsSet, $fieldsAdjust, $where) {
458
    return $this->doUpdateWhere($table, $fieldsSet, $fieldsAdjust, $where, DB_RECORD_ONE);
459
  }
460
461
  public function doUpdateTableAdjust($table, $fieldsSet, $fieldsAdjust, $where, $whereDanger = array()) {
462
    return $this->doUpdateWhere($table, $fieldsSet, $fieldsAdjust, $where, DB_RECORDS_ALL, $whereDanger);
463
  }
464
465
466
  //
467
  // DELETERS ----------------------------------------------------------------------------------------------------------
468
  /**
469
   * @param string $table
470
   * @param array  $where
471
   * @param bool   $isOneRecord
472
   *
473
   * @return DbQuery
474
   */
475
  protected function buildDeleteQuery($table, $where, $isOneRecord = DB_RECORDS_ALL) {
476
    return
477
      DbQuery::build($this)
478
        ->setTable($table)
479
        ->setWhereArray($where)
480
        ->setOneRow($isOneRecord);
481
  }
482
483
  /**
484
   * @param string $table
485
   * @param array  $where - simple WHERE statement list which can be combined with AND
486
   * @param bool   $isOneRecord
487
   *
488
   * @return array|bool|mysqli_result|null
489
   */
490
  public function doDeleteWhere($table, $where, $isOneRecord = DB_RECORDS_ALL) {
491
    return
492
      $this->doSql(
493
        $this->buildDeleteQuery($table, $where, $isOneRecord)
494
          ->delete()
495
      );
496
  }
497
498
  /**
499
   * Early deprecated function for complex delete conditions
500
   *
501
   * Used for malformed $where conditions
502
   * Also whereDanger can contain references for other {{tables}}
503
   *
504
   * @param string $table
505
   * @param array  $where
506
   * @param array  $whereDanger
507
   *
508
   * @return array|bool|mysqli_result|null
509
   * @deprecated
510
   */
511
  public function doDeleteDanger($table, $where, $whereDanger) {
512
    return
513
      $this->doSql(
514
        $this->buildDeleteQuery($table, $where, DB_RECORDS_ALL)
515
          ->setWhereArrayDanger($whereDanger)
516
          ->delete()
517
      );
518
  }
519
520
  /**
521
   * @param string $table
522
   * @param array  $where - simple WHERE statement list which can be combined with AND
523
   *
524
   * @return array|bool|mysqli_result|null
525
   */
526
  public function doDeleteRow($table, $where) {
527
    return $this->doDeleteWhere($table, $where, DB_RECORD_ONE);
528
  }
529
530
  /**
531
   * Perform simple delete queries on fixed tables w/o params
532
   *
533
   * @param string $query
534
   *
535
   * @return array|bool|mysqli_result|null
536
   */
537
  public function doDeleteSql($query) {
538
    return $this->doSql($query);
539
  }
540
541
542
  // LOCKERS ----------------------------------------------------------------------------------------------------------
543
  /**
544
   * @param DbQueryConstructor $stmt
545
   * @param bool               $skip_query_check
546
   */
547
  public function doStmtLockAll($stmt, $skip_query_check = false) {
548
    $this->doSql(
549
      $stmt
550
        ->select()
551
        ->field(1)
552
        ->setForUpdate()
553
        ->__toString(),
554
      $skip_query_check
555
    );
556
  }
557
558
559
  //
560
  // OTHER FUNCTIONS ----------------------------------------------------------------------------------------------------------
561
  // TODO Заменить это на новый логгер
562
  protected function security_watch_user_queries($query) {
563
    global $user;
564
565
    if (
566
      !$this->isWatching // Not already watching
567
      && !empty(classSupernova::$config->game_watchlist_array) // There is some players in watchlist
568
      && in_array($user['id'], classSupernova::$config->game_watchlist_array) // Current player is in watchlist
569
      && !preg_match('/^(select|commit|rollback|start transaction)/i', $query) // Current query should be watched
570
    ) {
571
      $this->isWatching = true;
572
      $msg = "\$query = \"{$query}\"\n\r";
573
      if (!empty($_POST)) {
574
        $msg .= "\n\r" . dump($_POST, '$_POST');
575
      }
576
      if (!empty($_GET)) {
577
        $msg .= "\n\r" . dump($_GET, '$_GET');
578
      }
579
      classSupernova::$debug->warning($msg, "Watching user {$user['id']}", 399, array('base_dump' => true));
580
      $this->isWatching = false;
581
    }
582
  }
583
584
585
  public function security_query_check_bad_words($query) {
586
    if ($this->skipQueryCheck) {
587
      return;
588
    }
589
590
    global $user, $dm_change_legit, $mm_change_legit;
591
592
    switch(true) {
593
      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...
594
      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...
595
      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...
596
      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...
597
      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...
598
      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...
599
      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...
600
      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...
601
      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...
602
      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...
603
        $report = "Hacking attempt (" . date("d.m.Y H:i:s") . " - [" . time() . "]):\n";
604
        $report .= ">Database Inforamation\n";
605
        $report .= "\tID - " . $user['id'] . "\n";
606
        $report .= "\tUser - " . $user['username'] . "\n";
607
        $report .= "\tAuth level - " . $user['authlevel'] . "\n";
608
        $report .= "\tAdmin Notes - " . $user['adminNotes'] . "\n";
609
        $report .= "\tCurrent Planet - " . $user['current_planet'] . "\n";
610
        $report .= "\tUser IP - " . $user['user_lastip'] . "\n";
611
        $report .= "\tUser IP at Reg - " . $user['ip_at_reg'] . "\n";
612
        $report .= "\tUser Agent- " . $_SERVER['HTTP_USER_AGENT'] . "\n";
613
        $report .= "\tCurrent Page - " . $user['current_page'] . "\n";
614
        $report .= "\tRegister Time - " . $user['register_time'] . "\n";
615
        $report .= "\n";
616
617
        $report .= ">Query Information\n";
618
        $report .= "\tQuery - " . $query . "\n";
619
        $report .= "\n";
620
621
        $report .= ">\$_SERVER Information\n";
622
        $report .= "\tIP - " . $_SERVER['REMOTE_ADDR'] . "\n";
623
        $report .= "\tHost Name - " . $_SERVER['HTTP_HOST'] . "\n";
624
        $report .= "\tUser Agent - " . $_SERVER['HTTP_USER_AGENT'] . "\n";
625
        $report .= "\tRequest Method - " . $_SERVER['REQUEST_METHOD'] . "\n";
626
        $report .= "\tCame From - " . $_SERVER['HTTP_REFERER'] . "\n";
627
        $report .= "\tPage is - " . $_SERVER['SCRIPT_NAME'] . "\n";
628
        $report .= "\tUses Port - " . $_SERVER['REMOTE_PORT'] . "\n";
629
        $report .= "\tServer Protocol - " . $_SERVER['SERVER_PROTOCOL'] . "\n";
630
631
        $report .= "\n--------------------------------------------------------------------------------------------------\n";
632
633
        $fp = fopen(SN_ROOT_PHYSICAL . 'badqrys.txt', 'a');
634
        fwrite($fp, $report);
0 ignored issues
show
Security File Manipulation introduced by
$report can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

7 paths for user data to reach this point

  1. Path: Fetching key HTTP_REFERER from $_SERVER, and $report is assigned in classes/db_mysql.php on line 626
  1. Fetching key HTTP_REFERER from $_SERVER, and $report is assigned
    in classes/db_mysql.php on line 626
  2. Path: Fetching key HTTP_USER_AGENT from $_SERVER, and $report is assigned in classes/db_mysql.php on line 624
  1. Fetching key HTTP_USER_AGENT from $_SERVER, and $report is assigned
    in classes/db_mysql.php on line 624
  2. $report is assigned
    in classes/db_mysql.php on line 626
  3. Path: Fetching key HTTP_HOST from $_SERVER, and $report is assigned in classes/db_mysql.php on line 623
  1. Fetching key HTTP_HOST from $_SERVER, and $report is assigned
    in classes/db_mysql.php on line 623
  2. $report is assigned
    in classes/db_mysql.php on line 624
  3. $report is assigned
    in classes/db_mysql.php on line 626
  4. Path: Read from $_GET in classes/db_mysql.php on line 577
  1. Read from $_GET
    in classes/db_mysql.php on line 577
  2. Data is passed through gettype()
    in vendor/classes/debug.php on line 306
  3. $msg is assigned
    in classes/db_mysql.php on line 577
  4. $msg is passed to debug::warning()
    in classes/db_mysql.php on line 579
  5. Data is escaped by mysqli_real_escape_string() for sql context(s)
    in vendor/classes/db_mysql_v5.php on line 87
  6. $query is assigned
    in classes/debug.php on line 271
  7. $query is passed to db_mysql::doSql()
    in classes/debug.php on line 276
  8. $query is passed to db_mysql::queryDriver()
    in classes/db_mysql.php on line 272
  9. $stringQuery is assigned
    in classes/db_mysql.php on line 229
  10. $stringQuery is passed through trim(), and $stringQuery is assigned
    in classes/db_mysql.php on line 230
  11. $stringQuery is passed to db_mysql::security_query_check_bad_words()
    in classes/db_mysql.php on line 235
  12. $report is assigned
    in classes/db_mysql.php on line 618
  13. $report is assigned
    in classes/db_mysql.php on line 623
  14. $report is assigned
    in classes/db_mysql.php on line 624
  15. $report is assigned
    in classes/db_mysql.php on line 626
  5. Path: Read from $_POST in classes/db_mysql.php on line 574
  1. Read from $_POST
    in classes/db_mysql.php on line 574
  2. Data is passed through gettype()
    in vendor/classes/debug.php on line 306
  3. $msg is assigned
    in classes/db_mysql.php on line 574
  4. $msg is passed to debug::warning()
    in classes/db_mysql.php on line 579
  5. Data is escaped by mysqli_real_escape_string() for sql context(s)
    in vendor/classes/db_mysql_v5.php on line 87
  6. $query is assigned
    in classes/debug.php on line 271
  7. $query is passed to db_mysql::doSql()
    in classes/debug.php on line 276
  8. $query is passed to db_mysql::queryDriver()
    in classes/db_mysql.php on line 272
  9. $stringQuery is assigned
    in classes/db_mysql.php on line 229
  10. $stringQuery is passed through trim(), and $stringQuery is assigned
    in classes/db_mysql.php on line 230
  11. $stringQuery is passed to db_mysql::security_query_check_bad_words()
    in classes/db_mysql.php on line 235
  12. $report is assigned
    in classes/db_mysql.php on line 618
  13. $report is assigned
    in classes/db_mysql.php on line 623
  14. $report is assigned
    in classes/db_mysql.php on line 624
  15. $report is assigned
    in classes/db_mysql.php on line 626
  6. Path: Read from $_POST in includes/general.php on line 253
  1. Read from $_POST
    in includes/general.php on line 253
  2. sys_get_param() returns tainted data
    in includes/general.php on line 285
  3. Data is passed through strip_tags(), and Data is passed through trim()
    in vendor/includes/general.php on line 1297
  4. sys_get_param_str_unsafe() returns tainted data, and sys_get_param_str_unsafe('uni_name') is passed through strip_tags(), and strip_tags(sys_get_param_str_unsafe('uni_name')) is passed through sprintf(), and sprintf(\classLocale::$lang['uni_msg_admin_rename'], $user['id'], $user['username'], $uni_price, $uni_system ? \classLocale::$lang['uni_system_of'] : \classLocale::$lang['uni_galaxy_of'], $uni_galaxy, $uni_system ? ":{$uni_system}" : '', strip_tags(sys_get_param_str_unsafe('uni_name'))) is passed to debug::warning()
    in includes/includes/uni_rename.php on line 55
  5. Data is escaped by mysqli_real_escape_string() for sql context(s)
    in vendor/classes/db_mysql_v5.php on line 87
  6. $query is assigned
    in classes/debug.php on line 271
  7. $query is passed to db_mysql::doSql()
    in classes/debug.php on line 276
  8. $query is passed to db_mysql::queryDriver()
    in classes/db_mysql.php on line 272
  9. $stringQuery is assigned
    in classes/db_mysql.php on line 229
  10. $stringQuery is passed through trim(), and $stringQuery is assigned
    in classes/db_mysql.php on line 230
  11. $stringQuery is passed to db_mysql::security_query_check_bad_words()
    in classes/db_mysql.php on line 235
  12. $report is assigned
    in classes/db_mysql.php on line 618
  13. $report is assigned
    in classes/db_mysql.php on line 623
  14. $report is assigned
    in classes/db_mysql.php on line 624
  15. $report is assigned
    in classes/db_mysql.php on line 626
  7. Path: Fetching key HTTP_USER_AGENT from $_SERVER, and $report is assigned in classes/db_mysql.php on line 612
  1. Fetching key HTTP_USER_AGENT from $_SERVER, and $report is assigned
    in classes/db_mysql.php on line 612
  2. $report is assigned
    in classes/db_mysql.php on line 618
  3. $report is assigned
    in classes/db_mysql.php on line 623
  4. $report is assigned
    in classes/db_mysql.php on line 624
  5. $report is assigned
    in classes/db_mysql.php on line 626

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
635
        fclose($fp);
636
637
        $message = 'Привет, я не знаю то, что Вы пробовали сделать, но команда, которую Вы только послали базе данных, не выглядела очень дружественной и она была заблокированна.<br /><br />Ваш IP, и другие данные переданны администрации сервера. Удачи!.';
638
        die($message);
639
      break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
640
    }
641
  }
642
643
  /**
644
   * @param bool $prefixed_only
645
   *
646
   * @return array
647
   */
648
  public function db_get_table_list($prefixed_only = true) {
649
    $query = $this->mysql_get_table_list();
650
651
    $prefix_length = strlen($this->db_prefix);
652
653
    $tl = array();
654
    while($row = $this->db_fetch($query)) {
0 ignored issues
show
Bug introduced by
It seems like $query defined by $this->mysql_get_table_list() on line 649 can also be of type boolean; however, db_mysql::db_fetch() does only seem to accept object<mysqli_result>, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
655
      foreach ($row as $table_name) {
656
        if (strpos($table_name, $this->db_prefix) === 0) {
657
          $table_name = substr($table_name, $prefix_length);
658
        } elseif ($prefixed_only) {
659
          continue;
660
        }
661
        // $table_name = str_replace($db_prefix, '', $table_name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
662
        $tl[$table_name] = $table_name;
663
      }
664
    }
665
666
    return $tl;
667
  }
668
669
  /**
670
   * @param string $statement
671
   *
672
   * @return bool|mysqli_stmt
673
   */
674 View Code Duplication
  public function db_prepare($statement) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
675
    $microtime = microtime(true);
676
    $result = $this->driver->mysql_prepare($statement);
677
    $this->time_mysql_total += microtime(true) - $microtime;
678
679
    return $result;
680
  }
681
682
683
  /**
684
   * L1 perform the query
685
   *
686
   * @param $query_string
687
   *
688
   * @return bool|mysqli_result
689
   */
690 View Code Duplication
  public function db_sql_query($query_string) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
691
    $microtime = microtime(true);
692
    $result = $this->driver->mysql_query($query_string);
693
    $this->time_mysql_total += microtime(true) - $microtime;
694
695
    return $result;
696
  }
697
698
  /**
699
   * L1 fetch assoc array
700
   *
701
   * @param mysqli_result $query
702
   *
703
   * @return array|null
704
   */
705 View Code Duplication
  public function db_fetch($query) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
706
    $microtime = microtime(true);
707
    $result = $this->driver->mysql_fetch_assoc($query);
708
    $this->time_mysql_total += microtime(true) - $microtime;
709
710
    return $result;
711
  }
712
713
  public function db_fetch_row(&$query) {
714
    return $this->driver->mysql_fetch_row($query);
715
  }
716
717
  public function db_escape($unescaped_string) {
718
    return $this->driver->mysql_real_escape_string($unescaped_string);
719
  }
720
721
  public function driver_disconnect() {
722
    return $this->driver->mysql_close_link();
723
  }
724
725
  public function db_error() {
726
    return $this->driver->mysql_error();
727
  }
728
729
  public function db_insert_id() {
730
    return $this->driver->mysql_insert_id();
731
  }
732
733
  public function db_num_rows(&$result) {
734
    return $this->driver->mysql_num_rows($result);
735
  }
736
737
  /**
738
   * @return int -1 means error
739
   */
740
  public function db_affected_rows() {
741
    return $this->driver->mysql_affected_rows();
742
  }
743
744
  /**
745
   * @return string
746
   */
747
  public function db_get_client_info() {
748
    return $this->driver->mysql_get_client_info();
749
  }
750
751
  /**
752
   * @return string
753
   */
754
  public function db_get_server_info() {
755
    return $this->driver->mysql_get_server_info();
756
  }
757
758
  /**
759
   * @return string
760
   */
761
  public function db_get_host_info() {
762
    return $this->driver->mysql_get_host_info();
763
  }
764
765
  public function db_get_server_stat() {
766
    $result = array();
767
768
    $status = explode('  ', $this->driver->mysql_stat());
769
    foreach ($status as $value) {
770
      $row = explode(': ', $value);
771
      $result[$row[0]] = $row[1];
772
    }
773
774
    return $result;
775
  }
776
777
  /**
778
   * @return array
779
   * @throws Exception
780
   */
781
  public function db_core_show_status() {
782
    $result = array();
783
784
    $query = $this->db_sql_query('SHOW STATUS;');
785
    if (is_bool($query)) {
786
      throw new Exception('Result of SHOW STATUS command is boolean - which should never happen. Connection to DB is lost?');
787
    }
788
    while($row = db_fetch($query)) {
789
      $result[$row['Variable_name']] = $row['Value'];
790
    }
791
792
    return $result;
793
  }
794
795
  public function mysql_get_table_list() {
796
    return $this->db_sql_query('SHOW TABLES;');
797
  }
798
799
  public function mysql_get_innodb_status() {
800
    return $this->db_sql_query('SHOW ENGINE INNODB STATUS;');
801
  }
802
803
  /**
804
   * @return DbRowDirectOperator
805
   */
806
  public function getOperator() {
807
    return $this->operator;
808
  }
809
810
811
812
  // Some wrappers to DbTransaction
813
  // Unused for now
814
  /**
815
   * @return DbTransaction
816
   */
817
  public function getTransaction() {
818
    return $this->transaction;
819
  }
820
821
  public function transactionCheck($status = null) {
822
    return $this->transaction->check($status);
823
  }
824
825
  public function transactionStart($level = '') {
826
    return $this->transaction->start($level);
827
  }
828
829
  public function transactionCommit() {
830
    return $this->transaction->commit();
831
  }
832
833
  public function transactionRollback() {
834
    return $this->transaction->rollback();
835
  }
836
837
}
838