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

debug::_writeLogMessage()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 8
nop 6
dl 0
loc 12
rs 9.6111
c 0
b 0
f 0
ccs 0
cts 9
cp 0
crap 30
1
<?php
2
3
/*
4
 * debug.php ::  Clase Debug, maneja reporte de eventos
5
 *
6
 * V4.0 copyright 2010-2011 by Gorlum for http://supernova.ws
7
 *  [!] Merged `errors` to `logs`
8
 *  [+] Now debugger can work with database detached. All messages would be dumped to page
9
 *  [+] Now `logs` has both human-readable and machine-readable fields
10
 *
11
 * V3.0 copyright 2010 by Gorlum for http://supernova.ws
12
 *  [+] Full rewrtie & optimize
13
 *  [*] Now there is fallback procedure if no link to db detected
14
 *
15
 * V2.0 copyright 2010 by Gorlum for http://supernova.ws
16
 *  [*] Now error also contains backtrace - to see exact way problem comes
17
 *  [*] New method 'warning' sends message to dedicated SQL-table for non-errors
18
 *
19
 * V1.0 Created by Perberos. All rights reversed (C) 2006
20
 *
21
 *  Experiment code!!!
22
 *
23
 * vamos a experimentar >:)
24
 * le veo futuro a las classes, ayudaria mucho a tener un codigo mas ordenado...
25
 * que esperabas!!! soy newbie!!! D':<
26
*/
27
28
if(!defined('INSIDE')) {
29
  die("attemp hacking");
30
}
31
32
class debug {
33
  protected $log;
34
  protected $numqueries;
35
  protected $log_array;
36
37
  public function log_file($message, $ident_change = 0) {
38
    if (!defined('SN_DEBUG_LOG') || !SN_DEBUG_LOG) {
0 ignored issues
show
Bug introduced by
The constant SN_DEBUG_LOG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
39
      return;
40
    }
41
42
    static $ident = 0;
43
    static $logFileName;
44
45
    if (!$logFileName) {
46
      $logFileName = SN_ROOT_PHYSICAL . '/.logs/supernova.log';
47
      file_put_contents($logFileName, "\r\n\r\n", FILE_APPEND);
48
    }
49
    if ($ident_change < 0) {
50
      $ident += $ident_change * 2;
51
    }
52
    file_put_contents($logFileName, date(FMT_DATE_TIME_SQL, time()) . str_repeat(' ', $ident + 1) . $message . "\r\n", FILE_APPEND);
53
    if ($ident_change > 0) {
54
      $ident += $ident_change * 2;
55
    }
56
  }
57
58
  public function __construct() {
59
    $this->log = '';
60
    $this->numqueries = 0;
61
  }
62
63
  function add($mes) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
64
    $this->log .= $mes;
65
    $this->numqueries++;
66
  }
67
68
  function add_to_array($mes) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
69
    $this->log_array[] = $mes;
70
  }
71
72
  function echo_log() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
73
    echo '<br><table><tr><td class=k colspan=4><a href="' . SN_ROOT_PHYSICAL . "admin/settings.php\">Debug Log</a>:</td></tr>{$this->log}</table>";
74
    die();
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...
75
  }
76
77
  function compact_backtrace($backtrace, $long_comment = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
78
    static $exclude_functions = array(
79
//      'doquery',
80
//      'db_query_select', 'db_query_delete', 'db_query_insert', 'db_query_update',
81
//      'db_get_record_list', 'db_user_by_id', 'db_get_user_by_id'
82
    );
83
84
    $result = array();
85
    $transaction_id = SN::db_transaction_check(false) ? SN::$transaction_id : SN::$transaction_id++;
86
    $result[] = "tID {$transaction_id}";
87
    foreach($backtrace as $a_trace) {
88
      if(in_array($a_trace['function'], $exclude_functions)) {
89
        continue;
90
      }
91
      $function =
92
        (!empty($a_trace['type'])
93
          ? ($a_trace['type'] == '->'
94
            ? "({$a_trace['class']})" . get_class($a_trace['object'])
95
            : $a_trace['class']
96
          ) . $a_trace['type']
97
          : ''
98
        ) . $a_trace['function'] . '()';
99
100
      $file = str_replace(SN_ROOT_PHYSICAL, '', str_replace('\\', '/', !empty($a_trace['file']) ? $a_trace['file'] : ''));
101
102
      $line = !empty($a_trace['line']) ? $a_trace['line'] : '_UNDEFINED_';
103
      $result[] = "{$function} - '{$file}' Line {$line}";
104
105
      if(!$long_comment) {
106
        break;
107
      }
108
    }
109
110
    return $result;
111
  }
112
113
  function dump($dump = false, $force_base = false, $deadlock = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
114
    if($dump === false) {
115
      return [];
116
    }
117
118
    $error_backtrace = array();
119
    $base_dump = false;
120
121
    if($force_base === true) {
122
      $base_dump = true;
123
    }
124
125
    if($dump === true) {
126
      $base_dump = true;
127
    } else {
128
      if(!is_array($dump)) {
129
        $dump = array('var' => $dump);
130
      }
131
132
      foreach($dump as $dump_var_name => $dump_var) {
133
        if($dump_var_name == 'base_dump') {
134
          $base_dump = $dump_var;
135
        } else {
136
          $error_backtrace[$dump_var_name] = $dump_var;
137
        }
138
      }
139
    }
140
141
    if($deadlock && ($q = SN::$db->mysql_get_innodb_status())) {
142
      $error_backtrace['deadlock'] = explode("\n", $q['Status']);
143
      $error_backtrace['locks'] = _SnCacheInternal::$locks;
144
      $error_backtrace['cSN_data'] = _SnCacheInternal::$data;
145
      foreach($error_backtrace['cSN_data'] as &$location) {
146
        foreach($location as $location_id => &$location_data) //          $location_data = $location_id;
147
        {
148
          $location_data = isset($location_data['username']) ? $location_data['username'] :
149
            (isset($location_data['name']) ? $location_data['name'] : $location_id);
150
        }
151
      }
152
    }
153
154
    if($base_dump) {
155
      if(!is_array($this->log_array) || empty($this->log_array)) {
156
        $this->log_array = [];
157
      } else {
158
        foreach($this->log_array as $log) {
159
          $error_backtrace['queries'][] = $log;
160
        }
161
      }
162
163
      $error_backtrace['backtrace'] = debug_backtrace();
164
      unset($error_backtrace['backtrace'][1]);
165
      unset($error_backtrace['backtrace'][0]);
166
167
      // Converting object instances to object names
168
169
      foreach ($error_backtrace['backtrace'] as &$backtrace) {
170
        if(is_object($backtrace['object'])) {
171
          $backtrace['object'] = get_class($backtrace['object']);
172
        }
173
174
        if(empty($backtrace['args'])) {
175
          continue;
176
        }
177
178
        // Doing same conversion for backtrace params
179
        foreach($backtrace['args'] as &$arg) {
180
          if(is_object($arg)) {
181
            $arg = 'object::' . get_class($arg);
182
          }
183
        }
184
      }
185
186
      // $error_backtrace['query_log'] = "\r\n\r\nQuery log\r\n<table><tr><th>Number</th><th>Query</th><th>Page</th><th>Table</th><th>Rows</th></tr>{$this->log}</table>\r\n";
187
      $error_backtrace['$_GET'] = $_GET;
188
      $error_backtrace['$_POST'] = $_POST;
189
      $error_backtrace['$_REQUEST'] = $_REQUEST;
190
      $error_backtrace['$_COOKIE'] = $_COOKIE;
191
      $error_backtrace['$_SESSION'] = $_SESSION;
192
      $error_backtrace['$_SERVER'] = $_SERVER;
193
      global $user, $planetrow;
194
      $error_backtrace['user'] = $user;
195
      $error_backtrace['planetrow'] = $planetrow;
196
    }
197
198
    return $error_backtrace;
199
  }
200
201
  function error_fatal($die_message, $details = 'There is a fatal error on page') {
0 ignored issues
show
Unused Code introduced by
The parameter $details 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

201
  function error_fatal($die_message, /** @scrutinizer ignore-unused */ $details = 'There is a fatal error on page') {

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...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
202
    // TODO - Записывать детали ошибки в лог-файл
203
    die($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...
204
  }
205
206
  function error($message = 'There is a error on page', $title = 'Internal Error', $httpCode = 500, $dump = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
207
    global $config, $sys_stop_log_hit, $lang, $sys_log_disabled, $user;
208
209
    if(empty(SN::$db->connected)) {
210
      // TODO - писать ошибку в файл
211
      die('SQL server currently unavailable. Please contact Administration...');
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...
212
    }
213
214
    SN::db_transaction_rollback();
215
216
    if(SN::$config->debug == 1) {
217
      /** @noinspection HtmlDeprecatedTag */
218
      /** @noinspection XmlDeprecatedElement */
219
      /** @noinspection HtmlDeprecatedAttribute */
220
      echo "<h2>{$title}</h2><br><font color=red>" . htmlspecialchars($message) . "</font><br><hr>";
221
      echo "<table>{$this->log}</table>";
222
    }
223
224
    $fatal_error = 'Fatal error: cannot write to `logs` table. Please contact Administration...';
225
226
    $error_text = SN::$db->db_escape($message);
227
    $error_backtrace = $this->dump($dump, true, strpos($message, 'Deadlock') !== false);
228
229
    if(!$sys_log_disabled) {
230
      $this->_writeLogMessage($httpCode, $user, $title, $message, $error_backtrace, $fatal_error);
231
232
      $message = "Пожалуйста, свяжитесь с админом, если ошибка повторится. Ошибка №: <b>" . SN::$db->db_insert_id() . "</b>";
233
234
      $sys_stop_log_hit = true;
235
      $sys_log_disabled = true;
236
      !function_exists('messageBox') ? die($message) : SnTemplate::messageBox($message, 'Ошибка', '', 0, false);
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...
237
    } else {
238
//        // TODO Здесь надо писать в файло
239
      ob_start();
240
      print("<hr>User ID {$user['id']} raised error code {$httpCode} titled '{$title}' with text '{$error_text}' on page {$_SERVER['SCRIPT_NAME']}");
241
242
      foreach($error_backtrace as $name => $value) {
243
        print('<hr>');
244
        pdump($value, $name);
245
      }
246
      ob_end_flush();
247
      die();
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...
248
    }
249
  }
250
251
  function warning($message, $title = 'System Message', $httpCode = 300, $dump = false) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
252
    global $user, $lang, $sys_log_disabled;
253
254
    if(empty(SN::$db->connected)) {
255
      // TODO - писать ошибку в файл
256
      die('SQL server currently unavailable. Please contact Administration...');
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...
257
    }
258
259
    $fatal_error = 'Fatal error: cannot write to `logs` table. Please contact Administration...';
260
261
    $error_backtrace = $this->dump($dump, false);
262
263
    if(empty($sys_log_disabled)) {
264
      $this->_writeLogMessage($httpCode, $user, $title, $message, $error_backtrace, $fatal_error);
265
    } else {
266
//        // TODO Здесь надо писать в файло
267
      print("<hr>User ID {$user['id']} made log entry with code {$httpCode} titled '{$title}' with text '{$message}' on page {$_SERVER['SCRIPT_NAME']}");
268
    }
269
  }
270
271
  /**
272
   * @param       $httpCode
273
   * @param       $user
274
   * @param       $title
275
   * @param       $message
276
   * @param array $error_backtrace
277
   * @param       $fatal_error
278
   *
279
   * @return void
280
   */
281
  function _writeLogMessage($httpCode, $user, $title, $message, array $error_backtrace, $fatal_error)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
282
  {
283
    /** @noinspection SqlResolve */
284
    $query = "INSERT INTO `{{logs}}` SET
285
        `log_time` = '" . time() . "', `log_code` = '" . SN::$db->db_escape($httpCode) . "', " .
286
      "`log_sender` = '" . ($user['id'] ? SN::$db->db_escape($user['id']) : 0) . "', " .
287
      "`log_username` = '" . SN::$db->db_escape($user['user_name']) . "', " .
288
      "`log_title` = '" . SN::$db->db_escape($title) . "',  `log_text` = '" . SN::$db->db_escape($message) . "', " .
289
      "`log_page` = '" . SN::$db->db_escape(strpos($_SERVER['SCRIPT_NAME'], SN_ROOT_RELATIVE) === false ? $_SERVER['SCRIPT_NAME'] : substr($_SERVER['SCRIPT_NAME'], strlen(SN_ROOT_RELATIVE))) . "'" . ", " .
290
      "`log_dump` = '" . ($error_backtrace ? SN::$db->db_escape(serialize($error_backtrace)) : '') . "'" . ";";
291
292
    doquery($query, '', false, true) or die($fatal_error . SN::$db->db_error());
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...
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

292
    /** @scrutinizer ignore-deprecated */ doquery($query, '', false, true) or die($fatal_error . SN::$db->db_error());
Loading history...
293
  }
294
}
295
296
// Copyright (c) 2009-2010 Gorlum for http://supernova.ws
297
// Dump variables nicer then var_dump()
298
299
function dump($value, $varname = null, $level = 0, $dumper = '') {
300
  if(isset($varname)) {
301
    $varname .= " = ";
302
  }
303
304
  if($level == -1) {
305
    $trans[' '] = '&there4;';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$trans was never initialized. Although not strictly required by PHP, it is generally a good practice to add $trans = array(); before regardless.
Loading history...
306
    $trans["\t"] = '&rArr;';
307
    $trans["\n"] = '&para;;';
308
    $trans["\r"] = '&lArr;';
309
    $trans["\0"] = '&oplus;';
310
311
    return strtr(htmlspecialchars($value), $trans);
312
  }
313
  if($level == 0) {
314
//    $dumper = '<pre>' . mt_rand(10, 99) . '|' . $varname;
315
    $dumper = mt_rand(10, 99) . '|' . $varname;
316
  }
317
318
  $type = gettype($value);
319
  $dumper .= $type;
320
321
  if($type == 'string') {
322
    $dumper .= '(' . strlen($value) . ')';
323
    $value = dump($value, '', -1);
324
  } elseif($type == 'boolean') {
325
    $value = ($value ? 'true' : 'false');
326
  } elseif($type == 'object') {
327
    $props = get_class_vars(get_class($value));
328
    $dumper .= '(' . count($props) . ') <u>' . get_class($value) . '</u>';
329
    foreach($props as $key => $val) {
330
      $dumper .= "\n" . str_repeat("\t", $level + 1) . $key . ' => ';
331
      $dumper .= dump($value->$key, '', $level + 1);
332
    }
333
    $value = '';
334
  } elseif($type == 'array') {
335
    $dumper .= '(' . count($value) . ')';
336
    foreach($value as $key => $val) {
337
      $dumper .= "\n" . str_repeat("\t", $level + 1) . dump($key, '', -1) . ' => ';
338
      $dumper .= dump($val, '', $level + 1);
339
    }
340
    $value = '';
341
  }
342
  $dumper .= " <b>$value</b>";
343
//  if($level == 0) {
344
//    $dumper .= '</pre>';
345
//  }
346
347
  return $dumper;
348
}
349
350
function pdump($value, $varname = null) {
351
  $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
352
//  print_rr($backtrace);
353
//  $backtrace = $backtrace[1];
354
355
  $caller = '';
356
  if(defined('SN_DEBUG_PDUMP_CALLER') && SN_DEBUG_PDUMP_CALLER) {
0 ignored issues
show
Bug introduced by
The constant SN_DEBUG_PDUMP_CALLER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
357
    $caller = (!empty($backtrace[1]['class']) ? $backtrace[1]['class'] : '') .
358
      (!empty($backtrace[1]['type']) ? $backtrace[1]['type'] : '') .
359
      $backtrace[1]['function'] .
360
      (!empty($backtrace[0]['file'])
361
        ? (
362
          ' (' . substr($backtrace[0]['file'], SN_ROOT_PHYSICAL_STR_LEN) .
363
          (!empty($backtrace[0]['line']) ? ':' . $backtrace[0]['line'] : '') .
364
          ')'
365
        )
366
        : ''
367
      );
368
    $caller = "\r\n" . $caller;
369
  }
370
371
  print('<pre style="text-align: left; background-color: #111111; color: #0A0; font-family: Courier, monospace !important; padding: 1em 0; font-weight: 800; font-size: 14px;">' .
372
    dump($value, $varname) .
373
    $caller .
374
    '</pre>'
375
  );
376
}
377
378
function debug($value, $varname = null) {
379
  pdump($value, $varname);
380
}
381
382
function pr($prePrint = false) {
383
  if($prePrint) {
384
    print("<br>");
385
  }
386
  print(mt_rand() . "<br>");
387
}
388
389
function pc($prePrint = false) {
390
  global $_PRINT_COUNT_VALUE;
391
  $_PRINT_COUNT_VALUE++;
392
393
  if($prePrint) {
394
    print("<br>");
395
  }
396
  print($_PRINT_COUNT_VALUE . "<br>");
397
}
398
399
function prep($message) {
400
  print('<pre>' . $message . '</pre>');
401
}
402
403
function backtrace_no_arg() {
404
  $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
405
  array_shift($trace);
406
  return $trace;
407
}